diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index 97d813da213..78bda6c0d3e 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -174,7 +174,8 @@ class ARMFastISel : public FastISel { private: bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); - bool ARMEmitCmp(const Value *Src1Value, const Value *Src2Value); + bool ARMEmitCmp(const Value *Src1Value, const Value *Src2Value, + bool isZExt); bool ARMEmitLoad(EVT VT, unsigned &ResultReg, Address &Addr); bool ARMEmitStore(EVT VT, unsigned SrcReg, Address &Addr); bool ARMComputeAddress(const Value *Obj, Address &Addr); @@ -1119,7 +1120,7 @@ bool ARMFastISel::SelectBranch(const Instruction *I) { if (ARMPred == ARMCC::AL) return false; // Emit the compare. - if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1))) + if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1), CI->isUnsigned())) return false; unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; @@ -1189,19 +1190,19 @@ bool ARMFastISel::SelectBranch(const Instruction *I) { return true; } -bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value) { - MVT VT; +bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value, + bool isZExt) { Type *Ty = Src1Value->getType(); - if (!isTypeLegal(Ty, VT)) - return false; + EVT SrcVT = TLI.getValueType(Ty, true); + if (!SrcVT.isSimple()) return false; bool isFloat = (Ty->isFloatTy() || Ty->isDoubleTy()); if (isFloat && !Subtarget->hasVFP2()) return false; unsigned CmpOpc; - switch (VT.SimpleTy) { - // TODO: Add support for non-legal types (i.e., i1, i8, i16). + bool needsExt = false; + switch (SrcVT.getSimpleVT().SimpleTy) { default: return false; // TODO: Verify compares. case MVT::f32: @@ -1210,19 +1211,36 @@ bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value) { case MVT::f64: CmpOpc = ARM::VCMPED; break; + case MVT::i1: + case MVT::i8: + case MVT::i16: + needsExt = true; + // Intentional fall-through. case MVT::i32: CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; break; } - unsigned Src1 = getRegForValue(Src1Value); - if (Src1 == 0) return false; + unsigned SrcReg1 = getRegForValue(Src1Value); + if (SrcReg1 == 0) return false; - unsigned Src2 = getRegForValue(Src2Value); - if (Src2 == 0) return false; + unsigned SrcReg2 = getRegForValue(Src2Value); + if (SrcReg2 == 0) return false; + + // We have i1, i8, or i16, we need to either zero extend or sign extend. + if (needsExt) { + unsigned ResultReg; + EVT DestVT = MVT::i32; + ResultReg = ARMEmitIntExt(SrcVT, SrcReg1, DestVT, isZExt); + if (ResultReg == 0) return false; + SrcReg1 = ResultReg; + ResultReg = ARMEmitIntExt(SrcVT, SrcReg2, DestVT, isZExt); + if (ResultReg == 0) return false; + SrcReg2 = ResultReg; + } AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) - .addReg(Src1).addReg(Src2)); + .addReg(SrcReg1).addReg(SrcReg2)); // For floating point we need to move the result to a comparison register // that we can then use for branches. @@ -1243,7 +1261,7 @@ bool ARMFastISel::SelectCmp(const Instruction *I) { if (ARMPred == ARMCC::AL) return false; // Emit the compare. - if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1))) + if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1), CI->isUnsigned())) return false; // Now set a register based on the comparison. Explicitly set the predicates @@ -1962,7 +1980,6 @@ bool ARMFastISel::SelectCall(const Instruction *I) { static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; - } bool ARMFastISel::SelectTrunc(const Instruction *I) { diff --git a/test/CodeGen/ARM/fast-isel-icmp.ll b/test/CodeGen/ARM/fast-isel-icmp.ll new file mode 100644 index 00000000000..deffe7bdb68 --- /dev/null +++ b/test/CodeGen/ARM/fast-isel-icmp.ll @@ -0,0 +1,47 @@ +; RUN: llc < %s -O0 -fast-isel-abort -relocation-model=dynamic-no-pic -mtriple=armv7-apple-darwin | FileCheck %s --check-prefix=ARM +; RUN: llc < %s -O0 -fast-isel-abort -relocation-model=dynamic-no-pic -mtriple=thumbv7-apple-darwin | FileCheck %s --check-prefix=THUMB + +define i32 @icmp_i16_unsigned(i16 %a, i16 %b) nounwind { +entry: +; ARM: icmp_i16_unsigned +; ARM: uxth r0, r0 +; ARM: uxth r1, r1 +; ARM: cmp r0, r1 +; THUMB: icmp_i16_unsigned +; THUMB: uxth r0, r0 +; THUMB: uxth r1, r1 +; THUMB: cmp r0, r1 + %cmp = icmp ult i16 %a, %b + %conv2 = zext i1 %cmp to i32 + ret i32 %conv2 +} + +define i32 @icmp_i8_signed(i8 %a, i8 %b) nounwind { +entry: +; ARM: icmp_i8_signed +; ARM: sxtb r0, r0 +; ARM: sxtb r1, r1 +; ARM: cmp r0, r1 +; THUMB: icmp_i8_signed +; THUMB: sxtb r0, r0 +; THUMB: sxtb r1, r1 +; THUMB: cmp r0, r1 + %cmp = icmp sgt i8 %a, %b + %conv2 = zext i1 %cmp to i32 + ret i32 %conv2 +} + +define i32 @icmp_i1_unsigned(i1 %a, i1 %b) nounwind { +entry: +; ARM: icmp_i1_unsigned +; ARM: and r0, r0, #1 +; ARM: and r1, r1, #1 +; ARM: cmp r0, r1 +; THUMB: icmp_i1_unsigned +; THUMB: and r0, r0, #1 +; THUMB: and r1, r1, #1 +; THUMB: cmp r0, r1 + %cmp = icmp ult i1 %a, %b + %conv2 = zext i1 %cmp to i32 + ret i32 %conv2 +}