|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
}
+/* Return 1 if the operand is an argument used in generating pic references
+ in either the medium/low or medium/anywhere code models of sparc64. */
+
+int
+sp64_medium_pic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ /* Check for (const (minus (symbol_ref:GOT)
+ (const (minus (label) (pc))))). */
+ if (GET_CODE (op) != CONST)
+ return 0;
+ op = XEXP (op, 0);
+ if (GET_CODE (op) != MINUS)
+ return 0;
+ if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
+ return 0;
+ /* ??? Ensure symbol is GOT. */
+ if (GET_CODE (XEXP (op, 1)) != CONST)
+ return 0;
+ if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
+ return 0;
+ return 1;
+}
+
/* Return 1 if the operand is a data segment reference. This includes
the readonly data segment, or in other words anything but the text segment.
This is needed in the medium/anywhere code model on v9. These values
case SYMBOL_REF :
return ! SYMBOL_REF_FLAG (op);
case PLUS :
- /* Assume canonical format of symbol + constant. */
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
case CONST :
return data_segment_operand (XEXP (op, 0));
default :
case SYMBOL_REF :
return SYMBOL_REF_FLAG (op);
case PLUS :
- /* Assume canonical format of symbol + constant. */
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
case CONST :
return text_segment_operand (XEXP (op, 0));
default :
return memory_address_p (mode, op);
}
-int
-move_pic_label (op, mode)
- rtx op;
- enum machine_mode mode;
-{
- /* Special case for PIC. */
- if (flag_pic && GET_CODE (op) == LABEL_REF)
- return 1;
- return 0;
-}
-
int
splittable_symbolic_memory_operand (op, mode)
rtx op;
won't get confused into thinking that these two instructions
are loading in the true address of the symbol. If in the
future a PIC rtx exists, that should be used instead. */
- emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
- gen_rtx (HIGH, Pmode,
- gen_rtx (UNSPEC, Pmode,
- gen_rtvec (1, orig),
- 0))));
- emit_insn (gen_rtx (SET, VOIDmode, temp_reg,
- gen_rtx (LO_SUM, Pmode, temp_reg,
- gen_rtx (UNSPEC, Pmode,
- gen_rtvec (1, orig),
- 0))));
+ emit_insn (gen_pic_sethi_si (temp_reg, orig));
+ emit_insn (gen_pic_lo_sum_si (temp_reg, temp_reg, orig));
+
address = temp_reg;
}
else
return gen_rtx (PLUS, Pmode, base, offset);
}
else if (GET_CODE (orig) == LABEL_REF)
+ /* ??? Why do we do this? */
current_function_uses_pic_offset_table = 1;
return orig;
abort ();
flag_pic = 0;
- l1 = gen_label_rtx ();
- l2 = gen_label_rtx ();
+
+ /* ??? sparc64 pic currently under construction. */
start_sequence ();
- emit_label (l1);
- /* Note that we pun calls and jumps here! */
- emit_jump_insn (gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (2,
- gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)),
- gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2)))));
- emit_label (l2);
+ l1 = gen_label_rtx ();
/* Initialize every time through, since we can't easily
know this to be permanent. */
gen_rtx (LABEL_REF, VOIDmode, l1),
pc_rtx))));
- if (Pmode == DImode)
- emit_insn (gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (2,
- gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
- gen_rtx (HIGH, Pmode, pic_pc_rtx)),
- gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, Pmode, 1)))));
+ if (! TARGET_ARCH64)
+ {
+ l2 = gen_label_rtx ();
+ emit_label (l1);
+ /* Note that we pun calls and jumps here! */
+ emit_jump_insn (gen_get_pc_sp32 (l2));
+ emit_label (l2);
+
+ emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
+ gen_rtx (HIGH, Pmode, pic_pc_rtx)));
+
+ emit_insn (gen_rtx (SET, VOIDmode,
+ pic_offset_table_rtx,
+ gen_rtx (LO_SUM, Pmode,
+ pic_offset_table_rtx, pic_pc_rtx)));
+ emit_insn (gen_rtx (SET, VOIDmode,
+ pic_offset_table_rtx,
+ gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx,
+ gen_rtx (REG, Pmode, 15))));
+
+ /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
+ LABEL_PRESERVE_P (l1) = 1;
+ LABEL_PRESERVE_P (l2) = 1;
+ }
else
- emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
- gen_rtx (HIGH, Pmode, pic_pc_rtx)));
-
- emit_insn (gen_rtx (SET, VOIDmode,
- pic_offset_table_rtx,
- gen_rtx (LO_SUM, Pmode,
- pic_offset_table_rtx, pic_pc_rtx)));
- emit_insn (gen_rtx (SET, VOIDmode,
- pic_offset_table_rtx,
- gen_rtx (PLUS, Pmode,
- pic_offset_table_rtx, gen_rtx (REG, Pmode, 15))));
- /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
- LABEL_PRESERVE_P (l1) = 1;
- LABEL_PRESERVE_P (l2) = 1;
+ {
+ /* ??? This definately isn't right for -mfullany. */
+ /* ??? And it doesn't quite seem right for the others either. */
+ emit_label (l1);
+ emit_insn (gen_get_pc_sp64 (gen_rtx (REG, Pmode, 1)));
+
+ /* Don't let the scheduler separate the previous insn from `l1'. */
+ emit_insn (gen_blockage ());
+
+ emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
+ gen_rtx (HIGH, Pmode, pic_pc_rtx)));
+
+ emit_insn (gen_rtx (SET, VOIDmode,
+ pic_offset_table_rtx,
+ gen_rtx (LO_SUM, Pmode,
+ pic_offset_table_rtx, pic_pc_rtx)));
+ emit_insn (gen_rtx (SET, VOIDmode,
+ pic_offset_table_rtx,
+ gen_rtx (PLUS, Pmode,
+ pic_offset_table_rtx, gen_rtx (REG, Pmode, 1))));
+
+ /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */
+ LABEL_PRESERVE_P (l1) = 1;
+ }
+
flag_pic = orig_flag_pic;
seq = gen_sequence ();
}
}
- /* Simplify the source if we need to. Must handle DImode HIGH operators
- here because such a move needs a clobber added. */
- if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
- || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode))
+ if (GET_CODE (operand1) == LABEL_REF
+ && mode == SImode && flag_pic)
+ {
+ if (TARGET_ARCH64)
+ abort ();
+ emit_insn (gen_move_pic_label_si (operand0, XEXP (operand1, 0)));
+ return 1;
+ }
+ /* Non-pic LABEL_REF's in sparc64 are expensive to do the normal way,
+ so always use special code. */
+ else if (GET_CODE (operand1) == LABEL_REF
+ && mode == DImode)
+ {
+ if (! TARGET_ARCH64)
+ abort ();
+ emit_insn (gen_move_label_di (operands[0], XEXP (operands[1], 0)));
+ return 1;
+ }
+ /* DImode HIGH values in sparc64 need a clobber added. */
+ else if (TARGET_ARCH64
+ && GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode)
+ {
+ emit_insn (gen_sethi_di_sp64 (operand0, XEXP (operand1, 0)));
+ return 1;
+ }
+ /* Simplify the source if we need to. */
+ else if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
{
if (flag_pic && symbolic_operand (operand1, mode))
{
? operand0 : gen_reg_rtx (mode));
if (TARGET_ARCH64 && mode == DImode)
- {
- int high_operand = 0;
-
- /* If the operand is already a HIGH, then remove the HIGH so
- that we won't get duplicate HIGH operators in this insn.
- Also, we must store the result into the original dest,
- because that is where the following LO_SUM expects it. */
- if (GET_CODE (operand1) == HIGH)
- {
- operand1 = XEXP (operand1, 0);
- high_operand = 1;
- }
-
- emit_insn (gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (2,
- gen_rtx (SET, VOIDmode, temp,
- gen_rtx (HIGH, mode, operand1)),
- gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, DImode, 1)))));
-
- /* If this was a high operand, then we are now finished. */
- if (high_operand)
- return 1;
- }
+ emit_insn (gen_sethi_di_sp64 (temp, operand1));
else
emit_insn (gen_rtx (SET, VOIDmode, temp,
gen_rtx (HIGH, mode, operand1)));
}
}
- if (GET_CODE (operand1) == LABEL_REF && flag_pic)
- {
- /* The procedure for doing this involves using a call instruction to
- get the pc into o7. We need to indicate this explicitly because
- the tablejump pattern assumes that it can use this value also. */
- emit_insn (gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (2,
- gen_rtx (SET, VOIDmode, operand0,
- operand1),
- gen_rtx (SET, VOIDmode,
- gen_rtx (REG, mode, 15),
- pc_rtx))));
- return 1;
- }
-
/* Now have insn-emit do whatever it normally does. */
return 0;
}
;; is not an "arith_operand".
[(set_attr "length" "1")])
+(define_insn "*sethi_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (match_operand 1 "" "")))]
+ "check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+(define_insn "*sethi_hi"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (high:HI (match_operand 1 "" "")))]
+ "check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
;; For PIC, symbol_refs are put inside unspec so that the optimizer will not
;; confuse them with real addresses.
-(define_insn "*pic_lo_sum_si"
+(define_insn "pic_lo_sum_si"
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] 0)))]
- ""
+ "flag_pic"
;; V9 needs "add" because of the code models. We still use "or" for v8
;; so we can compare the old compiler with the new.
"* return TARGET_ARCH64 ? \"add %1,%%lo(%a2),%0\" : \"or %1,%%lo(%a2),%0\";"
;; For PIC, symbol_refs are put inside unspec so that the optimizer will not
;; confuse them with real addresses.
-(define_insn "*pic_sethi_si"
+(define_insn "pic_sethi_si"
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (unspec:SI [(match_operand 1 "" "")] 0)))]
- "check_pic (1)"
+ "flag_pic && check_pic (1)"
"sethi %%hi(%a1),%0"
[(set_attr "type" "move")
(set_attr "length" "1")])
-(define_insn "*sethi_si"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (high:SI (match_operand 1 "" "")))]
- "check_pic (1)"
- "sethi %%hi(%a1),%0"
- [(set_attr "type" "move")
- (set_attr "length" "1")])
+(define_insn "get_pc_sp32"
+ [(set (pc) (label_ref (match_operand 0 "" "")))
+ (set (reg:SI 15) (label_ref (match_dup 0)))]
+ "! TARGET_PTR64"
+ "call %l0%#"
+ [(set_attr "type" "uncond_branch")])
-(define_insn "*sethi_hi"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (high:HI (match_operand 1 "" "")))]
- "check_pic (1)"
- "sethi %%hi(%a1),%0"
- [(set_attr "type" "move")
- (set_attr "length" "1")])
+(define_insn "get_pc_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r") (pc))]
+ "TARGET_PTR64"
+ "rd %%pc,%0"
+ [(set_attr "type" "move")])
;; Special pic pattern, for loading the address of a label into a register.
;; It clobbers o7 because the call puts the return address (i.e. pc value)
-;; there.
+;; there. The pic tablejump pattern also uses this.
-(define_insn "*move_pic_label_si"
+(define_insn "move_pic_label_si"
[(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:SI 1 "move_pic_label" "i"))
+ (label_ref:SI (match_operand 1 "" "")))
(set (reg:SI 15) (pc))]
- ""
- "\\n1:\;call 2f\;sethi %%hi(%l1-1b),%0\\n2:\\tor %0,%%lo(%l1-1b),%0\;add %0,%%o7,%0"
+ "flag_pic"
+ "*
+{
+ if (get_attr_length (insn) == 2)
+ return \"\\n1:\;call 2f\;add %%o7,%%lo(%l1-1b),%0\\n2:\";
+ else
+ return \"\\n1:\;call 2f\;sethi %%hi(%l1-1b),%0\\n2:\\tor %0,%%lo(%l1-1b),%0\;add %0,%%o7,%0\";
+}"
[(set_attr "type" "multi")
- (set_attr "length" "4")])
-
-;; v9 special pic pattern, for loading the address of a label into a register.
+ ; 1024 = 4096 bytes / 4 bytes/insn
+ (set (attr "length") (if_then_else (ltu (minus (match_dup 1) (pc))
+ (const_int 1024))
+ (const_int 2)
+ (const_int 4)))])
+
+;; Special sparc64 pattern for loading the address of a label into a register.
+;; The pic and non-pic cases are the same since it's the most efficient way.
+;;
+;; ??? The non-pic case doesn't need to use %o7, we could use a scratch
+;; instead. But the pic case doesn't need to use %o7 either. We handle them
+;; both here so that when this is fixed, they can both be fixed together.
+;; Don't forget that the pic jump table stuff uses %o7 (that will need to be
+;; changed too).
-(define_insn "*move_pic_label_di"
+(define_insn "move_label_di"
[(set (match_operand:DI 0 "register_operand" "=r")
- (match_operand:DI 1 "move_pic_label" "i"))
+ (label_ref:DI (match_operand 1 "" "")))
(set (reg:DI 15) (pc))]
"TARGET_ARCH64"
- "\\n1:\;call 2f\;sethi %%hi(%l1-1b),%0\\n2:\\tor %0,%%lo(%l1-1b),%0\;add %0,%%o7,%0"
+ "*
+{
+ if (get_attr_length (insn) == 2)
+ return \"\\n1:\;rd %%pc,%%o7\;add %%o7,%l1-1b,%0\";
+ else
+ return \"\\n1:\;rd %%pc,%%o7\;sethi %%hi(%l1-1b),%0\;add %0,%%lo(%l1-1b),%0\;sra %0,0,%0\;add %0,%%o7,%0\";
+}"
[(set_attr "type" "multi")
- (set_attr "length" "4")])
+ ; 1024 = 4096 bytes / 4 bytes/insn
+ (set (attr "length") (if_then_else (ltu (minus (match_dup 1) (pc))
+ (const_int 1024))
+ (const_int 2)
+ (const_int 5)))])
(define_insn "*lo_sum_di_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
;; is not an "arith_operand".
[(set_attr "length" "1")])
-;; ??? Gas does not handle %lo(DI), so we use the same code for ! TARGET_ARCH64.
-;; ??? The previous comment is obsolete.
;; ??? Optimizer does not handle "or %o1,%lo(0),%o1". How about add?
(define_insn "*lo_sum_di_sp64"
;;; e.g. by using a toc like the romp and rs6000 ports do for addresses, reg
;;; 1 will then no longer need to be considered a fixed reg.
-;;; Gas doesn't have any 64 bit constant support, so don't use %uhi and %ulo
-;;; on constants. Symbols have to be handled by the linker, so we must use
-;;; %uhi and %ulo for them, but gas will handle these correctly.
-;;; ??? This comment is obsolete, gas handles them now.
+(define_expand "sethi_di_sp64"
+ [(parallel
+ [(set (match_operand:DI 0 "register_operand" "")
+ (high:DI (match_operand 1 "general_operand" "")))
+ (clobber (reg:DI 1))])]
+ "TARGET_ARCH64"
+ "")
-(define_insn "*sethi_di_sp64"
+(define_insn "*sethi_di_sp64_const"
[(set (match_operand:DI 0 "register_operand" "=r")
(high:DI (match_operand 1 "const_double_operand" "")))
(clobber (reg:DI 1))]
;; When TARGET_MEDLOW, assume that the upper 32 bits of symbol addresses are
;; always 0.
-;; When TARGET_MEDANY, the upper 32 bits of function addresses are 0.
-;; The data segment has a maximum size of 32 bits, but may be located anywhere.
-;; MEDANY_BASE_REG contains the start address, currently %g4.
+;; When TARGET_MEDANY, the text and data segments have a maximum size of 32
+;; bits and may be located anywhere. MEDANY_BASE_REG contains the start
+;; address of the data segment, currently %g4.
;; When TARGET_FULLANY, symbolic addresses are 64 bits.
(define_insn "*sethi_di_medlow"
[(set_attr "type" "move")
(set_attr "length" "1")])
+(define_insn "*sethi_di_medium_pic"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "sp64_medium_pic_operand" "")))]
+ "(TARGET_MEDLOW || TARGET_MEDANY) && check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
;; WARNING: %0 gets %hi(%1)+%g4.
;; You cannot OR in %lo(%1), it must be added in.
(define_expand "tablejump"
[(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))])]
- "! TARGET_MEDANY"
+ ""
"
{
if (GET_MODE (operands[0]) != Pmode)
"jmp %a0%#"
[(set_attr "type" "uncond_branch")])
-(define_insn "*get_pc_sp32"
- [(set (pc) (label_ref (match_operand 0 "" "")))
- (set (reg:SI 15) (label_ref (match_dup 0)))]
- "! TARGET_PTR64"
- "call %l0%#"
- [(set_attr "type" "uncond_branch")])
-
-(define_insn "*get_pc_sp64"
- [(set (pc) (label_ref (match_operand 0 "" "")))
- (set (reg:DI 15) (label_ref (match_dup 0)))]
- "TARGET_PTR64"
- "call %l0%#"
- [(set_attr "type" "uncond_branch")])
-
-;; Implement a switch statement for the medium/anywhere code model.
-;; This wouldn't be necessary if we could distinguish label refs of the jump
-;; table from other label refs. The problem is that jump tables live in the
-;; .rodata section and thus we need to add %g4 to get their address.
-
-(define_expand "casesi"
- [(set (match_dup 5)
- (minus:SI (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "nonmemory_operand" "")))
- (set (reg:CC 0)
- (compare:CC (match_dup 5)
- (match_operand:SI 2 "nonmemory_operand" "")))
- (set (pc)
- (if_then_else (gtu (reg:CC 0)
- (const_int 0))
- (label_ref (match_operand 4 "" ""))
- (pc)))
- (parallel [(set (match_dup 6) (high:DI (label_ref (match_operand 3 "" ""))))
- (clobber (reg:DI 1))])
- (set (match_dup 6)
- (lo_sum:DI (match_dup 6) (label_ref (match_dup 3))))
- (set (match_dup 6) (plus:DI (match_dup 6) (reg:DI 4)))
- (set (match_dup 7) (zero_extend:DI (match_dup 5)))
- (set (match_dup 7) (ashift:DI (match_dup 7) (const_int 3)))
- (set (match_dup 7) (mem:DI (plus:DI (match_dup 6) (match_dup 7))))
- (set (pc) (match_dup 7))]
- "TARGET_MEDANY"
- "
-{
- operands[5] = gen_reg_rtx (SImode);
- operands[6] = gen_reg_rtx (DImode);
- operands[7] = gen_reg_rtx (DImode);
-}")
-
;; This pattern recognizes the "instruction" that appears in
;; a function call that wants a structure value,
;; to inform the called function if compiled with Sun CC.