w6c+w6c_ww: (*p)[i] deref base materializes the array ADDRESS (#61 C)
Both stages SEGV'd identically (byte-id-blind): cgun's TK_STAR emitted a scalar MOVQ (AX),AX for an array pointee, so the index consumed a[0]'s VALUE as its base — a wild deref. An array value IS its address everywhere in this cgen (#270-1a), so the ARRAY pointee now takes the same skip as the #185 *fn deref in both stages: `*p` leaves AX = p's value, and every consumer that materializes a complex index base via cgexpr(base) — N_INDEX read fallback, cgassign store/compound, TK_AMP, N_SLICE — gets the array address from the one deref choke-point. wwstage additionally joins the N_UN-TK_STAR base to the stamped-tinfo esz arms (cgindex / cgassign store + compound / TK_AMP &(*p)[i]) where cstage reads base->type uniformly: without it, esz fell to the 8B default and a narrow element would mis-stride the moment the base started materializing (cs!=ww only reachable post-choke-point-fix, which is why it rides this commit). 949_ptrarr_index_run grows the deref_* rows: read (8B/4B/param-base), write (8B / 1B+neighbor-guards), compound — runtime + byte-id, the only nets that can see a both-stages-identical miscompile.
This commit is contained in:
@@ -3976,11 +3976,19 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* load the first instruction word and CALL
|
||||
* would segfault on that junk. Mirror
|
||||
* ref/harec/src/check.c expr_call's
|
||||
* STORAGE_POINTER→STORAGE_FUNCTION skip. */
|
||||
* STORAGE_POINTER→STORAGE_FUNCTION skip.
|
||||
* #61 C: same skip for an ARRAY pointee — an
|
||||
* array value IS its address everywhere in
|
||||
* this cgen (#270-1a), so `*p` on `*[N]T`
|
||||
* leaves AX = p's value. The scalar load
|
||||
* below pulled a[0]'s VALUE and `(*p)[i]`
|
||||
* then dereferenced it as the index base —
|
||||
* a wild pointer, SIGSEGV on both stages. */
|
||||
Type *rt = n->type;
|
||||
Type *ru = (rt && rt->kind == TY_NAMED)
|
||||
? rt->under : rt;
|
||||
if (ru && ru->kind == TY_FN)
|
||||
if (ru && (ru->kind == TY_FN
|
||||
|| ru->kind == TY_ARRAY))
|
||||
break;
|
||||
}
|
||||
/* f64/f32 result rides X0 (SSE), not AX — an integer
|
||||
|
||||
@@ -21930,7 +21930,8 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
// `s.ptr[i]` / struct-field index: stride is the
|
||||
// checker-stamped element tinfo's natural size, the
|
||||
// same idiom as the N_INDEX-base arm below (#60/#72).
|
||||
@@ -21939,6 +21940,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// so a signed-narrow field element sign-extends on load
|
||||
// (loadopsz keys on (signed,sz)); cstage's fldloadop reads
|
||||
// it from the element type — align ww up (#255).
|
||||
// N_UN deref base (`(*p)[i]`, #61 C): same stamped-tinfo
|
||||
// source — cstage reads base->type uniformly; without
|
||||
// this arm esz fell to the 8B default (wrong stride for
|
||||
// narrow elements once the deref base materializes).
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; signed_elem = typeissigned(dt); elemisstr = typeisstr(dt); elemisslice = typeisslice(dt); float_elem = typeisfloat(dt); f32_elem = typeisf32(dt); };
|
||||
elem_isarray = tinfoisarray(dt);
|
||||
@@ -21997,7 +22002,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// cstage's fallback `MOVQ AX,BX; MOVQ (BX),AX`). #261: without
|
||||
// this an N_DOT-base tagged element fell to the scalar
|
||||
// loadopsz path and silently dropped the tag/payload-high word.
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX) {
|
||||
// N_UN deref base joins for the same reason (#61 C).
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) {
|
||||
if (typeistagged(dt)) {
|
||||
@@ -24489,12 +24496,17 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// `&p.ptr[i]`: stride is the checker-stamped
|
||||
// element tinfo's natural size, mirroring
|
||||
// cgindex's N_DOT arm so &p.ptr[i] and
|
||||
// p.ptr[i] agree. cstage idx_eff(base->type)
|
||||
// ->sub->size (cmd/w6c/cgen.c:3517-18). #72.
|
||||
// N_UN deref base (`&(*p)[i]`, #61 C): same
|
||||
// stamped source; cstage reads base->type
|
||||
// uniformly.
|
||||
let dt: *tinfo = opnd.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; };
|
||||
};};
|
||||
@@ -24583,9 +24595,15 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// would load the first instruction word and a subsequent
|
||||
// CALL would segfault. Mirror ref/harec/src/check.c
|
||||
// expr_call's STORAGE_POINTER→STORAGE_FUNCTION skip.
|
||||
// #61 C: same skip for an ARRAY pointee — an array value IS
|
||||
// its address everywhere in this cgen (#270-1a), so `*p` on
|
||||
// `*[N]T` leaves AX = p's value. The scalar load below
|
||||
// pulled a[0]'s VALUE and `(*p)[i]` then dereferenced it as
|
||||
// the index base — a wild pointer, SIGSEGV on both stages.
|
||||
let rti: *tinfo = n.type_: *tinfo;
|
||||
for (rti != nil && rti.kind == tykind.TY_NAMED) { rti = rti.under; };
|
||||
if (rti != nil && rti.kind == tykind.TY_FN) { return; };
|
||||
if (rti != nil && rti.kind == tykind.TY_ARRAY) { return; };
|
||||
// f64/f32 result rides X0 (SSE), not AX — an integer MOVQ
|
||||
// strands the value off the float ABI and the caller's
|
||||
// MOVSD X0 reads stale bits (#96). Mirrors the float
|
||||
@@ -27232,13 +27250,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// lhs.type_ is the checker-stamped element tinfo
|
||||
// of the N_INDEX: esz is its natural size and the
|
||||
// tagged-element gate (below) reads the same
|
||||
// .type_ — same idiom as cgindex's n.type_ read
|
||||
// (#60/#72). cstage idx_eff(base->type)->sub->size
|
||||
// (cmd/w6c/cgen.c:3517-18).
|
||||
// (cmd/w6c/cgen.c:3517-18). N_UN deref base
|
||||
// (`(*p)[i] = v`, #61 C): same stamped source.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
@@ -27677,7 +27698,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// N_UN deref base (`(*p)[i] OP= v`, #61 C):
|
||||
// same stamped source as the store arm.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
|
||||
@@ -1558,7 +1558,8 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
// `s.ptr[i]` / struct-field index: stride is the
|
||||
// checker-stamped element tinfo's natural size, the
|
||||
// same idiom as the N_INDEX-base arm below (#60/#72).
|
||||
@@ -1567,6 +1568,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// so a signed-narrow field element sign-extends on load
|
||||
// (loadopsz keys on (signed,sz)); cstage's fldloadop reads
|
||||
// it from the element type — align ww up (#255).
|
||||
// N_UN deref base (`(*p)[i]`, #61 C): same stamped-tinfo
|
||||
// source — cstage reads base->type uniformly; without
|
||||
// this arm esz fell to the 8B default (wrong stride for
|
||||
// narrow elements once the deref base materializes).
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; signed_elem = typeissigned(dt); elemisstr = typeisstr(dt); elemisslice = typeisslice(dt); float_elem = typeisfloat(dt); f32_elem = typeisf32(dt); };
|
||||
elem_isarray = tinfoisarray(dt);
|
||||
@@ -1625,7 +1630,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// cstage's fallback `MOVQ AX,BX; MOVQ (BX),AX`). #261: without
|
||||
// this an N_DOT-base tagged element fell to the scalar
|
||||
// loadopsz path and silently dropped the tag/payload-high word.
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX) {
|
||||
// N_UN deref base joins for the same reason (#61 C).
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) {
|
||||
if (typeistagged(dt)) {
|
||||
@@ -4117,12 +4124,17 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// `&p.ptr[i]`: stride is the checker-stamped
|
||||
// element tinfo's natural size, mirroring
|
||||
// cgindex's N_DOT arm so &p.ptr[i] and
|
||||
// p.ptr[i] agree. cstage idx_eff(base->type)
|
||||
// ->sub->size (cmd/w6c/cgen.c:3517-18). #72.
|
||||
// N_UN deref base (`&(*p)[i]`, #61 C): same
|
||||
// stamped source; cstage reads base->type
|
||||
// uniformly.
|
||||
let dt: *tinfo = opnd.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; };
|
||||
};};
|
||||
@@ -4211,9 +4223,15 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// would load the first instruction word and a subsequent
|
||||
// CALL would segfault. Mirror ref/harec/src/check.c
|
||||
// expr_call's STORAGE_POINTER→STORAGE_FUNCTION skip.
|
||||
// #61 C: same skip for an ARRAY pointee — an array value IS
|
||||
// its address everywhere in this cgen (#270-1a), so `*p` on
|
||||
// `*[N]T` leaves AX = p's value. The scalar load below
|
||||
// pulled a[0]'s VALUE and `(*p)[i]` then dereferenced it as
|
||||
// the index base — a wild pointer, SIGSEGV on both stages.
|
||||
let rti: *tinfo = n.type_: *tinfo;
|
||||
for (rti != nil && rti.kind == tykind.TY_NAMED) { rti = rti.under; };
|
||||
if (rti != nil && rti.kind == tykind.TY_FN) { return; };
|
||||
if (rti != nil && rti.kind == tykind.TY_ARRAY) { return; };
|
||||
// f64/f32 result rides X0 (SSE), not AX — an integer MOVQ
|
||||
// strands the value off the float ABI and the caller's
|
||||
// MOVSD X0 reads stale bits (#96). Mirrors the float
|
||||
@@ -6860,13 +6878,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// lhs.type_ is the checker-stamped element tinfo
|
||||
// of the N_INDEX: esz is its natural size and the
|
||||
// tagged-element gate (below) reads the same
|
||||
// .type_ — same idiom as cgindex's n.type_ read
|
||||
// (#60/#72). cstage idx_eff(base->type)->sub->size
|
||||
// (cmd/w6c/cgen.c:3517-18).
|
||||
// (cmd/w6c/cgen.c:3517-18). N_UN deref base
|
||||
// (`(*p)[i] = v`, #61 C): same stamped source.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
@@ -7305,7 +7326,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// N_UN deref base (`(*p)[i] OP= v`, #61 C):
|
||||
// same stamped source as the store arm.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
|
||||
@@ -21930,7 +21930,8 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
// `s.ptr[i]` / struct-field index: stride is the
|
||||
// checker-stamped element tinfo's natural size, the
|
||||
// same idiom as the N_INDEX-base arm below (#60/#72).
|
||||
@@ -21939,6 +21940,10 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// so a signed-narrow field element sign-extends on load
|
||||
// (loadopsz keys on (signed,sz)); cstage's fldloadop reads
|
||||
// it from the element type — align ww up (#255).
|
||||
// N_UN deref base (`(*p)[i]`, #61 C): same stamped-tinfo
|
||||
// source — cstage reads base->type uniformly; without
|
||||
// this arm esz fell to the 8B default (wrong stride for
|
||||
// narrow elements once the deref base materializes).
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; signed_elem = typeissigned(dt); elemisstr = typeisstr(dt); elemisslice = typeisslice(dt); float_elem = typeisfloat(dt); f32_elem = typeisf32(dt); };
|
||||
elem_isarray = tinfoisarray(dt);
|
||||
@@ -21997,7 +22002,9 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
// cstage's fallback `MOVQ AX,BX; MOVQ (BX),AX`). #261: without
|
||||
// this an N_DOT-base tagged element fell to the scalar
|
||||
// loadopsz path and silently dropped the tag/payload-high word.
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX) {
|
||||
// N_UN deref base joins for the same reason (#61 C).
|
||||
if (base.kind == nkind.N_DOT || base.kind == nkind.N_INDEX
|
||||
|| (base.kind == nkind.N_UN && base.op == tkind.TK_STAR)) {
|
||||
let dt: *tinfo = n.type_: *tinfo;
|
||||
if (dt != nil) {
|
||||
if (typeistagged(dt)) {
|
||||
@@ -24489,12 +24496,17 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// `&p.ptr[i]`: stride is the checker-stamped
|
||||
// element tinfo's natural size, mirroring
|
||||
// cgindex's N_DOT arm so &p.ptr[i] and
|
||||
// p.ptr[i] agree. cstage idx_eff(base->type)
|
||||
// ->sub->size (cmd/w6c/cgen.c:3517-18). #72.
|
||||
// N_UN deref base (`&(*p)[i]`, #61 C): same
|
||||
// stamped source; cstage reads base->type
|
||||
// uniformly.
|
||||
let dt: *tinfo = opnd.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; };
|
||||
};};
|
||||
@@ -24583,9 +24595,15 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// would load the first instruction word and a subsequent
|
||||
// CALL would segfault. Mirror ref/harec/src/check.c
|
||||
// expr_call's STORAGE_POINTER→STORAGE_FUNCTION skip.
|
||||
// #61 C: same skip for an ARRAY pointee — an array value IS
|
||||
// its address everywhere in this cgen (#270-1a), so `*p` on
|
||||
// `*[N]T` leaves AX = p's value. The scalar load below
|
||||
// pulled a[0]'s VALUE and `(*p)[i]` then dereferenced it as
|
||||
// the index base — a wild pointer, SIGSEGV on both stages.
|
||||
let rti: *tinfo = n.type_: *tinfo;
|
||||
for (rti != nil && rti.kind == tykind.TY_NAMED) { rti = rti.under; };
|
||||
if (rti != nil && rti.kind == tykind.TY_FN) { return; };
|
||||
if (rti != nil && rti.kind == tykind.TY_ARRAY) { return; };
|
||||
// f64/f32 result rides X0 (SSE), not AX — an integer MOVQ
|
||||
// strands the value off the float ABI and the caller's
|
||||
// MOVSD X0 reads stale bits (#96). Mirrors the float
|
||||
@@ -27232,13 +27250,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// lhs.type_ is the checker-stamped element tinfo
|
||||
// of the N_INDEX: esz is its natural size and the
|
||||
// tagged-element gate (below) reads the same
|
||||
// .type_ — same idiom as cgindex's n.type_ read
|
||||
// (#60/#72). cstage idx_eff(base->type)->sub->size
|
||||
// (cmd/w6c/cgen.c:3517-18).
|
||||
// (cmd/w6c/cgen.c:3517-18). N_UN deref base
|
||||
// (`(*p)[i] = v`, #61 C): same stamped source.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
@@ -27677,7 +27698,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT
|
||||
|| (base.kind == nkind.N_UN
|
||||
&& base.op == tkind.TK_STAR)) {
|
||||
// N_UN deref base (`(*p)[i] OP= v`, #61 C):
|
||||
// same stamped source as the store arm.
|
||||
let dt: *tinfo = lhs.type_: *tinfo;
|
||||
if (dt != nil) { esz = dt.size: i32; elemtn = lhs; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
|
||||
@@ -32,6 +32,18 @@
|
||||
* param / local / cast bases, read / write / compound routes,
|
||||
* neighbor-corruption guards, the &p[i] pointer-difference (B), and
|
||||
* the live consumer's mix-in-place shape (siphash round).
|
||||
*
|
||||
* C. `(*p)[i]` explicit deref + index — BOTH stages SEGV'd
|
||||
* identically (byte-id-blind): cgun's TK_STAR materialized an
|
||||
* 8-byte SCALAR load of a[0]'s value and the index used that
|
||||
* VALUE as its base — a wild deref. Fixed in both stages at the
|
||||
* deref choke-point: an ARRAY pointee takes the #185 *fn skip
|
||||
* (an array value IS its address, #270-1a), so `*p` leaves AX =
|
||||
* p's value and every index/addr-of/store route through
|
||||
* `cgexpr(base)` materializes the array address for free. The
|
||||
* deref_* rows pin read / write / compound at 8B and narrow
|
||||
* widths (the narrow rows also pin the wwstage N_UN-base
|
||||
* stamped-tinfo esz arm against the 8B default).
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -261,6 +273,60 @@ static const struct row rows[] = {
|
||||
" if (v[3] != 11u64) { return 4; };\n"
|
||||
" return 0;\n"
|
||||
"};\n", 0 },
|
||||
/* C: (*p)[i] read, 8B elem (ken p7 — SEGV'd both stages). */
|
||||
{ "deref_rd_u64",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u64 = [100u64, 101u64, 102u64, 103u64];\n"
|
||||
" let p: *[4]u64 = &a;\n"
|
||||
" return (*p)[1]: i32;\n"
|
||||
"};\n", 101 },
|
||||
/* C: (*p)[i] read, 4B elem — pins the N_UN-base esz arm (the 8B
|
||||
* default would mis-stride once the base materializes). */
|
||||
{ "deref_rd_u32",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u32 = [11u32, 22u32, 33u32, 44u32];\n"
|
||||
" let p: *[4]u32 = &a;\n"
|
||||
" return (*p)[2]: i32;\n"
|
||||
"};\n", 33 },
|
||||
/* C: (*p)[i] read through a param base. */
|
||||
{ "deref_rd_param",
|
||||
"package main;\n"
|
||||
"fn rd(p: *[4]u64) u64 = {\n"
|
||||
" return (*p)[1];\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u64 = [100u64, 101u64, 102u64, 103u64];\n"
|
||||
" return rd(&a): i32;\n"
|
||||
"};\n", 101 },
|
||||
/* C: (*p)[i] write, 8B elem. */
|
||||
{ "deref_wr_u64",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u64 = [1u64, 2u64, 3u64, 4u64];\n"
|
||||
" let p: *[4]u64 = &a;\n"
|
||||
" (*p)[1] = 7u64;\n"
|
||||
" return (a[0] + a[1] + a[2]): i32;\n"
|
||||
"};\n", 11 },
|
||||
/* C: (*p)[i] write, 1B elem, neighbor guards. */
|
||||
{ "deref_wr_u8",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u8 = [1u8, 2u8, 3u8, 4u8];\n"
|
||||
" let p: *[4]u8 = &a;\n"
|
||||
" (*p)[1] = 9u8;\n"
|
||||
" return (a[0] + a[1] + a[2]): i32;\n"
|
||||
"};\n", 13 },
|
||||
/* C: (*p)[i] compound. */
|
||||
{ "deref_compound_u64",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: [4]u64 = [100u64, 101u64, 102u64, 103u64];\n"
|
||||
" let p: *[4]u64 = &a;\n"
|
||||
" (*p)[1] += 5u64;\n"
|
||||
" return a[1]: i32;\n"
|
||||
"};\n", 106 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user