diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index df75c4a88f7..0f60cbfb9bb 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -339,34 +339,34 @@ bool FastISel::SelectBinaryOp(const User *I, unsigned ISDOpcode) { bool Op1IsKill = hasTrivialKill(I->getOperand(1)); - unsigned ResultReg = FastEmit_ri(VT.getSimpleVT(), VT.getSimpleVT(), - ISDOpcode, Op1, Op1IsKill, - CI->getZExtValue()); - if (ResultReg != 0) { - // We successfully emitted code for the given LLVM Instruction. - UpdateValueMap(I, ResultReg); - return true; - } + unsigned ResultReg = FastEmit_ri_(VT.getSimpleVT(), ISDOpcode, Op1, + Op1IsKill, CI->getZExtValue(), + VT.getSimpleVT()); + if (ResultReg == 0) return false; + + // We successfully emitted code for the given LLVM Instruction. + UpdateValueMap(I, ResultReg); + return true; } unsigned Op0 = getRegForValue(I->getOperand(0)); - if (Op0 == 0) - // Unhandled operand. Halt "fast" selection and bail. + if (Op0 == 0) // Unhandled operand. Halt "fast" selection and bail. return false; bool Op0IsKill = hasTrivialKill(I->getOperand(0)); // Check if the second operand is a constant and handle it appropriately. if (ConstantInt *CI = dyn_cast(I->getOperand(1))) { - unsigned ResultReg = FastEmit_ri(VT.getSimpleVT(), VT.getSimpleVT(), - ISDOpcode, Op0, Op0IsKill, - CI->getZExtValue()); - if (ResultReg != 0) { - // We successfully emitted code for the given LLVM Instruction. - UpdateValueMap(I, ResultReg); - return true; - } + uint64_t Imm = CI->getZExtValue(); + + unsigned ResultReg = FastEmit_ri_(VT.getSimpleVT(), ISDOpcode, Op0, + Op0IsKill, Imm, VT.getSimpleVT()); + if (ResultReg == 0) return false; + + // We successfully emitted code for the given LLVM Instruction. + UpdateValueMap(I, ResultReg); + return true; } // Check if the second operand is a constant float. @@ -986,6 +986,18 @@ unsigned FastISel::FastEmit_rri(MVT, MVT, unsigned FastISel::FastEmit_ri_(MVT VT, unsigned Opcode, unsigned Op0, bool Op0IsKill, uint64_t Imm, MVT ImmType) { + // If this is a multiply by a power of two, emit this as a shift left. + if (Opcode == ISD::MUL && isPowerOf2_64(Imm)) { + Opcode = ISD::SHL; + Imm = Log2_64(Imm); + } + + // Horrible hack (to be removed), check to make sure shift amounts are + // in-range. + if ((Opcode == ISD::SHL || Opcode == ISD::SRA || Opcode == ISD::SRL) && + Imm >= VT.getSizeInBits()) + return 0; + // First check if immediate type is legal. If not, we can't use the ri form. unsigned ResultReg = FastEmit_ri(VT, VT, Opcode, Op0, Op0IsKill, Imm); if (ResultReg != 0) diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 8aa2a72e4e5..7be7f18e985 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -1084,42 +1084,42 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) { } bool X86FastISel::X86SelectShift(const Instruction *I) { - unsigned CReg = 0, OpReg = 0, OpImm = 0; + unsigned CReg = 0, OpReg = 0; const TargetRegisterClass *RC = NULL; if (I->getType()->isIntegerTy(8)) { CReg = X86::CL; RC = &X86::GR8RegClass; switch (I->getOpcode()) { - case Instruction::LShr: OpReg = X86::SHR8rCL; OpImm = X86::SHR8ri; break; - case Instruction::AShr: OpReg = X86::SAR8rCL; OpImm = X86::SAR8ri; break; - case Instruction::Shl: OpReg = X86::SHL8rCL; OpImm = X86::SHL8ri; break; + case Instruction::LShr: OpReg = X86::SHR8rCL; break; + case Instruction::AShr: OpReg = X86::SAR8rCL; break; + case Instruction::Shl: OpReg = X86::SHL8rCL; break; default: return false; } } else if (I->getType()->isIntegerTy(16)) { CReg = X86::CX; RC = &X86::GR16RegClass; switch (I->getOpcode()) { - case Instruction::LShr: OpReg = X86::SHR16rCL; OpImm = X86::SHR16ri; break; - case Instruction::AShr: OpReg = X86::SAR16rCL; OpImm = X86::SAR16ri; break; - case Instruction::Shl: OpReg = X86::SHL16rCL; OpImm = X86::SHL16ri; break; + case Instruction::LShr: OpReg = X86::SHR16rCL; break; + case Instruction::AShr: OpReg = X86::SAR16rCL; break; + case Instruction::Shl: OpReg = X86::SHL16rCL; break; default: return false; } } else if (I->getType()->isIntegerTy(32)) { CReg = X86::ECX; RC = &X86::GR32RegClass; switch (I->getOpcode()) { - case Instruction::LShr: OpReg = X86::SHR32rCL; OpImm = X86::SHR32ri; break; - case Instruction::AShr: OpReg = X86::SAR32rCL; OpImm = X86::SAR32ri; break; - case Instruction::Shl: OpReg = X86::SHL32rCL; OpImm = X86::SHL32ri; break; + case Instruction::LShr: OpReg = X86::SHR32rCL; break; + case Instruction::AShr: OpReg = X86::SAR32rCL; break; + case Instruction::Shl: OpReg = X86::SHL32rCL; break; default: return false; } } else if (I->getType()->isIntegerTy(64)) { CReg = X86::RCX; RC = &X86::GR64RegClass; switch (I->getOpcode()) { - case Instruction::LShr: OpReg = X86::SHR64rCL; OpImm = X86::SHR64ri; break; - case Instruction::AShr: OpReg = X86::SAR64rCL; OpImm = X86::SAR64ri; break; - case Instruction::Shl: OpReg = X86::SHL64rCL; OpImm = X86::SHL64ri; break; + case Instruction::LShr: OpReg = X86::SHR64rCL; break; + case Instruction::AShr: OpReg = X86::SAR64rCL; break; + case Instruction::Shl: OpReg = X86::SHL64rCL; break; default: return false; } } else { @@ -1133,15 +1133,6 @@ bool X86FastISel::X86SelectShift(const Instruction *I) { unsigned Op0Reg = getRegForValue(I->getOperand(0)); if (Op0Reg == 0) return false; - // Fold immediate in shl(x,3). - if (const ConstantInt *CI = dyn_cast(I->getOperand(1))) { - unsigned ResultReg = createResultReg(RC); - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(OpImm), - ResultReg).addReg(Op0Reg).addImm(CI->getZExtValue() & 0xff); - UpdateValueMap(I, ResultReg); - return true; - } - unsigned Op1Reg = getRegForValue(I->getOperand(1)); if (Op1Reg == 0) return false; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), diff --git a/test/CodeGen/X86/fast-isel-shift-imm.ll b/test/CodeGen/X86/fast-isel-shift-imm.ll deleted file mode 100644 index 5c62c188051..00000000000 --- a/test/CodeGen/X86/fast-isel-shift-imm.ll +++ /dev/null @@ -1,8 +0,0 @@ -; RUN: llc < %s -march=x86 -O0 | grep {sarl \$80, %e} -; PR3242 - -define void @foo(i32 %x, i32* %p) nounwind { - %y = ashr i32 %x, 50000 - store i32 %y, i32* %p - ret void -} diff --git a/test/CodeGen/X86/fast-isel-x86-64.ll b/test/CodeGen/X86/fast-isel-x86-64.ll index e98c4730af7..e74fd30b644 100644 --- a/test/CodeGen/X86/fast-isel-x86-64.ll +++ b/test/CodeGen/X86/fast-isel-x86-64.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -fast-isel -O0 -regalloc=fast | FileCheck %s +; RUN: llc < %s -fast-isel -O0 -regalloc=fast -asm-verbose=0 | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin10.0.0" @@ -61,3 +61,35 @@ define i32 @test4(i64 %idxprom9) nounwind { ; CHECK-NEXT: movzbl (%rax,%rdi), %eax ; CHECK-NEXT: ret } + + +; PR3242 - Out of range shifts should not be folded by fastisel. +define void @test5(i32 %x, i32* %p) nounwind { + %y = ashr i32 %x, 50000 + store i32 %y, i32* %p + ret void + +; CHECK: test5: +; CHECK: movl $50000, %ecx +; CHECK: sarl %cl, %edi +; CHECK: ret +} + +; rdar://9289501 - fast isel should fold trivial multiplies to shifts. +define i64 @test6(i64 %x) nounwind ssp { +entry: + %mul = mul nsw i64 %x, 8 + ret i64 %mul + +; CHECK: test6: +; CHECK: leaq (,%rdi,8), %rax +} + +define i32 @test7(i32 %x) nounwind ssp { +entry: + %mul = mul nsw i32 %x, 8 + ret i32 %mul +; CHECK: test7: +; CHECK: leal (,%rdi,8), %eax +} + diff --git a/test/CodeGen/X86/lock-inst-encoding.ll b/test/CodeGen/X86/lock-inst-encoding.ll index 03468e2b3f4..159aeeeca1a 100644 --- a/test/CodeGen/X86/lock-inst-encoding.ll +++ b/test/CodeGen/X86/lock-inst-encoding.ll @@ -4,10 +4,10 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 target triple = "x86_64-apple-darwin10.0.0" ; CHECK: f0: -; CHECK: addq %rax, (%rdi) -; CHECK: # encoding: [0xf0,0x48,0x01,0x07] +; CHECK: addq %rcx, (%rdi) +; CHECK: # encoding: [0xf0,0x48,0x01,0x0f] ; CHECK: ret -define void @f0(i64* %a0) { +define void @f0(i64* %a0) nounwind { %t0 = and i64 1, 1 call void @llvm.memory.barrier(i1 true, i1 true, i1 true, i1 true, i1 true) nounwind %1 = call i64 @llvm.atomic.load.add.i64.p0i64(i64* %a0, i64 %t0) nounwind diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index f01de1dcfce..b6631c848e0 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -52,8 +52,7 @@ struct OperandsSignature { /// of the Operands array accordingly. Return true if all the operands /// are supported, false otherwise. /// - bool initialize(TreePatternNode *InstPatNode, - const CodeGenTarget &Target, + bool initialize(TreePatternNode *InstPatNode, const CodeGenTarget &Target, MVT::SimpleValueType VT) { if (!InstPatNode->isLeaf()) { @@ -74,13 +73,7 @@ struct OperandsSignature { // For now, filter out any operand with a predicate. // For now, filter out any operand with multiple values. - if (!Op->getPredicateFns().empty() || - Op->getNumTypes() != 1) - return false; - - assert(Op->hasTypeSet(0) && "Type infererence not done?"); - // For now, all the operands must have the same type. - if (Op->getType(0) != VT) + if (!Op->getPredicateFns().empty() || Op->getNumTypes() != 1) return false; if (!Op->isLeaf()) { @@ -95,6 +88,15 @@ struct OperandsSignature { // For now, ignore other non-leaf nodes. return false; } + + assert(Op->hasTypeSet(0) && "Type infererence not done?"); + + // For now, all the operands must have the same type (if they aren't + // immediates). Note that this causes us to reject variable sized shifts + // on X86. + if (Op->getType(0) != VT) + return false; + DefInit *OpDI = dynamic_cast(Op->getLeafValue()); if (!OpDI) return false; @@ -321,6 +323,11 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { assert(InstPatNode->getChild(0)->getNumTypes() == 1); VT = InstPatNode->getChild(0)->getType(0); } + + if (InstPatOp->getName() =="shl") { + InstPatNode->dump(); + } + // For now, filter out instructions which just set a register to // an Operand or an immediate, like MOV32ri.