ia64 reload failure
Richard Henderson
rth@cygnus.com
Mon Jul 17 15:33:00 GMT 2000
Given
struct
{
int offset;
struct slot
{
int field[6];
}
slot[4];
} s;
int
x ()
{
int toggle = 0;
int r = s.slot[0].field[!toggle];
return r;
}
we'd generate incorrect code at -O0, by emitting `movl r14 = s#',
which is wrong since IA-64 code is by default PIC.
This came from having a register be REG_EQUIV to (symbol_ref "s")
and the pseudo used across two basic blocks. Reload would elide
the spill/fill and emit `(set (reg 14) (symbol_ref "s"))' without
calling gen_movdi again.
There are a number of possible fixes. The one I'm guessing leads
to the most efficient output for IA-64 is to provisionally accept
such instructions and then split them after reload.
I'll probably check in the test case. Even though it doesn't fail
under Linux (due to a number of things not worth discussing here),
it does fail under other IA-64 operating systems.
r~
2000-07-17 Richard Henderson <rth@cygnus.com>
* config/ia64/ia64.md (movdi): Split out load address code.
New post-reload splitter for symbolic operands.
(movdi_internal): Abort if we didn't split symbolic operands
when we should have.
* config/ia64/ia64.c (ia64_expand_load_address): New, from movdi bits.
(ia64_reorg): Split insns when not optimizing.
* config/ia64/ia64-protos.h (ia64_expand_load_address): Declare.
Index: ia64-protos.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64-protos.h,v
retrieving revision 1.15
diff -c -p -d -r1.15 ia64-protos.h
*** ia64-protos.h 2000/07/15 20:30:46 1.15
--- ia64-protos.h 2000/07/17 21:55:41
*************** extern int call_multiple_values_operatio
*** 52,57 ****
--- 52,58 ----
extern int predicate_operator PARAMS((rtx, enum machine_mode));
extern int ia64_move_ok PARAMS((rtx, rtx));
+ extern void ia64_expand_load_address PARAMS((rtx, rtx));
extern void ia64_expand_fetch_and_op PARAMS ((enum fetchop_code,
enum machine_mode, rtx []));
extern void ia64_expand_op_and_fetch PARAMS ((enum fetchop_code,
Index: ia64.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 ia64.c
*** ia64.c 2000/07/15 20:30:46 1.70
--- ia64.c 2000/07/17 21:55:41
*************** predicate_operator (op, mode)
*** 542,548 ****
return ((GET_MODE (op) == mode || mode == VOIDmode)
&& (code == EQ || code == NE));
}
!
/* Return 1 if the operands of a move are ok. */
int
--- 542,548 ----
return ((GET_MODE (op) == mode || mode == VOIDmode)
&& (code == EQ || code == NE));
}
!
/* Return 1 if the operands of a move are ok. */
int
*************** ia64_move_ok (dst, src)
*** 566,571 ****
--- 566,618 ----
else
return GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src);
}
+
+ /* Expand a symbolic constant load. */
+ /* ??? Should generalize this, so that we can also support 32 bit pointers. */
+
+ void
+ ia64_expand_load_address (dest, src)
+ rtx dest, src;
+ {
+ rtx temp;
+
+ /* The destination could be a MEM during initial rtl generation,
+ which isn't a valid destination for the PIC load address patterns. */
+ if (! register_operand (dest, DImode))
+ temp = gen_reg_rtx (DImode);
+ else
+ temp = dest;
+
+ if (TARGET_AUTO_PIC)
+ emit_insn (gen_load_gprel64 (temp, src));
+ else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src))
+ emit_insn (gen_load_fptr (temp, src));
+ else if (sdata_symbolic_operand (src, DImode))
+ emit_insn (gen_load_gprel (temp, src));
+ else if (GET_CODE (src) == CONST
+ && GET_CODE (XEXP (src, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT
+ && (INTVAL (XEXP (XEXP (src, 0), 1)) & 0x1fff) != 0)
+ {
+ rtx subtarget = no_new_pseudos ? temp : gen_reg_rtx (DImode);
+ rtx sym = XEXP (XEXP (src, 0), 0);
+ HOST_WIDE_INT ofs, hi, lo;
+
+ /* Split the offset into a sign extended 14-bit low part
+ and a complementary high part. */
+ ofs = INTVAL (XEXP (XEXP (src, 0), 1));
+ lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000;
+ hi = ofs - lo;
+
+ emit_insn (gen_load_symptr (subtarget, plus_constant (sym, hi)));
+ emit_insn (gen_adddi3 (temp, subtarget, GEN_INT (lo)));
+ }
+ else
+ emit_insn (gen_load_symptr (temp, src));
+
+ if (temp != dest)
+ emit_move_insn (dest, temp);
+ }
/* Begin the assembly file. */
*************** void
*** 3016,3021 ****
--- 3063,3072 ----
ia64_reorg (insns)
rtx insns;
{
+ /* If optimizing, we'll have split before scheduling. */
+ if (optimize == 0)
+ split_all_insns (0);
+
emit_predicate_relation_info (insns);
emit_insn_group_barriers (insns);
}
Index: ia64.md
===================================================================
RCS file: /cvs/cvsfiles/devo/gcc/config/ia64/ia64.md,v
retrieving revision 1.68
diff -c -p -d -r1.68 ia64.md
*** ia64.md 2000/07/15 20:30:46 1.68
--- ia64.md 2000/07/17 21:55:41
***************
*** 247,299 ****
""
"
{
- /* ??? Should generalize this, so that we can also support 32 bit
- pointers. */
if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
{
! rtx temp;
!
! /* Operand[0] could be a MEM, which isn't a valid destination for the
! PIC load address patterns. */
! if (! register_operand (operands[0], DImode))
! temp = gen_reg_rtx (DImode);
! else
! temp = operands[0];
!
! if (TARGET_AUTO_PIC)
! emit_insn (gen_load_gprel64 (temp, operands[1]));
! else if (GET_CODE (operands[1]) == SYMBOL_REF
! && SYMBOL_REF_FLAG (operands[1]))
! emit_insn (gen_load_fptr (temp, operands[1]));
! else if (sdata_symbolic_operand (operands[1], DImode))
! emit_insn (gen_load_gprel (temp, operands[1]));
! else if (GET_CODE (operands[1]) == CONST
! && GET_CODE (XEXP (operands[1], 0)) == PLUS
! && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
! && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x1fff) != 0)
! {
! rtx subtarget = no_new_pseudos ? temp : gen_reg_rtx (DImode);
! rtx sym = XEXP (XEXP (operands[1], 0), 0);
! HOST_WIDE_INT ofs, hi, lo;
!
! /* Split the offset into a sign extended 14-bit low part
! and a complementary high part. */
! ofs = INTVAL (XEXP (XEXP (operands[1], 0), 1));
! lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000;
! hi = ofs - lo;
!
! emit_insn (gen_load_symptr (subtarget, plus_constant (sym, hi)));
! emit_insn (gen_adddi3 (temp, subtarget, GEN_INT (lo)));
! }
! else
! emit_insn (gen_load_symptr (temp, operands[1]));
!
! if (temp == operands[0])
! DONE;
!
! operands[1] = temp;
}
-
if (! reload_in_progress && ! reload_completed
&& ! ia64_move_ok (operands[0], operands[1]))
operands[1] = force_reg (DImode, operands[1]);
--- 247,257 ----
""
"
{
if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
{
! ia64_expand_load_address (operands[0], operands[1]);
! DONE;
}
if (! reload_in_progress && ! reload_completed
&& ! ia64_move_ok (operands[0], operands[1]))
operands[1] = force_reg (DImode, operands[1]);
***************
*** 303,322 ****
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r, m,r,*f,*f,*f,Q, r,*b")
(match_operand:DI 1 "move_operand" "rO,J,i,m,rO,*f,rO,*f,Q,*f,*b,rO"))]
"ia64_move_ok (operands[0], operands[1])"
! "@
! mov %0 = %r1
! addl %0 = %1, r0
! movl %0 = %1
! ld8%O1 %0 = %1%P1
! st8%Q0 %0 = %r1%P0
! getf.sig %0 = %1
! setf.sig %0 = %r1
! mov %0 = %1
! ldf8 %0 = %1%P1
! stf8 %0 = %1%P0
! mov %0 = %1
! mov %0 = %r1"
[(set_attr "type" "A,A,L,M,M,M,M,F,M,M,I,I")])
(define_expand "load_fptr"
[(set (match_dup 2)
--- 261,312 ----
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r, m,r,*f,*f,*f,Q, r,*b")
(match_operand:DI 1 "move_operand" "rO,J,i,m,rO,*f,rO,*f,Q,*f,*b,rO"))]
"ia64_move_ok (operands[0], operands[1])"
! "*
! {
! static const char * const alt[] = {
! \"mov %0 = %r1\",
! \"addl %0 = %1, r0\",
! \"movl %0 = %1\",
! \"ld8%O1 %0 = %1%P1\",
! \"st8%Q0 %0 = %r1%P0\",
! \"getf.sig %0 = %1\",
! \"setf.sig %0 = %r1\",
! \"mov %0 = %1\",
! \"ldf8 %0 = %1%P1\",
! \"stf8 %0 = %1%P0\",
! \"mov %0 = %1\",
! \"mov %0 = %r1\"
! };
!
! /* We use 'i' for alternative 2 despite possible PIC problems.
!
! If we define LEGITIMATE_CONSTANT_P such that symbols are not
! allowed, then the compiler dumps the data into constant memory
! instead of letting us read the values from the GOT. Similarly
! if we use 'n' instead of 'i'.
!
! Instead, we allow such insns through reload and then split them
! afterward (even without optimization). Therefore, we should
! never get so far with a symbolic operand. */
!
! if (which_alternative == 2 && ! TARGET_NO_PIC
! && symbolic_operand (operands[1], VOIDmode))
! abort ();
!
! return alt[which_alternative];
! }"
[(set_attr "type" "A,A,L,M,M,M,M,F,M,M,I,I")])
+
+ (define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "symbolic_operand" ""))]
+ "reload_completed && ! TARGET_NO_PIC"
+ [(const_int 0)]
+ "
+ {
+ ia64_expand_load_address (operands[0], operands[1]);
+ DONE;
+ }")
(define_expand "load_fptr"
[(set (match_dup 2)
More information about the Gcc-patches
mailing list