return NULL;
}
case ARMISD::CMOV: {
- bool isThumb = Subtarget->isThumb();
MVT VT = Op.getValueType();
SDValue N0 = Op.getOperand(0);
SDValue N1 = Op.getOperand(1);
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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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)<<P:Predicate_so_imm>><<X:so_imm_XFORM>>:$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<ConstantSDNode>(N1)->getZExtValue()),
- MVT::i32);
- Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode());
- SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
- cast<ConstantSDNode>(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)<<P:Predicate_so_imm>><<X:so_imm_XFORM>>:$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<ConstantSDNode>(N1)->getZExtValue()),
+ MVT::i32);
+ Tmp1 = Transform_t2_so_imm_XFORM(Tmp1.getNode());
+ SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
+ cast<ConstantSDNode>(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<ConstantSDNode>(N1)->getZExtValue()),
+ MVT::i32);
+ Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode());
+ SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
+ cast<ConstantSDNode>(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)
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;
// 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
--- /dev/null
+; 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
+}