summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gcc/config/rs6000/predicates.md13
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c123
-rw-r--r--gcc/config/rs6000/rs6000.md98
4 files changed, 204 insertions, 31 deletions
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 2f40462159e..b45cda1b981 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1195,6 +1195,19 @@
(match_code ("unlt,unle,ungt,unge"))))
(match_operand 0 "comparison_operator")))
+;; Return 1 if OP is a valid comparison operator for "fused cbranch"
+;; instructions
+(define_predicate "rs6000_fused_cbranch_operator"
+ (match_operand 0 "comparison_operator")
+{
+ if(GET_CODE(XEXP(op,1)) == CONST_INT )
+ {
+ if((INTVAL(XEXP(op,1)) < 32) && (INTVAL(XEXP(op,1)) >= 0)) return 1;
+ else return 0;
+ }
+ return 1;
+})
+
;; Return 1 if OP is a comparison operation that is valid for an SCC insn --
;; it must be a positive comparison.
(define_predicate "scc_comparison_operator"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index e1355b3a615..62e6c558b5c 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -111,6 +111,7 @@ extern enum rtx_code rs6000_reverse_condition (enum machine_mode,
extern void rs6000_emit_sISEL (enum machine_mode, rtx[]);
extern void rs6000_emit_sCOND (enum machine_mode, rtx[]);
extern void rs6000_emit_cbranch (enum machine_mode, rtx[]);
+extern char * output_fused_cbranch (rtx operands[], const char *, rtx);
extern char * output_cbranch (rtx, const char *, int, rtx);
extern char * output_e500_flip_gt_bit (rtx, rtx);
extern const char * output_probe_stack_range (rtx, rtx);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index c4864144abd..e1f66c99ab9 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -19134,13 +19134,51 @@ rs6000_emit_cbranch (enum machine_mode mode, rtx operands[])
{
rtx condition_rtx, loc_ref;
- condition_rtx = rs6000_generate_compare (operands[0], mode);
+ // For fused compare-branch
+ // jump distance +- 2k
+ // Compare immediate limited to uint_5 (0-31)
+ //
+ //debug_rtx(operands[0]); // (eq (reg/v:SI 157 [ a ]) (const_int 31 [0x1f]))
+ //debug_rtx(operands[1]); // (reg/v:SI 157 [ a ])
+ //debug_rtx(operands[2]); // (const_int 31 [0x1f])
+ //debug_rtx(operands[3]); // (code_label 0 0 0 9 "" [0 uses])
+ //debug_rtx(condition_rtx); // (eq (reg:CC 158) (const_int 0 [0]))
+ //debug_rtx(loc_ref); // (label_ref 0)
+
loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
- emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
- gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
- loc_ref, pc_rtx)));
+
+ // TODO if not PPE42
+ // Split the compare and branch if not optimized for size
+ // or can't meet the constraints of fused compare-branch.
+ if(!optimize_size ||
+ ((GET_CODE (operands[2]) == CONST_INT) &&
+ ((INTVAL(operands[2]) < 0) || (INTVAL(operands[2]) > 31))))
+ {
+ condition_rtx = rs6000_generate_compare (operands[0], mode);
+
+ emit_jump_insn (gen_rtx_SET (VOIDmode,
+ pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ condition_rtx,
+ loc_ref,
+ pc_rtx)));
+ // Note: even if the compare/branch is split here, the compiler might
+ // re-combine them (fuse) later in the 201r.combine step based
+ // on the *.md match - that can be controlled with the
+ // rs6000_fused_cbranch_operator predicate and the optimize_size flag.
+ }
+ else // Use the PPE fused compare-branch instructions
+ {
+ emit_jump_insn(gen_rtx_SET(VOIDmode,
+ pc_rtx,
+ gen_rtx_IF_THEN_ELSE(VOIDmode,
+ operands[0],
+ loc_ref,
+ pc_rtx)));
+ }
}
+
/* Return the string to output a conditional branch to LABEL, which is
the operand template of the label, or NULL if the branch is really a
conditional return.
@@ -19154,6 +19192,83 @@ rs6000_emit_cbranch (enum machine_mode mode, rtx operands[])
INSN is the insn. */
char *
+output_fused_cbranch (rtx operands[], const char *label, rtx insn)
+{
+ static char string[64];
+ enum rtx_code code = GET_CODE (operands[1]);
+ int need_longbranch = get_attr_length (insn) == 8;
+ char *s = string;
+ const char *ccode;
+ const char *immed = "";
+ const char *logical = "";
+ int op3 = 0;
+
+ if(need_longbranch)
+ code = reverse_condition (code);
+
+ switch (code)
+ {
+ case NE:
+ case LTGT:
+ ccode = "ne";
+ break;
+ case EQ:
+ case UNEQ:
+ ccode = "eq";
+ break;
+ case GE:
+ case GEU:
+ ccode = "ge";
+ break;
+ case GT:
+ case GTU:
+ case UNGT:
+ ccode = "gt";
+ break;
+ case LE:
+ case LEU:
+ ccode = "le";
+ break;
+ case LT:
+ case LTU: case UNLT:
+ ccode = "lt";
+ break;
+ default:
+ gcc_unreachable();
+ }
+
+ // Set immediate
+ // Can't do unsigned(logical) compare on immediate
+ if(GET_CODE (operands[3]) == CONST_INT)
+ {
+ op3 = INTVAL(operands[3]);
+ immed = "i";
+ }
+ else if( unsigned_reg_p (operands[2]) &&
+ unsigned_reg_p (operands[3]))
+ {
+ logical = "l";
+ op3 = REGNO(operands[3]);
+ }
+ else
+ {
+ op3 = REGNO(operands[3]);
+ }
+
+
+ s += sprintf(s, "cmp%sw%sb%s %d, %d", logical,
+ immed, ccode, REGNO(operands[2]), op3);
+
+ if (need_longbranch)
+ s += sprintf(s, ",$+8\n\tb %s", label);
+ else
+ s += sprintf(s, ",%s", label);
+
+ return string;
+}
+
+
+char *
output_cbranch (rtx op, const char *label, int reversed, rtx insn)
{
static char string[64];
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 47aa2398fe2..4860b1731b2 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -160,7 +160,8 @@
;; Define an insn type attribute. This is used in function unit delay
;; computations.
-(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,vecdouble,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr,isel,popcnt,crypto,htm"
+(define_attr "type"
+"integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,fused_branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,vecdouble,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr,isel,popcnt,crypto,htm"
(const_string "integer"))
;; Define floating point instruction sub-types for use with Xfpu.md
@@ -177,7 +178,14 @@
(const_int 32764)))
(const_int 4)
(const_int 8))
- (const_int 4)))
+ (if_then_else (eq_attr "type" "fused_branch")
+ (if_then_else (and (ge(minus (match_dup 0) (pc))
+ (const_int -2048))
+ (lt (minus (match_dup 0) (pc))
+ (const_int 2044)))
+ (const_int 4)
+ (const_int 8))
+ (const_int 4))))
;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in rs6000-opts.h.
@@ -1221,7 +1229,8 @@
(match_test "update_address_mem (operands[1], VOIDmode)")
(const_string "load_ext_u")
(const_string "load_ext")))
- (const_string "exts")])])
+ (const_string "exts")])
+ (set_attr "length" "8,4")])
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
@@ -10202,13 +10211,13 @@
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
- #
- #
- #
+ stvd%U0%X0 %1, %0
+ lvd%U1%X1 %0, %1
+ # ret to reg not supported
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
- #"
+ # What is this? movdi_internal32"
[(set_attr_alternative "type"
[(const_string "store")
(const_string "load")
@@ -10249,14 +10258,15 @@
operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
}")
-(define_split
- [(set (match_operand:DIFD 0 "rs6000_nonimmediate_operand" "")
- (match_operand:DIFD 1 "input_operand" ""))]
- "reload_completed && !TARGET_POWERPC64
- && gpr_or_gpr_p (operands[0], operands[1])
- && !direct_move_p (operands[0], operands[1])"
- [(pc)]
-{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
+;; disable DImode load/store splits for PPE - use 64-bit load/store instructions
+;;(define_split
+;; [(set (match_operand:DIFD 0 "rs6000_nonimmediate_operand" "")
+;; (match_operand:DIFD 1 "input_operand" ""))]
+;; "reload_completed && !TARGET_POWERPC64
+;; && gpr_or_gpr_p (operands[0], operands[1])
+;; && !direct_move_p (operands[0], operands[1])"
+;; [(pc)]
+;;{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
(define_insn "*movdi_internal64"
[(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,r,?*wg,r,?*wj,?*wi")
@@ -11043,7 +11053,8 @@
"@
lwzx %3,%0,%2\;add %0,%0,%2
lwzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movsi_update2"
[(set (match_operand:DI 3 "gpc_reg_operand" "=r")
@@ -11071,7 +11082,8 @@
"@
stwx %3,%0,%2\;add %0,%0,%2
stwu %3,%2(%0)"
- [(set_attr "type" "store_ux,store_u")])
+ [(set_attr "type" "store_ux,store_u")
+ (set_attr "length" "8,4")])
;; This is an unconditional pattern; needed for stack allocation, even
;; if the user passes -mno-update.
@@ -11085,7 +11097,8 @@
"@
stwx %3,%0,%2\;add %0,%0,%2
stwu %3,%2(%0)"
- [(set_attr "type" "store_ux,store_u")])
+ [(set_attr "type" "store_ux,store_u")
+ (set_attr "length" "8,4")])
(define_insn "*movhi_update1"
[(set (match_operand:HI 3 "gpc_reg_operand" "=r,r")
@@ -11099,7 +11112,8 @@
"@
lhzx %3,%0,%2\;add %0,%0,%2
lhzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movhi_update2"
[(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
@@ -11114,7 +11128,8 @@
"@
lhzx %3,%0,%2\;add %0,%0,%2
lhzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movhi_update3"
[(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
@@ -11129,7 +11144,8 @@
"@
lhzx %3,%0,%2\;add %0,%0,%2\;extsh %3,%3
lhzu %3,%2(%0)\;extsh %3,%3"
- [(set_attr "type" "load_ext_ux,load_ext_u")])
+ [(set_attr "type" "load_ext_ux,load_ext_u")
+ (set_attr "length" "12,8")])
(define_insn "*movhi_update4"
[(set (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
@@ -11143,7 +11159,8 @@
"@
sthx %3,%0,%2\;add %0,%0,%2
sthu %3,%2(%0)"
- [(set_attr "type" "store_ux,store_u")])
+ [(set_attr "type" "store_ux,store_u")
+ (set_attr "length" "8,4")])
(define_insn "*movqi_update1"
[(set (match_operand:QI 3 "gpc_reg_operand" "=r,r")
@@ -11157,7 +11174,8 @@
"@
lbzx %3, %0, %2\;add %0,%0,%2
lbzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movqi_update2"
[(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
@@ -11172,7 +11190,8 @@
"@
lbzx %3,%0,%2\;add %0,%0,%2
lbzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movqi_update3"
[(set (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
@@ -11186,7 +11205,8 @@
"@
stbx %3,%0,%2\;add %0,%0,%2
stbu %3,%2(%0)"
- [(set_attr "type" "store_ux,store_u")])
+ [(set_attr "type" "store_ux,store_u")
+ (set_attr "length" "8,4")])
(define_insn "*movsf_update1"
[(set (match_operand:SF 3 "gpc_reg_operand" "=f,f")
@@ -11228,7 +11248,8 @@
"@
lwzx %3,%0,%2\;add %0,%0,%2
lwzu %3,%2(%0)"
- [(set_attr "type" "load_ux,load_u")])
+ [(set_attr "type" "load_ux,load_u")
+ (set_attr "length" "8,4")])
(define_insn "*movsf_update4"
[(set (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
@@ -11242,7 +11263,8 @@
"@
stwx %3,%0,%2\;add %0,%0,%2
stwu %3,%2(%0)"
- [(set_attr "type" "store_ux,store_u")])
+ [(set_attr "type" "store_ux,store_u")
+ (set_attr "length" "8,4")])
(define_insn "*movdf_update1"
[(set (match_operand:DF 3 "gpc_reg_operand" "=d,d")
@@ -14657,6 +14679,28 @@
[(set_attr "type" "jmpreg")
(set_attr "length" "4")])
+;; Define PPE fused compare and branch
+;; TODO handle branch outside of signed short int range?
+;; There is no cmplwib<cond> fused instruction!!!
+;; If op 3 is a reg then no problem - if op3 is short then use
+;; something else
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 1 "rs6000_fused_cbranch_operator"
+ [(match_operand:GPR 2 "gpc_reg_operand" "r")
+ (match_operand:GPR 3 "reg_or_short_operand" "rI")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "optimize_size"
+ "*
+{
+ return output_fused_cbranch (operands, \"%l0\", insn);
+}"
+ [(set_attr "type" "fused_branch")])
+
+
+
+
;; Logic on condition register values.
; This pattern matches things like
OpenPOWER on IntegriCloud