From 95726648efb29340078bdea2a882341c867434ba Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Fri, 9 Feb 1996 19:46:19 +0000 Subject: [PATCH] sparc.c (sp64_medium_pic_operand): New function. * sparc/sparc.c (sp64_medium_pic_operand): New function. (move_pic_label): Delete. (legitimize_pic_address): Simplify using some named patterns. (finalize_pic): Add preliminary sparc64 support. (emit_move_sequence): Reorganize. * sparc/sparc.md (pic_lo_sum_si,pic_sethi_si,get_pc_sp32,get_pc_sp64, move_pic_label_si,move_label_di,sethi_di_sp64): Make named patterns. (sethi_di_sp64_const,sethi_di_medium_pic): New anonymous patterns. (move_pic_label_si,move_label_di): Optimize for near labels. (tablejump): Use for TARGET_MEDANY. (casesi): Delete. From-SVN: r11185 --- gcc/config/sparc/sparc.c | 208 +++++++++++++++++++++----------------- gcc/config/sparc/sparc.md | 179 ++++++++++++++++---------------- 2 files changed, 204 insertions(+), 183 deletions(-) diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 244cd93b1a3..4dc9e5b2dc8 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -341,6 +341,31 @@ symbolic_memory_operand (op, mode) || 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 @@ -356,7 +381,8 @@ data_segment_operand (op, mode) 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 : @@ -379,7 +405,8 @@ text_segment_operand (op, mode) 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 : @@ -452,17 +479,6 @@ move_operand (op, mode) 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; @@ -1150,16 +1166,9 @@ legitimize_pic_address (orig, mode, reg) 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 @@ -1215,6 +1224,7 @@ legitimize_pic_address (orig, mode, reg) 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; @@ -1247,18 +1257,12 @@ finalize_pic () 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. */ @@ -1271,27 +1275,57 @@ finalize_pic () 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 (); @@ -1352,10 +1386,33 @@ emit_move_sequence (operands, mode) } } - /* 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)) { @@ -1387,29 +1444,7 @@ emit_move_sequence (operands, 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))); @@ -1418,21 +1453,6 @@ emit_move_sequence (operands, mode) } } - 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; } diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 85dae7c71c5..d454a6f0105 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -1467,13 +1467,29 @@ ;; 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\";" @@ -1483,53 +1499,77 @@ ;; 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") @@ -1548,8 +1588,6 @@ ;; 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" @@ -1617,12 +1655,15 @@ ;;; 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))] @@ -1661,9 +1702,9 @@ ;; 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" @@ -1676,6 +1717,14 @@ [(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. @@ -4782,7 +4831,7 @@ (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) @@ -4830,54 +4879,6 @@ "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. -- 2.30.2