diff options
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.td | 71 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrThumb2.td | 90 | ||||
-rw-r--r-- | test/CodeGen/ARM/carry.ll | 4 | ||||
-rw-r--r-- | test/CodeGen/Thumb2/carry.ll | 4 |
4 files changed, 120 insertions, 49 deletions
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index a2a8607..4958f70 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -103,6 +103,8 @@ def HasThumb2 : Predicate<"Subtarget->hasThumb2()">; def IsARM : Predicate<"!Subtarget->isThumb()">; def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; def IsNotDarwin : Predicate<"!Subtarget->isTargetDarwin()">; +def CarryDefIsUnused : Predicate<"N.getNode()->hasNUsesOfValue(0, 1)">; +def CarryDefIsUsed : Predicate<"N.getNode()->hasAnyUseOfValue(1)">; //===----------------------------------------------------------------------===// // ARM Flag Definitions. @@ -430,19 +432,40 @@ multiclass AI_bin_rrot<bits<8> opcod, string opc, PatFrag opnode> { Requires<[IsARM, HasV6]>; } -/// AI1_bin_cs_irs - A binary operation that both uses and defines CPSR. It's -/// currently not predicable. -let Defs = [CPSR], Uses = [CPSR] in { -multiclass AI1_bin_cs_irs<bits<4> opcod, string opc, PatFrag opnode> { - def ri : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), +/// AI1_adde_sube_irs - Define instructions and patterns for adde and sube. +let Uses = [CPSR] in { +multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode> { + def ri : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), + DPFrm, opc, " $dst, $a, $b", + [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>, + Requires<[IsARM, CarryDefIsUnused]>; + def rr : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), + DPFrm, opc, " $dst, $a, $b", + [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>, + Requires<[IsARM, CarryDefIsUnused]>; + def rs : AsI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), + DPSoRegFrm, opc, " $dst, $a, $b", + [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>, + Requires<[IsARM, CarryDefIsUnused]>; + // Carry setting variants + def Sri : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm, !strconcat(opc, "s $dst, $a, $b"), - [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>; - def rr : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), + [(set GPR:$dst, (opnode GPR:$a, so_imm:$b))]>, + Requires<[IsARM, CarryDefIsUsed]> { + let Defs = [CPSR]; + } + def Srr : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, !strconcat(opc, "s $dst, $a, $b"), - [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>; - def rs : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), + [(set GPR:$dst, (opnode GPR:$a, GPR:$b))]>, + Requires<[IsARM, CarryDefIsUsed]> { + let Defs = [CPSR]; + } + def Srs : AXI1<opcod, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, !strconcat(opc, "s $dst, $a, $b"), - [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>; + [(set GPR:$dst, (opnode GPR:$a, so_reg:$b))]>, + Requires<[IsARM, CarryDefIsUsed]> { + let Defs = [CPSR]; + } } } @@ -910,11 +933,10 @@ defm ADDS : AI1_bin_s_irs<0b0100, "add", defm SUBS : AI1_bin_s_irs<0b0010, "sub", BinOpFrag<(subc 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)>>; +defm ADC : AI1_adde_sube_irs<0b0101, "adc", + BinOpFrag<(adde node:$LHS, node:$RHS)>>; +defm SBC : AI1_adde_sube_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 +957,27 @@ 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. +let Uses = [CPSR] in { +def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), + DPFrm, "rsc", " $dst, $a, $b", + [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>, + Requires<[IsARM, CarryDefIsUnused]>; +def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), + DPSoRegFrm, "rsc", " $dst, $a, $b", + [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>, + Requires<[IsARM, CarryDefIsUnused]>; +} + +// FIXME: Allow these to be predicated. 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))]>; + [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>, + Requires<[IsARM, CarryDefIsUnused]>; 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))]>; + [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>, + Requires<[IsARM, CarryDefIsUnused]>; } // (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 3a44bbd..8276356 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -223,43 +223,80 @@ multiclass T2I_bin_ii12rs<string opc, PatFrag opnode> { [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } -/// T2I_bin_cs_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a +/// T2I_adde_sube_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<string opc, PatFrag opnode> { +let Uses = [CPSR] in { +multiclass T2I_adde_sube_irs<string opc, PatFrag opnode> { // shifted imm - 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))]>; + def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), + opc, " $dst, $lhs, $rhs", + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>; // register - 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))]>; + def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + opc, " $dst, $lhs, $rhs", + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>; // shifted register - 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))]>; + def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), + opc, "s $dst, $lhs, $rhs", + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>; + // Carry setting variants + // shifted imm + def Sri : 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))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> { + let Defs = [CPSR]; + } + // register + def Srr : T2XI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> { + let Defs = [CPSR]; + } + // shifted register + def Srs : 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))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> { + let Defs = [CPSR]; + } } } -/// T2I_rbin_cs_is - Same as T2I_bin_cs_irs except the order of operands are +/// T2I_rsc_is - Same as T2I_adde_sube_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. +/// T2I_adde_sube_irs counterpart. let Defs = [CPSR], Uses = [CPSR] in { -multiclass T2I_rbin_cs_is<string opc, PatFrag opnode> { +multiclass T2I_rsc_is<string opc, PatFrag opnode> { // 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), + def ri : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), + opc, " $dst, $rhs, $lhs", + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>; + // shifted register + def rs : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), + opc, " $dst, $rhs, $lhs", + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUnused]>; + // shifted imm + def Sri : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), !strconcat(opc, "s $dst, $rhs, $lhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> { + let Defs = [CPSR]; + } // shifted register - def rs : T2XI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), + def Srs : 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))]>; + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>, + Requires<[IsThumb, HasThumb2, CarryDefIsUsed]> { + let Defs = [CPSR]; + } } } @@ -385,14 +422,13 @@ defm t2SUB : T2I_bin_ii12rs<"sub", BinOpFrag<(sub 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_cs_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; -defm t2SBC : T2I_bin_cs_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; +defm t2ADC : T2I_adde_sube_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; +defm t2SBC : T2I_adde_sube_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; // RSB, RSC 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)>>; +defm t2RSC : T2I_rsc_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 index 82a5693..3bf2dc0 100644 --- a/test/CodeGen/ARM/carry.ll +++ b/test/CodeGen/ARM/carry.ll @@ -1,6 +1,6 @@ ; 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 +; RUN: llvm-as < %s | llc -march=arm | grep "adc r" +; RUN: llvm-as < %s | llc -march=arm | grep "sbc r" | count 2 define i64 @f1(i64 %a, i64 %b) { entry: diff --git a/test/CodeGen/Thumb2/carry.ll b/test/CodeGen/Thumb2/carry.ll index aa551c7..3450c5a 100644 --- a/test/CodeGen/Thumb2/carry.ll +++ b/test/CodeGen/Thumb2/carry.ll @@ -1,6 +1,6 @@ ; 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 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep "adc r" +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep "sbc r" | count 2 define i64 @f1(i64 %a, i64 %b) { entry: |