#include "X86InstrInfo.h"
#include "X86InstrBuilder.h"
#include "llvm/Function.h"
-#include "llvm/iTerminators.h"
-#include "llvm/iOperators.h"
-#include "llvm/iOther.h"
-#include "llvm/iPHINode.h"
-#include "llvm/iMemory.h"
-#include "llvm/Type.h"
+#include "llvm/Instructions.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
#include "llvm/Pass.h"
+#include "llvm/Intrinsics.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Support/InstVisitor.h"
#include "llvm/Target/MRegisterInfo.h"
-#include <map>
+#include "llvm/Support/InstVisitor.h"
/// BMI - A special BuildMI variant that takes an iterator to insert the
/// instruction at as well as a basic block. This is the version for when you
/// have a destination register in mind.
inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &I,
- MachineOpCode Opcode,
- unsigned NumOperands,
+ int Opcode, unsigned NumOperands,
unsigned DestReg) {
assert(I >= MBB->begin() && I <= MBB->end() && "Bad iterator!");
MachineInstr *MI = new MachineInstr(Opcode, NumOperands+1, true, true);
/// instruction at as well as a basic block.
inline static MachineInstrBuilder BMI(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &I,
- MachineOpCode Opcode,
- unsigned NumOperands) {
+ int Opcode, unsigned NumOperands) {
assert(I >= MBB->begin() && I <= MBB->end() && "Bad iterator!");
MachineInstr *MI = new MachineInstr(Opcode, NumOperands, true, true);
I = MBB->insert(I, MI)+1;
namespace {
struct ISel : public FunctionPass, InstVisitor<ISel> {
TargetMachine &TM;
- MachineFunction *F; // The function we are compiling into
- MachineBasicBlock *BB; // The current MBB we are compiling
+ MachineFunction *F; // The function we are compiling into
+ MachineBasicBlock *BB; // The current MBB we are compiling
+ int VarArgsFrameIndex; // FrameIndex for start of varargs area
std::map<Value*, unsigned> RegMap; // Mapping between Val's and SSA Regs
F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I));
BB = &F->front();
+
+ // Copy incoming arguments off of the stack...
LoadArgumentsToVirtualRegs(Fn);
// Instruction select everything except PHI nodes
void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
const std::vector<ValueRecord> &Args);
void visitCallInst(CallInst &I);
+ void visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &I);
// Arithmetic operators
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
void visitShiftInst(ShiftInst &I);
void visitPHINode(PHINode &I) {} // PHI nodes handled by second pass
void visitCastInst(CastInst &I);
+ void visitVarArgInst(VarArgInst &I);
void visitInstruction(Instruction &I) {
std::cerr << "Cannot instruction select: " << I;
void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator&IP,
Value *Src, const Type *DestTy, unsigned TargetReg);
+ /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary
+ /// and constant expression support.
+ void emitSimpleBinaryOperation(MachineBasicBlock *BB,
+ MachineBasicBlock::iterator &IP,
+ Value *Op0, Value *Op1,
+ unsigned OperatorClass, unsigned TargetReg);
+
/// copyConstantToRegister - Output the instructions required to put the
/// specified constant into the specified register.
///
MachineBasicBlock::iterator &IP,
Constant *C, unsigned R) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
- if (CE->getOpcode() == Instruction::GetElementPtr) {
+ unsigned Class = 0;
+ switch (CE->getOpcode()) {
+ case Instruction::GetElementPtr:
emitGEPOperation(MBB, IP, CE->getOperand(0),
CE->op_begin()+1, CE->op_end(), R);
return;
- } else if (CE->getOpcode() == Instruction::Cast) {
+ case Instruction::Cast:
emitCastOperation(MBB, IP, CE->getOperand(0), CE->getType(), R);
return;
- }
- std::cerr << "Offending expr: " << C << "\n";
- assert(0 && "Constant expressions not yet handled!\n");
+ case Instruction::Xor: ++Class; // FALL THROUGH
+ case Instruction::Or: ++Class; // FALL THROUGH
+ case Instruction::And: ++Class; // FALL THROUGH
+ case Instruction::Sub: ++Class; // FALL THROUGH
+ case Instruction::Add:
+ emitSimpleBinaryOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1),
+ Class, R);
+ return;
+
+ default:
+ std::cerr << "Offending expr: " << C << "\n";
+ assert(0 && "Constant expressions not yet handled!\n");
+ }
}
if (C->getType()->isIntegral()) {
}
ArgOffset += 4; // Each argument takes at least 4 bytes on the stack...
}
+
+ // If the function takes variable number of arguments, add a frame offset for
+ // the start of the first vararg value... this is used to expand
+ // llvm.va_start.
+ if (Fn.getFunctionType()->isVarArg())
+ VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
}
MBB->insert(MBB->begin()+NumPHIs++, LongPhiMI);
}
+ // PHIValues - Map of blocks to incoming virtual registers. We use this
+ // so that we only initialize one incoming value for a particular block,
+ // even if the block has multiple entries in the PHI node.
+ //
+ std::map<MachineBasicBlock*, unsigned> PHIValues;
+
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
MachineBasicBlock *PredMBB = MBBMap[PN->getIncomingBlock(i)];
+ unsigned ValReg;
+ std::map<MachineBasicBlock*, unsigned>::iterator EntryIt =
+ PHIValues.lower_bound(PredMBB);
+
+ if (EntryIt != PHIValues.end() && EntryIt->first == PredMBB) {
+ // We already inserted an initialization of the register for this
+ // predecessor. Recycle it.
+ ValReg = EntryIt->second;
+
+ } else {
+ // Get the incoming value into a virtual register. If it is not
+ // already available in a virtual register, insert the computation
+ // code into PredMBB
+ //
+ MachineBasicBlock::iterator PI = PredMBB->end();
+ while (PI != PredMBB->begin() &&
+ TII.isTerminatorInstr((*(PI-1))->getOpcode()))
+ --PI;
+ ValReg = getReg(PN->getIncomingValue(i), PredMBB, PI);
+
+ // Remember that we inserted a value for this PHI for this predecessor
+ PHIValues.insert(EntryIt, std::make_pair(PredMBB, ValReg));
+ }
- // Get the incoming value into a virtual register. If it is not already
- // available in a virtual register, insert the computation code into
- // PredMBB
- //
- MachineBasicBlock::iterator PI = PredMBB->end();
- while (PI != PredMBB->begin() &&
- TII.isTerminatorInstr((*(PI-1))->getOpcode()))
- --PI;
- unsigned ValReg = getReg(PN->getIncomingValue(i), PredMBB, PI);
PhiMI->addRegOperand(ValReg);
PhiMI->addMachineBasicBlockOperand(PredMBB);
if (LongPhiMI) {
case cShort:
case cInt:
promote32(X86::EAX, ValueRecord(RetReg, RetVal->getType()));
+ // Declare that EAX is live on exit
+ BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::EAX).addReg(X86::ESP);
break;
case cFP: // Floats & Doubles: Return in ST(0)
BuildMI(BB, X86::FpSETRESULT, 1).addReg(RetReg);
+ // Declare that top-of-stack is live on exit
+ BuildMI(BB, X86::IMPLICIT_USE, 2).addReg(X86::ST0).addReg(X86::ESP);
break;
case cLong:
BuildMI(BB, X86::MOVrr32, 1, X86::EAX).addReg(RetReg);
BuildMI(BB, X86::MOVrr32, 1, X86::EDX).addReg(RetReg+1);
+ // Declare that EAX & EDX are live on exit
+ BuildMI(BB, X86::IMPLICIT_USE, 3).addReg(X86::EAX).addReg(X86::EDX).addReg(X86::ESP);
break;
default:
visitInstruction(I);
void ISel::visitCallInst(CallInst &CI) {
MachineInstr *TheCall;
if (Function *F = CI.getCalledFunction()) {
+ // Is it an intrinsic function call?
+ if (LLVMIntrinsic::ID ID = (LLVMIntrinsic::ID)F->getIntrinsicID()) {
+ visitIntrinsicCall(ID, CI); // Special intrinsics are not handled here
+ return;
+ }
+
// Emit a CALL instruction with PC-relative displacement.
TheCall = BuildMI(X86::CALLpcrel32, 1).addGlobalAddress(F, true);
} else { // Emit an indirect call...
doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args);
}
+void ISel::visitIntrinsicCall(LLVMIntrinsic::ID ID, CallInst &CI) {
+ unsigned TmpReg1, TmpReg2;
+ switch (ID) {
+ case LLVMIntrinsic::va_start:
+ // Get the address of the first vararg value...
+ TmpReg1 = makeAnotherReg(Type::UIntTy);
+ addFrameReference(BuildMI(BB, X86::LEAr32, 5, TmpReg1), VarArgsFrameIndex);
+ TmpReg2 = getReg(CI.getOperand(1));
+ addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+ return;
+
+ case LLVMIntrinsic::va_end: return; // Noop on X86
+ case LLVMIntrinsic::va_copy:
+ TmpReg1 = getReg(CI.getOperand(2)); // Get existing va_list
+ TmpReg2 = getReg(CI.getOperand(1)); // Get va_list* to store into
+ addDirectMem(BuildMI(BB, X86::MOVrm32, 5), TmpReg2).addReg(TmpReg1);
+ return;
+
+ default: assert(0 && "Unknown intrinsic for X86!");
+ }
+}
+
+
+/// visitSimpleBinary - Implement simple binary operators for integral types...
+/// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, 4 for
+/// Xor.
+void ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
+ unsigned DestReg = getReg(B);
+ MachineBasicBlock::iterator MI = BB->end();
+ emitSimpleBinaryOperation(BB, MI, B.getOperand(0), B.getOperand(1),
+ OperatorClass, DestReg);
+}
/// visitSimpleBinary - Implement simple binary operators for integral types...
/// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or,
/// 4 for Xor.
///
-void ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
- unsigned Class = getClassB(B.getType());
+/// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary
+/// and constant expression support.
+void ISel::emitSimpleBinaryOperation(MachineBasicBlock *BB,
+ MachineBasicBlock::iterator &IP,
+ Value *Op0, Value *Op1,
+ unsigned OperatorClass,unsigned TargetReg){
+ unsigned Class = getClassB(Op0->getType());
static const unsigned OpcodeTab[][4] = {
// Arithmetic operators
unsigned Opcode = OpcodeTab[OperatorClass][Class];
assert(Opcode && "Floating point arguments to logical inst?");
- unsigned Op0r = getReg(B.getOperand(0));
- unsigned Op1r = getReg(B.getOperand(1));
- unsigned DestReg = getReg(B);
- BuildMI(BB, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r);
+ unsigned Op0r = getReg(Op0, BB, IP);
+ unsigned Op1r = getReg(Op1, BB, IP);
+ BMI(BB, IP, Opcode, 2, TargetReg).addReg(Op0r).addReg(Op1r);
if (isLong) { // Handle the upper 32 bits of long values...
static const unsigned TopTab[] = {
X86::ADCrr32, X86::SBBrr32, X86::ANDrr32, X86::ORrr32, X86::XORrr32
};
- BuildMI(BB, TopTab[OperatorClass], 2,
- DestReg+1).addReg(Op0r+1).addReg(Op1r+1);
+ BMI(BB, IP, TopTab[OperatorClass], 2,
+ TargetReg+1).addReg(Op0r+1).addReg(Op1r+1);
}
}
}
}
} else {
- visitInstruction(I); // FIXME: Implement long shift by non-constant
+ unsigned TmpReg = makeAnotherReg(Type::IntTy);
+
+ if (!isLeftShift && isSigned) {
+ // If this is a SHR of a Long, then we need to do funny sign extension
+ // stuff. TmpReg gets the value to use as the high-part if we are
+ // shifting more than 32 bits.
+ BuildMI(BB, X86::SARir32, 2, TmpReg).addReg(SrcReg).addZImm(31);
+ } else {
+ // Other shifts use a fixed zero value if the shift is more than 32
+ // bits.
+ BuildMI(BB, X86::MOVir32, 1, TmpReg).addZImm(0);
+ }
+
+ // Initialize CL with the shift amount...
+ unsigned ShiftAmount = getReg(I.getOperand(1));
+ BuildMI(BB, X86::MOVrr8, 1, X86::CL).addReg(ShiftAmount);
+
+ unsigned TmpReg2 = makeAnotherReg(Type::IntTy);
+ unsigned TmpReg3 = makeAnotherReg(Type::IntTy);
+ if (isLeftShift) {
+ // TmpReg2 = shld inHi, inLo
+ BuildMI(BB, X86::SHLDrr32, 2, TmpReg2).addReg(SrcReg+1).addReg(SrcReg);
+ // TmpReg3 = shl inLo, CL
+ BuildMI(BB, X86::SHLrr32, 1, TmpReg3).addReg(SrcReg);
+
+ // Set the flags to indicate whether the shift was by more than 32 bits.
+ BuildMI(BB, X86::TESTri8, 2).addReg(X86::CL).addZImm(32);
+
+ // DestHi = (>32) ? TmpReg3 : TmpReg2;
+ BuildMI(BB, X86::CMOVNErr32, 2,
+ DestReg+1).addReg(TmpReg2).addReg(TmpReg3);
+ // DestLo = (>32) ? TmpReg : TmpReg3;
+ BuildMI(BB, X86::CMOVNErr32, 2, DestReg).addReg(TmpReg3).addReg(TmpReg);
+ } else {
+ // TmpReg2 = shrd inLo, inHi
+ BuildMI(BB, X86::SHRDrr32, 2, TmpReg2).addReg(SrcReg).addReg(SrcReg+1);
+ // TmpReg3 = s[ah]r inHi, CL
+ BuildMI(BB, isSigned ? X86::SARrr32 : X86::SHRrr32, 1, TmpReg3)
+ .addReg(SrcReg+1);
+
+ // Set the flags to indicate whether the shift was by more than 32 bits.
+ BuildMI(BB, X86::TESTri8, 2).addReg(X86::CL).addZImm(32);
+
+ // DestLo = (>32) ? TmpReg3 : TmpReg2;
+ BuildMI(BB, X86::CMOVNErr32, 2,
+ DestReg).addReg(TmpReg2).addReg(TmpReg3);
+
+ // DestHi = (>32) ? TmpReg : TmpReg3;
+ BuildMI(BB, X86::CMOVNErr32, 2,
+ DestReg+1).addReg(TmpReg3).addReg(TmpReg);
+ }
}
return;
}
// Implement casts to bool by using compare on the operand followed by set if
// not zero on the result.
if (DestTy == Type::BoolTy) {
- if (SrcClass == cFP || SrcClass == cLong)
- abort(); // FIXME: implement cast (long & FP) to bool
-
- BMI(BB, IP, X86::CMPri8, 2).addReg(SrcReg).addZImm(0);
+ switch (SrcClass) {
+ case cByte:
+ BMI(BB, IP, X86::TESTrr8, 2).addReg(SrcReg).addReg(SrcReg);
+ break;
+ case cShort:
+ BMI(BB, IP, X86::TESTrr16, 2).addReg(SrcReg).addReg(SrcReg);
+ break;
+ case cInt:
+ BMI(BB, IP, X86::TESTrr32, 2).addReg(SrcReg).addReg(SrcReg);
+ break;
+ case cLong: {
+ unsigned TmpReg = makeAnotherReg(Type::IntTy);
+ BMI(BB, IP, X86::ORrr32, 2, TmpReg).addReg(SrcReg).addReg(SrcReg+1);
+ break;
+ }
+ case cFP:
+ assert(0 && "FIXME: implement cast FP to bool");
+ abort();
+ }
+
+ // If the zero flag is not set, then the value is true, set the byte to
+ // true.
BMI(BB, IP, X86::SETNEr, 1, DestReg);
return;
}
BMI(BB, IP, X86::MOVrr32, 1, DestReg).addReg(SrcReg);
BMI(BB, IP, X86::MOVrr32, 1, DestReg+1).addReg(SrcReg+1);
} else {
+ assert(0 && "Cannot handle this type of cast instruction!");
abort();
}
return;
// Handle casts from integer to floating point now...
if (DestClass == cFP) {
- // unsigned int -> load as 64 bit int.
- // unsigned long long -> more complex
- if (SrcTy->isUnsigned() && SrcTy != Type::UByteTy)
- abort(); // don't handle unsigned src yet!
-
- // We don't have the facilities for directly loading byte sized data from
- // memory. Promote it to 16 bits.
- if (SrcClass == cByte) {
- unsigned TmpReg = makeAnotherReg(Type::ShortTy);
+ // Promote the integer to a type supported by FLD. We do this because there
+ // are no unsigned FLD instructions, so we must promote an unsigned value to
+ // a larger signed value, then use FLD on the larger value.
+ //
+ const Type *PromoteType = 0;
+ unsigned PromoteOpcode;
+ switch (SrcTy->getPrimitiveID()) {
+ case Type::BoolTyID:
+ case Type::SByteTyID:
+ // We don't have the facilities for directly loading byte sized data from
+ // memory (even signed). Promote it to 16 bits.
+ PromoteType = Type::ShortTy;
+ PromoteOpcode = X86::MOVSXr16r8;
+ break;
+ case Type::UByteTyID:
+ PromoteType = Type::ShortTy;
+ PromoteOpcode = X86::MOVZXr16r8;
+ break;
+ case Type::UShortTyID:
+ PromoteType = Type::IntTy;
+ PromoteOpcode = X86::MOVZXr32r16;
+ break;
+ case Type::UIntTyID: {
+ // Make a 64 bit temporary... and zero out the top of it...
+ unsigned TmpReg = makeAnotherReg(Type::LongTy);
+ BMI(BB, IP, X86::MOVrr32, 1, TmpReg).addReg(SrcReg);
+ BMI(BB, IP, X86::MOVir32, 1, TmpReg+1).addZImm(0);
+ SrcTy = Type::LongTy;
+ SrcClass = cLong;
+ SrcReg = TmpReg;
+ break;
+ }
+ case Type::ULongTyID:
+ assert("FIXME: not implemented: cast ulong X to fp type!");
+ default: // No promotion needed...
+ break;
+ }
+
+ if (PromoteType) {
+ unsigned TmpReg = makeAnotherReg(PromoteType);
BMI(BB, IP, SrcTy->isSigned() ? X86::MOVSXr16r8 : X86::MOVZXr16r8,
1, TmpReg).addReg(SrcReg);
- SrcTy = Type::ShortTy; // Pretend the short is our input now!
- SrcClass = cShort;
+ SrcTy = PromoteType;
+ SrcClass = getClass(PromoteType);
SrcReg = TmpReg;
}
F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData());
if (SrcClass == cLong) {
- if (SrcTy == Type::ULongTy) abort(); // FIXME: Handle ulong -> FP
addFrameReference(BMI(BB, IP, X86::MOVrm32, 5), FrameIdx).addReg(SrcReg);
addFrameReference(BMI(BB, IP, X86::MOVrm32, 5),
FrameIdx, 4).addReg(SrcReg+1);
}
static const unsigned Op2[] =
- { 0, X86::FILDr16, X86::FILDr32, 0, X86::FILDr64 };
+ { 0/*byte*/, X86::FILDr16, X86::FILDr32, 0/*FP*/, X86::FILDr64 };
addFrameReference(BMI(BB, IP, Op2[SrcClass], 5, DestReg), FrameIdx);
return;
}
case cByte: StoreTy = Type::ShortTy; StoreClass = cShort; break;
case cShort: StoreTy = Type::IntTy; StoreClass = cInt; break;
case cInt: StoreTy = Type::LongTy; StoreClass = cLong; break;
- case cLong: abort(); // FIXME: unsigned long long -> more complex
+ case cLong:
+ assert(0 &&"FIXME not implemented: cast FP to unsigned long long");
+ abort();
default: assert(0 && "Unknown store class!");
}
}
// Anything we haven't handled already, we can't (yet) handle at all.
+ assert(0 && "Unhandled cast instruction!");
abort();
}
+/// visitVarArgInst - Implement the va_arg instruction...
+///
+void ISel::visitVarArgInst(VarArgInst &I) {
+ unsigned SrcReg = getReg(I.getOperand(0));
+ unsigned DestReg = getReg(I);
+
+ // Load the va_list into a register...
+ unsigned VAList = makeAnotherReg(Type::UIntTy);
+ addDirectMem(BuildMI(BB, X86::MOVmr32, 4, VAList), SrcReg);
+
+ unsigned Size;
+ switch (I.getType()->getPrimitiveID()) {
+ default:
+ std::cerr << I;
+ assert(0 && "Error: bad type for va_arg instruction!");
+ return;
+ case Type::PointerTyID:
+ case Type::UIntTyID:
+ case Type::IntTyID:
+ Size = 4;
+ addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+ break;
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ Size = 8;
+ addDirectMem(BuildMI(BB, X86::MOVmr32, 4, DestReg), VAList);
+ addRegOffset(BuildMI(BB, X86::MOVmr32, 4, DestReg+1), VAList, 4);
+ break;
+ case Type::DoubleTyID:
+ Size = 8;
+ addDirectMem(BuildMI(BB, X86::FLDr64, 4, DestReg), VAList);
+ break;
+ }
+
+ // Increment the VAList pointer...
+ unsigned NextVAList = makeAnotherReg(Type::UIntTy);
+ BuildMI(BB, X86::ADDri32, 2, NextVAList).addReg(VAList).addZImm(Size);
+
+ // Update the VAList in memory...
+ addDirectMem(BuildMI(BB, X86::MOVrm32, 5), SrcReg).addReg(NextVAList);
+}
+
+
// ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N. It
// returns zero when the input is not exactly a power of two.
static unsigned ExactLog2(unsigned Val) {
// the stack pointer.
BuildMI(BB, X86::MOVrr32, 1, getReg(I)).addReg(X86::ESP);
- // Inform the Frame Information that we have just allocated a variable sized
+ // Inform the Frame Information that we have just allocated a variable-sized
// object.
F->getFrameInfo()->CreateVariableSizedObject();
}