[M3devel] m3_load/m3_store/bit_field_ref lose offset??
Jay
jay.krell at cornell.edu
Sat Nov 8 16:40:50 CET 2008
Tony, how about switching these #if's?
I explain some of why below.
parse.c:
static void
m3_store (tree v, int o, tree src_t, m3_type src_T, tree dst_t, m3_type dst_T)
{
tree val;
#if 0
if (o != 0 || TREE_TYPE (v) != dst_t) {
v = m3_build3 (BIT_FIELD_REF, dst_t, v, TYPE_SIZE (dst_t),
bitsize_int (o));
}
#else
/* failsafe, but inefficient */
if (o != 0 || TREE_TYPE (v) != dst_t) {
v = m3_build1 (ADDR_EXPR, t_addr, v);
v = m3_build2 (PLUS_EXPR, t_addr, v, size_int (o / BITS_PER_UNIT));
v = m3_build1 (INDIRECT_REF, dst_t,
m3_cast (build_pointer_type (dst_t), v));
}
#endif
TREE_THIS_VOLATILE (v) = 1; /* force this to avoid aliasing problems */
val = m3_cast (src_t, EXPR_REF (-1));
if (src_T != dst_T) {
val = m3_build1 (CONVERT_EXPR, dst_t, val);
}
add_stmt (build2 (MODIFY_EXPR, dst_t, v, val));
EXPR_POP ();
}
m3_load (tree v, int o, tree src_t, m3_type src_T, tree dst_t, m3_type dst_T)
{
#if 0
if (o != 0 || TREE_TYPE (v) != src_t) {
v = m3_build3 (BIT_FIELD_REF, src_t, v, TYPE_SIZE (src_t),
bitsize_int (o));
}
#else
/* failsafe, but inefficient */
if (o != 0 || TREE_TYPE (v) != src_t) {
v = m3_build1 (ADDR_EXPR, t_addr, v);
v = m3_build2 (PLUS_EXPR, t_addr, v, size_int (o / BITS_PER_UNIT));
v = m3_build1 (INDIRECT_REF, src_t,
m3_cast (build_pointer_type (src_t), v));
}
#endif
TREE_THIS_VOLATILE (v) = 1; /* force this to avoid aliasing problems */
if (src_T != dst_T) {
v = m3_build1 (CONVERT_EXPR, dst_t, v);
}
EXPR_PUSH (v);
}
I'm working on MIPS64_OPENBSD (OpenBSD on an SGI O2).
In an early version it seems that many loads/stores of global variables is wrong.
The first code affected is RTLinker_ExpandModuleTable.
PROCEDURE ExpandModuleTable () =
CONST InitialTableSize = 500;
VAR new_mods: ADDRESS; n_bytes: INTEGER;
BEGIN
IF (modules = NIL) THEN
(* first time... *)
max_modules := InitialTableSize;
modules := Cstdlib.malloc (InitialTableSize * BYTESIZE (RT0.ModulePtr));
IF (modules = NIL) THEN Cstdlib.abort (); END;
ELSE
n_bytes := max_modules * BYTESIZE (RT0.ModulePtr);
new_mods := Cstdlib.malloc (n_bytes + n_bytes);
IF (new_mods = NIL) THEN Cstdlib.abort (); END;
EVAL Cstring.memcpy (new_mods, modules, n_bytes);
Cstdlib.free (modules);
modules := new_mods;
INC (max_modules, max_modules);
END;
END ExpandModuleTable;
It should read back modules as NIL.
What happens is it reads back modules as not NIL,
and then max_modules should also be zero, but is "large", leading to malloc to fail,
and abort called.
The output of cm3cg -y is reasonable.
It indicates offset loads.
What is incorrect is that in many loads and stores, but not all, the
offsets are lost.
(923) begin_procedure
procedure RTLinker__ExpandModuleTable
RTLinker__ExpandModuleTable(924) set_source_line
source line 208
(925) load_nil
(926) store
store (M3_AJWxb1_new_mods) offset 0x0 src_t 0xb dst_t 0xb
(927) set_source_line
source line 207
(928) set_source_line
source line 210
(929) load_nil
(930) load
m3cg_load (MM_RTLinker): offset 0x440, convert 0xb -> 0xb
Here is the incorrect code:
.globl RTLinker__ExpandModuleTable
.stabd 46,0,0
.stabn 68,0,206,.LM108
.LM108:
.LFBB8:
.set nomips16
.ent RTLinker__ExpandModuleTable
RTLinker__ExpandModuleTable:
.frame $fp,64,$31 # vars= 32, regs= 3/0, args= 0, gp= 0
.mask 0xd0000000,-8
.fmask 0x00000000,0
daddiu $sp,$sp,-64
sd $31,56($sp)
sd $fp,48($sp)
sd $28,40($sp)
move $fp,$sp
lui $28,%hi(%neg(%gp_rel(RTLinker__ExpandModuleTable)))
daddu $28,$28,$25
daddiu $28,$28,%lo(%neg(%gp_rel(RTLinker__ExpandModuleTable)))
.LBB9:
.stabn 68,0,208,.LM109
.LM109:
sd $0,16($fp)
.stabn 68,0,210,.LM110
.LM110:
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
bne $2,$0,.L61
.stabn 68,0,212,.LM111
.LM111:
dla $3,MM_RTLinker
ld $2,128($3)
andi $2,$2,0x0
ori $2,$2,0x1f4
sd $2,128($3)
.stabn 68,0,213,.LM112
.LM112:
li $4,4000 # 0xfa0
jal malloc
sd $2,0($fp)
ld $4,0($fp)
dla $3,MM_RTLinker
ld $2,136($3)
andi $2,$2,0x0
or $2,$4,$2
sd $2,136($3) << OK, offset seems low, but it agrees with elsewhere
.stabn 68,0,214,.LM113
.LM113:
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
bne $2,$0,.L65
jal abort
b .L65
.L61:
.stabn 68,0,216,.LM114
.LM114:
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
dsll $2,$2,3
sd $2,8($fp)
.stabn 68,0,217,.LM115
.LM115:
ld $3,8($fp)
ld $2,8($fp)
daddu $2,$3,$2
move $4,$2
jal malloc
sd $2,0($fp)
ld $2,0($fp)
sd $2,16($fp)
.stabn 68,0,218,.LM116
.LM116:
ld $2,16($fp)
bne $2,$0,.L64
jal abort
.L64:
.stabn 68,0,219,.LM117
.LM117:
ld $4,16($fp)
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
ld $3,8($fp)
move $5,$2
move $6,$3
jal memcpy
sd $2,0($fp)
.stabn 68,0,220,.LM118
.LM118:
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
move $4,$2
jal free
.stabn 68,0,221,.LM119
.LM119:
ld $4,16($fp)
dla $3,MM_RTLinker
ld $2,136($3) << OK
andi $2,$2,0x0
or $2,$4,$2
sd $2,136($3) << OK
.stabn 68,0,222,.LM120
.LM120:
dla $2,MM_RTLinker
ld $3,0($2) << WRONG
dla $2,MM_RTLinker
ld $2,0($2) << WRONG
daddu $4,$3,$2
dla $3,MM_RTLinker
ld $2,128($3) << OK
andi $2,$2,0x0
or $2,$2,$4
sd $2,128($3) << OK
.L65:
.LBE9:
.stabn 68,0,224,.LM121
.LM121:
move $sp,$fp
ld $31,56($sp)
ld $fp,48($sp)
ld $28,40($sp)
daddiu $sp,$sp,64
j $31
.end RTLinker__ExpandModuleTable
Here is corrected code:
RTLinker__ExpandModuleTable:
.frame $fp,64,$31 # vars= 32, regs= 3/0, args= 0, gp= 0
.mask 0xd0000000,-8
.fmask 0x00000000,0
daddiu $sp,$sp,-64
sd $31,56($sp)
sd $fp,48($sp)
sd $28,40($sp)
move $fp,$sp
lui $28,%hi(%neg(%gp_rel(RTLinker__ExpandModuleTable)))
daddu $28,$28,$25
daddiu $28,$28,%lo(%neg(%gp_rel(RTLinker__ExpandModuleTable)))
.LBB9:
.stabn 68,0,208,.LM109
.LM109:
sd $0,16($fp)
.stabn 68,0,210,.LM110
.LM110:
dla $2,MM_RTLinker
daddiu $2,$2,136 << CORRECT (offset seems low, but at least it isn't zero)
ld $2,0($2)
bne $2,$0,.L61
.stabn 68,0,212,.LM111
.LM111:
dla $2,MM_RTLinker
daddiu $3,$2,128 << CORRECT
li $2,500 # 0x1f4
sd $2,0($3)
.stabn 68,0,213,.LM112
.LM112:
li $4,4000 # 0xfa0
jal malloc
sd $2,0($fp)
dla $2,MM_RTLinker
daddiu $3,$2,136 << CORRECT
ld $2,0($fp)
sd $2,0($3)
.stabn 68,0,214,.LM113
.LM113:
dla $2,MM_RTLinker
daddiu $2,$2,136 << CORRECT
ld $2,0($2)
bne $2,$0,.L65
jal abort
b .L65
.L61:
I still dump core with this change, but I get much further.
I have not tested this change at all otherwise -- i.e. on working platforms.
I have not debugged through the gcc/m3cg code to see why
the offsets are only sometimes lost, or why other platforms
have no problem. Is MIPS's "global pointer" unusual these days?
I know SPARC has similar, and all the non-x86, non-AMD64 NT platforms
had similar, but that's essentially nothing now (I'm not counting IA64).
I know Linux has PLT (procedure linkage table) and GOT (global offset table).
Same thing?
I haven't looked much at other MIPS ports yet.
http://modula3.elegosoft.com/cgi-bin/cvsweb.cgi/cm3/m3-sys/m3cc/gcc/gcc/m3cg/parse.c.diff?r1=1.7;r2=1.8
is what made it look about like it does -- in particularing using BIT_FIELD_REF.
1.7:
static void m3_load (v, o, src_t, src_T, dest_t, dest_T) /* GCC32OK */
tree v;
int o;
tree src_t, dest_t;
m3_type src_T, dest_T;
{
if (o == 0 && TREE_TYPE (v) == src_t) {
EXPR_PUSH (v);
} else {
tree adr = m3_build1 (ADDR_EXPR, t_addr, v);
if (o != 0) {
adr = m3_build2 (PLUS_EXPR, t_addr, adr, size_int (o / BITS_PER_UNIT));
}
EXPR_PUSH (m3_build1 (INDIRECT_REF, src_t,
m3_cast (build_pointer_type (src_t), adr)));
}
#if 1
if (src_T != dest_T) {
EXPR_REF (-1) = m3_build1 (CONVERT_EXPR, dest_t, EXPR_REF (-1));
}
if (debug_vars) {
const char *name = "noname";
if (v != 0 && DECL_NAME(v) != 0) {
name = IDENTIFIER_POINTER(DECL_NAME(v));
}
fprintf(stderr, " m3_load (%s): offset %d, convert %d -> %d\n", name,
o, src_T, dest_T);
}
#else
if (src_T != dest_T) {
if (IS_INTEGER_TYPE(dest_T) && dest_t != t_int) {
EXPR_REF (-1) = m3_build1 (CONVERT_EXPR, t_int, EXPR_REF (-1));
} else if (IS_WORD_TYPE(dest_T) && dest_t != t_word) {
EXPR_REF (-1) = m3_build1 (CONVERT_EXPR, t_word, EXPR_REF (-1));
} else if (IS_INTEGER_TYPE(dest_T) || IS_WORD_TYPE(dest_T)) {
/* okay */
} else {
fatal_error("m3load: cannot convert types: src_t %d dest_t %d\n",
src_T, dest_T);
}
}
#endif
}
static void
m3_store (v, o, src_t, dest_t) /* GCC32OK */
tree v;
int o;
tree src_t, dest_t;
{
tree lhs, rhs;
if (TREE_TYPE (EXPR_REF (-1)) == src_t) {
rhs = EXPR_REF (-1);
} else {
rhs = m3_cast (src_t, EXPR_REF (-1));
}
if (o == 0 && TREE_TYPE (v) == dest_t) {
lhs = v;
} else {
tree f = make_node (FIELD_DECL);
TREE_TYPE (f) = dest_t;
DECL_ALIGN (f) = TYPE_ALIGN (dest_t);
DECL_SIZE (f) = TYPE_SIZE (dest_t);
DECL_MODE (f) = TYPE_MODE (dest_t);
DECL_FIELD_OFFSET (f) = size_int (o / BITS_PER_UNIT);
DECL_FIELD_BIT_OFFSET (f) = bitsize_int (o % BITS_PER_UNIT);
DECL_FIELD_CONTEXT (f) = TREE_TYPE (v);
lhs = m3_build2 (COMPONENT_REF, dest_t, v, f);
}
#if 1
expand_assignment (lhs, m3_build1 (CONVERT_EXPR, dest_t, rhs), 0, 0);
#else
if (dest_t == NULL) {
expand_assignment (lhs, rhs, 0, 0);
} else {
expand_assignment (lhs, m3_build1 (CONVERT_EXPR, dest_t, rhs), 0, 0);
}
#endif
EXPR_POP ();
}
1.8:
static void
m3_load (tree v, int o,
tree src_t, m3_type src_T,
tree dst_t, m3_type dst_T) /* GCC32OK */
{
if (o == 0 && TREE_TYPE (v) == src_t) {
EXPR_PUSH (v);
} else {
EXPR_PUSH (m3_build3 (BIT_FIELD_REF, src_t, v, TYPE_SIZE (src_t),
bitsize_int (o)));
}
if (src_T != dst_T) {
EXPR_REF (-1) = m3_build1 (CONVERT_EXPR, dst_t, EXPR_REF (-1));
}
if (option_vars_trace) {
const char *name = "noname";
if (v != 0 && DECL_NAME(v) != 0) {
name = IDENTIFIER_POINTER(DECL_NAME(v));
}
fprintf(stderr, " m3_load (%s): offset %d, convert %d -> %d\n", name,
o, src_T, dst_T);
}
}
static void
m3_store (tree v, int o, tree src_t, tree dst_t) /* GCC32OK */
{
tree lhs, rhs;
if (TREE_TYPE (EXPR_REF (-1)) == src_t) {
rhs = EXPR_REF (-1);
} else {
rhs = m3_cast (src_t, EXPR_REF (-1));
}
if (o == 0 && TREE_TYPE (v) == dst_t) {
lhs = v;
} else {
lhs = m3_build3 (BIT_FIELD_REF, dst_t, v, TYPE_SIZE (dst_t),
bitsize_int (o));
}
if (src_t != dst_t) {
rhs = m3_build1 (CONVERT_EXPR, dst_t, rhs);
}
expand_assignment (lhs, rhs, 0, 0);
EXPR_POP ();
}
You should be able to repro this by configuring m3cg for mips64-openbsd.
I've only tested on cygwin host, but I could check others..
Thanks,
- Jay
More information about the M3devel
mailing list