diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index affa5e09c35..a2a8607061e 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -365,10 +365,10 @@ multiclass AsI1_bin_irs opcod, string opc, PatFrag opnode> { [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>; } -/// ASI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the +/// AI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the /// instruction modifies the CSPR register. let Defs = [CPSR] in { -multiclass ASI1_bin_s_irs opcod, string opc, PatFrag opnode> { +multiclass AI1_bin_s_irs opcod, string opc, PatFrag opnode> { def ri : AI1; @@ -430,18 +430,18 @@ multiclass AI_bin_rrot opcod, string opc, PatFrag opnode> { Requires<[IsARM, HasV6]>; } -/// AsXI1_bin_c_irs - Same as AsI1_bin_irs but without the predicate operand and -/// setting carry bit. But it can optionally set CPSR. -let Uses = [CPSR] in { -multiclass AsXI1_bin_c_irs opcod, string opc, PatFrag opnode> { - def ri : AXI1 opcod, string opc, PatFrag opnode> { + def ri : AXI1; - def rr : AXI1; - def rs : AXI1; } } @@ -905,16 +905,16 @@ defm SUB : AsI1_bin_irs<0b0010, "sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; // ADD and SUB with 's' bit set. -defm ADDS : ASI1_bin_s_irs<0b0100, "add", - BinOpFrag<(addc node:$LHS, node:$RHS)>>; -defm SUBS : ASI1_bin_s_irs<0b0010, "sub", - BinOpFrag<(subc node:$LHS, node:$RHS)>>; +defm ADDS : AI1_bin_s_irs<0b0100, "add", + BinOpFrag<(addc node:$LHS, node:$RHS)>>; +defm SUBS : AI1_bin_s_irs<0b0010, "sub", + BinOpFrag<(subc node:$LHS, node:$RHS)>>; -// FIXME: Do not allow ADC / SBC to be predicated for now. -defm ADC : AsXI1_bin_c_irs<0b0101, "adc", - BinOpFrag<(adde node:$LHS, node:$RHS)>>; -defm SBC : AsXI1_bin_c_irs<0b0110, "sbc", - BinOpFrag<(sube node:$LHS, node:$RHS)>>; +// FIXME: Do not allow ADCS / SBCS to be predicated for now. +defm ADCS : AI1_bin_cs_irs<0b0101, "adc", + BinOpFrag<(adde node:$LHS, node:$RHS)>>; +defm SBCS : AI1_bin_cs_irs<0b0110, "sbc", + BinOpFrag<(sube node:$LHS, node:$RHS)>>; // These don't define reg/reg forms, because they are handled above. def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm, @@ -935,14 +935,14 @@ def RSBSrs : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, [(set GPR:$dst, (subc so_reg:$b, GPR:$a))]>; } -// FIXME: Do not allow RSC to be predicated for now. But they can set CPSR. -let Uses = [CPSR] in { -def RSCri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b, cc_out:$s), - DPFrm, "rsc${s} $dst, $a, $b", - [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>; -def RSCrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b, cc_out:$s), - DPSoRegFrm, "rsc${s} $dst, $a, $b", - [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>; +// FIXME: Do not allow RSC to be predicated for now. +let Defs = [CPSR], Uses = [CPSR] in { +def RSCSri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), + DPFrm, "rscs $dst, $a, $b", + [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>; +def RSCSrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), + DPSoRegFrm, "rscs $dst, $a, $b", + [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>; } // (sub X, imm) gets canonicalized to (add X, -imm). Match this form. diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 273dce57eeb..2b633242f43 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -169,16 +169,14 @@ multiclass T2I_bin_irs { [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } -/// T2I_rbin_irs - Same as T2I_bin_irs except the order of operands are reversed. -multiclass T2I_rbin_irs { +/// T2I_rbin_is - Same as T2I_bin_irs except the order of operands are +/// reversed. It doesn't define the 'rr' form since it's handled by its +/// T2I_bin_irs counterpart. +multiclass T2I_rbin_is { // shifted imm def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), opc, " $dst, $rhs, $lhs", [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; - // register - def rr : T2I<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs), - opc, " $dst, $rhs, $lhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), opc, " $dst, $rhs, $lhs", @@ -204,25 +202,6 @@ multiclass T2I_bin_s_irs { } } -/// T2I_rbin_s_irs - Same as T2I_bin_s_irs except the order of operands are -/// reversed. -let Defs = [CPSR] in { -multiclass T2I_rbin_s_irs { - // shifted imm - def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), - !strconcat(opc, "s"), " $dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; - // register - def rr : T2I<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs), - !strconcat(opc, "s"), " $dst, $rhs, $lhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; - // shifted register - def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), - !strconcat(opc, "s"), " $dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>; -} -} - /// T2I_bin_ii12rs - Defines a set of (op reg, {so_imm|imm0_4095|r|so_reg}) /// patterns for a binary operation that produces a value. multiclass T2I_bin_ii12rs { @@ -244,38 +223,55 @@ multiclass T2I_bin_ii12rs { [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } -/// T2I_bin_c_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a -// binary operation that produces a value and set the carry bit. It can also -/// optionally set CPSR. -let Uses = [CPSR] in { -multiclass T2I_bin_c_irs { +/// T2I_bin_cs_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a +/// binary operation that produces a value and use and define the carry bit. +/// It's not predicable. +let Defs = [CPSR], Uses = [CPSR] in { +multiclass T2I_bin_cs_irs { // shifted imm - def ri : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), + def ri : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>; // register - def rr : T2XI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), + def rr : T2XI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register - def rs : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), + def rs : T2XI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } } -/// T2I_rbin_c_irs - Same as T2I_bin_c_irs except the order of operands are -/// reversed. -let Uses = [CPSR] in { -multiclass T2I_rbin_c_irs { +/// T2I_rbin_cs_is - Same as T2I_bin_cs_irs except the order of operands are +/// reversed. It doesn't define the 'rr' form since it's handled by its +/// T2I_bin_cs_irs counterpart. +let Defs = [CPSR], Uses = [CPSR] in { +multiclass T2I_rbin_cs_is { + // shifted imm + def ri : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), + !strconcat(opc, "s $dst, $rhs, $lhs"), + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; + // register + def rr : T2XI<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs), + !strconcat(opc, "s $dst, $rhs, $lhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; + // shifted register + def rs : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), + !strconcat(opc, "s $dst, $rhs, $lhs"), + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>; +} +} + +/// T2I_rbin_s_is - Same as T2I_bin_s_irs except the order of operands are +/// reversed. It doesn't define the 'rr' form since it's handled by its +/// T2I_bin_s_irs counterpart. +let Defs = [CPSR] in { +multiclass T2I_rbin_s_is { // shifted imm def ri : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs, cc_out:$s), !strconcat(opc, "${s} $dst, $rhs, $lhs"), [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; - // register - def rr : T2XI<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $rhs, $lhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register def rs : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s), !strconcat(opc, "${s} $dst, $rhs, $lhs"), @@ -386,17 +382,17 @@ defm t2ADD : T2I_bin_ii12rs<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>; defm t2SUB : T2I_bin_ii12rs<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; // ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants. -defm t2ADDS : T2I_bin_s_irs<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>; -defm t2SUBS : T2I_bin_s_irs<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>; +defm t2ADDS : T2I_bin_s_irs <"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>; +defm t2SUBS : T2I_bin_s_irs <"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>; // FIXME: predication support -defm t2ADC : T2I_bin_c_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; -defm t2SBC : T2I_bin_c_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; +defm t2ADC : T2I_bin_cs_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; +defm t2SBC : T2I_bin_cs_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; // RSB, RSC -defm t2RSB : T2I_rbin_irs <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; -defm t2RSBS : T2I_rbin_c_irs<"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>; -defm t2RSC : T2I_rbin_s_irs<"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; +defm t2RSB : T2I_rbin_is <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; +defm t2RSBS : T2I_rbin_s_is <"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>; +defm t2RSC : T2I_rbin_cs_is<"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; // (sub X, imm) gets canonicalized to (add X, -imm). Match this form. def : Thumb2Pat<(add GPR:$src, t2_so_imm_neg:$imm), diff --git a/test/CodeGen/ARM/carry.ll b/test/CodeGen/ARM/carry.ll new file mode 100644 index 00000000000..82a569398da --- /dev/null +++ b/test/CodeGen/ARM/carry.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | llc -march=arm | grep "subs r" | count 2 +; RUN: llvm-as < %s | llc -march=arm | grep adc +; RUN: llvm-as < %s | llc -march=arm | grep sbc + +define i64 @f1(i64 %a, i64 %b) { +entry: + %tmp = sub i64 %a, %b + ret i64 %tmp +} + +define i64 @f2(i64 %a, i64 %b) { +entry: + %tmp1 = shl i64 %a, 1 + %tmp2 = sub i64 %tmp1, %b + ret i64 %tmp2 +} diff --git a/test/CodeGen/Thumb2/carry.ll b/test/CodeGen/Thumb2/carry.ll new file mode 100644 index 00000000000..aa551c7d479 --- /dev/null +++ b/test/CodeGen/Thumb2/carry.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep "subs r" | count 2 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep adc +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep sbc + +define i64 @f1(i64 %a, i64 %b) { +entry: + %tmp = sub i64 %a, %b + ret i64 %tmp +} + +define i64 @f2(i64 %a, i64 %b) { +entry: + %tmp1 = shl i64 %a, 1 + %tmp2 = sub i64 %tmp1, %b + ret i64 %tmp2 +}