\\ ******** Creating Abstract Patterns that are further extended or instantiated later by Concrete patterns****************** abstract set_plus extends set { root.2 := plus; } abstract set_mem extends set { root.2 := mem; } abstract set_set_clobber extends sequence { root.1 := set_mem; root.2 := set_plus; root.3 := clobber; root.3.1 := mem; } abstract set_clobber extends sequence { root.1 := set; root.2 := clobber; } \\ ********* extends the previously created abstract pattern set_clobber **************** abstract set_clobber_mem extends set_clobber { root.2.1 := mem; } abstract set_mem_set_plus extends sequence { root.1 := set_mem; root.2 := set_plus; } abstract set_mem2 extends set { root.1 := mem; } abstract set_set extends sequence { root.1 := set; root.2 := set; } abstract set_strict_low_part extends set { root.1 := strict_low_part; } abstract strict_low_part_clobber extends sequence { root.1 := set_strict_low_part; root.2 := clobber; } abstract set_strict_low_part_clobber extends sequence { root.1 := set_strict_low_part; root.2 := clobber; } abstract set_sign_extract extends set { root.2 := sign_extract; } abstract set_mem extends set { root.1 := mem; } abstract set_zero_extract extends set { root.2 := zero_extract; } abstract set_subreg_zero_extract extends set { root.2 := subreg; root.2.1 := zero_extract; } abstract set_zero_extract_2 extends set { root.1 := zero_extract; } abstract set_zeroextract_lshiftrt extends set { root.1 := zero_extract; root.2 := lshiftrt; } abstract set_clobber_mem2 extends sequence { root.1 := set; root.2 := clobber; root.2.1 := mem; } abstract set_set_plus_clobber extends sequence { root.1 := set; root.1.2 := mem; root.2 := set; root.2.2 := plus; root.3 := clobber; root.3.1 := mem; } abstract set_plus_set_mem2 extends sequence { root.1 := set_plus; root.2 := set_mem2; } abstract set_and extends set { root.2 := and; } abstract set_and_clobber extends sequence { root.1 := set_and; root.2 := clobber; } abstract zero_extract_and extends and { root.1 := zero_extract; } abstract set_and_zero_extract extends set { root.1 := zero_extract; root.2 := zero_extract_and; } abstract parallel_zero_extract_clobber extends parallel { root.1 := set_and_zero_extract; root.2 := clobber; } abstract set_plus_clobber extends sequence { root.1 := set_plus; root.2 := clobber; } abstract set_unspec extends set { root.2 := unspec; } abstract parallel_unspec_plus extends parallel { root.1 := set_unspec; root.2 := set_plus; } abstract parallel_plus_ltu_clobber extends parallel { root.1 := set_plus; root.1.2.2 := plus; root.1.2.2.1 := ltu; root.2 := clobber; } abstract unspec_plus_plus_clobber extends sequence { root.1 := parallel_unspec_plus; root.2 := parallel_plus_ltu_clobber; } abstract sequence_set extends sequence { root.1 := set; } abstract set_floatext extends set { root.2 := float_extend; } abstract set_neg extends set { root.2 := neg; } \\ ***************** CONCRETE INSTRUCTIONS ************************** \\** Concrete pattern 'movsi' instantiates abstract pattern 'set' which is a predefined RTL operator **** concrete movsi.expand instantiates set { set(nonimmediate_operand:SI:"", general_operand:SI:""); } {: "" "ix86_expand_move (SImode, operands); DONE;" :} concrete *pushsi2.insn instantiates set { set(push_operand:SI:"=<", general_no_elim_operand:SI:"ri*m"); } {: "!TARGET_64BIT" "push{l}\t%1" [(set_attr "type" "push") (set_attr "mode" "SI")] :} concrete *pushsi2_rex64.insn instantiates set { set(push_operand:SI:"=X", nonmemory_no_elim_operand:SI:"ri"); } {: "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") (set_attr "mode" "SI")] :} \\*****Concrete pattern *pushsi2_prologue instantiates the abstract pattern set_clobber_mem which has three abstract leaf nodes*** concrete *pushsi2_prologue.insn instantiates set_clobber_mem { set_clobber_mem(push_operand:SI:"=<", general_no_elim_operand:SI:"ri*m", scratch); root.2.1.mode := BLK; } {: "!TARGET_64BIT" "push{l}\t%1" [(set_attr "type" "push") (set_attr "mode" "SI")] :} \\ ***** Concrete pattern *popsi_epilogue instantiates set_set_clobber with operands which are an operand with predicate,mode, constraint; register-reg(SI:SP_REG); fixed register-scratch; constant-const_int:4 *************** concrete *popsi1_epilogue.insn instantiates set_set_clobber { set_set_clobber(nonimmediate_operand:SI:"=r*m", reg(SI:SP_REG), reg(SI:SP_REG), reg(SI:SP_REG), const_int:4, scratch); root.1.2.mode := SI; root.2.2.mode := SI; root.3.1.mode := BLK; } {: "!TARGET_64BIT" "pop{l}\t%0" [(set_attr "type" "pop") (set_attr "mode" "SI")] :} concrete popsi1.insn instantiates set_mem_set_plus { set_mem_set_plus(nonimmediate_operand:SI:"=r*m", reg(SI:SP_REG), reg(SI:SP_REG), reg(SI:SP_REG), const_int:4); root.1.2.mode := SI; root.2.2.mode := SI; } {: "!TARGET_64BIT" "pop{l}\t%0" [(set_attr "type" "pop") (set_attr "mode" "SI")] :} concrete *movsi_xor.insn instantiates set_clobber { set_clobber(register_operand:SI:"=r", const0_operand:SI:"", reg(CC:FLAGS_REG)); } {: "reload_completed" "xor{l}\t%0, %0" [(set_attr "type" "alu1") (set_attr "mode" "SI") (set_attr "length_immediate" "0")]) :} \\**** Concrete pattern *movsi_or overrides previously defined concrete pattern *movsi_xor by changing the attributes: constraint and predicate of the operand given by root.1.2**** concrete *movsi_or.insn overrides *movsi_xor.insn { root.1.2.constraint := "i" ; root.1.2.predicate := immediate_operand; } {: "reload_completed && operands[1] == constm1_rtx" { operands[1] = constm1_rtx; return "or{l}\t{%1, %0|%0, %1}"; } [(set_attr "type" "alu1") (set_attr "mode" "SI") (set_attr "length_immediate" "1")] :} concrete *movsi_1.insn instantiates set { set(nonimmediate_operand:SI:"=r,m,*y,*y,?rm,?*y,*x,*x,?r,m,?*Yi,*x", general_operand: SI:"g,ri,C,*y,*y,rm,C,*x,*Yi,*x,r,m"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (get_attr_type (insn)) { case TYPE_SSELOG1: if (get_attr_mode (insn) == MODE_TI) return "%vpxor\t%0, %d0"; return "%vxorps\t%0, %d0"; case TYPE_SSEMOV: switch (get_attr_mode (insn)) { case MODE_TI: return "%vmovdqa\t{%1, %0|%0, %1}"; case MODE_V4SF: return "%vmovaps\t{%1, %0|%0, %1}"; case MODE_SI: return "%vmovd\t{%1, %0|%0, %1}"; case MODE_SF: return "%vmovss\t{%1, %0|%0, %1}"; default: gcc_unreachable (); } case TYPE_MMX: return "pxor\t%0, %0"; case TYPE_MMXMOV: if (get_attr_mode (insn) == MODE_DI) return "movq\t{%1, %0|%0, %1}"; return "movd\t{%1, %0|%0, %1}"; case TYPE_LEA: return "lea{l}\t{%1, %0|%0, %1}"; default: gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); return "mov{l}\t{%1, %0|%0, %1}"; } } [(set (attr "type") (cond [(eq_attr "alternative" "2") (const_string "mmx") (eq_attr "alternative" "3,4,5") (const_string "mmxmov") (eq_attr "alternative" "6") (const_string "sselog1") (eq_attr "alternative" "7,8,9,10,11") (const_string "ssemov") (match_operand:DI 1 "pic_32bit_operand" "") (const_string "lea") ] (const_string "imov"))) (set (attr "prefix") (if_then_else (eq_attr "alternative" "0,1,2,3,4,5") (const_string "orig") (const_string "maybe_vex"))) (set (attr "prefix_data16") (if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "SI")) (const_string "1") (const_string "*"))) (set (attr "mode") (cond [(eq_attr "alternative" "2,3") (const_string "DI") (eq_attr "alternative" "6,7") (if_then_else (eq (symbol_ref "TARGET_SSE2") (const_int 0)) (const_string "V4SF") (const_string "TI")) (and (eq_attr "alternative" "8,9,10,11") (eq (symbol_ref "TARGET_SSE2") (const_int 0))) (const_string "SF") ] (const_string "SI")))] :} concrete *movabssi_1_rex64.insn instantiates set_mem2 { set_mem2(x86_64_movabs_operand:DI:"i,r", nonmemory_operand:SI:"a,er"); root.1.mode := SI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 0)" "@ movabs{l}\t{%1, %P0|%P0, %1} mov{l}\t{%1, %a0|%a0, %1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0,*") (set_attr "memory" "store") (set_attr "mode" "SI")] :} concrete *movabssi_2_rex64.insn instantiates set_mem { set_mem( register_operand:SI:"=a,r", x86_64_movabs_operand:DI:"i,r"); root.2.mode := SI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 1)" "@ movabs{l}\t{%P1, %0|%0, %P1} mov{l}\t{%a1, %0|%0, %a1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0") (set_attr "memory" "load") (set_attr "mode" "SI")] :} concrete *swapsi.insn instantiates set_set { set_set(register_operand:SI:"+r", register_operand:SI:"+r", duplicate 1, duplicate 0); } {: "" "xchg{l}\t%1, %0" [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector") (set_attr "amdfam10_decode" "double")] :} concrete movhi.insn instantiates set { set(nonimmediate_operand:HI:"", general_operand:HI:""); } {: "" "ix86_expand_move (HImode, operands); DONE;" :} concrete *pushhi2.insn instantiates set { set(push_operand:HI:"=X", nonmemory_no_elim_operand:HI:"rn"); } {: "!TARGET_64BIT" "push{l}\t%k1" [(set_attr "type" "push") (set_attr "mode" "SI")] :} concrete *pushhi2_rex64 overrides *pushhi2.insn { } {: "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") (set_attr "mode" "DI")] :} concrete *movhi_1.insn instantiates set { set(nonimmediate_operand:HI:"=r,r,r,m", general_operand:HI:"r,rn,rm,rn"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (get_attr_type (insn)) { case TYPE_IMOVX: /* movzwl is faster than movw on p2 due to partial word stalls, though not as fast as an aligned movl. */ return "movz{wl|x}\t{%1, %k0|%k0, %1}"; default: if (get_attr_mode (insn) == MODE_SI) return "mov{l}\t{%k1, %k0|%k0, %k1}"; else return "mov{w}\t{%1, %0|%0, %1}"; } } [(set (attr "type") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "imov") (and (eq_attr "alternative" "0") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_HIMODE_MATH") (const_int 0)))) (const_string "imov") (and (eq_attr "alternative" "1,2") (match_operand:HI 1 "aligned_operand" "")) (const_string "imov") (and (ne (symbol_ref "TARGET_MOVX") (const_int 0)) (eq_attr "alternative" "0,2")) (const_string "imovx") ] (const_string "imov"))) (set (attr "mode") (cond [(eq_attr "type" "imovx") (const_string "SI") (and (eq_attr "alternative" "1,2") (match_operand:HI 1 "aligned_operand" "")) (const_string "SI") (and (eq_attr "alternative" "0") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_HIMODE_MATH") (const_int 0)))) (const_string "SI") ] (const_string "HI")))] :} \\ Stores and loads of ax to arbitrary constant address. \\ We fake an second form of instruction to force reload to load address \\ into register when rax is not available concrete *movabshi_1_rex64.insn instantiates set_mem { set_mem(x86_64_movabs_operand:DI:"i,r", nonmemory_operand:HI:"a,er"); root.1.mode := HI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 0)" "@ movabs{w}\t{%1, %P0|%P0, %1} mov{w}\t{%1, %a0|%a0, %1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0,*") (set_attr "memory" "store") (set_attr "mode" "HI")] :} concrete *movabshi_2_rex64.insn instantiates set_mem2 { set_mem2(register_operand:HI:"=a,r", x86_64_movabs_operand:null:"i,r"); root.2.mode := HI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 1)" "@ movabs{w}\t{%P1, %0|%0, %P1} mov{w}\t{%a1, %0|%0, %a1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0") (set_attr "memory" "load") (set_attr "mode" "HI")] :} concrete *swaphi_1.insn instantiates set_set { set_set(register_operand:HI:"+r", register_operand:HI:"+r", duplicate 1, duplicate 0); } {: "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "xchg{l}\t%k1, %k0" [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector") (set_attr "amdfam10_decode" "double")] :} concrete *swaphi_1.insn instantiates set_set { set_set(register_operand:HI:"+r", register_operand:HI:"+r", duplicate 1 , duplicate 0); } {: "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "xchg{l}\t%k1, %k0" [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector") (set_attr "amdfam10_decode" "double")] :} \\******Concrete Pattern *swaphi_2 has an RTL template identical to previously defined concrete pattern *swaphi_1 and thus overrides it without changing any attribute value *** concrete *swaphi_2.insn overrides *swaphi_1.insn { } {: "TARGET_PARTIAL_REG_STALL" "xchg{w}\t%1, %0" [(set_attr "type" "imov") (set_attr "mode" "HI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector")] :} concrete movstricthi.expand instantiates set_strict_low_part { set_strict_low_part(nonimmediate_operand:HI:"+rm,r", general_operand:HI:"rn,m"); } {: "" { if (TARGET_PARTIAL_REG_STALL && optimize_function_for_speed_p (cfun)) FAIL; /* Don't generate memory->memory moves, go through a register */ if (MEM_P (operands[0]) && MEM_P (operands[1])) operands[1] = force_reg (HImode, operands[1]); } :} \\ ******Concrete pattern *movstricthi_1 overrides movstricthi.expand by merely changing the constraints of all operands using the construct 'allconstraints' ******* concrete *movstricthi_1.insn overrides movstricthi.expand { allconstraints := ("+rm,r", "rn,m"); } {: "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "mov{w}\t{%1, %0|%0, %1}" [(set_attr "type" "imov") (set_attr "mode" "HI")] :} concrete *movstricthi_xor.insn instantiates strict_low_part_clobber { strict_low_part_clobber(register_operand:HI:"+r", const0_operand:HI:"", reg(CC:FLAGS_REG)); } {: "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "mov{w}\t{%1, %0|%0, %1}" [(set_attr "type" "imov") (set_attr "mode" "HI")] :} concrete movqi.expand instantiates set { set(nonimmediate_operand:QI:"", general_operand:QI:""); } {: "" "ix86_expand_move (QImode, operands); DONE;" :} \\ emit_push_insn when it calls move_by_pieces requires an insn to \\ "push a byte". But actually we use pushl, which has the effect \\ of rounding the amount pushed up to a word. concrete *pushqi2.insn instantiates set { set(push_operand:QI:"=X", nonmemory_no_elim_operand:QI:"rn"); } {: "!TARGET_64BIT" "push{l}\t%k1" [(set_attr "type" "push") (set_attr "mode" "SI")] :} \\ For 64BIT abi we always round up to 8 bytes. concrete *pushqi2_rex64.insn overrides *pushqi2 { root.2.constraint := "qn"; } {: "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") (set_attr "mode" "DI")] :} \\ Situation is quite tricky about when to choose full sized (SImode) move \\ over QImode moves. For Q_REG -> Q_REG move we use full size only for \\ partial register dependency machines (such as AMD Athlon), where QImode \\ moves issue extra dependency and for partial register stalls machines \\ that don't use QImode patterns (and QImode move cause stall on the next \\ instruction). \\ \\ For loads of Q_REG to NONQ_REG we use full sized moves except for partial \\ register stall machines with, where we use QImode instructions, since \\ partial register stall can be caused there. Then we use movzx. concrete *movqi_1.insn instantiates set { set(nonimmediate_operand:QI:"=q,q,q,r,r,?r,m", general_operand:QI:"q,qn,qm,q,rn,qm,qn"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (get_attr_type (insn)) { case TYPE_IMOVX: gcc_assert (ANY_QI_REG_P (operands[1]) || MEM_P (operands[1])); return "movz{bl|x}\t{%1, %k0|%k0, %1}"; default: if (get_attr_mode (insn) == MODE_SI) return "mov{l}\t{%k1, %k0|%k0, %k1}"; else return "mov{b}\t{%1, %0|%0, %1}"; } } [(set (attr "type") (cond [(and (eq_attr "alternative" "5") (not (match_operand:QI 1 "aligned_operand" ""))) (const_string "imovx") (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "imov") (and (eq_attr "alternative" "3") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_QIMODE_MATH") (const_int 0)))) (const_string "imov") (eq_attr "alternative" "3,5") (const_string "imovx") (and (ne (symbol_ref "TARGET_MOVX") (const_int 0)) (eq_attr "alternative" "2")) (const_string "imovx") ] (const_string "imov"))) (set (attr "mode") (cond [(eq_attr "alternative" "3,4,5") (const_string "SI") (eq_attr "alternative" "6") (const_string "QI") (eq_attr "type" "imovx") (const_string "SI") (and (eq_attr "type" "imov") (and (eq_attr "alternative" "0,1") (and (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY") (const_int 0)) (and (eq (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)))))) (const_string "SI") ;; Avoid partial register stalls when not using QImode arithmetic (and (eq_attr "type" "imov") (and (eq_attr "alternative" "0,1") (and (ne (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)) (eq (symbol_ref "TARGET_QIMODE_MATH") (const_int 0))))) (const_string "SI") ] (const_string "QI")))] :} concrete *swapqi_1.insn instantiates set_set { set_set(register_operand:QI:"+r", register_operand:QI:"+r", duplicate 2, duplicate 1); } {: "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "xchg{l}\t%k1, %k0" [(set_attr "type" "imov") (set_attr "mode" "SI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector") (set_attr "amdfam10_decode" "vector")] :} \\ Not added amdfam10_decode since TARGET_PARTIAL_REG_STALL is disabled for AMDFAM10 concrete *swapqi_2.insn overrides *swapqi_1.insn { root.1.1.constraint := "+q"; root.1.2.constraint := "+q"; } {: "TARGET_PARTIAL_REG_STALL" "xchg{b}\t%1, %0" [(set_attr "type" "imov") (set_attr "mode" "QI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector")] :} concrete movstrictqi.insn instantiates set_strict_low_part { set_strict_low_part(nonimmeidate_operand:QI:"", general_operand:QI:""); } {: "" { if (TARGET_PARTIAL_REG_STALL && optimize_function_for_speed_p (cfun)) FAIL; /* Don't generate memory->memory moves, go through a register. */ if (MEM_P (operands[0]) && MEM_P (operands[1])) operands[1] = force_reg (QImode, operands[1]); } :} concrete *movstrictqi_1.insn instantiates set_strict_low_part { set_strict_low_part(nonimmediate_operand:QI:"+qm,q", general_operand:QI:"*qn,m"); } {: "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "mov{b}\t{%1, %0|%0, %1}" [(set_attr "type" "imov") (set_attr "mode" "QI")] :} concrete *movstrictqi_xor.insn instantiates set_strict_low_part_clobber { set_strict_low_part_clobber(q_regs_operand:QI:"+q", const0_operand:QI:"", reg(CC:FLAGS_REG)); } {: "reload_completed" "xor{b}\t%0, %0" [(set_attr "type" "alu1") (set_attr "mode" "QI") (set_attr "length_immediate" "0")] :} concrete *movsi_extv_1.insn instantiates set_sign_extract { set_sign_extract(register_operand:SI:"=R", ext_register_operand:NULL:"Q", const_int:8, const_int:8); root.2.mode := SI; } {: "" "movs{bl|x}\t{%h1, %0|%0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")] :} concrete *movhi_extv_1.insn overrides *movsi_extv_1.insn { SI -> HI; } {: "" "movs{bl|x}\t{%h1, %k0|%k0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")] :} concrete *movqi_extv_1.insn instantiates set_sign_extract { set_sign_extract(nonimmediate_operand:QI:"=Qm,?r", ext_register_operand:QI:"Q,Q", const_int:8, const_int:8); root.2.mode := QI; } {: "!TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_IMOVX: return "movs{bl|x}\t{%h1, %k0|%k0, %h1}"; default: return "mov{b}\t{%h1, %0|%0, %h1}"; } } [(set (attr "type") (if_then_else (and (match_operand:QI 0 "register_operand" "") (ior (not (match_operand:QI 0 "q_regs_operand" "")) (ne (symbol_ref "TARGET_MOVX") (const_int 0)))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") (if_then_else (eq_attr "type" "imovx") (const_string "SI") (const_string "QI")))] :} concrete *movqi_extv_1_rex64.insn overrides *movqi_extv_1.insn { root.1 := register_operand:QI:"=Q,?R"; } {: "TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_IMOVX: return "movs{bl|x}\t{%h1, %k0|%k0, %h1}"; default: return "mov{b}\t{%h1, %0|%0, %h1}"; } } [(set (attr "type") (if_then_else (and (match_operand:QI 0 "register_operand" "") (ior (not (match_operand:QI 0 "q_regs_operand" "")) (ne (symbol_ref "TARGET_MOVX") (const_int 0)))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") (if_then_else (eq_attr "type" "imovx") (const_string "SI") (const_string "QI")))] :} \\ Stores and loads of ax to arbitrary constant address. \\ We fake an second form of instruction to force reload to load address \\ into register when rax is not available concrete *movabsqi_1_rex64.insn instantiates set_mem { set_mem2(x86_64_movabs_operand:DI:"i,r", nonmemory_operand:QI:"a,er"); root.1.mode := QI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 0)" "@ movabs{b}\t{%1, %P0|%P0, %1} mov{b}\t{%1, %a0|%a0, %1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0,*") (set_attr "memory" "store") (set_attr "mode" "QI")] :} concrete *movabsqi_2_rex64.insn instantiates set_mem { set_mem(register_operand:QI:"=a,r", x86_64_movabs_operand:DI:"i,r"); root.2.mode := QI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 1)" "@ movabs{b}\t{%P1, %0|%0, %P1} mov{b}\t{%a1, %0|%0, %a1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0") (set_attr "memory" "load") (set_attr "mode" "QI")] :} concrete *movdi_extzv_1.insn instantiates set_zero_extract { set_zero_extract(register_operand:DI:"=R", ext_register_operand:NULL:"Q", const_int:8, const_int:8); root.2.mode := DI; } {: "TARGET_64BIT" "movz{bl|x}\t{%h1, %k0|%k0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")] :} \\ ***** Concrete pattern *movsi_extzv_1 overrides *movdi_extzv_1 by only changing each occurence of mode DI with SI ************ concrete *movsi_extzv_1.insn overrides *movdi_extzv_1.insn { DI -> SI; } {: "" "movz{bl|x}\t{%h1, %0|%0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")] :} concrete *movqi_extzv_2.insn instantiates set_subreg_zero_extract { set_subreg_zero_extract(nonimmediate_operand:QI:"=Qm,?R", ext_register_operand:NULL:"Q,Q", const_int:8, const_int:8); root.2.mode := QI; root.2.1.mode := SI; } {: "!TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_IMOVX: return "movz{bl|x}\t{%h1, %k0|%k0, %h1}"; default: return "mov{b}\t{%h1, %0|%0, %h1}"; } } [(set (attr "type") (if_then_else (and (match_operand:QI 0 "register_operand" "") (ior (not (match_operand:QI 0 "q_regs_operand" "")) (ne (symbol_ref "TARGET_MOVX") (const_int 0)))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") (if_then_else (eq_attr "type" "imovx") (const_string "SI") (const_string "QI")))] :} \\ ******** concrete pattern *movqi_extzv_2_rex64 overrides *movqi_extzv_2 by only changing the operand given by root.1 ************** concrete *movqi_extzv_2_rex64.insn overrides *movqi_extzv_2.insn { root.1 := register_operand:QI:"=Q,,?R"; } {: "TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_IMOVX: return "movz{bl|x}\t{%h1, %k0|%k0, %h1}"; default: return "mov{b}\t{%h1, %0|%0, %h1}"; } } [(set (attr "type") (if_then_else (ior (not (match_operand:QI 0 "q_regs_operand" "")) (ne (symbol_ref "TARGET_MOVX") (const_int 0))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") (if_then_else (eq_attr "type" "imovx") (const_string "SI") (const_string "QI")))] :} concrete movsi_insv_1.insn instantiates set_zero_extract_2 { set_zero_extract_2(ext_register_operand:NLL:"+Q", const_int:8, const_int:8, general_operand:SI:"Qmn"); root.1.mode := SI; } {: "!TARGET_64BIT" "mov{b}\t{%b1, %h0|%h0, %b1}" [(set_attr "type" "imov") (set_attr "mode" "QI")] :} concrete *movsi_insv_1_rex64.insn overrides movsi_insv_1.insn { root.2 := nonmemory_operand:SI:"Qn"; } {: "TARGET_64BIT" "mov{b}\t{%b1, %h0|%h0, %b1}" [(set_attr "type" "imov") (set_attr "mode" "QI")] :} concrete movdi_insv_1_rex64.insn overrides *movsi_insv_1_rex64 { SI -> DI; } {: "TARGET_64BIT" "mov{b}\t{%b1, %h0|%h0, %b1}" [(set_attr "type" "imov") (set_attr "mode" "QI")] :} concrete *movqi_insv_2.insn instantiates set_zeroextract_lshiftrt { set_zeroextract_lshiftrt(ext_register_operand:NULL:"+Q", const_int:8, const_int:8, register_operand:SI:"Q", const_int:8); root.1.mode := SI; root.2.mode := SI; } {: "" "mov{b}\t{%h1, %h0|%h0, %h1}" [(set_attr "type" "imov") (set_attr "mode" "QI")] :} concrete movdi.expand instantiates set { set(nonimmediate_operand:DI:"", general_operand:DI:""); } {: "" "ix86_expand_move (DImode, operands); DONE;" :} concrete *pushdi.insn instantiates set { set(push_operand:DI:"=<", general_no_elim_operand:DI:"riF*m"); } {: "!TARGET_64BIT" "#" :} concrete *pushdi2_rex64.insn instantiates set { set(push_operand:DI:"=<,!<", general_no_elim_operand:DI:"re*m,n"); } {: "TARGET_64BIT" "@ push{q}\t%1 #" [(set_attr "type" "push,multi") (set_attr "mode" "DI")] :} \\ Convert impossible pushes of immediate to existing instructions. \\ First try to get scratch register and go through it. In case this \\ fails, push sign extended lower part first and then overwrite \\ upper part by 32bit move. \\ ********** Concrete Peephole pattern **************** \\*** Peephole pattern with multiple input RTL templates given by instantiates.in and cmd_spec.in *** concrete .peephole2 instantiates.in set { set(push_operand:DI:"", immediate_oeprand:DI:""); } cmd_spec.in {: (match_scratch:DI 2 "r"); :} cmd_spec.in {: "TARGET_64BIT && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode)" :} instantiates.out set { set(duplicate 2, duplicate 1); } instantiates.out set { set( duplicate 0,duplicate 2); } cmd_spec.out {: "" :} \\ We need to define this as both peepholer and splitter for case \\ peephole2 pass is not run. \\ "&& 1" is needed to keep it from matching the previous pattern. concrete .peephole2 instantiates.in set { set(push_operand:DI:"", immediate_operand:DI:""); } cmd_spec.in {: "TARGET_64BIT && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode) && 1" :} instantiates.out set { set(duplicate 0, duplicate 1); } instantiates.out set { set( duplicate 2, duplicate 3); } cmd_spec.out {: "split_di (&operands[1], 1, &operands[2], &operands[3]); operands[1] = gen_lowpart (DImode, operands[2]); operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, GEN_INT (4))); " :} \\***** Split Pattern **** \\ ** Split pattern with multiple output RTL templates which have been given by instantiates.out or cmd_spec.out ** concrete .split instantiates.in set { set(push_operand:DI:"", immediate_operand:DI:""); } cmd_spec.in {: "TARGET_64BIT && ((optimize > 0 && flag_peephole2) ? epilogue_completed : reload_completed) && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode)" :} instantiates.out set { set(duplicate 0, duplicate 1); } instantiates.out set { set( duplicate 2, duplicate 3); } cmd_spec.out {: "split_di (&operands[1], 1, &operands[2], &operands[3]); operands[1] = gen_lowpart (DImode, operands[2]); operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, GEN_INT (4))); " :} concrete *pushdi2_prologue_rex64.insn instantiates set_clobber_mem2 { set_clobber_mem2(push_operand:DI:"=<", general_no_elim_operand:DI:"re*m", scratch); root.2.1.mode := BLK; } {: "TARGET_64BIT" "push{q}\t%1" [(set_attr "type" "push") (set_attr "mode" "DI")] :} concrete *popdi1_epilogue_rex64.insn instantiates set_set_plus_clobber { set_set_plus_clobber(nonimmediate_operand:DI:"=r*m", reg(DI: SP_REG), reg(DI: SP_REG), reg(DI:SP_REG), const_int:8, scratch); root.1.2.mode := DI; root.2.2.mode := DI; root.3.1.mode := BLK; } {: "TARGET_64BIT" "pop{q}\t%0" [(set_attr "type" "pop") (set_attr "mode" "DI")] :} concrete popdi.insn instantiates set_mem_set_plus { set_mem_set_plus(nonimmediate_operand:DI:"=r*m", reg(DI:SP_REG), reg(DI:SP_REG), reg(DI:SP_REG), const_int:8); root.1.2.mode := DI; root.2.2.mode := DI; } {: "TARGET_64BIT" "pop{q}\t%0" [(set_attr "type" "pop") (set_attr "mode" "DI")] :} concrete *movdi_xor_rex64.insn instantiates set_clobber { set_clobber(register_operand:DI:"=r", const0_operand:DI:"", reg(CC:FLAGS_REG)); } {: "TARGET_64BIT && reload_completed" "xor{l}\t%k0, %k0"; [(set_attr "type" "alu1") (set_attr "mode" "SI") (set_attr "length_immediate" "0")] :} concrete *movdi_or_rex64.insn instantiates set_clobber { set_clobber(register_operand:DI:"=r", const_int_operand:DI:"i", reg(CC:FLAGS_REG)); } {: "TARGET_64BIT && reload_completed && operands[1] == constm1_rtx" { operands[1] = constm1_rtx; return "or{q}\t{%1, %0|%0, %1}"; } [(set_attr "type" "alu1") (set_attr "mode" "DI") (set_attr "length_immediate" "1")] :} concrete *movdi_2.insn instantiates set { set(nonimmediate_operand:DI:"=r,o,*y,m*y,*y,*Y2,m,*Y2,*Y2,*x,m,*x,*x", general_operand:DI:"riFo,riF,C,*y,m,C,*Y2,*Y2,m,C,*x,*x,m"); } {: "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "@ # # pxor\t%0, %0 movq\t{%1, %0|%0, %1} movq\t{%1, %0|%0, %1} %vpxor\t%0, %d0 %vmovq\t{%1, %0|%0, %1} %vmovdqa\t{%1, %0|%0, %1} %vmovq\t{%1, %0|%0, %1} xorps\t%0, %0 movlps\t{%1, %0|%0, %1} movaps\t{%1, %0|%0, %1} movlps\t{%1, %0|%0, %1}" [(set_attr "type" "*,*,mmx,mmxmov,mmxmov,sselog1,ssemov,ssemov,ssemov,sselog1,ssemov,ssemov,ssemov") (set (attr "prefix") (if_then_else (eq_attr "alternative" "5,6,7,8") (const_string "vex") (const_string "orig"))) (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI,TI,DI,V4SF,V2SF,V4SF,V2SF")] :} \\ ****** The following split pattern has an output RTL pattern which is not an instantiation of an abstract pattern. Such templates can be given as conventional machine descriptions using the construct 'cmd_spec'********* concrete .split instantiates.in set { set(push_operand:DI:"", general_operand:DI:""); } cmd_spec.in {: "!TARGET_64BIT && reload_completed && (! MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} concrete .split instantiates.in set { set(nonimmediate_operand:DI:"", general_operand:DI:""); } cmd_spec.in {: "!TARGET_64BIT && reload_completed && (!MMX_REG_P (operands[0]) && !SSE_REG_P (operands[0])) && (!MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" :} cmd_spec.out {: [( const_int 0)] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} concrete *movdi_1_rex64.insn instantiates set { set(nonimmediate_operand:DI:"=r,r,r,m,!m,*y,*y,?r,m,?*Ym,?*y,*x,*x,?r,m,?*Yi,*x,?*x,?*Ym", general_operand:DI:"Z,rem,i,re,n,C,*y,*Ym,*y,r,m,C,*x,*Yi,*x,r,m,*Ym,*x"); } {: "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (get_attr_type (insn)) { case TYPE_SSECVT: if (SSE_REG_P (operands[0])) return "movq2dq\t{%1, %0|%0, %1}"; else return "movdq2q\t{%1, %0|%0, %1}"; case TYPE_SSEMOV: if (TARGET_AVX) { if (get_attr_mode (insn) == MODE_TI) return "vmovdqa\t{%1, %0|%0, %1}"; else return "vmovq\t{%1, %0|%0, %1}"; } if (get_attr_mode (insn) == MODE_TI) return "movdqa\t{%1, %0|%0, %1}"; /* FALLTHRU */ case TYPE_MMXMOV: /* Moves from and into integer register is done using movd opcode with REX prefix. */ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1])) return "movd\t{%1, %0|%0, %1}"; return "movq\t{%1, %0|%0, %1}"; case TYPE_SSELOG1: return "%vpxor\t%0, %d0"; case TYPE_MMX: return "pxor\t%0, %0"; case TYPE_MULTI: return "#"; case TYPE_LEA: return "lea{q}\t{%a1, %0|%0, %a1}"; default: gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); if (get_attr_mode (insn) == MODE_SI) return "mov{l}\t{%k1, %k0|%k0, %k1}"; else if (which_alternative == 2) return "movabs{q}\t{%1, %0|%0, %1}"; else return "mov{q}\t{%1, %0|%0, %1}"; } } [(set (attr "type") (cond [(eq_attr "alternative" "5") (const_string "mmx") (eq_attr "alternative" "6,7,8,9,10") (const_string "mmxmov") (eq_attr "alternative" "11") (const_string "sselog1") (eq_attr "alternative" "12,13,14,15,16") (const_string "ssemov") (eq_attr "alternative" "17,18") (const_string "ssecvt") (eq_attr "alternative" "4") (const_string "multi") (match_operand:DI 1 "pic_32bit_operand" "") (const_string "lea") ] (const_string "imov"))) (set (attr "modrm") (if_then_else (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) (const_string "0") (const_string "*"))) (set (attr "length_immediate") (if_then_else (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) (const_string "8") (const_string "*"))) (set_attr "prefix_rex" "*,*,*,*,*,*,*,1,*,1,*,*,*,*,*,*,*,*,*") (set_attr "prefix_data16" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,1,*,*,*") (set (attr "prefix") (if_then_else (eq_attr "alternative" "11,12,13,14,15,16") (const_string "maybe_vex") (const_string "orig"))) (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI,DI,DI")] :} \\ Stores and loads of ax to arbitrary constant address. \\ We fake an second form of instruction to force reload to load address \\ into register when rax is not available concrete *movabsdi_1_rex64.insn instantiates set_mem2 { set_mem2(x86_64_movabs_operand:DI:"i,r", nonmemory_operand:DI:"a,er"); root.1.mode := DI; } {: "TARGET_64BIT && ix86_check_movabs (insn, 0)" "@ movabs{q}\t{%1, %P0|%P0, %1} mov{q}\t{%1, %a0|%a0, %1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0,*") (set_attr "memory" "store") (set_attr "mode" "DI")] :} concrete *movabsdi_2_rex64.insn instantiates set_mem { set_mem(register_operand:DI:"=a,r", x86_64_movabs_operand:DI:"i,r"); } {: "TARGET_64BIT && ix86_check_movabs (insn, 1)" "@ movabs{q}\t{%P1, %0|%0, %P1} mov{q}\t{%a1, %0|%0, %a1}" [(set_attr "type" "imov") (set_attr "modrm" "0,*") (set_attr "length_address" "8,0") (set_attr "length_immediate" "0") (set_attr "memory" "load") (set_attr "mode" "DI")] :} \\ Convert impossible stores of immediate to existing instructions. \\ First try to get scratch register and go through it. In case this \\ fails, move by 32bit parts. concrete .peephole2 instantiates.in set { set(memory_operand:DI:"", immediate_operand:DI:"r"); } cmd_spec.in {: [match_scratch:DI 2 "r"] :} instantiates.in set { set( immediate_operand:DI:"", DI:"r"); } cmd_spec.in {: "TARGET_64BIT && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode)" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (match_dup 2))] "" :} instantiates.out set { set(duplicate 2, duplicate 1); } instantiates.out set { set( duplicate 0, duplicate 2); } cmd_spec.out {: "" :} \\We need to define this as both peepholer and splitter for case \\ peephole2 pass is not run. \\ "&& 1" is needed to keep it from matching the previous pattern. concrete .peephole2 instantiates.in set { set(memory_operand:DI:"", immediate_oeprand:DI:""); } cmd_spec.in {: "TARGET_64BIT && !symbolic_operand (operands[1], DImode) && !x86_64_immediate_operand (operands[1], DImode) && 1" :} instantiates.out set { set(duplicate 2, duplicate 3); } instantiates.out set { set( duplicate 4, duplicate 5); } cmd_spec.out {: "split_di (&operands[0], 2, &operands[2], &operands[4]);") :} concrete *swapdi_rex64.insn instantiates set_set { set_set(register_operand:DI:"+r", register_operand:DI:"+r", duplicate 2, duplicate 1); } {: "TARGET_64BIT" "xchg{q}\t%1, %0" [(set_attr "type" "imov") (set_attr "mode" "DI") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector") (set_attr "amdfam10_decode" "double")] :} concrete movoi.expand instantiates set { set(nonimmediate_operand:OI:"", general_operand:OI:""); } {: "TARGET_AVX" "ix86_expand_move (OImode, operands); DONE;" :} concrete *movoi_internal.insn instantiates set { set(nonimmediate_operand:OI:"=x,x,m", vector_move_operand:OI:"C,xm,x"); } {: "TARGET_AVX && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (which_alternative) { case 0: return "vxorps\t%0, %0, %0"; case 1: case 2: if (misaligned_operand (operands[0], OImode) || misaligned_operand (operands[1], OImode)) return "vmovdqu\t{%1, %0|%0, %1}"; else return "vmovdqa\t{%1, %0|%0, %1}"; default: gcc_unreachable (); } } [(set_attr "type" "sselog1,ssemov,ssemov") (set_attr "prefix" "vex") (set_attr "mode" "OI")] :} concrete movti.expand instantiates set { set(nonimmediate_operand:TI:"", nonimmediate_operand:TI:""); } {: "TARGET_SSE || TARGET_64BIT" { if (TARGET_64BIT) ix86_expand_move (TImode, operands); else if (push_operand (operands[0], TImode)) ix86_expand_push (TImode, operands[1]); else ix86_expand_vector_move (TImode, operands); DONE; } :} concrete *movti_internal.insn instantiates set { set(nonimmediate_operand:TI:"=x,x,m", vector_move_operand:TI:"C,xm,x"); } {: "TARGET_SSE && !TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (which_alternative) { case 0: if (get_attr_mode (insn) == MODE_V4SF) return "%vxorps\t%0, %d0"; else return "%vpxor\t%0, %d0"; case 1: case 2: /* TDmode values are passed as TImode on the stack. Moving them to stack may result in unaligned memory access. */ if (misaligned_operand (operands[0], TImode) || misaligned_operand (operands[1], TImode)) { if (get_attr_mode (insn) == MODE_V4SF) return "%vmovups\t{%1, %0|%0, %1}"; else return "%vmovdqu\t{%1, %0|%0, %1}"; } else { if (get_attr_mode (insn) == MODE_V4SF) return "%vmovaps\t{%1, %0|%0, %1}"; else return "%vmovdqa\t{%1, %0|%0, %1}"; } default: gcc_unreachable (); } } [(set_attr "type" "sselog1,ssemov,ssemov") (set_attr "prefix" "maybe_vex") (set (attr "mode") (cond [(ior (eq (symbol_ref "TARGET_SSE2") (const_int 0)) (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0))) (const_string "V4SF") (and (eq_attr "alternative" "2") (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") (const_int 0))) (const_string "V4SF")] (const_string "TI")))] :} concrete *movti_rex64.insn instantiates set { set(nonimmediate_operand:TI:"=!r,o,x,x,xm", general_operand:TI:"riFo,riF,C,xm,x"); } {: "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (which_alternative) { case 0: case 1: return "#"; case 2: if (get_attr_mode (insn) == MODE_V4SF) return "%vxorps\t%0, %d0"; else return "%vpxor\t%0, %d0"; case 3: case 4: /* TDmode values are passed as TImode on the stack. Moving them to stack may result in unaligned memory access. */ if (misaligned_operand (operands[0], TImode) || misaligned_operand (operands[1], TImode)) { if (get_attr_mode (insn) == MODE_V4SF) return "%vmovups\t{%1, %0|%0, %1}"; else return "%vmovdqu\t{%1, %0|%0, %1}"; } else { if (get_attr_mode (insn) == MODE_V4SF) return "%vmovaps\t{%1, %0|%0, %1}"; else return "%vmovdqa\t{%1, %0|%0, %1}"; } default: gcc_unreachable (); } } [(set_attr "type" "*,*,sselog1,ssemov,ssemov") (set_attr "prefix" "*,*,maybe_vex,maybe_vex,maybe_vex") (set (attr "mode") (cond [(eq_attr "alternative" "2,3") (if_then_else (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (const_string "TI")) (eq_attr "alternative" "4") (if_then_else (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") (const_int 0)) (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0))) (const_string "V4SF") (const_string "TI"))] (const_string "DI")))] :} concrete .split instantiates.in set { set(nonimmediate_oeprand:TI:"", general_oeprand:TI:""); } cmd_spec.in {: "reload_completed && !SSE_REG_P (operands[0]) && !SSE_REG_P (operands[1])" :} cmd_spec.out {: [(const_int 0)] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} \\ This expands to what emit_move_complex would generate if we didn't \\ have a movti pattern. Having this avoids problems with reload on \\ 32-bit targets when SSE is present, but doesn't seem to be harmful \\ to have around all the time. concrete movcdi.expand instantiates set { set(nonimmediate_oeprand:CDI:"", general_operand:CDI:""); } {: "" { if (push_operand (operands[0], CDImode)) emit_move_complex_push (CDImode, operands[0], operands[1]); else emit_move_complex_parts (operands[0], operands[1]); DONE; } :} concrete movsf.insn instantiates set { set(nonimmediate_operand:SF:"", general_operand:SF:""); } {: "" "ix86_expand_move (SFmode, operands); DONE;" :} concrete *pushsf.insn instantiates set { set(push_operand:SF:"=<,<,<", geenral_no_elim_operand:SF:"f,rFm,x"); } {: "!TARGET_64BIT" { /* Anything else should be already split before reg-stack. */ gcc_assert (which_alternative == 1); return "push{l}\t%1"; } [(set_attr "type" "multi,push,multi") (set_attr "unit" "i387,*,*") (set_attr "mode" "SF,SI,SF")] :} concrete *pushsf_rex64.insn instantiates set { set(push_operand:SF:"=X,X,X", nonmemory_no_elim_operand:SF:"f,rF,x"); } {: "TARGET_64BIT" { /* Anything else should be already split before reg-stack. */ gcc_assert (which_alternative == 1); return "push{q}\t%q1"; } [(set_attr "type" "multi,push,multi") (set_attr "unit" "i387,*,*") (set_attr "mode" "SF,DI,SF")] :} concrete .split instantiates.in set { set(push_operand:SF:"", memory_operand:SF:""); } cmd_spec.in {: "reload_completed && MEM_P (operands[1]) && (operands[2] = find_constant_src (insn))" :} instantiates.out set { set(duplicate 0, duplicate 2); } \\ %%% Kill this when call knows how to work this out. concrete .split instantiates.in set { set(push_operand:SF:"", any_fp_register_operand:SF:""); } cmd_spec.in {: "!TARGET_64BIT" :} instantiates.out set_plus { set_plus(reg(DI:SP_REG), reg(DI:SP_REG), const_int:-8); root.1.2.mode := SI; } instantiates.out set_mem2 { set_mem2( reg(DI:SP_REG), duplicate 1); root.2.1.mode := SF; } concrete .split instantiates.in set { set(push_operand:SF:"", any_fp_register_operand:SF:""); } cmd_spec.in {: "TARGET_64BIT" :} instantiates.out set_plus_set_mem2 { set_plus(reg(DI:SP_REG), reg(DI:SP_REG), const_int:-8); root.1.2.mode := DI; } instantiates.out set_mem2 { set_mem2( reg(DI:SP_REG), duplicate 1); root.2.1.mode := SF; } concrete *movsf_1.insn instantiates set { set(nonimmediate_operand:SF:"=f,m,f,r,m,x,x,x,m,!*y,!m,!*y,?Yi,?r,!*Ym,!r", general_operand:SF:"fm,f,G,rmF,Fr,C,x,xm,x,m,*y,*y,r,Yi,r,*Ym"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1])) && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) || (!TARGET_SSE_MATH && optimize_function_for_size_p (cfun) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE || memory_operand (operands[0], SFmode))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "mov{l}\t{%1, %0|%0, %1}"; case 5: if (get_attr_mode (insn) == MODE_TI) return "%vpxor\t%0, %d0"; else return "%vxorps\t%0, %d0"; case 6: if (get_attr_mode (insn) == MODE_V4SF) return "%vmovaps\t{%1, %0|%0, %1}"; else return "%vmovss\t{%1, %d0|%d0, %1}"; case 7: if (TARGET_AVX) return REG_P (operands[1]) ? "vmovss\t{%1, %0, %0|%0, %0, %1}" : "vmovss\t{%1, %0|%0, %1}"; else return "movss\t{%1, %0|%0, %1}"; case 8: return "%vmovss\t{%1, %0|%0, %1}"; case 9: case 10: case 14: case 15: return "movd\t{%1, %0|%0, %1}"; case 12: case 13: return "%vmovd\t{%1, %0|%0, %1}"; case 11: return "movq\t{%1, %0|%0, %1}"; default: gcc_unreachable (); } } [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov,ssemov,ssemov,mmxmov,mmxmov") (set (attr "prefix") (if_then_else (eq_attr "alternative" "5,6,7,8,12,13") (const_string "maybe_vex") (const_string "orig"))) (set (attr "mode") (cond [(eq_attr "alternative" "3,4,9,10") (const_string "SI") (eq_attr "alternative" "5") (if_then_else (and (and (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) (ne (symbol_ref "TARGET_SSE2") (const_int 0))) (eq (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0))) (const_string "TI") (const_string "V4SF")) /* For architectures resolving dependencies on whole SSE registers use APS move to break dependency chains, otherwise use short move to avoid extra work. Do the same for architectures resolving dependencies on the parts. While in DF mode it is better to always handle just register parts, the SF mode is different due to lack of instructions to load just part of the register. It is better to maintain the whole registers in single format to avoid problems on using packed logical operations. */ (eq_attr "alternative" "6") (if_then_else (ior (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (const_int 0)) (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") (const_int 0))) (const_string "V4SF") (const_string "SF")) (eq_attr "alternative" "11") (const_string "DI")] (const_string "SF")))] :} concrete *swapsf.insn instantiates set_set { set_set(fp_register_operand:SF:"+f", fp_register_operand:SF:"+f", duplicate 2, duplicate 1); } {: "reload_completed || TARGET_80387" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; else return "fxch\t%0"; } [(set_attr "type" "fxch") (set_attr "mode" "SF")] :} concrete movdf.expand instantiates set { set(nonimmediate_operand:DF:"", general_operand:DF:""); } {: "" "ix86_expand_move (DFmode, operands); DONE;" :} \\ Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. \\ Size of pushdf using integer instructions is 2+2*memory operand size \\ On the average, pushdf using integers can be still shorter. Allow this \\ pattern for optimize_size too. concrete *pushdf_nointeger.insn instantiates set { set(push_operand:DF:"=<,<,<,<", general_no_elim_operand:DF:"f,Fo,*r,Y2"); } {: "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES" { /* This insn should be already split before reg-stack. */ gcc_unreachable (); } [(set_attr "type" "multi") (set_attr "unit" "i387,*,*,*") (set_attr "mode" "DF,SI,SI,DF")] :} concrete *pushdf_integer.insn instantiates set { set(push_operand:DF:"=<,<,<",general_no_elim_operand:DF:"f,rFo,Y2"); } {: "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES" { /* This insn should be already split before reg-stack. */ gcc_unreachable (); } [(set_attr "type" "multi") (set_attr "unit" "i387,*,*") (set_attr "mode" "DF,SI,DF")] :} \\ %%% Kill this when call knows how to work this out. concrete .split instantiates.in set { set(push_operand:DF:"", any_fp_register_operand:DF:""); } cmd_spec.in {: "reload_completed" :} instantiates.out set_plus { set_plus(reg(P:SP_REG), reg(P:SP_REG), const_int:-8); root.1.2.mode := P; } instantiates.out set_mem2 { set_mem2( reg(P:SP_REG), duplicate 1); root.2.1.mode := DF; } cmd_spec.out {: "" :} concrete .split instantiates.in set { set(push_operand:DF:"", general_operand:DF:""); } cmd_spec.in {: "reload_completed" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;") :} \\ Moving is usually shorter when only FP registers are used. This separate \\ movdf pattern avoids the use of integer registers for FP operations \\ when optimizing for size. concrete *movdf_nointeger.insn instantiates set { set(nonimmediate_operand:DF:"=f,m,f,*r,o,Y2*x,Y2*x,Y2*x,m", general_operand:DF:"fm,f,G,*roF,*Fr,C,Y2*x,mY2*x,Y2*x"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1])) && ((optimize_function_for_size_p (cfun) || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT) && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) || (!(TARGET_SSE2 && TARGET_SSE_MATH) && optimize_function_for_size_p (cfun) && !memory_operand (operands[0], DFmode) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE || ((optimize_function_for_size_p (cfun) || !TARGET_MEMORY_MISMATCH_STALL || reload_in_progress || reload_completed) && memory_operand (operands[0], DFmode)))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "#"; case 5: switch (get_attr_mode (insn)) { case MODE_V4SF: return "%vxorps\t%0, %d0"; case MODE_V2DF: return "%vxorpd\t%0, %d0"; case MODE_TI: return "%vpxor\t%0, %d0"; default: gcc_unreachable (); } case 6: case 7: case 8: switch (get_attr_mode (insn)) { case MODE_V4SF: return "%vmovaps\t{%1, %0|%0, %1}"; case MODE_V2DF: return "%vmovapd\t{%1, %0|%0, %1}"; case MODE_TI: return "%vmovdqa\t{%1, %0|%0, %1}"; case MODE_DI: return "%vmovq\t{%1, %0|%0, %1}"; case MODE_DF: if (TARGET_AVX) { if (REG_P (operands[0]) && REG_P (operands[1])) return "vmovsd\t{%1, %0, %0|%0, %0, %1}"; else return "vmovsd\t{%1, %0|%0, %1}"; } else return "movsd\t{%1, %0|%0, %1}"; case MODE_V1DF: if (TARGET_AVX) { if (REG_P (operands[0])) return "vmovlpd\t{%1, %0, %0|%0, %0, %1}"; else return "vmovlpd\t{%1, %0|%0, %1}"; } else return "movlpd\t{%1, %0|%0, %1}"; case MODE_V2SF: if (TARGET_AVX) { if (REG_P (operands[0])) return "vmovlps\t{%1, %0, %0|%0, %0, %1}"; else return "vmovlps\t{%1, %0|%0, %1}"; } else return "movlps\t{%1, %0|%0, %1}"; default: gcc_unreachable (); } default: gcc_unreachable (); } } [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") (set (attr "prefix") (if_then_else (eq_attr "alternative" "0,1,2,3,4") (const_string "orig") (const_string "maybe_vex"))) (set (attr "prefix_data16") (if_then_else (eq_attr "mode" "V1DF") (const_string "1") (const_string "*"))) (set (attr "mode") (cond [(eq_attr "alternative" "0,1,2") (const_string "DF") (eq_attr "alternative" "3,4") (const_string "SI") /* For SSE1, we have many fewer alternatives. */ (eq (symbol_ref "TARGET_SSE2") (const_int 0)) (cond [(eq_attr "alternative" "5,6") (const_string "V4SF") ] (const_string "V2SF")) /* xorps is one byte shorter. */ (eq_attr "alternative" "5") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) (const_string "TI") ] (const_string "V2DF")) /* For architectures resolving dependencies on whole SSE registers use APD move to break dependency chains, otherwise use short move to avoid extra work. movaps encodes one byte shorter. */ (eq_attr "alternative" "6") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (const_int 0)) (const_string "V2DF") ] (const_string "DF")) /* For architectures resolving dependencies on register parts we may avoid extra work to zero out upper part of register. */ (eq_attr "alternative" "7") (if_then_else (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") (const_int 0)) (const_string "V1DF") (const_string "DF")) ] (const_string "DF")))] :} concrete *movdf_integer.insn instantiates set { set(nonimmediate_operand:DF:"=f,m,f,r,o,Y2*x,Y2*x,Y2*x,m", general_operand:DF:"fm,f,G,roF,Fr,C,Y2*x,m,Y2*x"); } {: "!(MEM_P (operands[0]) && MEM_P (operands[1])) && optimize_function_for_speed_p (cfun) && TARGET_INTEGER_DFMODE_MOVES && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) || (!(TARGET_SSE2 && TARGET_SSE_MATH) && optimize_function_for_size_p (cfun) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE || memory_operand (operands[0], DFmode))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "#"; case 5: switch (get_attr_mode (insn)) { case MODE_V4SF: return "xorps\t%0, %0"; case MODE_V2DF: return "xorpd\t%0, %0"; case MODE_TI: return "pxor\t%0, %0"; default: gcc_unreachable (); } case 6: case 7: case 8: switch (get_attr_mode (insn)) { case MODE_V4SF: return "movaps\t{%1, %0|%0, %1}"; case MODE_V2DF: return "movapd\t{%1, %0|%0, %1}"; case MODE_TI: return "movdqa\t{%1, %0|%0, %1}"; case MODE_DI: return "movq\t{%1, %0|%0, %1}"; case MODE_DF: return "movsd\t{%1, %0|%0, %1}"; case MODE_V1DF: return "movlpd\t{%1, %0|%0, %1}"; case MODE_V2SF: return "movlps\t{%1, %0|%0, %1}"; default: gcc_unreachable (); } default: gcc_unreachable(); } } [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") (set (attr "prefix_data16") (if_then_else (eq_attr "mode" "V1DF") (const_string "1") (const_string "*"))) (set (attr "mode") (cond [(eq_attr "alternative" "0,1,2") (const_string "DF") (eq_attr "alternative" "3,4") (const_string "SI") /* For SSE1, we have many fewer alternatives. */ (eq (symbol_ref "TARGET_SSE2") (const_int 0)) (cond [(eq_attr "alternative" "5,6") (const_string "V4SF") ] (const_string "V2SF")) /* xorps is one byte shorter. */ (eq_attr "alternative" "5") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) (const_string "TI") ] (const_string "V2DF")) /* For architectures resolving dependencies on whole SSE registers use APD move to break dependency chains, otherwise use short move to avoid extra work. movaps encodes one byte shorter. */ (eq_attr "alternative" "6") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (const_int 0)) (const_string "V2DF") ] (const_string "DF")) /* For architectures resolving dependencies on register parts we may avoid extra work to zero out upper part of register. */ (eq_attr "alternative" "7") (if_then_else (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") (const_int 0)) (const_string "V1DF") (const_string "DF")) ] (const_string "DF")))] :} concrete *movdf_integer_rex64.insn overrides *movdf_integer.insn { allconstraints := ("=f,m,f,r ,m ,Y2*x,Y2*x,Y2*x,m ,Yi,r ", "fm,f,G,rmF,Fr,C ,Y2*x,m ,Y2*x,r ,Yi"); } {: "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1])) && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) || (!(TARGET_SSE2 && TARGET_SSE_MATH) && optimize_function_for_size_p (cfun) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE || memory_operand (operands[0], DFmode))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "#"; case 5: switch (get_attr_mode (insn)) { case MODE_V4SF: return "%vxorps\t%0, %d0"; case MODE_V2DF: return "%vxorpd\t%0, %d0"; case MODE_TI: return "%vpxor\t%0, %d0"; default: gcc_unreachable (); } case 6: case 7: case 8: switch (get_attr_mode (insn)) { case MODE_V4SF: return "%vmovaps\t{%1, %0|%0, %1}"; case MODE_V2DF: return "%vmovapd\t{%1, %0|%0, %1}"; case MODE_TI: return "%vmovdqa\t{%1, %0|%0, %1}"; case MODE_DI: return "%vmovq\t{%1, %0|%0, %1}"; case MODE_DF: if (TARGET_AVX) { if (REG_P (operands[0]) && REG_P (operands[1])) return "vmovsd\t{%1, %0, %0|%0, %0, %1}"; else return "vmovsd\t{%1, %0|%0, %1}"; } else return "movsd\t{%1, %0|%0, %1}"; case MODE_V1DF: return "%vmovlpd\t{%1, %d0|%d0, %1}"; case MODE_V2SF: return "%vmovlps\t{%1, %d0|%d0, %1}"; default: gcc_unreachable (); } case 9: case 10: return "%vmovd\t{%1, %0|%0, %1}"; default: gcc_unreachable(); } } [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov,ssemov,ssemov") (set (attr "prefix") (if_then_else (eq_attr "alternative" "0,1,2,3,4") (const_string "orig") (const_string "maybe_vex"))) (set (attr "prefix_data16") (if_then_else (eq_attr "mode" "V1DF") (const_string "1") (const_string "*"))) (set (attr "mode") (cond [(eq_attr "alternative" "0,1,2") (const_string "DF") (eq_attr "alternative" "3,4,9,10") (const_string "DI") /* For SSE1, we have many fewer alternatives. */ (eq (symbol_ref "TARGET_SSE2") (const_int 0)) (cond [(eq_attr "alternative" "5,6") (const_string "V4SF") ] (const_string "V2SF")) /* xorps is one byte shorter. */ (eq_attr "alternative" "5") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") (const_int 0)) (const_string "TI") ] (const_string "V2DF")) /* For architectures resolving dependencies on whole SSE registers use APD move to break dependency chains, otherwise use short move to avoid extra work. movaps encodes one byte shorter. */ (eq_attr "alternative" "6") (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") (const_int 0)) (const_string "V2DF") ] (const_string "DF")) /* For architectures resolving dependencies on register parts we may avoid extra work to zero out upper part of register. */ (eq_attr "alternative" "7") (if_then_else (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") (const_int 0)) (const_string "V1DF") (const_string "DF")) ] (const_string "DF")))] :} concrete .split instantiates.in set { set(nonimmediate_operand:DF:"", general_operand:DF:""); } cmd_spec.in {: "reload_completed && !(MEM_P (operands[0]) && MEM_P (operands[1])) && ! (ANY_FP_REG_P (operands[0]) || (GET_CODE (operands[0]) == SUBREG && ANY_FP_REG_P (SUBREG_REG (operands[0])))) && ! (ANY_FP_REG_P (operands[1]) || (GET_CODE (operands[1]) == SUBREG && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} concrete *swapdf.insn instantiates set_set { set_set(fp_register_operand:DF:"+f", fp_register_operand:DF:"+f", duplicate 2, duplicate 1); } {: "reload_completed || TARGET_80387" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; else return "fxch\t%0"; } [(set_attr "type" "fxch") (set_attr "mode" "DF")] :} concrete movxf.expand instantiates set { set(nonimmediate_operand:XF:"", general_operand:XF:""); } {: "" "ix86_expand_move (XFmode, operands); DONE;" :} \\ Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. \\ Size of pushdf using integer instructions is 3+3*memory operand size \\ Pushing using integer instructions is longer except for constants \\ and direct memory references. \\ (assuming that any given constant is pushed only once, but this ought to be \\ handled elsewhere). concrete *pushxf_nointeger.insn instantiates set { set(push_operand:XF:"=X,X,X", general_no_elim_operand:XF:"f,Fo,*r"); } {: "optimize_function_for_size_p (cfun)" { /* This insn should be already split before reg-stack. */ gcc_unreachable (); } [(set_attr "type" "multi") (set_attr "unit" "i387,*,*") (set_attr "mode" "XF,SI,SI")] :} concrete *pushxf_integer.insn instantiates set { set(push_operand:XF:"=<,<", general_no_elim_operand:XF:"f,ro"); } {: "optimize_function_for_speed_p (cfun)" { /* This insn should be already split before reg-stack. */ gcc_unreachable (); } [(set_attr "type" "multi") (set_attr "unit" "i387,*") (set_attr "mode" "XF,SI")] :} concrete .split instantiates.in set { set(push_operand:NULL:"", general_operand:NULL:""); } cmd_spec.in {: "reload_completed && (GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == DFmode) && !ANY_FP_REG_P (operands[1])" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;") :} concrete .split instantiates.in set { set(push_operand:XF:"", any_fp_register_oeprand:XF:""); } cmd_spec.in {: "" :} instantiates.out set_plus_set_mem2 { set_plus_set_mem2(reg(P:SP_REG), reg(P:SP_REG), duplicate 2, reg(P:SP_REG), duplicate 1); root.1.2.mode := P; root.2.2.mode := XF; } cmd_spec.out {: "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") :} \\ Do not use integer registers when optimizing for size concrete *movxf_integer.insn instantiates set { set(nonimmediate_operand:XF:"=f,m,f,r,o", general_operand:XF:"fm,f,G,roF,Fr"); } {: "optimize_function_for_speed_p (cfun) && !(MEM_P (operands[0]) && MEM_P (operands[1])) && (reload_in_progress || reload_completed || GET_CODE (operands[1]) != CONST_DOUBLE || memory_operand (operands[0], XFmode))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "#"; default: gcc_unreachable (); } } [(set_attr "type" "fmov,fmov,fmov,multi,multi") (set_attr "mode" "XF,XF,XF,SI,SI")] :} concrete *movxf_nointeger.insn overrides *movxf_integer.insn { allconstraints := ("=f,m,f,*r,o", "fm,f,G,*roF,F*r"); } {: "optimize_function_for_size_p (cfun) && !(MEM_P (operands[0]) && MEM_P (operands[1])) && (reload_in_progress || reload_completed || standard_80387_constant_p (operands[1]) || GET_CODE (operands[1]) != CONST_DOUBLE || memory_operand (operands[0], XFmode))" { switch (which_alternative) { case 0: case 1: return output_387_reg_move (insn, operands); case 2: return standard_80387_constant_opcode (operands[1]); case 3: case 4: return "#"; default: gcc_unreachable (); } } [(set_attr "type" "fmov,fmov,fmov,multi,multi") (set_attr "mode" "XF,XF,XF,SI,SI")] :} concrete movtf.expand instantiates set { set(nonimmediate_operand:TF:"", nonimmediate_operand:TF:""); } {: "TARGET_SSE2" { ix86_expand_move (TFmode, operands); DONE; } :} concrete *movtf_internal.insn instantiates set { set(nonimmediate_operand:TF:"=x,m,x,?r,?o", general_operand:TF:"xm,x,C,roF,Fr"); } {: "TARGET_SSE2 && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (which_alternative) { case 0: case 1: if (get_attr_mode (insn) == MODE_V4SF) return "%vmovaps\t{%1, %0|%0, %1}"; else return "%vmovdqa\t{%1, %0|%0, %1}"; case 2: if (get_attr_mode (insn) == MODE_V4SF) return "%vxorps\t%0, %d0"; else return "%vpxor\t%0, %d0"; case 3: case 4: return "#"; default: gcc_unreachable (); } } [(set_attr "type" "ssemov,ssemov,sselog1,*,*") (set_attr "prefix" "maybe_vex,maybe_vex,maybe_vex,*,*") (set (attr "mode") (cond [(eq_attr "alternative" "0,2") (if_then_else (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) (const_string "V4SF") (const_string "TI")) (eq_attr "alternative" "1") (if_then_else (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") (const_int 0)) (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0))) (const_string "V4SF") (const_string "TI"))] (const_string "DI")))] :} concrete *pushtf_sse.insn instantiates set { set(push_operand:TF:"=<,<,<", general_no_elim_operand:TF:"x,Fo,*r"); } {: "TARGET_SSE2" { /* This insn should be already split before reg-stack. */ gcc_unreachable (); } [(set_attr "type" "multi") (set_attr "unit" "sse,*,*") (set_attr "mode" "TF,SI,SI")] :} concrete .split instantiates.in set { set(push_operand:TF:"", general_operand:TF:""); } cmd_spec.in {: "TARGET_SSE2 && reload_completed && !SSE_REG_P (operands[1])" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} concrete .split instantiates.in set { set(push_operand:TF:"", any_fp_register_operand:TF:""); } cmd_spec.in {: "TARGET_SSE2" :} instantiates.out set_plus { set_plus(reg(P:SP_REG), reg(P:SP_REG), const_int:-16); root.1.2.mode := P; } instantiates.out set_mem2 { set_mem2( reg(P:SP_REG), duplicate 1); root.2.1.mode := TF; } cmd_spec.out {: "" :} concrete .split instantiates.in set { set(nonimmediate_operand:NULL:"", general_operand:NULL:""); } cmd_spec.in {: "reload_completed && !(MEM_P (operands[0]) && MEM_P (operands[1])) && GET_MODE (operands[0]) == XFmode && ! (ANY_FP_REG_P (operands[0]) || (GET_CODE (operands[0]) == SUBREG && ANY_FP_REG_P (SUBREG_REG (operands[0])))) && ! (ANY_FP_REG_P (operands[1]) || (GET_CODE (operands[1]) == SUBREG && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;") :} concrete .split instantiates.in set { set(register_operand:NULL:"", memory_operand:NULl:""); } cmd_spec.in {: "reload_completed && MEM_P (operands[1]) && (GET_MODE (operands[0]) == TFmode || GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == SFmode || GET_MODE (operands[0]) == DFmode) && (operands[2] = find_constant_src (insn))" :} instantiates.out set { set(duplicate 0, duplicate 2); } cmd_spec.out {: rtx c = operands[2]; rtx r = operands[0]; if (GET_CODE (r) == SUBREG) r = SUBREG_REG (r); if (SSE_REG_P (r)) { if (!standard_sse_constant_p (c)) FAIL; } else if (FP_REG_P (r)) { if (!standard_80387_constant_p (c)) FAIL; } else if (MMX_REG_P (r)) FAIL; } :} concrete .split instantiates.in set_floatext { set_floatext(register_operand:NULL:"", memory_operand:NULL:""); } cmd_spec.in {: "reload_completed && MEM_P (operands[1]) && (GET_MODE (operands[0]) == TFmode || GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == SFmode || GET_MODE (operands[0]) == DFmode) && (operands[2] = find_constant_src (insn))" :} instantiates.out set { set( duplicate 0, duplicate 2); } cmd_spec.out {: "reload_completed && MEM_P (operands[1]) && (GET_MODE (operands[0]) == TFmode || GET_MODE (operands[0]) == XFmode || GET_MODE (operands[0]) == SFmode || GET_MODE (operands[0]) == DFmode) && (operands[2] = find_constant_src (insn))" :} concrete swapxf.insn instantiates set_set { set_set(register_operand:XF:"+f", register_operand:XF:"+f", duplicate 2, duplicate 1); } {: "TARGET_80387" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; else return "fxch\t%0"; } [(set_attr "type" "fxch") (set_attr "mode" "XF")]) :} \\ Split the load of -0.0 or -1.0 into fldz;fchs or fld1;fchs sequence concrete .split instantiates.in set { set(register_operand:X87MODEF:"", immediate_operand:X87MODEF:""); } cmd_spec.in {: "reload_completed && FP_REGNO_P (REGNO (operands[0])) && (standard_80387_constant_p (operands[1]) == 8 || standard_80387_constant_p (operands[1]) == 9)" :} instantiates.out set { set(duplicate 0, duplicate 1); } instantiates.out set_neg { set_neg(duplicate 0, duplicate 0); root.2.mode := X87MODEF; } cmd_spec.out {: { REAL_VALUE_TYPE r; REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); if (real_isnegzero (&r)) operands[1] = CONST0_RTX (mode); else operands[1] = CONST1_RTX (mode); } :} concrete .split instantiates.in set { set(nonimmediate_operand:TF:"",genral_operand:TF:""); } cmd_spec.in {: "reload_completed && !(SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]))" :} cmd_spec.out {: [const_int 0] :} cmd_spec.out {: "ix86_split_long_move (operands); DONE;" :} \\********* Zero-Extension Instructions using the Conventional Machine Description format********* {: (define_expand "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "") (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "" { if (TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)) { operands[1] = force_reg (HImode, operands[1]); emit_insn (gen_zero_extendhisi2_and (operands[0], operands[1])); DONE; } }) :} {: (define_insn "zero_extendhisi2_and" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" "#" [(set_attr "type" "alu1") (set_attr "mode" "SI")]) :}