summaryrefslogtreecommitdiff
path: root/gcc/config/mips/mips.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mips/mips.md')
-rw-r--r--gcc/config/mips/mips.md301
1 files changed, 173 insertions, 128 deletions
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index a510e0a7b74..4e1e7852c71 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -29,11 +29,13 @@
(UNSPEC_STORE_WORD 2)
(UNSPEC_GET_FNADDR 3)
(UNSPEC_BLOCKAGE 4)
- (UNSPEC_CPRESTORE 5)
- (UNSPEC_RESTORE_GP 6)
- (UNSPEC_EH_RETURN 7)
- (UNSPEC_CONSTTABLE_INT 8)
- (UNSPEC_CONSTTABLE_FLOAT 9)
+ (UNSPEC_POTENTIAL_CPRESTORE 5)
+ (UNSPEC_CPRESTORE 6)
+ (UNSPEC_RESTORE_GP 7)
+ (UNSPEC_MOVE_GP 8)
+ (UNSPEC_EH_RETURN 9)
+ (UNSPEC_CONSTTABLE_INT 10)
+ (UNSPEC_CONSTTABLE_FLOAT 11)
(UNSPEC_ALIGN 14)
(UNSPEC_HIGH 17)
(UNSPEC_LOAD_LEFT 18)
@@ -77,6 +79,7 @@
(UNSPEC_ADDRESS_FIRST 100)
(TLS_GET_TP_REGNUM 3)
+ (CPRESTORE_SLOT_REGNUM 76)
(GOT_VERSION_REGNUM 79)
;; For MIPS Paired-Singled Floating Point Instructions.
@@ -256,6 +259,9 @@
(UNSPEC_MIPS_CACHE 600)
(UNSPEC_R10K_CACHE_BARRIER 601)
+
+ ;; PIC long branch sequences are never longer than 100 bytes.
+ (MAX_PIC_BRANCH_LENGTH 100)
]
)
@@ -281,12 +287,11 @@
;;
;; jal is always a macro for TARGET_CALL_CLOBBERED_GP because it includes
;; an instruction to restore $gp. Direct jals are also macros for
-;; flag_pic && !TARGET_ABSOLUTE_ABICALLS because they first load
-;; the target address into a register.
+;; !TARGET_ABSOLUTE_JUMPS because they first load the target address
+;; into a register.
(define_attr "jal_macro" "no,yes"
(cond [(eq_attr "jal" "direct")
- (symbol_ref "((TARGET_CALL_CLOBBERED_GP
- || (flag_pic && !TARGET_ABSOLUTE_ABICALLS))
+ (symbol_ref "(TARGET_CALL_CLOBBERED_GP || !TARGET_ABSOLUTE_JUMPS
? JAL_MACRO_YES : JAL_MACRO_NO)")
(eq_attr "jal" "indirect")
(symbol_ref "(TARGET_CALL_CLOBBERED_GP
@@ -498,9 +503,10 @@
(ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
(const_int 8)
- ;; Direct branch instructions have a range of [-0x40000,0x3fffc].
- ;; If a branch is outside this range, we have a choice of two
- ;; sequences. For PIC, an out-of-range branch like:
+ ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
+ ;; relative to the address of the delay slot. If a branch is
+ ;; outside this range, we have a choice of two sequences.
+ ;; For PIC, an out-of-range branch like:
;;
;; bne r1,r2,target
;; dslot
@@ -514,9 +520,6 @@
;; nop
;; 1:
;;
- ;; where the load address can be up to three instructions long
- ;; (lw, nop, addiu).
- ;;
;; The non-PIC case is similar except that we use a direct
;; jump instead of an la/jr pair. Since the target of this
;; jump is an absolute 28-bit bit address (the other bits
@@ -531,12 +534,21 @@
;; will add the length of the implicit nop. The values for
;; forward and backward branches will be different as well.
(eq_attr "type" "branch")
- (cond [(and (le (minus (match_dup 1) (pc)) (const_int 131064))
- (le (minus (pc) (match_dup 1)) (const_int 131068)))
- (const_int 4)
- (ne (symbol_ref "flag_pic") (const_int 0))
- (const_int 24)
- ] (const_int 12))
+ (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
+ (le (minus (pc) (match_dup 0)) (const_int 131068)))
+ (const_int 4)
+
+ ;; The non-PIC case: branch, first delay slot, and J.
+ (ne (symbol_ref "TARGET_ABSOLUTE_JUMPS") (const_int 0))
+ (const_int 12)]
+
+ ;; Use MAX_PIC_BRANCH_LENGTH as a (gross) overestimate.
+ ;; mips_adjust_insn_length substitutes the correct length.
+ ;;
+ ;; Note that we can't simply use (symbol_ref ...) here
+ ;; because genattrtab needs to know the maximum length
+ ;; of an insn.
+ (const_int MAX_PIC_BRANCH_LENGTH))
;; "Ghost" instructions occupy no space.
(eq_attr "type" "ghost")
@@ -4754,12 +4766,12 @@
;; function address.
(define_insn_and_split "loadgp_newabi_<mode>"
[(set (match_operand:P 0 "register_operand" "=d")
- (unspec_volatile:P [(match_operand:P 1)
- (match_operand:P 2 "register_operand" "d")]
- UNSPEC_LOADGP))]
+ (unspec:P [(match_operand:P 1)
+ (match_operand:P 2 "register_operand" "d")]
+ UNSPEC_LOADGP))]
"mips_current_loadgp_style () == LOADGP_NEWABI"
- "#"
- ""
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "&& mips_must_initialize_gp_p ()"
[(set (match_dup 0) (match_dup 3))
(set (match_dup 0) (match_dup 4))
(set (match_dup 0) (match_dup 5))]
@@ -4768,21 +4780,21 @@
operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]);
operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]);
}
- [(set_attr "length" "12")])
+ [(set_attr "type" "ghost")])
;; Likewise, for -mno-shared code. Operand 0 is the __gnu_local_gp symbol.
(define_insn_and_split "loadgp_absolute_<mode>"
[(set (match_operand:P 0 "register_operand" "=d")
- (unspec_volatile:P [(match_operand:P 1)] UNSPEC_LOADGP))]
+ (unspec:P [(match_operand:P 1)] UNSPEC_LOADGP))]
"mips_current_loadgp_style () == LOADGP_ABSOLUTE"
- "#"
- ""
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "&& mips_must_initialize_gp_p ()"
[(const_int 0)]
{
mips_emit_move (operands[0], operands[1]);
DONE;
}
- [(set_attr "length" "8")])
+ [(set_attr "type" "ghost")])
;; This blockage instruction prevents the gp load from being
;; scheduled after an implicit use of gp. It also prevents
@@ -4791,19 +4803,18 @@
[(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)]
""
""
- [(set_attr "type" "ghost")
- (set_attr "mode" "none")])
+ [(set_attr "type" "ghost")])
;; Initialize $gp for RTP PIC. Operand 0 is the __GOTT_BASE__ symbol
;; and operand 1 is the __GOTT_INDEX__ symbol.
(define_insn_and_split "loadgp_rtp_<mode>"
[(set (match_operand:P 0 "register_operand" "=d")
- (unspec_volatile:P [(match_operand:P 1 "symbol_ref_operand")
- (match_operand:P 2 "symbol_ref_operand")]
- UNSPEC_LOADGP))]
+ (unspec:P [(match_operand:P 1 "symbol_ref_operand")
+ (match_operand:P 2 "symbol_ref_operand")]
+ UNSPEC_LOADGP))]
"mips_current_loadgp_style () == LOADGP_RTP"
- "#"
- ""
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "&& mips_must_initialize_gp_p ()"
[(set (match_dup 0) (high:P (match_dup 3)))
(set (match_dup 0) (unspec:P [(match_dup 0)
(match_dup 3)] UNSPEC_LOAD_GOT))
@@ -4813,37 +4824,72 @@
operands[3] = mips_unspec_address (operands[1], SYMBOL_ABSOLUTE);
operands[4] = mips_unspec_address (operands[2], SYMBOL_HALF);
}
- [(set_attr "length" "12")])
+ [(set_attr "type" "ghost")])
;; Initialize the global pointer for MIPS16 code. Operand 0 is the
;; global pointer and operand 1 is the MIPS16 register that holds
;; the required value.
(define_insn_and_split "copygp_mips16"
[(set (match_operand:SI 0 "register_operand" "=y")
- (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "d")]
- UNSPEC_COPYGP))]
+ (unspec:SI [(match_operand:SI 1 "register_operand" "d")]
+ UNSPEC_COPYGP))]
"TARGET_MIPS16"
- "#"
- "&& reload_completed"
- [(set (match_dup 0) (match_dup 1))])
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "&& mips_must_initialize_gp_p ()"
+ [(set (match_dup 0) (match_dup 1))]
+ ""
+ [(set_attr "type" "ghost")])
+
+;; A placeholder for where the cprestore instruction should go,
+;; if we decide we need one. Operand 0 and operand 1 are as for
+;; "cprestore". Operand 2 is a register that holds the gp value.
+;;
+;; The "cprestore" pattern requires operand 2 to be pic_offset_table_rtx,
+;; otherwise any register that holds the correct value will do.
+(define_insn_and_split "potential_cprestore"
+ [(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
+ (unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
+ (match_operand:SI 2 "register_operand" "d,d")]
+ UNSPEC_POTENTIAL_CPRESTORE))
+ (clobber (match_operand:SI 3 "scratch_operand" "=X,&d"))]
+ "!TARGET_CPRESTORE_DIRECTIVE || operands[2] == pic_offset_table_rtx"
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "mips_must_initialize_gp_p ()"
+ [(const_int 0)]
+{
+ mips_save_gp_to_cprestore_slot (operands[0], operands[1],
+ operands[2], operands[3]);
+ DONE;
+}
+ [(set_attr "type" "ghost")])
;; Emit a .cprestore directive, which normally expands to a single store
-;; instruction. Note that we continue to use .cprestore for explicit reloc
-;; code so that jals inside inline asms will work correctly.
+;; instruction. Operand 0 is a (possibly illegitimate) sp-based MEM
+;; for the cprestore slot. Operand 1 is the offset of the slot from
+;; the stack pointer. (This is redundant with operand 0, but it makes
+;; things a little simpler.)
(define_insn "cprestore"
- [(unspec_volatile [(match_operand 0 "const_int_operand" "I,i")
- (use (reg:SI 28))]
- UNSPEC_CPRESTORE)]
- ""
+ [(set (match_operand:SI 0 "cprestore_save_slot_operand" "=X,X")
+ (unspec:SI [(match_operand:SI 1 "const_int_operand" "I,i")
+ (reg:SI 28)]
+ UNSPEC_CPRESTORE))]
+ "TARGET_CPRESTORE_DIRECTIVE"
{
if (mips_nomacro.nesting_level > 0 && which_alternative == 1)
- return ".set\tmacro\;.cprestore\t%0\;.set\tnomacro";
+ return ".set\tmacro\;.cprestore\t%1\;.set\tnomacro";
else
- return ".cprestore\t%0";
+ return ".cprestore\t%1";
}
[(set_attr "type" "store")
(set_attr "length" "4,12")])
+(define_insn "use_cprestore"
+ [(set (reg:SI CPRESTORE_SLOT_REGNUM)
+ (match_operand:SI 0 "cprestore_load_slot_operand"))]
+ ""
+ ""
+ [(set_attr "type" "ghost")])
+
;; Expand in-line code to clear the instruction cache between operand[0] and
;; operand[1].
(define_expand "clear_cache"
@@ -5149,100 +5195,94 @@
(define_insn "*branch_fp"
[(set (pc)
(if_then_else
- (match_operator 0 "equality_operator"
+ (match_operator 1 "equality_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
- (label_ref (match_operand 1 "" ""))
+ (label_ref (match_operand 0 "" ""))
(pc)))]
"TARGET_HARD_FLOAT"
{
return mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("b%F0", "%Z2%1"),
- MIPS_BRANCH ("b%W0", "%Z2%1"));
+ MIPS_BRANCH ("b%F1", "%Z2%0"),
+ MIPS_BRANCH ("b%W1", "%Z2%0"));
}
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
(define_insn "*branch_fp_inverted"
[(set (pc)
(if_then_else
- (match_operator 0 "equality_operator"
+ (match_operator 1 "equality_operator"
[(match_operand:CC 2 "register_operand" "z")
(const_int 0)])
(pc)
- (label_ref (match_operand 1 "" ""))))]
+ (label_ref (match_operand 0 "" ""))))]
"TARGET_HARD_FLOAT"
{
return mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("b%W0", "%Z2%1"),
- MIPS_BRANCH ("b%F0", "%Z2%1"));
+ MIPS_BRANCH ("b%W1", "%Z2%0"),
+ MIPS_BRANCH ("b%F1", "%Z2%0"));
}
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
;; Conditional branches on ordered comparisons with zero.
(define_insn "*branch_order<mode>"
[(set (pc)
(if_then_else
- (match_operator 0 "order_operator"
+ (match_operator 1 "order_operator"
[(match_operand:GPR 2 "register_operand" "d")
(const_int 0)])
- (label_ref (match_operand 1 "" ""))
+ (label_ref (match_operand 0 "" ""))
(pc)))]
"!TARGET_MIPS16"
{ return mips_output_order_conditional_branch (insn, operands, false); }
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
(define_insn "*branch_order<mode>_inverted"
[(set (pc)
(if_then_else
- (match_operator 0 "order_operator"
+ (match_operator 1 "order_operator"
[(match_operand:GPR 2 "register_operand" "d")
(const_int 0)])
(pc)
- (label_ref (match_operand 1 "" ""))))]
+ (label_ref (match_operand 0 "" ""))))]
"!TARGET_MIPS16"
{ return mips_output_order_conditional_branch (insn, operands, true); }
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
;; Conditional branch on equality comparison.
(define_insn "*branch_equality<mode>"
[(set (pc)
(if_then_else
- (match_operator 0 "equality_operator"
+ (match_operator 1 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d")
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
- (label_ref (match_operand 1 "" ""))
+ (label_ref (match_operand 0 "" ""))
(pc)))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("b%C0", "%2,%z3,%1"),
- MIPS_BRANCH ("b%N0", "%2,%z3,%1"));
+ MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
+ MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
}
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
(define_insn "*branch_equality<mode>_inverted"
[(set (pc)
(if_then_else
- (match_operator 0 "equality_operator"
+ (match_operator 1 "equality_operator"
[(match_operand:GPR 2 "register_operand" "d")
(match_operand:GPR 3 "reg_or_0_operand" "dJ")])
(pc)
- (label_ref (match_operand 1 "" ""))))]
+ (label_ref (match_operand 0 "" ""))))]
"!TARGET_MIPS16"
{
return mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
- MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
+ MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
+ MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
}
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
;; MIPS16 branches
@@ -5271,8 +5311,7 @@
return "bt%N0z\t%3";
}
}
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
(define_expand "cbranch<mode>4"
[(set (pc)
@@ -5313,42 +5352,40 @@
[(set (pc)
(if_then_else
(equality_op (zero_extract:GPR
- (match_operand:GPR 0 "register_operand" "d")
+ (match_operand:GPR 1 "register_operand" "d")
(const_int 1)
(match_operand 2 "const_int_operand" ""))
(const_int 0))
- (label_ref (match_operand 1 ""))
+ (label_ref (match_operand 0 ""))
(pc)))]
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
{
return
mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("bbit<bbv>", "%0,%2,%1"),
- MIPS_BRANCH ("bbit<bbinv>", "%0,%2,%1"));
+ MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"),
+ MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"));
}
[(set_attr "type" "branch")
- (set_attr "mode" "none")
(set_attr "branch_likely" "no")])
(define_insn "*branch_bit<bbv><mode>_inverted"
[(set (pc)
(if_then_else
(equality_op (zero_extract:GPR
- (match_operand:GPR 0 "register_operand" "d")
+ (match_operand:GPR 1 "register_operand" "d")
(const_int 1)
(match_operand 2 "const_int_operand" ""))
(const_int 0))
(pc)
- (label_ref (match_operand 1 ""))))]
+ (label_ref (match_operand 0 ""))))]
"ISA_HAS_BBIT && UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
{
return
mips_output_conditional_branch (insn, operands,
- MIPS_BRANCH ("bbit<bbinv>", "%0,%2,%1"),
- MIPS_BRANCH ("bbit<bbv>", "%0,%2,%1"));
+ MIPS_BRANCH ("bbit<bbinv>", "%1,%2,%0"),
+ MIPS_BRANCH ("bbit<bbv>", "%1,%2,%0"));
}
[(set_attr "type" "branch")
- (set_attr "mode" "none")
(set_attr "branch_likely" "no")])
;;
@@ -5535,47 +5572,41 @@
;; Unconditional branches.
-(define_insn "jump"
+(define_expand "jump"
[(set (pc)
- (label_ref (match_operand 0 "" "")))]
- "!TARGET_MIPS16"
+ (label_ref (match_operand 0)))])
+
+(define_insn "*jump_absolute"
+ [(set (pc)
+ (label_ref (match_operand 0)))]
+ "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
+ { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+ [(set_attr "type" "jump")])
+
+(define_insn "*jump_pic"
+ [(set (pc)
+ (label_ref (match_operand 0)))]
+ "!TARGET_MIPS16 && !TARGET_ABSOLUTE_JUMPS"
{
- if (flag_pic)
+ if (get_attr_length (insn) <= 8)
+ return "%*b\t%l0%/";
+ else
{
- if (get_attr_length (insn) <= 8)
- return "%*b\t%l0%/";
- else
- {
- output_asm_insn (mips_output_load_label (), operands);
- return "%*jr\t%@%/%]";
- }
+ mips_output_load_label (operands[0]);
+ return "%*jr\t%@%/%]";
}
- else
- return "%*j\t%l0%/";
}
- [(set_attr "type" "jump")
- (set_attr "mode" "none")
- (set (attr "length")
- ;; We can't use `j' when emitting PIC. Emit a branch if it's
- ;; in range, otherwise load the address of the branch target into
- ;; $at and then jump to it.
- (if_then_else
- (ior (eq (symbol_ref "flag_pic") (const_int 0))
- (lt (abs (minus (match_dup 0)
- (plus (pc) (const_int 4))))
- (const_int 131072)))
- (const_int 4) (const_int 16)))])
+ [(set_attr "type" "branch")])
;; We need a different insn for the mips16, because a mips16 branch
;; does not have a delay slot.
-(define_insn ""
+(define_insn "*jump_mips16"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
"TARGET_MIPS16"
"b\t%l0"
- [(set_attr "type" "branch")
- (set_attr "mode" "none")])
+ [(set_attr "type" "branch")])
(define_expand "indirect_jump"
[(set (pc) (match_operand 0 "register_operand"))]
@@ -5876,14 +5907,28 @@
(clobber (match_scratch:SI 0 "=&d"))]
"TARGET_CALL_CLOBBERED_GP"
"#"
- "&& reload_completed"
+ "&& epilogue_completed"
[(const_int 0)]
{
- mips_restore_gp (operands[0]);
+ mips_restore_gp_from_cprestore_slot (operands[0]);
DONE;
}
- [(set_attr "type" "load")
- (set_attr "length" "12")])
+ [(set_attr "type" "ghost")])
+
+;; Move between $gp and its register save slot.
+(define_insn_and_split "move_gp<mode>"
+ [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,m")
+ (unspec:GPR [(match_operand:GPR 1 "move_operand" "m,d")]
+ UNSPEC_MOVE_GP))]
+ ""
+ { return mips_must_initialize_gp_p () ? "#" : ""; }
+ "mips_must_initialize_gp_p ()"
+ [(const_int 0)]
+{
+ mips_emit_move (operands[0], operands[1]);
+ DONE;
+}
+ [(set_attr "type" "ghost")])
;;
;; ....................