Commit fed58818 authored by Doug Gilbert's avatar Doug Gilbert Committed by Patrick Williams

Compare-branch fused instructions

parent 0081fa34
......@@ -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"
......
......@@ -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);
......
......@@ -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.
......@@ -19153,6 +19191,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)
{
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment