[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