From e253c951b38e47f14a097db6ac7731c857837ae2 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Tue, 7 Jul 2009 20:39:03 +0000 Subject: [PATCH] Add Thumb2 movcc instructions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74946 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMISelDAGToDAG.cpp | 98 ++++++++++++++-------- lib/Target/ARM/ARMInstrThumb2.td | 19 ++++- test/CodeGen/Thumb2/thumb2-select.ll | 48 +++++++++++ test/CodeGen/Thumb2/thumb2-select_xform.ll | 23 +++++ 4 files changed, 153 insertions(+), 35 deletions(-) create mode 100644 test/CodeGen/Thumb2/thumb2-select.ll create mode 100644 test/CodeGen/Thumb2/thumb2-select_xform.ll diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 5d8925f1bd4..6d7e41cc35f 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -1031,7 +1031,6 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { return NULL; } case ARMISD::CMOV: { - bool isThumb = Subtarget->isThumb(); MVT VT = Op.getValueType(); SDValue N0 = Op.getOperand(0); SDValue N1 = Op.getOperand(1); @@ -1041,39 +1040,68 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { assert(N2.getOpcode() == ISD::Constant); assert(N3.getOpcode() == ISD::Register); - // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) - // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) - // Pattern complexity = 18 cost = 1 size = 0 - SDValue CPTmp0; - SDValue CPTmp1; - SDValue CPTmp2; - if (!isThumb && VT == MVT::i32 && - SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) { - SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) - cast(N2)->getZExtValue()), - MVT::i32); - SDValue Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag }; - return CurDAG->SelectNodeTo(Op.getNode(), ARM::MOVCCs, MVT::i32, Ops, 7); - } + if (!Subtarget->isThumb1Only() && VT == MVT::i32) { + // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) + // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) + // Pattern complexity = 18 cost = 1 size = 0 + SDValue CPTmp0; + SDValue CPTmp1; + SDValue CPTmp2; + if (Subtarget->isThumb()) { + if (SelectT2ShifterOperandReg(Op, N1, CPTmp0, CPTmp1)) { + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, CPTmp0, CPTmp1, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), + ARM::t2MOVCCs, MVT::i32,Ops, 6); + } + } else { + if (SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) { + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), + ARM::MOVCCs, MVT::i32, Ops, 7); + } + } - // Pattern: (ARMcmov:i32 GPR:i32:$false, - // (imm:i32)<><>:$true, - // (imm:i32):$cc) - // Emits: (MOVCCi:i32 GPR:i32:$false, - // (so_imm_XFORM:i32 (imm:i32):$true), (imm:i32):$cc) - // Pattern complexity = 10 cost = 1 size = 0 - if (VT == MVT::i32 && - N3.getOpcode() == ISD::Constant && - Predicate_so_imm(N3.getNode())) { - SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned) - cast(N1)->getZExtValue()), - MVT::i32); - Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode()); - SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) - cast(N2)->getZExtValue()), - MVT::i32); - SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag }; - return CurDAG->SelectNodeTo(Op.getNode(), ARM::MOVCCi, MVT::i32, Ops, 5); + // Pattern: (ARMcmov:i32 GPR:i32:$false, + // (imm:i32)<><>:$true, + // (imm:i32):$cc) + // Emits: (MOVCCi:i32 GPR:i32:$false, + // (so_imm_XFORM:i32 (imm:i32):$true), (imm:i32):$cc) + // Pattern complexity = 10 cost = 1 size = 0 + if (N3.getOpcode() == ISD::Constant) { + if (Subtarget->isThumb()) { + if (Predicate_t2_so_imm(N3.getNode())) { + SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned) + cast(N1)->getZExtValue()), + MVT::i32); + Tmp1 = Transform_t2_so_imm_XFORM(Tmp1.getNode()); + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), + ARM::t2MOVCCi, MVT::i32, Ops, 5); + } + } else { + if (Predicate_so_imm(N3.getNode())) { + SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned) + cast(N1)->getZExtValue()), + MVT::i32); + Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode()); + SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) + cast(N2)->getZExtValue()), + MVT::i32); + SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag }; + return CurDAG->SelectNodeTo(Op.getNode(), + ARM::MOVCCi, MVT::i32, Ops, 5); + } + } + } } // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) @@ -1094,7 +1122,9 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { default: assert(false && "Illegal conditional move type!"); break; case MVT::i32: - Opc = isThumb ? ARM::tMOVCCr : ARM::MOVCCr; + Opc = Subtarget->isThumb() + ? (Subtarget->hasThumb2() ? ARM::t2MOVCCr : ARM::tMOVCCr) + : ARM::MOVCCr; break; case MVT::f32: Opc = ARM::FCPYScc; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index e961462983c..47aca18042b 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -1028,7 +1028,24 @@ defm t2TEQ : T2I_cmp_is<"teq", // Short range conditional branch. Looks awesome for loops. Need to figure // out how to use this one. -// FIXME: Conditional moves + +// Conditional moves +// FIXME: should be able to write a pattern for ARMcmov, but can't use +// a two-value operand where a dag node expects two operands. :( +def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true), + "mov", " $dst, $true", + [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $dst">; + +def t2MOVCCs : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_reg:$true), + "mov", " $dst, $true", +[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_reg:$true, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $dst">; + +def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true), + "mov", " $dst, $true", +[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $dst">; //===----------------------------------------------------------------------===// // Control-Flow Instructions diff --git a/test/CodeGen/Thumb2/thumb2-select.ll b/test/CodeGen/Thumb2/thumb2-select.ll new file mode 100644 index 00000000000..57f61569c19 --- /dev/null +++ b/test/CodeGen/Thumb2/thumb2-select.ll @@ -0,0 +1,48 @@ +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep moveq | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movgt | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movlt | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movle | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movls | count 1 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movhi | count 1 + +define i32 @f1(i32 %a.s) { +entry: + %tmp = icmp eq i32 %a.s, 4 + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} + +define i32 @f2(i32 %a.s) { +entry: + %tmp = icmp sgt i32 %a.s, 4 + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} + +define i32 @f3(i32 %a.s, i32 %b.s) { +entry: + %tmp = icmp slt i32 %a.s, %b.s + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} + +define i32 @f4(i32 %a.s, i32 %b.s) { +entry: + %tmp = icmp sle i32 %a.s, %b.s + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} + +define i32 @f5(i32 %a.u, i32 %b.u) { +entry: + %tmp = icmp ule i32 %a.u, %b.u + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} + +define i32 @f6(i32 %a.u, i32 %b.u) { +entry: + %tmp = icmp ugt i32 %a.u, %b.u + %tmp1.s = select i1 %tmp, i32 2, i32 3 + ret i32 %tmp1.s +} diff --git a/test/CodeGen/Thumb2/thumb2-select_xform.ll b/test/CodeGen/Thumb2/thumb2-select_xform.ll new file mode 100644 index 00000000000..9da4ebe17d2 --- /dev/null +++ b/test/CodeGen/Thumb2/thumb2-select_xform.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | count 3 +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mvn | count 1 + +define i32 @t1(i32 %a, i32 %b, i32 %c) nounwind { + %tmp1 = icmp sgt i32 %c, 10 + %tmp2 = select i1 %tmp1, i32 0, i32 2147483647 + %tmp3 = add i32 %tmp2, %b + ret i32 %tmp3 +} + +define i32 @t2(i32 %a, i32 %b, i32 %c) nounwind { + %tmp1 = icmp sgt i32 %c, 10 + %tmp2 = select i1 %tmp1, i32 0, i32 2147483648 + %tmp3 = add i32 %tmp2, %b + ret i32 %tmp3 +} + +define i32 @t3(i32 %a, i32 %b, i32 %c, i32 %d) nounwind { + %tmp1 = icmp sgt i32 %c, 10 + %tmp2 = select i1 %tmp1, i32 0, i32 10 + %tmp3 = sub i32 %b, %tmp2 + ret i32 %tmp3 +} -- 2.34.1