* pa.c (secondary_reload_class): Refine. Readonly data needs a
secondary reload only during PIC generation. Loading a floating
point register with a constant requires a register from R1_REGS
during -fPIC code generation.
(read_only_operand): Constant pool entries are no longer read only
during PIC code generation.
(hppa_legitimize_address): If flag_pic is nonzero, then
immediately call legitimize_pic_address.
(emit_move_sequence): Call legitimize_pic_address to handle
constant data. Handle secondary reloads for PIC. Use
pic_label_operand rather than open coding the test. Handle
loading a LABEL_REF when generating PIC.
(legitimzie_pic_address): Handle constant data addressing for PIC
here. Fix loading of symbolic addresses for -fPIC generation.
(pic_label_operand): Renamed from pic_operand. Handle any read
only operand (such as constant data). Reject function addresses,
Accept SYMBOL_REF with the read-only bit set. Generalize to
handle (const (plus (reg) (int))).
(finalize_pic): Delete unused function.
(check_pic): Delete function.
(pic_pc_rtx): Delete variable definition.
(current_function_uses_pic_offset_table): Delete extern decl.
(force_reg, validize_mem): Likewise.
(output_global_address): Don't tack on "-$global$" when generating
PIC code.
(finalize_pic): Don't emit code for initialization of
hppa_save_pic_table_rtx here. Don't claim we USE
pic_offset_table_rtx at function end.
* pa.h (SELECT_RTX_SECTION): Define. During PIC generation
everything (in the constant pool) goes into the data space.
(PRINT_OPERAND_ADDRESS): Handle CONST_INTs during PIC
generation. Handle LO_SUM address during -fPIC generation.
(LEGITIMATE_CONSTANT_P): Reject function labels when generating
PIC code.
(GO_IF_LEGITIMATE_ADDRESS): Only accept pic_reg + SYMBOL_REF for
-fpic.
(EXTRA_SECTION_FUNCTIONS): For -fpic, use the TEXT section for
constants to avoid GAS lossage.
(OVERRIDE_OPTIONS): Delete.
(PIC_OFFSET_TABLE_REG_CALL_CLOBBERED): Define.
(FINALIZE_PIC): Delete definition.
(INIT_EXPANDERS): Define. Clear hppa_save_pic_table_rtx here.
* pa.md: Use !flag_pic rather than calling check_pic.
(HImode high and lo_sum): Only accept const_int_operands.
(pic_load_label): Force output to be in %r1.
(pic_highpart): New pattern. Output must go into %r1. More
linker trickery.
(symbolic high and lo_sum): Disallow during PIC generation if
source is a symbolic operand. Handle CONST_INT LO_SUM during PIC
generation. Simplify.
(define_split for symbolic_operand load): Do not accept a symbolic
operand that is a pic_label_operand.
(pic_load_label): Name this pattern. Mask least significant bits
and optimize when a simple label is within reach of an ldo.
(call, call_value): Emit new-style USE information for
pic_offset_table_rtx. Emit code for initialization of
hppa_save_pic_table_rtx and wrap it into push_topmost_sequence()
and pop_topmost_sequence() calls.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@8419
138bc75d-0d04-0410-961f-
82ee72b054a4
}
int
-pic_operand (op, mode)
+pic_label_operand (op, mode)
rtx op;
enum machine_mode mode;
{
- return flag_pic && GET_CODE (op) == LABEL_REF;
+ if (!flag_pic)
+ return 0;
+
+ switch (GET_CODE (op))
+ {
+ case LABEL_REF:
+ return 1;
+ case SYMBOL_REF:
+ return (read_only_operand (op) && !FUNCTION_NAME_P (XSTR (op, 0)));
+ case CONST:
+ op = XEXP (op, 0);
+ return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ && read_only_operand (XEXP (op, 0))
+ && !FUNCTION_NAME_P (XSTR (XEXP (op, 0), 0)))
+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT);
+ default:
+ return 0;
+ }
}
int
}
\f
-extern int current_function_uses_pic_offset_table;
-extern rtx force_reg (), validize_mem ();
-
-/* The rtx for the global offset table which is a special form
- that *is* a position independent symbolic constant. */
-rtx pic_pc_rtx;
-
-/* Ensure that we are not using patterns that are not OK with PIC. */
-
-int
-check_pic (i)
- int i;
-{
- extern rtx recog_operand[];
- switch (flag_pic)
- {
- case 1:
- if (GET_CODE (recog_operand[i]) == SYMBOL_REF
- || (GET_CODE (recog_operand[i]) == CONST
- && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
- abort ();
- case 2:
- default:
- return 1;
- }
-}
/* Return truth value of whether OP can be used as an operand in a
three operand arithmetic insn that accepts registers of mode MODE
{
rtx pic_ref = orig;
+ /* Lables and read-only data need special handling. */
+ if (pic_label_operand (orig))
+ {
+ emit_insn (gen_pic_load_label (reg, orig));
+ current_function_uses_pic_offset_table = 1;
+ return reg;
+ }
if (GET_CODE (orig) == SYMBOL_REF)
{
if (reg == 0)
if (flag_pic == 2)
{
- emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (HIGH, Pmode, orig)));
- emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (LO_SUM, Pmode, reg, orig)));
- orig = reg;
+ emit_insn (gen_pic_highpart (reg, pic_offset_table_rtx, orig));
+ pic_ref = (gen_rtx (MEM, Pmode, gen_rtx (LO_SUM, Pmode, reg, orig)));
}
- pic_ref = gen_rtx (MEM, Pmode,
- gen_rtx (PLUS, Pmode,
- pic_offset_table_rtx, orig));
+ else
+ pic_ref = gen_rtx (MEM, Pmode,
+ gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
current_function_uses_pic_offset_table = 1;
RTX_UNCHANGING_P (pic_ref) = 1;
emit_move_insn (reg, pic_ref);
return pic_ref;
}
-/* Emit special PIC prologues and epilogues. */
-
-void
-finalize_pic ()
-{
- if (hppa_save_pic_table_rtx)
- {
- emit_insn_after (gen_rtx (SET, VOIDmode,
- hppa_save_pic_table_rtx,
- gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)),
- get_insns ());
- /* Need to emit this whether or not we obey regdecls,
- since setjmp/longjmp can cause life info to screw up. */
- hppa_save_pic_table_rtx = 0;
- }
- emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
-}
-
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
This macro is used in only one place: `memory_address' in explow.c.
{
rtx orig = x;
+ if (flag_pic)
+ return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
+
/* Strip off CONST. */
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
}
}
- if (flag_pic)
- return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
-
return orig;
}
rtx temp;
if (reload_in_progress || reload_completed)
- temp = operand0;
+ temp = scratch_reg ? scratch_reg : operand0;
else
temp = gen_reg_rtx (Pmode);
operands[1] = legitimize_pic_address (operand1, mode, temp);
- emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1]));
+ emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1]));
}
- /* On the HPPA, references to data space are supposed to */
- /* use dp, register 27, but showing it in the RTL inhibits various
- cse and loop optimizations. */
+ /* On the HPPA, references to data space are supposed to use dp,
+ register 27, but showing it in the RTL inhibits various cse
+ and loop optimizations. */
else
{
rtx temp, set, const_part = NULL;
{
if (GET_CODE (operand) == CONST)
operand = XEXP (XEXP (operand, 0), 0);
- if (GET_CODE (operand) == SYMBOL_REF)
- return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
+ if (flag_pic)
+ {
+ if (GET_CODE (operand) == SYMBOL_REF)
+ return SYMBOL_REF_FLAG (operand) && !CONSTANT_POOL_ADDRESS_P (operand);
+ }
+ else
+ {
+ if (GET_CODE (operand) == SYMBOL_REF)
+ return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
+ }
return 1;
}
if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
assemble_name (file, XSTR (x, 0));
- else if (GET_CODE (x) == SYMBOL_REF)
+ else if (GET_CODE (x) == SYMBOL_REF && !flag_pic)
{
assemble_name (file, XSTR (x, 0));
fprintf (file, "-$global$");
sep = "-";
else abort ();
- if (!read_only_operand (base))
+ if (!read_only_operand (base) && !flag_pic)
fprintf (file, "-$global$");
fprintf (file, "%s", sep);
if (offset) fprintf (file,"%d", offset);
{
int regno = true_regnum (in);
+ /* Trying to load a constant into a FP register during PIC code
+ generation will require %r1 as a scratch register. */
+ if (flag_pic == 2
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && FP_REG_CLASS_P (class)
+ && (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
+ return R1_REGS;
+
if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
&& GET_MODE_CLASS (mode) == MODE_INT
&& FP_REG_CLASS_P (class))
if (GET_CODE (in) == HIGH)
in = XEXP (in, 0);
+ if (!flag_pic
+ && symbolic_operand (in, VOIDmode)
+ && read_only_operand (in))
+ return NO_REGS;
+
if (class != R1_REGS && symbolic_operand (in, VOIDmode))
return R1_REGS;
#define WCHAR_TYPE "unsigned int"
#define WCHAR_TYPE_SIZE 32
-/* Sometimes certain combinations of command options do not make sense
- on a particular target machine. You can define a macro
- `OVERRIDE_OPTIONS' to take account of this. This macro, if
- defined, is executed once just after all the command options have
- been parsed.
-
- On the PA, it is used to explicitly warn the user that -fpic and -fPIC
- do not work. */
-
-#define OVERRIDE_OPTIONS \
-{ \
- if (flag_pic != 0) \
- warning ("-fpic and -fPIC are not supported on the PA."); \
-}
-
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
data references. */
#define PIC_OFFSET_TABLE_REGNUM 19
+#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED 1
-#define FINALIZE_PIC finalize_pic ()
+/* Initialize hppa_save_pic_table_rtx before RTL generation for
+ each function. We used to do this in FINALIZE_PIC, but FINALIZE_PIC
+ isn't always called for static inline functions. */
+#define INIT_EXPANDERS hppa_save_pic_table_rtx = 0;
/* SOM ABI says that objects larger than 64 bits are returned in memory. */
#define RETURN_IN_MEMORY(TYPE) \
floating-point, except for floating-point zero. */
#define LEGITIMATE_CONSTANT_P(X) \
- (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
- || (X) == CONST0_RTX (GET_MODE (X)))
+ ((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
+ || (X) == CONST0_RTX (GET_MODE (X))) \
+ && !(flag_pic && function_label_operand (X, VOIDmode)))
/* Subroutine for EXTRA_CONSTRAINT.
&& REG_OK_FOR_BASE_P (XEXP (X, 1))) \
goto ADDR; \
else if (flag_pic == 1 \
- && GET_CODE (XEXP (X, 1)) != REG \
- && GET_CODE (XEXP (X, 1)) != LO_SUM \
- && GET_CODE (XEXP (X, 1)) != MEM) \
+ && GET_CODE (XEXP (X, 1)) == SYMBOL_REF)\
goto ADDR; \
} \
else if (REG_P (XEXP (X, 0)) \
1 + (SYMBOL_NAME)[1] == '@'\
: (SYMBOL_NAME)[0] == '@'))
+/* Arghh. This is used for stuff in the constant pool; this may include
+ function addresses on the PA, which during PIC code generation must
+ reside in the data space. Unfortuantely, there's no way to determine
+ if a particular label in the constant pool refers to a function address.
+ So just force everything into the data space during PIC generation. */
+#define SELECT_RTX_SECTION(RTX,MODE) \
+ if (flag_pic) \
+ data_section (); \
+ else \
+ readonly_data_section ();
+
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE DImode
#define EXTRA_SECTIONS in_bss, in_readonly_data
+/* FIXME: GAS doesn't grok expressions involving two symbols in different
+ segments (aka subspaces). Two avoid creating such expressions, we place
+ readonly data into the $CODE$ subspace when generating PIC code. If
+ GAS ever handles such expressions, this hack can disappear. */
#define EXTRA_SECTION_FUNCTIONS \
void \
bss_section () \
{ \
if (in_section != in_readonly_data) \
{ \
- fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP); \
+ if (flag_pic) \
+ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); \
+ else \
+ fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP); \
in_section = in_readonly_data; \
} \
}
fprintf (FILE, "%d(0,%s)", offset, reg_names [REGNO (base)]); \
break; \
case LO_SUM: \
- fputs ("R'", FILE); \
+ if (flag_pic == 0 || !symbolic_operand (XEXP (addr, 1))) \
+ fputs ("R'", FILE); \
+ else if (flag_pic == 1) \
+ abort (); \
+ else if (flag_pic == 2) \
+ fputs ("RT'", FILE); \
output_global_address (FILE, XEXP (addr, 1)); \
fputs ("(", FILE); \
output_operand (XEXP (addr, 0), 0); \
(set_attr "length" "4")])
;; For pic
-(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:SI 1 "pic_operand" "i"))
- (clobber (match_scratch:SI 2 "=a"))]
+;; Note since this pattern can be created at reload time (via movsi), all
+;; the same rules for movsi apply here. (no new pseudos, no temporaries).
+(define_insn "pic_load_label"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (match_operand:SI 1 "pic_label_operand" ""))]
""
"*
{
xoperands[0] = operands[0];
xoperands[1] = operands[1];
xoperands[2] = label_rtx;
- output_asm_insn (\"bl .+8,%0\;addil L'%1-%2,%0\", xoperands);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label_rtx));
- output_asm_insn (\"ldo R'%1-%2(1),%0\", xoperands);
+ output_asm_insn (\"bl .+8,%0\", xoperands);
+ output_asm_insn (\"depi 0,31,2,%0\", xoperands);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (label_rtx));
+
+ /* If we're trying to load the address of a label that happens to be
+ close, then we can use a shorter sequence. */
+ if (GET_CODE (operands[1]) == LABEL_REF
+ && insn_addresses
+ && abs (insn_addresses[INSN_UID (XEXP (operands[1], 0))]
+ - insn_current_address) < 8100)
+ {
+ /* Prefixing with R% here is wrong, it extracts just 11 bits and is
+ always non-negative. */
+ output_asm_insn (\"ldo %1-%2(%0),%0\", xoperands);
+ }
+ else
+ {
+ output_asm_insn (\"addil L%%%1-%2,%0\", xoperands);
+ output_asm_insn (\"ldo R%%%1-%2(%0),%0\", xoperands);
+ }
return \"\";
- }
-"
+}"
[(set_attr "type" "multi")
- (set_attr "length" "12")])
+ (set_attr "length" "16")]) ; 12 or 16
+
+(define_insn "pic_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (plus (match_operand:SI 1 "register_operand" "r")
+ (high:SI (match_operand 2 "" ""))))]
+ "symbolic_operand (operands[2], Pmode)
+ && ! function_label_operand (operands[2])
+ && ! read_only_operand (operands[2])
+ && flag_pic == 2"
+ "addil LT'%G2,%1"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
;; Always use addil rather than ldil;add sequences. This allows the
;; HP linker to eliminate the dp relocation if the symbolic operand
(high:SI (match_operand 1 "" "")))]
"symbolic_operand (operands[1], Pmode)
&& ! function_label_operand (operands[1])
- && ! read_only_operand (operands[1])"
- "@
- addil L'%G1,%%r27"
+ && ! read_only_operand (operands[1])
+ && ! flag_pic"
+ "addil L'%G1,%%r27"
[(set_attr "type" "binary")
(set_attr "length" "4")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (match_operand 1 "" "")))]
- "check_pic (1) && !is_function_label_plus_const (operands[1])"
+ "(!flag_pic || !symbolic_operand (operands[1]), Pmode)
+ && !is_function_label_plus_const (operands[1])"
"ldil L'%G1,%0"
[(set_attr "type" "move")
(set_attr "length" "4")])
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "i")))]
"!is_function_label_plus_const (operands[2])"
- "ldo R'%G2(%1),%0"
+ "*
+{
+ if (flag_pic == 2 && symbolic_operand (operands[2], Pmode))
+ return \"ldw RT'%G2(%1),%0\";
+ else if (flag_pic == 1 && symbolic_operand (operands[2], Pmode))
+ abort ();
+ else
+ return \"ldo R'%G2(%1),%0\";
+}"
[(set_attr "length" "4")])
;; Now that a symbolic_address plus a constant is broken up early
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "symbolic_operand" ""))
(clobber (match_operand:SI 2 "register_operand" ""))]
- ""
+ "! (flag_pic && pic_label_operand (operands[1], SImode))"
[(set (match_dup 2) (high:SI (match_dup 1)))
(set (match_dup 0) (lo_sum:SI (match_dup 2) (match_dup 1)))]
"")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
- (high:HI (match_operand 1 "" "")))]
- "check_pic (1)"
+ (high:HI (match_operand 1 "const_int_operand" "")))]
+ ""
"ldil L'%G1,%0"
[(set_attr "type" "move")
(set_attr "length" "4")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(lo_sum:HI (match_operand:HI 1 "register_operand" "r")
- (match_operand 2 "immediate_operand" "i")))]
+ (match_operand 2 "const_int_operand" "i")))]
""
"ldo R'%G2(%1),%0"
[(set_attr "length" "4")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(high:DI (match_operand 1 "" "")))]
- "check_pic (1)"
+ ""
"*
{
rtx op0 = operands[0];
"
{
rtx op;
-
- if (flag_pic)
- emit_insn (gen_rtx (USE, VOIDmode,
- gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
+ rtx call_insn;
if (TARGET_LONG_CALLS)
op = force_reg (SImode, XEXP (operands[0], 0));
to change the named call into an indirect call in some cases (using
two patterns keeps CSE from performing this optimization). */
if (GET_CODE (op) == SYMBOL_REF)
- emit_call_insn (gen_call_internal_symref (op, operands[1]));
+ call_insn = emit_call_insn (gen_call_internal_symref (op, operands[1]));
else
- emit_call_insn (gen_call_internal_reg (force_reg (SImode, op),
- operands[1]));
+ call_insn = emit_call_insn (gen_call_internal_reg (force_reg (SImode, op),
+ operands[1]));
if (flag_pic)
{
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
if (!hppa_save_pic_table_rtx)
- hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
- emit_insn (gen_rtx (SET, VOIDmode,
- gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM),
+ {
+ hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
+ push_topmost_sequence ();
+ emit_insn_after (gen_rtx (SET, VOIDmode,
+ hppa_save_pic_table_rtx,
+ pic_offset_table_rtx),
+ get_insns ());
+ pop_topmost_sequence ();
+ }
+
+ emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
hppa_save_pic_table_rtx));
}
DONE;
(call (match_operand:SI 1 "" "")
(match_operand 2 "" "")))
(clobber (reg:SI 2))])]
- ;;- Don't use operand 1 for most machines.
""
"
{
rtx op;
-
- if (flag_pic)
- emit_insn (gen_rtx (USE, VOIDmode,
- gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
+ rtx call_insn;
if (TARGET_LONG_CALLS)
op = force_reg (SImode, XEXP (operands[1], 0));
to change the named call into an indirect call in some cases (using
two patterns keeps CSE from performing this optimization). */
if (GET_CODE (op) == SYMBOL_REF)
- emit_call_insn (gen_call_value_internal_symref (operands[0], op,
- operands[2]));
+ call_insn = emit_call_insn (gen_call_value_internal_symref (operands[0],
+ op,
+ operands[2]));
else
- emit_call_insn (gen_call_value_internal_reg (operands[0],
- force_reg (SImode, op),
- operands[2]));
+ call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
+ force_reg (SImode, op),
+ operands[2]));
if (flag_pic)
{
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
if (!hppa_save_pic_table_rtx)
- hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
- emit_insn (gen_rtx (SET, VOIDmode,
- gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM),
+ {
+ hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
+ push_topmost_sequence ();
+ emit_insn_after (gen_rtx (SET, VOIDmode,
+ hppa_save_pic_table_rtx,
+ pic_offset_table_rtx),
+ get_insns ());
+ pop_topmost_sequence ();
+ }
+
+ emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
hppa_save_pic_table_rtx));
}
DONE;
(match_operand 2 "" "i")))
(clobber (reg:SI 2))
(use (const_int 1))]
- ;;- Don't use operand 1 for most machines.
""
"*
{