diff options
-rw-r--r-- | gcc/config/rs6000/predicates.md | 13 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 123 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 98 |
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 |