summaryrefslogtreecommitdiff
path: root/src/lj_opt_mem.c
diff options
context:
space:
mode:
authorMike Pall <mike>2012-08-27 20:52:15 +0200
committerMike Pall <mike>2012-08-27 20:53:37 +0200
commitc7826af5a0403b48eeeb6c18532dc076146b1966 (patch)
treeb5f1e86268e3e4ab49d3bb4c8044a9efd61d322f /src/lj_opt_mem.c
parent76b18b2b465532e528af2162e79365794c8ba290 (diff)
downloadluajit2-c7826af5a0403b48eeeb6c18532dc076146b1966.tar.gz
FFI: Detect type punning through unions.
Diffstat (limited to 'src/lj_opt_mem.c')
-rw-r--r--src/lj_opt_mem.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c
index a7e0d35e..560c4ade 100644
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -601,17 +601,8 @@ static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *xa, IRIns *xb)
ptrdiff_t ofsa = 0, ofsb = 0;
IRIns *refb = IR(xb->op1);
IRIns *basea = refa, *baseb = refb;
- /* This implements (very) strict aliasing rules.
- ** Different types do NOT alias, except for differences in signedness.
- ** NYI: this also prevents type punning through unions.
- */
- if (irt_sametype(xa->t, xb->t)) {
- if (refa == refb)
- return ALIAS_MUST; /* Shortcut for same refs with identical type. */
- } else if (!(irt_typerange(xa->t, IRT_I8, IRT_U64) &&
- ((xa->t.irt - IRT_I8) ^ (xb->t.irt - IRT_I8)) == 1)) {
- return ALIAS_NO;
- }
+ if (refa == refb && irt_sametype(xa->t, xb->t))
+ return ALIAS_MUST; /* Shortcut for same refs with identical type. */
/* Offset-based disambiguation. */
if (refa->o == IR_ADD && irref_isk(refa->op2)) {
IRIns *irk = IR(refa->op2);
@@ -629,12 +620,25 @@ static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *xa, IRIns *xb)
if (refa == baseb && ofsb != 0)
return ALIAS_NO; /* base vs. base+-ofs. */
}
+ /* This implements (very) strict aliasing rules.
+ ** Different types do NOT alias, except for differences in signedness.
+ ** Type punning through unions is allowed (but forces a reload).
+ */
if (basea == baseb) {
- /* This assumes strictly-typed, non-overlapping accesses. */
- if (ofsa != ofsb)
- return ALIAS_NO; /* base+-o1 vs. base+-o2 and o1 != o2. */
- return ALIAS_MUST; /* Unsigned vs. signed access to the same address. */
+ ptrdiff_t sza = irt_size(xa->t), szb = irt_size(xb->t);
+ if (ofsa == ofsb) {
+ if (sza == szb && irt_isfp(xa->t) == irt_isfp(xb->t))
+ return ALIAS_MUST; /* Same-sized, same-kind. May need to convert. */
+ } else if (ofsa + sza <= ofsb || ofsb + szb <= ofsa) {
+ return ALIAS_NO; /* Non-overlapping base+-o1 vs. base+-o2. */
+ }
+ /* NYI: extract, extend or reinterpret bits (int <-> fp). */
+ return ALIAS_MAY; /* Overlapping or type punning: force reload. */
}
+ if (!irt_sametype(xa->t, xb->t) &&
+ !(irt_typerange(xa->t, IRT_I8, IRT_U64) &&
+ ((xa->t.irt - IRT_I8) ^ (xb->t.irt - IRT_I8)) == 1))
+ return ALIAS_NO;
/* NYI: structural disambiguation. */
return aa_cnew(J, basea, baseb); /* Try to disambiguate allocations. */
}
@@ -730,7 +734,7 @@ retry:
if (st == IRT_I8 || st == IRT_I16) { /* Trunc + sign-extend. */
st |= IRCONV_SEXT;
} else if (st == IRT_U8 || st == IRT_U16) { /* Trunc + zero-extend. */
- } else if (st == IRT_INT && !irt_isint(IR(store->op2)->t)) {
+ } else if (st == IRT_INT) {
st = irt_type(IR(store->op2)->t); /* Needs dummy CONV.int.*. */
} else { /* I64/U64 are boxed, U32 is hidden behind a CONV.num.u32. */
goto store_fwd;