Add initial support for fast-isel of the [SU]ADDO intrinsics. It isn't

complete. For instance, it lowers the common case into this less-than-optimal
code:

        addl    %ecx, %eax
        seto    %cl
        testb   %cl, %cl
        jne     LBB1_2  ## overflow

instead of:

        addl    %ecx, %eax
        jo      LBB1_2  ## overflow

That will come in a future commit.

llvm-svn: 60737
This commit is contained in:
Bill Wendling 2008-12-09 02:42:50 +00:00
parent 16516ba7b3
commit 80b34b3f47
1 changed files with 84 additions and 7 deletions

View File

@ -22,6 +22,7 @@
#include "llvm/CallingConv.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
@ -106,6 +107,9 @@ private:
bool X86SelectFPExt(Instruction *I);
bool X86SelectFPTrunc(Instruction *I);
bool X86SelectExtractValue(Instruction *I);
bool X86VisitIntrinsicCall(CallInst &I, unsigned Intrinsic);
bool X86SelectCall(Instruction *I);
CCAssignFn *CCAssignFnForCall(unsigned CC, bool isTailCall = false);
@ -292,8 +296,6 @@ bool X86FastISel::X86FastEmitStore(MVT VT, Value *Val,
return X86FastEmitStore(VT, ValReg, AM);
}
/// X86FastEmitExtend - Emit a machine instruction to extend a value Src of
/// type SrcVT to type DstVT using the specified extension opcode Opc (e.g.
/// ISD::SIGN_EXTEND).
@ -938,6 +940,79 @@ bool X86FastISel::X86SelectTrunc(Instruction *I) {
return true;
}
bool X86FastISel::X86SelectExtractValue(Instruction *I) {
ExtractValueInst *EI = cast<ExtractValueInst>(I);
Value *Agg = EI->getAggregateOperand();
if (CallInst *CI = dyn_cast<CallInst>(Agg)) {
Function *F = CI->getCalledFunction();
if (F && F->isDeclaration()) {
switch (F->getIntrinsicID()) {
default: break;
case Intrinsic::sadd_with_overflow:
case Intrinsic::uadd_with_overflow:
// Cheat a little. We know that the register for the "add" and "seto"
// are allocated sequentially. However, we only keep track of the
// register for "add" in the value map. Use the extractvalue's index to
// get the correct register for "seto".
UpdateValueMap(I, lookUpRegForValue(Agg) + *EI->idx_begin());
return true;
}
}
}
return false;
}
bool X86FastISel::X86VisitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
// FIXME: Handle more intrinsics.
switch (Intrinsic) {
default: return false;
case Intrinsic::sadd_with_overflow:
case Intrinsic::uadd_with_overflow: {
// Replace these intrinsics with an "add" instruction followed by a
// "set[co]" instruction. Later on, when the "extractvalue" instructions are
// encountered, we use the fact that two registers were created sequentially
// to get the correct registers for the "sum" and the "overflow bit".
MVT VT;
const Function *Callee = I.getCalledFunction();
const Type *RetTy =
cast<StructType>(Callee->getReturnType())->getTypeAtIndex(unsigned(0));
if (!isTypeLegal(RetTy, VT))
return false;
Value *Op1 = I.getOperand(1);
Value *Op2 = I.getOperand(2);
unsigned Reg1 = getRegForValue(Op1);
unsigned Reg2 = getRegForValue(Op2);
if (Reg1 == 0 || Reg2 == 0)
// FIXME: Handle values *not* in registers.
return false;
unsigned OpC = 0;
if (VT == MVT::i32)
OpC = X86::ADD32rr;
else if (VT == MVT::i64)
OpC = X86::ADD64rr;
else
return false;
unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT));
BuildMI(MBB, TII.get(OpC), ResultReg).addReg(Reg1).addReg(Reg2);
UpdateValueMap(&I, ResultReg);
ResultReg = createResultReg(TLI.getRegClassFor(MVT::i8));
BuildMI(MBB, TII.get((Intrinsic == Intrinsic::sadd_with_overflow) ?
X86::SETOr : X86::SETCr), ResultReg);
return true;
}
}
}
bool X86FastISel::X86SelectCall(Instruction *I) {
CallInst *CI = cast<CallInst>(I);
Value *Callee = I->getOperand(0);
@ -946,11 +1021,11 @@ bool X86FastISel::X86SelectCall(Instruction *I) {
if (isa<InlineAsm>(Callee))
return false;
// FIXME: Handle some intrinsics.
if (Function *F = CI->getCalledFunction()) {
if (F->isDeclaration() &&F->getIntrinsicID())
return false;
}
// Handle intrinsic calls.
if (Function *F = CI->getCalledFunction())
if (F->isDeclaration())
if (unsigned IID = F->getIntrinsicID())
return X86VisitIntrinsicCall(*CI, IID);
// Handle only C and fastcc calling conventions for now.
CallSite CS(CI);
@ -1234,6 +1309,8 @@ X86FastISel::TargetSelectInstruction(Instruction *I) {
return X86SelectFPExt(I);
case Instruction::FPTrunc:
return X86SelectFPTrunc(I);
case Instruction::ExtractValue:
return X86SelectExtractValue(I);
}
return false;