https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78355
Bug ID: 78355 Summary: LRA generates unaligned accesses when SLOW_UNALIGNED_ACCESS is 1 Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: pipcet at gmail dot com Target Milestone: --- Created attachment 40041 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=40041&action=edit patch to illustrate proposed fix (I hope I've selected the right component). I'm working on a gcc (+binutils,glibc) backend for asm.js at https://github.com/pipcet/asmjs. Things are working fairly well, but I think I found a bug in the LRA handling of (subreg:SI (mem:HI ...)) expressions when STRICT_ALIGNMENT is true. Summary: applying the attached patch will prevent the creation of unaligned memory accesses on targets that don't support them, but it's probably not the best fix. I'm using LRA, as is required for new ports. asm.js truncates unaligned accesses. I read the documentation as suggesting I #define STRICT_ALIGNMENT 1 in this case, and #define SLOW_UNALIGNED_ACCESS(x,y) 1 as well, which is what defaults.h would have done had I not provided a definition. In compiling the following code: short int x[] = { 1, 2, 3, 4, 5, -1, -2, }; int f(int index) { return x[index]; } I see that the reload (LRA) pass turns (insn 10 9 11 2 (set (reg:SI 45) (ashift:SI (subreg:SI (mem:HI (plus:SI (reg:SI 47) (symbol_ref:SI ("y") [flags 0x2] <var_decl 0x7ffff7fec510 y>)) [1 y S2 A16]) 0) (const_int 16 [0x10]))) "sign-extend.c":16 9 {*assignsi_binop} (expr_list:REG_DEAD (reg:SI 47) (nil))) into (insn 10 9 11 2 (set (reg:SI 8 r0 [45]) (ashift:SI (mem:SI (plus:SI (reg:SI 8 r0 [47]) (symbol_ref:SI ("y") [flags 0x2] <var_decl 0x7ffff7fec510 y>)) [1 y S4 A16]) (const_int 16 [0x10]))) "sign-extend.c":16 9 {*assignsi_binop} (nil)) The former is correct; the latter is not, because the access might be unaligned and silently access the wrong data. The problem is this code in simplify_operand_subreg (lra-constraints.c): if (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (reg)) || SLOW_UNALIGNED_ACCESS (innermode, MEM_ALIGN (reg)) || MEM_ALIGN (reg) >= GET_MODE_ALIGNMENT (mode)) return true; ... reload the mem in innermode the second SLOW_UNALIGNED_ACCESS() expression is true (as it's defined to be so in all cases), so we never reload the mem expression in the right mode. Commenting out the second line fixes the problem. I think the problem here is that SLOW_UNALIGNED_ACCESS is sloppily defined by my port, and defaults.h, to be a constant, but it is then used with naturally-aligned data, access to which is never slow, and expected to return false. So it would probably be best to replace the condition by if (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (reg)) || (MEM_ALIGN (reg) < GET_MODE_ALIGNMENT (innermode) && SLOW_UNALIGNED_ACCESS (innermode, MEM_ALIGN (reg))) || MEM_ALIGN (reg) >= GET_MODE_ALIGNMENT (mode)) return true; Or is there a better way? I hope I'm not totally wrong in my analysis.