--- gcc/config/sparc.md 2018/04/24 17:54:53 1.1.1.2 +++ gcc/config/sparc.md 2018/04/24 18:05:41 1.1.1.4 @@ -29,7 +29,7 @@ ;; type "call_no_delay_slot" is a call followed by an unimp instruction. (define_attr "type" - "move,unary,binary,compare,load,store,branch,call,call_no_delay_slot,address,fpload,fpstore,fp,fpcmp,fpmul,fpdiv,fpsqrt,multi,misc" + "move,unary,binary,compare,load,store,uncond_branch,branch,call,call_no_delay_slot,address,fpload,fpstore,fp,fpcmp,fpmul,fpdiv,fpsqrt,multi,misc" (const_string "binary")) ;; Set true if insn uses call-clobbered intermediate register. @@ -72,7 +72,7 @@ ;; Attributes for instruction and branch scheduling (define_attr "in_call_delay" "false,true" - (cond [(eq_attr "type" "branch,call,call_no_delay_slot,multi") + (cond [(eq_attr "type" "uncond_branch,branch,call,call_no_delay_slot,multi") (const_string "false") (eq_attr "type" "load,fpload,store,fpstore") (if_then_else (eq_attr "length" "1") @@ -93,20 +93,44 @@ ;; branches. This would allow us to remove the nop always inserted before ;; a floating point branch. +;; ??? It is OK for fill_simple_delay_slots to put load/store instructions +;; in a delay slot, but it is not OK for fill_eager_delay_slots to do so. +;; This is because doing so will add several pipeline stalls to the path +;; that the load/store did not come from. Unfortunately, there is no way +;; to prevent fill_eager_delay_slots from using load/store without completely +;; disabling them. For the SPEC benchmark set, this is a serious lose, +;; because it prevents us from moving back the final store of inner loops. + (define_attr "in_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!branch,call,call_no_delay_slot,multi") + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi") + (eq_attr "length" "1")) + (const_string "true") + (const_string "false"))) + +(define_attr "in_uncond_branch_delay" "false,true" + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi") + (eq_attr "length" "1")) + (const_string "true") + (const_string "false"))) + +(define_attr "in_annul_branch_delay" "false,true" + (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi") (eq_attr "length" "1")) (const_string "true") (const_string "false"))) (define_delay (eq_attr "type" "branch") [(eq_attr "in_branch_delay" "true") - (nil) (eq_attr "in_branch_delay" "true")]) + (nil) (eq_attr "in_annul_branch_delay" "true")]) +(define_delay (eq_attr "type" "uncond_branch") + [(eq_attr "in_uncond_branch_delay" "true") + (nil) (nil)]) + ;; Function units of the SPARC ;; (define_function_unit {name} {num-units} {n-users} {test} -;; {ready-delay} {busy-delay} [{conflict-list}]) +;; {ready-delay} {issue-delay} [{conflict-list}]) ;; The integer ALU. ;; (Noted only for documentation; units that take one cycle do not need to @@ -116,7 +140,7 @@ ;; (eq_attr "type" "unary,binary,move,address") 1 0) ;; Memory with load-delay of 1 (i.e., 2 cycle load). -(define_function_unit "memory" 1 0 (eq_attr "type" "load,fpload") 2 0) +(define_function_unit "memory" 1 1 (eq_attr "type" "load,fpload") 2 0) ;; SPARC has two floating-point units: the FP ALU, ;; and the FP MUL/DIV/SQRT unit. @@ -135,14 +159,12 @@ ;; FiTOs/d 9/5 ;; The CY7C602 can only support 2 fp isnsn simultaneously. -;; More insns cause the chip to stall. Until we handle this -;; better in the scheduler, we use excess cycle times to -;; more evenly spread out fp insns. - -(define_function_unit "fp_alu" 1 2 (eq_attr "type" "fp") 8 0) -(define_function_unit "fp_mul" 1 2 (eq_attr "type" "fpmul") 10 0) -(define_function_unit "fp_div" 1 2 (eq_attr "type" "fpdiv") 23 0) -(define_function_unit "fp_sqrt" 1 2 (eq_attr "type" "fpsqrt") 34 0) +;; More insns cause the chip to stall. + +(define_function_unit "fp_alu" 1 1 (eq_attr "type" "fp") 5 0) +(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpmul") 7 0) +(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpdiv") 37 0) +(define_function_unit "fp_mds" 1 1 (eq_attr "type" "fpsqrt") 63 0) ;; Compare instructions. ;; This controls RTL generation and register allocation. @@ -198,6 +220,18 @@ DONE; }") +(define_expand "cmptf" + [(set (reg:CCFP 0) + (compare:CCFP (match_operand:TF 0 "register_operand" "") + (match_operand:TF 1 "register_operand" "")))] + "" + " +{ + sparc_compare_op0 = operands[0]; + sparc_compare_op1 = operands[1]; + DONE; +}") + ;; Next come the scc insns. For seq, sne, sgeu, and sltu, we can do this ;; without jumps using the addx/subx instructions. For the rest, we do ;; branches. Seq_special and sne_special clobber the CC reg, because they @@ -350,18 +384,42 @@ (define_insn "" [(set (reg:CC 0) - (compare:CC (match_operand:SI 0 "register_operand" "rJ") + (compare:CC (match_operand:SI 0 "register_operand" "r") (match_operand:SI 1 "arith_operand" "rI")))] "" "cmp %r0,%1" [(set_attr "type" "compare")]) (define_insn "" + [(set (reg:CCFPE 0) + (compare:CCFPE (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f")))] + "" + "fcmped %0,%1" + [(set_attr "type" "fpcmp")]) + +(define_insn "" + [(set (reg:CCFPE 0) + (compare:CCFPE (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f")))] + "" + "fcmpes %0,%1" + [(set_attr "type" "fpcmp")]) + +(define_insn "" + [(set (reg:CCFPE 0) + (compare:CCFPE (match_operand:TF 0 "register_operand" "f") + (match_operand:TF 1 "register_operand" "f")))] + "" + "fcmpeq %0,%1" + [(set_attr "type" "fpcmp")]) + +(define_insn "" [(set (reg:CCFP 0) (compare:CCFP (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f")))] "" - "fcmped %0,%1" + "fcmpd %0,%1" [(set_attr "type" "fpcmp")]) (define_insn "" @@ -369,7 +427,15 @@ (compare:CCFP (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "register_operand" "f")))] "" - "fcmpes %0,%1" + "fcmps %0,%1" + [(set_attr "type" "fpcmp")]) + +(define_insn "" + [(set (reg:CCFP 0) + (compare:CCFP (match_operand:TF 0 "register_operand" "f") + (match_operand:TF 1 "register_operand" "f")))] + "" + "fcmpq %0,%1" [(set_attr "type" "fpcmp")]) ;; The SEQ and SNE patterns are special because they can be done @@ -567,7 +633,7 @@ ;; turn something that does not require a jump into something that does. (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") - (match_operator:SI 1 "normal_comp_operator" [(reg 0) (const_int 0)]))] + (match_operator:SI 1 "noov_compare_op" [(reg 0) (const_int 0)]))] "" "* return output_scc_insn (operands, insn); " [(set_attr "type" "multi") @@ -830,7 +896,7 @@ (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") - (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "0") (match_operand:DI 2 "immediate_operand" "in")))] "" "* @@ -989,8 +1055,8 @@ }") (define_insn "" - [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) - (mem:BLK (match_operand:SI 1 "register_operand" "r"))) + [(set (mem:BLK (match_operand:SI 0 "register_operand" "+r")) + (mem:BLK (match_operand:SI 1 "register_operand" "+r"))) (use (match_operand:SI 2 "nonmemory_operand" "rn")) (use (match_operand:SI 3 "immediate_operand" "i")) (clobber (match_dup 0)) @@ -1005,14 +1071,77 @@ ;; Floating point move insns +;; This pattern forces (set (reg:TF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movtf pattern. +(define_insn "" + [(set (match_operand:TF 0 "general_operand" "=?r,f,o") + (match_operand:TF 1 "" "?E,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + switch (which_alternative) + { + case 0: + return output_move_quad (operands); + case 1: + return output_fp_move_quad (operands); + case 2: + operands[1] = adj_offsettable_operand (operands[0], 4); + operands[2] = adj_offsettable_operand (operands[0], 8); + operands[3] = adj_offsettable_operand (operands[0], 12); + return \"st %%g0,%0\;st %%g0,%1\;st %%g0,%2\;st %%g0,%3\"; + } +}" + [(set_attr "type" "load,fpload,store") + (set_attr "length" "5,5,5")]) + +(define_expand "movtf" + [(set (match_operand:TF 0 "general_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "" + " +{ + if (emit_move_sequence (operands, TFmode, 0)) + DONE; +}") + +(define_insn "" + [(set (match_operand:TF 0 "reg_or_nonsymb_mem_operand" "=f,r,Q,Q,f,&r,?f,?r") + (match_operand:TF 1 "reg_or_nonsymb_mem_operand" "f,r,f,r,Q,Q,r,f"))] + "register_operand (operands[0], TFmode) + || register_operand (operands[1], TFmode)" + "* +{ + if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) + return output_fp_move_quad (operands); + return output_move_quad (operands); +}" + [(set_attr "type" "fp,move,fpstore,store,fpload,load,multi,multi") + (set_attr "length" "4,4,5,5,5,5,5,5")]) + +(define_insn "" + [(set (mem:TF (match_operand:SI 0 "symbolic_operand" "i,i")) + (match_operand:TF 1 "reg_or_0_operand" "rf,G")) + (clobber (match_scratch:SI 2 "=&r,&r"))] + "" + "* +{ + output_asm_insn (\"sethi %%hi(%a0),%2\", operands); + if (which_alternative == 0) + return \"std %1,[%2+%%lo(%a0)]\;std %S1,[%2+%%lo(%a0+8)]\"; + else + return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\; st %%g0,[%2+%%lo(%a0+8)]\;st %%g0,[%2+%%lo(%a0+12)]\"; +}" + [(set_attr "type" "store") + (set_attr "length" "5")]) + ;; This pattern forces (set (reg:DF ...) (const_double ...)) ;; to be reloaded by putting the constant into memory. ;; It must come before the more general movdf pattern. -;; ??? A similar pattern for SF mode values would also be useful, but it -;; is not as easy to write. (define_insn "" - [(set (match_operand:DF 0 "general_operand" "=?r,r,f,o") - (match_operand:DF 1 "" "?E,G,m,G"))] + [(set (match_operand:DF 0 "general_operand" "=?r,f,o") + (match_operand:DF 1 "" "?E,m,G"))] "GET_CODE (operands[1]) == CONST_DOUBLE" "* { @@ -1021,16 +1150,14 @@ case 0: return output_move_double (operands); case 1: - return \"mov %%g0,%0\;mov %%g0,%R0\"; - case 2: return output_fp_move_double (operands); - case 3: + case 2: operands[1] = adj_offsettable_operand (operands[0], 4); return \"st %%g0,%0\;st %%g0,%1\"; } }" - [(set_attr "type" "load,move,fpload,store") - (set_attr "length" "3,2,3,3")]) + [(set_attr "type" "load,fpload,store") + (set_attr "length" "3,3,3")]) (define_expand "movdf" [(set (match_operand:DF 0 "general_operand" "") @@ -1043,8 +1170,8 @@ }") (define_insn "" - [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=f,r,Q,Q,f,&r,?f,?r") - (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "f,r,f,r,Q,Q,r,f"))] + [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=T,U,f,r,Q,Q,f,&r,?f,?r") + (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "U,T,f,r,f,r,Q,Q,r,f"))] "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" "* @@ -1053,8 +1180,8 @@ return output_fp_move_double (operands); return output_move_double (operands); }" - [(set_attr "type" "fp,move,fpstore,store,fpload,load,multi,multi") - (set_attr "length" "2,2,3,3,3,3,3,3")]) + [(set_attr "type" "fpstore,fpload,fp,move,fpstore,store,fpload,load,multi,multi") + (set_attr "length" "1,1,2,2,3,3,3,3,3,3")]) (define_insn "" [(set (mem:DF (match_operand:SI 0 "symbolic_operand" "i,i")) @@ -1101,6 +1228,28 @@ ;; Floating-point move insns. +;; This pattern forces (set (reg:SF ...) (const_double ...)) +;; to be reloaded by putting the constant into memory. +;; It must come before the more general movsf pattern. +(define_insn "" + [(set (match_operand:SF 0 "general_operand" "=?r,f,m") + (match_operand:SF 1 "" "?E,m,G"))] + "GET_CODE (operands[1]) == CONST_DOUBLE" + "* +{ + switch (which_alternative) + { + case 0: + return singlemove_string (operands); + case 1: + return \"ld %1,%0\"; + case 2: + return \"st %%g0,%0\"; + } +}" + [(set_attr "type" "load,fpload,store") + (set_attr "length" "2,1,1")]) + (define_expand "movsf" [(set (match_operand:SF 0 "general_operand" "") (match_operand:SF 1 "general_operand" ""))] @@ -1322,7 +1471,7 @@ return \"andcc %0,%1,%%g0\"; }") -;; Conversions between float and double. +;; Conversions between float, double and long double. (define_insn "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1332,6 +1481,22 @@ "fstod %1,%0" [(set_attr "type" "fp")]) +(define_insn "extendsftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (float_extend:TF + (match_operand:SF 1 "register_operand" "f")))] + "" + "fstoq %1,%0" + [(set_attr "type" "fp")]) + +(define_insn "extenddftf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (float_extend:TF + (match_operand:DF 1 "register_operand" "f")))] + "" + "fdtoq %1,%0" + [(set_attr "type" "fp")]) + (define_insn "truncdfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF @@ -1339,71 +1504,69 @@ "" "fdtos %1,%0" [(set_attr "type" "fp")]) + +(define_insn "trunctfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF + (match_operand:TF 1 "register_operand" "f")))] + "" + "fqtos %1,%0" + [(set_attr "type" "fp")]) + +(define_insn "trunctfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float_truncate:DF + (match_operand:TF 1 "register_operand" "f")))] + "" + "fqtod %1,%0" + [(set_attr "type" "fp")]) ;; Conversion between fixed point and floating point. (define_insn "floatsisf2" - [(set (match_operand:SF 0 "general_operand" "=f") - (float:SF (match_operand:SI 1 "nonimmediate_operand" "rfm")))] + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "register_operand" "f")))] "" - "* return output_floatsisf2 (operands);" - [(set_attr "type" "fp") - (set_attr "length" "3")]) + "fitos %1,%0" + [(set_attr "type" "fp")]) (define_insn "floatsidf2" - [(set (match_operand:DF 0 "general_operand" "=f") - (float:DF (match_operand:SI 1 "nonimmediate_operand" "rfm")))] + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "register_operand" "f")))] "" - "* return output_floatsidf2 (operands);" - [(set_attr "type" "fp") - (set_attr "length" "3")]) + "fitod %1,%0" + [(set_attr "type" "fp")]) + +(define_insn "floatsitf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (float:TF (match_operand:SI 1 "register_operand" "f")))] + "" + "fitox %1,%0" + [(set_attr "type" "fp")]) ;; Convert a float to an actual integer. ;; Truncation is performed as part of the conversion. (define_insn "fix_truncsfsi2" - [(set (match_operand:SI 0 "general_operand" "=rm") - (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm")))) - (clobber (match_scratch:SF 2 "=&f"))] + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))] "" - "* -{ - if (FP_REG_P (operands[1])) - output_asm_insn (\"fstoi %1,%2\", operands); - else - output_asm_insn (\"ld %1,%2\;fstoi %2,%2\", operands); - if (GET_CODE (operands[0]) == MEM) - return \"st %2,%0\"; - else - return \"st %2,[%%fp-4]\;ld [%%fp-4],%0\"; -}" - [(set_attr "type" "fp") - (set_attr "length" "3")]) + "fstoi %1,%0" + [(set_attr "type" "fp")]) (define_insn "fix_truncdfsi2" - [(set (match_operand:SI 0 "general_operand" "=rm") - (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm")))) - (clobber (match_scratch:DF 2 "=&f"))] + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))] "" - "* -{ - if (FP_REG_P (operands[1])) - output_asm_insn (\"fdtoi %1,%2\", operands); - else - { - rtx xoperands[3]; - xoperands[0] = operands[2]; - xoperands[1] = operands[1]; - output_asm_insn (output_fp_move_double (xoperands), xoperands); - output_asm_insn (\"fdtoi %2,%2\", operands); - } - if (GET_CODE (operands[0]) == MEM) - return \"st %2,%0\"; - else - return \"st %2,[%%fp-4]\;ld [%%fp-4],%0\"; -}" - [(set_attr "type" "fp") - (set_attr "length" "3")]) + "fdtoi %1,%0" + [(set_attr "type" "fp")]) + +(define_insn "fix_trunctfsi2" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "f"))))] + "" + "fqtoi %1,%0" + [(set_attr "type" "fp")]) ;;- arithmetic instructions @@ -1523,6 +1686,88 @@ "" "subcc %1,%2,%0") +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "arith_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI")))] + "TARGET_V8 || TARGET_SPARCLITE" + "smul %1,%2,%0") + +;; It is not known whether this will match. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "arith_operand" "%r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (reg:CC_NOOV 0) + (compare:CC_NOOV (mult:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "TARGET_V8 || TARGET_SPARCLITE" + "smulcc %1,%2,%0") + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (mult:DI (sign_extend:DI (match_operand:SI 1 "arith_operand" "%r")) + (sign_extend:DI (match_operand:SI 2 "arith_operand" "rI"))))] + "TARGET_V8 || TARGET_SPARCLITE" + "smul %1,%2,%R0\;rd %y,%0" + [(set_attr "length" "2")]) + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "arith_operand" "%r")) + (zero_extend:DI (match_operand:SI 2 "arith_operand" "rI"))))] + "TARGET_V8 || TARGET_SPARCLITE" + "umul %1,%2,%R0\;rd %y,%0" + [(set_attr "length" "2")]) + +;; The architecture specifies that there must be 3 instructions between +;; a y register write and a use of it for correct results. + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (clobber (match_scratch:SI 3 "=&r"))] + "TARGET_V8" + "sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdiv %1,%2,%0" + [(set_attr "length" "3")]) + +;; It is not known whether this will match. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (reg:CC 0) + (compare:CC (div:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (clobber (match_scratch:SI 3 "=&r"))] + "TARGET_V8" + "sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdivcc %1,%2,%0" + [(set_attr "length" "3")]) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI")))] + "TARGET_V8" + "wr %%g0,%%g0,%%y\;nop\;nop\;nop\;udiv %1,%2,%0" + [(set_attr "length" "2")]) + +;; It is not known whether this will match. + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "arith_operand" "rI"))) + (set (reg:CC 0) + (compare:CC (udiv:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "TARGET_V8" + "wr %%g0,%%g0,%%y\;nop\;nop\;nop\;udivcc %1,%2,%0" + [(set_attr "length" "2")]) + ;;- and instructions ;; We define DImode `and` so with DImode `not` we can get ;; DImode `andn`. Other combinations are possible. @@ -1572,6 +1817,21 @@ "" "and %1,%2,%0") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "" ""))) + (clobber (match_operand:SI 3 "register_operand" ""))] + "GET_CODE (operands[2]) == CONST_INT + && !SMALL_INT (operands[2]) + && (INTVAL (operands[2]) & 0x3ff) == 0x3ff" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) (and:SI (not:SI (match_dup 3)) (match_dup 1)))] + " +{ + operands[4] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); +}") + (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (and:DI (not:DI (match_operand:DI 1 "register_operand" "r")) @@ -1632,6 +1892,21 @@ "" "or %1,%2,%0") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (ior:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "" ""))) + (clobber (match_operand:SI 3 "register_operand" ""))] + "GET_CODE (operands[2]) == CONST_INT + && !SMALL_INT (operands[2]) + && (INTVAL (operands[2]) & 0x3ff) == 0x3ff" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) (ior:SI (not:SI (match_dup 3)) (match_dup 1)))] + " +{ + operands[4] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); +}") + (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r")) @@ -1663,7 +1938,7 @@ { rtx op2 = operands[2]; - /* If constant is postive, upper bits zeroed, otherwise unchanged. + /* If constant is positive, upper bits zeroed, otherwise unchanged. Give the assembler a chance to pick the move instruction. */ if (GET_CODE (op2) == CONST_INT) { @@ -1692,6 +1967,36 @@ "" "xor %r1,%2,%0") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "" ""))) + (clobber (match_operand:SI 3 "register_operand" ""))] + "GET_CODE (operands[2]) == CONST_INT + && !SMALL_INT (operands[2]) + && (INTVAL (operands[2]) & 0x3ff) == 0x3ff" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) (not:SI (xor:SI (match_dup 3) (match_dup 1))))] + " +{ + operands[4] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); +}") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (not:SI (xor:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "" "")))) + (clobber (match_operand:SI 3 "register_operand" ""))] + "GET_CODE (operands[2]) == CONST_INT + && !SMALL_INT (operands[2]) + && (INTVAL (operands[2]) & 0x3ff) == 0x3ff" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) (xor:SI (match_dup 3) (match_dup 1)))] + " +{ + operands[4] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); +}") + ;; xnor patterns. Note that (a ^ ~b) == (~a ^ b) == ~(a ^ b). ;; Combine now canonicalizes to the rightmost expression. (define_insn "" @@ -1880,6 +2185,14 @@ ;; Floating point arithmetic instructions. +(define_insn "addtf3" + [(set (match_operand:TF 0 "register_operand" "=f") + (plus:TF (match_operand:TF 1 "register_operand" "f") + (match_operand:TF 2 "register_operand" "f")))] + "" + "faddq %1,%2,%0" + [(set_attr "type" "fp")]) + (define_insn "adddf3" [(set (match_operand:DF 0 "register_operand" "=f") (plus:DF (match_operand:DF 1 "register_operand" "f") @@ -1896,6 +2209,14 @@ "fadds %1,%2,%0" [(set_attr "type" "fp")]) +(define_insn "subtf3" + [(set (match_operand:TF 0 "register_operand" "=f") + (minus:TF (match_operand:TF 1 "register_operand" "f") + (match_operand:TF 2 "register_operand" "f")))] + "" + "fsubq %1,%2,%0" + [(set_attr "type" "fp")]) + (define_insn "subdf3" [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (match_operand:DF 1 "register_operand" "f") @@ -1912,6 +2233,14 @@ "fsubs %1,%2,%0" [(set_attr "type" "fp")]) +(define_insn "multf3" + [(set (match_operand:TF 0 "register_operand" "=f") + (mult:TF (match_operand:TF 1 "register_operand" "f") + (match_operand:TF 2 "register_operand" "f")))] + "" + "fmulq %1,%2,%0" + [(set_attr "type" "fpmul")]) + (define_insn "muldf3" [(set (match_operand:DF 0 "register_operand" "=f") (mult:DF (match_operand:DF 1 "register_operand" "f") @@ -1928,6 +2257,14 @@ "fmuls %1,%2,%0" [(set_attr "type" "fpmul")]) +(define_insn "divtf3" + [(set (match_operand:TF 0 "register_operand" "=f") + (div:TF (match_operand:TF 1 "register_operand" "f") + (match_operand:TF 2 "register_operand" "f")))] + "" + "fdivq %1,%2,%0" + [(set_attr "type" "fpdiv")]) + (define_insn "divdf3" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "register_operand" "f") @@ -1944,6 +2281,16 @@ "fdivs %1,%2,%0" [(set_attr "type" "fpdiv")]) +(define_insn "negtf2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (neg:TF (match_operand:TF 1 "register_operand" "0,f")))] + "" + "@ + fnegs %0,%0 + fnegs %1,%0\;fmovs %R1,%R0\;fmovs %S1,%S0\;fmovs %T1,%T0" + [(set_attr "type" "fp") + (set_attr "length" "1,4")]) + (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f,f") (neg:DF (match_operand:DF 1 "register_operand" "0,f")))] @@ -1954,7 +2301,6 @@ [(set_attr "type" "fp") (set_attr "length" "1,2")]) - (define_insn "negsf2" [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "register_operand" "f")))] @@ -1962,6 +2308,16 @@ "fnegs %1,%0" [(set_attr "type" "fp")]) +(define_insn "abstf2" + [(set (match_operand:TF 0 "register_operand" "=f,f") + (abs:TF (match_operand:TF 1 "register_operand" "0,f")))] + "" + "@ + fabss %0,%0 + fabss %1,%0\;fmovs %R1,%R0\;fmovs %S1,%S0\;fmovs %T1,%T0" + [(set_attr "type" "fp") + (set_attr "length" "1,4")]) + (define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=f,f") (abs:DF (match_operand:DF 1 "register_operand" "0,f")))] @@ -1979,6 +2335,13 @@ "fabss %1,%0" [(set_attr "type" "fp")]) +(define_insn "sqrttf2" + [(set (match_operand:TF 0 "register_operand" "=f") + (sqrt:TF (match_operand:TF 1 "register_operand" "f")))] + "" + "fsqrtq %1,%0" + [(set_attr "type" "fpsqrt")]) + (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (match_operand:DF 1 "register_operand" "f")))] @@ -2018,10 +2381,10 @@ (define_insn "" [(set (match_operand:DI 0 "register_operand" "=&r") (ashift:DI (const_int 1) - (match_operand:SI 2 "register_operand" "r"))) + (match_operand:SI 1 "register_operand" "r"))) (clobber (reg:SI 0))] "" - "subcc %2,32,%%g0\;addx %%g0,0,%R0\;xor %R0,1,%0\;sll %R0,%2,%R0\;sll %0,%2,%0" + "subcc %1,32,%%g0\;addx %%g0,0,%R0\;xor %R0,1,%0\;sll %R0,%1,%R0\;sll %0,%1,%0" [(set_attr "type" "multi") (set_attr "length" "5")]) @@ -2047,14 +2410,14 @@ "srl %1,%2,%0") ;; Unconditional and other jump instructions -;; Note that for the Sparc, by setting the annul bit on an unconditional -;; branch, the following insn is never executed. This saves us a nop, -;; but requires a debugger which can handle annulled branches. +;; On the Sparc, by setting the annul bit on an unconditional branch, the +;; following insn is never executed. This saves us a nop. Dbx does not +;; handle such branches though, so we only use them when optimizing. (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" - "b%* %l0" - [(set_attr "type" "branch")]) + "b%* %l0%(" + [(set_attr "type" "uncond_branch")]) (define_expand "tablejump" [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "r")) @@ -2077,21 +2440,21 @@ (use (reg:SI 15))] "" "jmp %%o7+%0%#" - [(set_attr "type" "branch")]) + [(set_attr "type" "uncond_branch")]) (define_insn "" [(set (pc) (match_operand:SI 0 "address_operand" "p")) (use (label_ref (match_operand 1 "" "")))] "" "jmp %a0%#" - [(set_attr "type" "branch")]) + [(set_attr "type" "uncond_branch")]) (define_insn "" [(set (pc) (label_ref (match_operand 0 "" ""))) (set (reg:SI 15) (label_ref (match_dup 0)))] "" "call %l0%#" - [(set_attr "type" "branch")]) + [(set_attr "type" "uncond_branch")]) ;; This pattern recognizes the "instruction" that appears in ;; a function call that wants a structure value, @@ -2266,7 +2629,7 @@ [(set (pc) (match_operand:SI 0 "address_operand" "p"))] "" "jmp %a0%#" - [(set_attr "type" "branch")]) + [(set_attr "type" "uncond_branch")]) (define_expand "nonlocal_goto" [(match_operand:SI 0 "general_operand" "") @@ -2276,12 +2639,16 @@ "" " { - rtx temp; /* Trap instruction to flush all the registers window. */ emit_insn (gen_rtx (UNSPEC_VOLATILE, VOIDmode, gen_rtvec (1, const0_rtx), 0)); /* Load the fp value for the containing fn into %fp. - This is needed because operands[2] refers to %fp. */ + This is needed because operands[2] refers to %fp. + Virtual register instantiation fails if the virtual %fp isn't set from a + register. Thus we must copy operands[0] into a register if it isn't + already one. */ + if (GET_CODE (operands[0]) != REG) + operands[0] = force_reg (SImode, operands[0]); emit_move_insn (virtual_stack_vars_rtx, operands[0]); /* Find the containing function's current nonlocal goto handler, which will do any cleanups and then jump to the label. */ @@ -2317,12 +2684,6 @@ "jmp %%o0+0\;restore" [(set_attr "type" "misc") (set_attr "length" "2")]) - -;(define_insn "tail_call" ;; tail call -; [(set (pc) (match_operand 0 "memory_operand" "m"))] -; "tail_call_valid_p ()" -; "* return output_tail_call (operands, insn);" -; [(set_attr "type" "branch")]) ;; Split up troublesome insns for better scheduling. */ @@ -2506,8 +2867,93 @@ ;; Peepholes go at the end. +;; Optimize consecutive loads or stores into ldd and std when possible. +;; The conditions in which we do this are very restricted and are +;; explained in the code for {registers,memory}_ok_for_ldd functions. + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "register_operand" "=rf") + (match_operand:SI 3 "memory_operand" ""))] + "registers_ok_for_ldd_peep (operands[0], operands[2]) + && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3]) + && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))" + "ldd %1,%0") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "register_operand" "rf")) + (set (match_operand:SI 2 "memory_operand" "") + (match_operand:SI 3 "register_operand" "rf"))] + "registers_ok_for_ldd_peep (operands[1], operands[3]) + && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2]) + && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))" + "std %1,%0") + +(define_peephole + [(set (match_operand:SF 0 "register_operand" "=fr") + (match_operand:SF 1 "memory_operand" "")) + (set (match_operand:SF 2 "register_operand" "=fr") + (match_operand:SF 3 "memory_operand" ""))] + "registers_ok_for_ldd_peep (operands[0], operands[2]) + && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3]) + && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))" + "ldd %1,%0") + +(define_peephole + [(set (match_operand:SF 0 "memory_operand" "") + (match_operand:SF 1 "register_operand" "fr")) + (set (match_operand:SF 2 "memory_operand" "") + (match_operand:SF 3 "register_operand" "fr"))] + "registers_ok_for_ldd_peep (operands[1], operands[3]) + && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2]) + && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))" + "std %1,%0") + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "=rf") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "register_operand" "=rf") + (match_operand:SI 3 "memory_operand" ""))] + "registers_ok_for_ldd_peep (operands[2], operands[0]) + && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1]) + && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" + "ldd %3,%2") + +(define_peephole + [(set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "register_operand" "rf")) + (set (match_operand:SI 2 "memory_operand" "") + (match_operand:SI 3 "register_operand" "rf"))] + "registers_ok_for_ldd_peep (operands[3], operands[1]) + && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0]) + && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" + "std %3,%2") + +(define_peephole + [(set (match_operand:SF 0 "register_operand" "=fr") + (match_operand:SF 1 "memory_operand" "")) + (set (match_operand:SF 2 "register_operand" "=fr") + (match_operand:SF 3 "memory_operand" ""))] + "registers_ok_for_ldd_peep (operands[2], operands[0]) + && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1]) + && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))" + "ldd %3,%2") + +(define_peephole + [(set (match_operand:SF 0 "memory_operand" "") + (match_operand:SF 1 "register_operand" "fr")) + (set (match_operand:SF 2 "memory_operand" "") + (match_operand:SF 3 "register_operand" "fr"))] + "registers_ok_for_ldd_peep (operands[3], operands[1]) + && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0]) + && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))" + "std %3,%2") + ;; Optimize the case of following a reg-reg move with a test -;; of reg just moved. +;; of reg just moved. Don't allow floating point regs for operand 0 or 1. +;; This can result from a float to fix conversion. (define_peephole [(set (match_operand:SI 0 "register_operand" "=r") @@ -2515,8 +2961,9 @@ (set (reg:CC 0) (compare:CC (match_operand:SI 2 "register_operand" "r") (const_int 0)))] - "rtx_equal_p (operands[2], operands[0]) - || rtx_equal_p (operands[2], operands[1])" + "(rtx_equal_p (operands[2], operands[0]) + || rtx_equal_p (operands[2], operands[1])) + && ! FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])" "orcc %1,%%g0,%0") ;; Do {sign,zero}-extended compares somewhat more efficiently. @@ -2603,6 +3050,37 @@ ;; Return peepholes. First the "normal" ones +;; ??? There are QImode, HImode, and SImode versions of this pattern. +;; It might be possible to write one more general pattern instead of three. + +(define_insn "" + [(set (match_operand:QI 0 "restore_operand" "") + (match_operand:QI 1 "arith_operand" "rI")) + (return)] + "! TARGET_EPILOGUE" + "* +{ + if (current_function_returns_struct) + return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + else + return \"ret\;restore %%g0,%1,%Y0\"; +}" + [(set_attr "type" "multi")]) + +(define_insn "" + [(set (match_operand:HI 0 "restore_operand" "") + (match_operand:HI 1 "arith_operand" "rI")) + (return)] + "! TARGET_EPILOGUE" + "* +{ + if (current_function_returns_struct) + return \"jmp %%i7+12\;restore %%g0,%1,%Y0\"; + else + return \"ret\;restore %%g0,%1,%Y0\"; +}" + [(set_attr "type" "multi")]) + (define_insn "" [(set (match_operand:SI 0 "restore_operand" "") (match_operand:SI 1 "arith_operand" "rI"))