diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 45b41a32..7009e613 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -3554,9 +3554,22 @@ cgexpr(Cg *c, Node *n, Local *locals) case TK_CARETEQ: ins2(c, A_XORQ, areg(D_CX), areg(D_AX)); break; case TK_LSHIFTEQ: ins2(c, A_SHLQ, areg(D_CX), areg(D_AX)); break; case TK_RSHIFTEQ: ins2(c, A_SHRQ, areg(D_CX), areg(D_AX)); break; + case TK_SLASHEQ: + case TK_PERCENTEQ: { + int unsignd = (vt && type_isunsigned(vt)) + || (n->rhs && type_isunsigned(n->rhs->type)); + if (unsignd) + ins2(c, A_MOVQ, aimm(0), areg(D_DX)); + else + ins0(c, A_CQO); + ins1(c, unsignd ? A_DIVQ : A_IDIVQ, areg(D_CX)); + if (n->op == TK_PERCENTEQ) + ins2(c, A_MOVQ, areg(D_DX), areg(D_AX)); + break; + } default: - /* TK_SLASHEQ / unknown: store rhs only, - * matching the IDENT-compound fallback. */ + /* unknown compound: legacy fallback — + * store rhs only. */ ins2(c, A_MOVQ, areg(D_CX), areg(D_AX)); break; } @@ -3719,10 +3732,33 @@ cgexpr(Cg *c, Node *n, Local *locals) ins2(c, A_MOVQ, areg(D_AX), areg(D_CX)); ins2(c, A_SHRQ, areg(D_CX), areg(D_BX)); break; + case TK_SLASHEQ: + case TK_PERCENTEQ: { + /* Sister site of the IDENT-local path + * below. Park rhs (AX) in CX, slot value + * (BX) into AX, CQO sign-extend (or + * MOVQ $0, DX zero-extend), IDIVQ (or + * DIVQ) CX, ferry AX (quotient) or DX + * (remainder) back to BX for the shared + * store-BX tail. */ + int unsignd = (n->lhs && type_isunsigned(n->lhs->type)) + || (n->rhs && type_isunsigned(n->rhs->type)); + ins2(c, A_MOVQ, areg(D_AX), areg(D_CX)); + ins2(c, A_MOVQ, areg(D_BX), areg(D_AX)); + if (unsignd) + ins2(c, A_MOVQ, aimm(0), areg(D_DX)); + else + ins0(c, A_CQO); + ins1(c, unsignd ? A_DIVQ : A_IDIVQ, areg(D_CX)); + if (n->op == TK_SLASHEQ) + ins2(c, A_MOVQ, areg(D_AX), areg(D_BX)); + else + ins2(c, A_MOVQ, areg(D_DX), areg(D_BX)); + break; + } default: - /* Unsupported compound op: store rhs - * directly. Mirrors the local path's - * fallback for TK_SLASHEQ etc. */ + /* unknown compound: legacy fallback — + * store rhs only. */ did_compound = 0; ins2(c, A_MOVQ, areg(D_AX), masym(c, n->lhs->str)); @@ -3772,12 +3808,29 @@ cgexpr(Cg *c, Node *n, Local *locals) ins2(c, A_SHRQ, areg(D_CX), areg(D_BX)); break; case TK_SLASHEQ: - /* BX = BX / AX. IDIV uses DX:AX/RAX. Move - * BX→AX first, sign-extend via CQO would be - * cleanest; skip for now and fall back to - * MOVQ to avoid emitting wrong code. */ - ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, off)); - goto skip_assign_store; + case TK_PERCENTEQ: { + /* IDIV/DIV needs dividend in RDX:RAX, divisor + * in a GPR. Park rhs (currently AX) in CX, move + * slot value (BX) into AX, sign- or zero-extend + * into RDX:RAX, divide, then ferry the quotient + * (AX) or remainder (DX) back into BX for the + * shared store-BX-to-slot tail below. Post-#16: + * CQO is now in the assembler. */ + int unsignd = (n->lhs && type_isunsigned(n->lhs->type)) + || (n->rhs && type_isunsigned(n->rhs->type)); + ins2(c, A_MOVQ, areg(D_AX), areg(D_CX)); + ins2(c, A_MOVQ, areg(D_BX), areg(D_AX)); + if (unsignd) + ins2(c, A_MOVQ, aimm(0), areg(D_DX)); + else + ins0(c, A_CQO); + ins1(c, unsignd ? A_DIVQ : A_IDIVQ, areg(D_CX)); + if (n->op == TK_SLASHEQ) + ins2(c, A_MOVQ, areg(D_AX), areg(D_BX)); + else + ins2(c, A_MOVQ, areg(D_DX), areg(D_BX)); + break; + } default: /* unknown: just store rhs (legacy fallback) */ ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off)); diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 32c2e414..daafa212 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -13124,6 +13124,10 @@ fn cgassign(c: *cgen, n: *node) void = { let inner: *node = lhs.lhs; let loadop: str = "MOVQ"; let storeop: str = "MOVQ"; + // Pointee node for the lhs-sign side of the /= + // and %= dispatch. Mirror of cstage's `vt` at + // cmd/w6c/cgen.c's TK_STAR-compound branch. + let pe: *node = nil; if (inner != nil) { if (inner.kind == nkind.N_IDENT) { let lc: *local = localfindnode(c, inner.str); @@ -13131,7 +13135,7 @@ fn cgassign(c: *cgen, n: *node) void = { let tn: *node = lc.tnode; if (tn != nil) { if (tn.kind == nkind.N_TPTR) { - let pe: *node = tn.lhs; + pe = tn.lhs; if (pe != nil) { let ps: i32 = fieldsize(c, pe); if (ps == 1 || ps == 2 || ps == 4) { @@ -13152,6 +13156,30 @@ fn cgassign(c: *cgen, n: *node) void = { emitline(loadop); emitline("\t(BX), AX\n"); emitline("\tPOPQ\tCX\n"); + // Post-63332fe: /= and %= via CQO/IDIVQ on the + // signed arm and MOVQ-zero/DIVQ on the unsigned + // arm. Pre-fix the default branch silently stored + // rhs into *p (combineop = MOVQ shape). + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, pe); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_PERCENTEQ) { + emitline("\tMOVQ\tDX, AX\n"); + }; + emitline("\t"); + emitline(storeop); + emitline("\tAX, (BX)\n"); + return; + }; let combineop: str = "MOVQ"; if (n.op == tkind.TK_PLUSEQ) { combineop = "ADDQ"; } else { if (n.op == tkind.TK_MINUSEQ) { combineop = "SUBQ"; } @@ -14976,15 +15004,41 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); } + // Post-63332fe: /= and %= for a top-level + // let. Same shape as the IDENT-local path: + // park rhs in CX, slot value (BX) into AX, + // CQO (or zero DX), IDIVQ (or DIVQ) CX, + // ferry AX or DX back to BX for the shared + // store-BX tail below. + else { if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, lvftn); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + } else { // Unsupported compound: store rhs // directly. Mirrors the local path's - // fallback for TK_SLASHEQ etc. + // legacy fallback for unknown ops. didcompound = false; emitline("\tMOVQ\tAX, "); emitsymname(c, nm); emitline("(SB)\n"); - };};};};};};};}; + };};};};};};};};}; if (didcompound) { emitline("\tMOVQ\tBX, "); emitsymname(c, nm); @@ -15215,6 +15269,36 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); }; + // Post-63332fe: /= and %= for an IDENT local. Pre-fix + // fell through with no case, so BX (still holding the + // freshly loaded slot value) was stored back unchanged + // — a silent no-op rather than the natural rhs-only + // shape the global/deref siblings took. Park rhs in + // CX, slot value (BX) into AX, CQO/IDIVQ, ferry AX + // (quotient) or DX (remainder) back to BX. + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = false; + if (lcn != nil) { + unsignd = typenodeisunsignedc(c, lcn.tnode); + }; + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + }; emitline("\tMOVQ\tBX, "); emitoff(off: i64); emitline("(BP)\n"); diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index 5f44a073..48904996 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -3307,6 +3307,10 @@ fn cgassign(c: *cgen, n: *node) void = { let inner: *node = lhs.lhs; let loadop: str = "MOVQ"; let storeop: str = "MOVQ"; + // Pointee node for the lhs-sign side of the /= + // and %= dispatch. Mirror of cstage's `vt` at + // cmd/w6c/cgen.c's TK_STAR-compound branch. + let pe: *node = nil; if (inner != nil) { if (inner.kind == nkind.N_IDENT) { let lc: *local = localfindnode(c, inner.str); @@ -3314,7 +3318,7 @@ fn cgassign(c: *cgen, n: *node) void = { let tn: *node = lc.tnode; if (tn != nil) { if (tn.kind == nkind.N_TPTR) { - let pe: *node = tn.lhs; + pe = tn.lhs; if (pe != nil) { let ps: i32 = fieldsize(c, pe); if (ps == 1 || ps == 2 || ps == 4) { @@ -3335,6 +3339,30 @@ fn cgassign(c: *cgen, n: *node) void = { emitline(loadop); emitline("\t(BX), AX\n"); emitline("\tPOPQ\tCX\n"); + // Post-63332fe: /= and %= via CQO/IDIVQ on the + // signed arm and MOVQ-zero/DIVQ on the unsigned + // arm. Pre-fix the default branch silently stored + // rhs into *p (combineop = MOVQ shape). + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, pe); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_PERCENTEQ) { + emitline("\tMOVQ\tDX, AX\n"); + }; + emitline("\t"); + emitline(storeop); + emitline("\tAX, (BX)\n"); + return; + }; let combineop: str = "MOVQ"; if (n.op == tkind.TK_PLUSEQ) { combineop = "ADDQ"; } else { if (n.op == tkind.TK_MINUSEQ) { combineop = "SUBQ"; } @@ -5159,15 +5187,41 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); } + // Post-63332fe: /= and %= for a top-level + // let. Same shape as the IDENT-local path: + // park rhs in CX, slot value (BX) into AX, + // CQO (or zero DX), IDIVQ (or DIVQ) CX, + // ferry AX or DX back to BX for the shared + // store-BX tail below. + else { if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, lvftn); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + } else { // Unsupported compound: store rhs // directly. Mirrors the local path's - // fallback for TK_SLASHEQ etc. + // legacy fallback for unknown ops. didcompound = false; emitline("\tMOVQ\tAX, "); emitsymname(c, nm); emitline("(SB)\n"); - };};};};};};};}; + };};};};};};};};}; if (didcompound) { emitline("\tMOVQ\tBX, "); emitsymname(c, nm); @@ -5398,6 +5452,36 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); }; + // Post-63332fe: /= and %= for an IDENT local. Pre-fix + // fell through with no case, so BX (still holding the + // freshly loaded slot value) was stored back unchanged + // — a silent no-op rather than the natural rhs-only + // shape the global/deref siblings took. Park rhs in + // CX, slot value (BX) into AX, CQO/IDIVQ, ferry AX + // (quotient) or DX (remainder) back to BX. + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = false; + if (lcn != nil) { + unsignd = typenodeisunsignedc(c, lcn.tnode); + }; + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + }; emitline("\tMOVQ\tBX, "); emitoff(off: i64); emitline("(BP)\n"); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 19d628e3..24ee16e0 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -13124,6 +13124,10 @@ fn cgassign(c: *cgen, n: *node) void = { let inner: *node = lhs.lhs; let loadop: str = "MOVQ"; let storeop: str = "MOVQ"; + // Pointee node for the lhs-sign side of the /= + // and %= dispatch. Mirror of cstage's `vt` at + // cmd/w6c/cgen.c's TK_STAR-compound branch. + let pe: *node = nil; if (inner != nil) { if (inner.kind == nkind.N_IDENT) { let lc: *local = localfindnode(c, inner.str); @@ -13131,7 +13135,7 @@ fn cgassign(c: *cgen, n: *node) void = { let tn: *node = lc.tnode; if (tn != nil) { if (tn.kind == nkind.N_TPTR) { - let pe: *node = tn.lhs; + pe = tn.lhs; if (pe != nil) { let ps: i32 = fieldsize(c, pe); if (ps == 1 || ps == 2 || ps == 4) { @@ -13152,6 +13156,30 @@ fn cgassign(c: *cgen, n: *node) void = { emitline(loadop); emitline("\t(BX), AX\n"); emitline("\tPOPQ\tCX\n"); + // Post-63332fe: /= and %= via CQO/IDIVQ on the + // signed arm and MOVQ-zero/DIVQ on the unsigned + // arm. Pre-fix the default branch silently stored + // rhs into *p (combineop = MOVQ shape). + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, pe); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_PERCENTEQ) { + emitline("\tMOVQ\tDX, AX\n"); + }; + emitline("\t"); + emitline(storeop); + emitline("\tAX, (BX)\n"); + return; + }; let combineop: str = "MOVQ"; if (n.op == tkind.TK_PLUSEQ) { combineop = "ADDQ"; } else { if (n.op == tkind.TK_MINUSEQ) { combineop = "SUBQ"; } @@ -14976,15 +15004,41 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); } + // Post-63332fe: /= and %= for a top-level + // let. Same shape as the IDENT-local path: + // park rhs in CX, slot value (BX) into AX, + // CQO (or zero DX), IDIVQ (or DIVQ) CX, + // ferry AX or DX back to BX for the shared + // store-BX tail below. + else { if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = typenodeisunsignedc(c, lvftn); + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + } else { // Unsupported compound: store rhs // directly. Mirrors the local path's - // fallback for TK_SLASHEQ etc. + // legacy fallback for unknown ops. didcompound = false; emitline("\tMOVQ\tAX, "); emitsymname(c, nm); emitline("(SB)\n"); - };};};};};};};}; + };};};};};};};};}; if (didcompound) { emitline("\tMOVQ\tBX, "); emitsymname(c, nm); @@ -15215,6 +15269,36 @@ fn cgassign(c: *cgen, n: *node) void = { emitline("\tMOVQ\tAX, CX\n"); emitline("\tSHRQ\tCX, BX\n"); }; + // Post-63332fe: /= and %= for an IDENT local. Pre-fix + // fell through with no case, so BX (still holding the + // freshly loaded slot value) was stored back unchanged + // — a silent no-op rather than the natural rhs-only + // shape the global/deref siblings took. Park rhs in + // CX, slot value (BX) into AX, CQO/IDIVQ, ferry AX + // (quotient) or DX (remainder) back to BX. + if (n.op == tkind.TK_SLASHEQ || n.op == tkind.TK_PERCENTEQ) { + let unsignd: bool = false; + if (lcn != nil) { + unsignd = typenodeisunsignedc(c, lcn.tnode); + }; + if (!unsignd) { + unsignd = nodeisunsigned(c, n.rhs); + }; + emitline("\tMOVQ\tAX, CX\n"); + emitline("\tMOVQ\tBX, AX\n"); + if (unsignd) { + emitline("\tMOVQ\t$0, DX\n"); + emitline("\tDIVQ\tCX\n"); + } else { + emitline("\tCQO\n"); + emitline("\tIDIVQ\tCX\n"); + }; + if (n.op == tkind.TK_SLASHEQ) { + emitline("\tMOVQ\tAX, BX\n"); + } else { + emitline("\tMOVQ\tDX, BX\n"); + }; + }; emitline("\tMOVQ\tBX, "); emitoff(off: i64); emitline("(BP)\n"); diff --git a/test/wcc/978_intdiv_signed.c b/test/wcc/978_intdiv_signed.c index e0ac55d2..4f9b1c64 100644 --- a/test/wcc/978_intdiv_signed.c +++ b/test/wcc/978_intdiv_signed.c @@ -283,6 +283,93 @@ static const struct row rows[] = { " return 0;\n" "};\n", 42 }, + + /* ---- COMPOUND ASSIGN rows ------------------------------------- * + * + * The siblings of the binary `/` and `%` paths above: `x /= v`, + * `x %= v`, and `*p /= v`. Pre-#16's-B2 these emitted the worst + * shape catalog: + * - cstage cgen.c:3765 IDENT-local: silent no-op (BX held + * loaded slot value, the trailing store wrote it back + * unchanged — no IDIV emit at all). + * - wwstage cgenexpr.ww:5381-5403 IDENT-local: identical silent + * no-op shape; the load-bearing sentinel — a future regression + * here passes byte-id (no asm = no divergence) AND passes the + * selfhost corpus (no consumer of signed compound /=). The + * semantic test below is the only catch. + * - cstage cgen.c:3549 / wwstage cgenexpr.ww:3338 deref-compound + * `*p OP= v`: silent rhs-only store, value of *p clobbered with + * the divisor instead of computed quotient. + * + * Top-level-let compound coverage (cstage cgen.c:3735 / wwstage + * cgenexpr.ww:5147) is deferred per task #18 — the inline-driver + * 978 fixture can't currently exercise it because of a pre-existing + * linker `undefined reference to '.gs'` for single-file + * top-level lets that flow through `LEAQ name(SB)`. The cstage:3735 + * and wwstage:5147 sites are code-review-verified for rule-10 + * symmetry; runtime coverage follows once #18 lands. */ + { "compound_ident_local_div_neg_dividend", + "fn main() i32 = {\n" + " let a: i64 = -100i64;\n" + " a /= 7i64;\n" + " if (a == -14i64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_ident_local_mod_neg_dividend", + "fn main() i32 = {\n" + " let a: i64 = -100i64;\n" + " a %= 7i64;\n" + " if (a == -2i64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_ident_local_div_neg_divisor", + "fn main() i32 = {\n" + " let a: i64 = 100i64;\n" + " a /= -7i64;\n" + " if (a == -14i64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_ident_local_div_unsigned", + "fn main() i32 = {\n" + " let a: u64 = 0x8000000000000001u64;\n" + " a /= 2u64;\n" + " if (a == 0x4000000000000000u64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_deref_div_neg_dividend", + "fn main() i32 = {\n" + " let arr: [1]i64;\n" + " arr[0] = -50i64;\n" + " let p: *i64 = &arr[0];\n" + " *p /= 3i64;\n" + " if (arr[0] == -16i64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_deref_mod_neg_dividend", + "fn main() i32 = {\n" + " let arr: [1]i64;\n" + " arr[0] = -50i64;\n" + " let p: *i64 = &arr[0];\n" + " *p %= 3i64;\n" + " if (arr[0] == -2i64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, + { "compound_deref_div_unsigned", + "fn main() i32 = {\n" + " let arr: [1]u64;\n" + " arr[0] = 0x8000000000000001u64;\n" + " let p: *u64 = &arr[0];\n" + " *p /= 2u64;\n" + " if (arr[0] == 0x4000000000000000u64) { return 42; };\n" + " return 0;\n" + "};\n", + 42 }, }; static int