// $Id$ //*************************************************************************** // File: // SparcInstrInfo.cpp // // Purpose: // // History: // 10/15/01 - Vikram Adve - Created //**************************************************************************/ #include "SparcInternals.h" #include "SparcInstrSelectionSupport.h" #include "llvm/Target/Sparc.h" #include "llvm/CodeGen/InstrSelection.h" #include "llvm/CodeGen/InstrSelectionSupport.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineCodeForMethod.h" #include "llvm/Function.h" #include "llvm/ConstantVals.h" #include "llvm/DerivedTypes.h" //************************ Internal Functions ******************************/ static inline MachineInstr* CreateIntSetInstruction(int64_t C, Value* dest, std::vector& tempVec) { MachineInstr* minstr; uint64_t absC = (C >= 0)? C : -C; if (absC > (unsigned int) ~0) { // C does not fit in 32 bits TmpInstruction* tmpReg = new TmpInstruction(Type::IntTy); tempVec.push_back(tmpReg); minstr = new MachineInstr(SETX); minstr->SetMachineOperandConst(0, MachineOperand::MO_SignExtendedImmed, C); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister, tmpReg, /*isdef*/ true); minstr->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister,dest); } else { minstr = new MachineInstr(SETSW); minstr->SetMachineOperandConst(0,MachineOperand::MO_SignExtendedImmed,C); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister,dest); } return minstr; } static inline MachineInstr* CreateUIntSetInstruction(uint64_t C, Value* dest, std::vector& tempVec) { MachineInstr* minstr; if (C > (unsigned int) ~0) { // C does not fit in 32 bits assert(dest->getType() == Type::ULongTy && "Sign extension problems"); TmpInstruction *tmpReg = new TmpInstruction(Type::IntTy); tempVec.push_back(tmpReg); minstr = new MachineInstr(SETX); minstr->SetMachineOperandConst(0,MachineOperand::MO_SignExtendedImmed,C); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister, tmpReg, /*isdef*/ true); minstr->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister,dest); } else if (dest->getType() == Type::ULongTy) { minstr = new MachineInstr(SETUW); minstr->SetMachineOperandConst(0, MachineOperand::MO_UnextendedImmed, C); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister,dest); } else { // cast to signed type of the right length and use signed op (SETSW) // to get correct sign extension // minstr = new MachineInstr(SETSW); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister,dest); switch (dest->getType()->getPrimitiveID()) { case Type::UIntTyID: minstr->SetMachineOperandConst(0, MachineOperand::MO_SignExtendedImmed, (int) C); break; case Type::UShortTyID: minstr->SetMachineOperandConst(0, MachineOperand::MO_SignExtendedImmed, (short) C); break; case Type::UByteTyID: minstr->SetMachineOperandConst(0, MachineOperand::MO_SignExtendedImmed, (char) C); break; default: assert(0 && "Unexpected unsigned type"); break; } } return minstr; } //************************* External Classes *******************************/ //--------------------------------------------------------------------------- // class UltraSparcInstrInfo // // Purpose: // Information about individual instructions. // Most information is stored in the SparcMachineInstrDesc array above. // Other information is computed on demand, and most such functions // default to member functions in base class MachineInstrInfo. //--------------------------------------------------------------------------- /*ctor*/ UltraSparcInstrInfo::UltraSparcInstrInfo(const TargetMachine& tgt) : MachineInstrInfo(tgt, SparcMachineInstrDesc, /*descSize = */ NUM_TOTAL_OPCODES, /*numRealOpCodes = */ NUM_REAL_OPCODES) { } // // Create an instruction sequence to put the constant `val' into // the virtual register `dest'. `val' may be a Constant or a // GlobalValue, viz., the constant address of a global variable or function. // The generated instructions are returned in `minstrVec'. // Any temp. registers (TmpInstruction) created are returned in `tempVec'. // void UltraSparcInstrInfo::CreateCodeToLoadConst(Function *F, Value* val, Instruction* dest, std::vector&minstrVec, std::vector& tempVec) const { MachineInstr* minstr; assert(isa(val) || isa(val) && "I only know about constant values and global addresses"); // Use a "set" instruction for known constants that can go in an integer reg. // Use a "load" instruction for all other constants, in particular, // floating point constants and addresses of globals. // const Type* valType = val->getType(); if (valType->isIntegral() || valType == Type::BoolTy) { if (ConstantUInt* uval = dyn_cast(val)) { uint64_t C = uval->getValue(); minstr = CreateUIntSetInstruction(C, dest, tempVec); } else { bool isValidConstant; int64_t C = GetConstantValueAsSignedInt(val, isValidConstant); assert(isValidConstant && "Unrecognized constant"); minstr = CreateIntSetInstruction(C, dest, tempVec); } minstrVec.push_back(minstr); } else { // Make an instruction sequence to load the constant, viz: // SETX , tmpReg, addrReg // LOAD /*addr*/ addrReg, /*offset*/ 0, dest // Only the SETX is needed if `val' is a GlobalValue, i.e,. it is // itself a constant address. Otherwise, both are needed. Value* addrVal; int64_t zeroOffset = 0; // to avoid ambiguity with (Value*) 0 TmpInstruction* tmpReg = new TmpInstruction(PointerType::get(val->getType()), val); tempVec.push_back(tmpReg); if (isa(val)) { // Create another TmpInstruction for the hidden integer register TmpInstruction* addrReg = new TmpInstruction(PointerType::get(val->getType()), val); tempVec.push_back(addrReg); addrVal = addrReg; } else addrVal = dest; minstr = new MachineInstr(SETX); minstr->SetMachineOperandVal(0, MachineOperand::MO_PCRelativeDisp, val); minstr->SetMachineOperandVal(1, MachineOperand::MO_VirtualRegister,tmpReg, /*isdef*/ true); minstr->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister, addrVal); minstrVec.push_back(minstr); if (isa(val)) { // Make sure constant is emitted to constant pool in assembly code. MachineCodeForMethod& mcinfo = MachineCodeForMethod::get(F); mcinfo.addToConstantPool(cast(val)); // Generate the load instruction minstr = new MachineInstr(ChooseLoadInstruction(val->getType())); minstr->SetMachineOperandVal(0, MachineOperand::MO_VirtualRegister, addrVal); minstr->SetMachineOperandConst(1,MachineOperand::MO_SignExtendedImmed, zeroOffset); minstr->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister, dest); minstrVec.push_back(minstr); } } } // Create an instruction sequence to copy an integer value `val' // to a floating point value `dest' by copying to memory and back. // val must be an integral type. dest must be a Float or Double. // The generated instructions are returned in `minstrVec'. // Any temp. registers (TmpInstruction) created are returned in `tempVec'. // void UltraSparcInstrInfo::CreateCodeToCopyIntToFloat(Function *F, Value* val, Instruction* dest, std::vector& minstrVec, std::vector& tempVec, TargetMachine& target) const { assert((val->getType()->isIntegral() || val->getType()->isPointerType()) && "Source type must be integral"); assert((dest->getType() == Type::FloatTy || dest->getType() == Type::DoubleTy) && "Dest type must be float/double"); MachineCodeForMethod& mcinfo = MachineCodeForMethod::get(F); int offset = mcinfo.allocateLocalVar(target, val); // Store instruction stores `val' to [%fp+offset]. // The store and load opCodes are based on the value being copied, and // they use integer and float types that accomodate the // larger of the source type and the destination type: // On SparcV9: int for float, long for double. // Type* tmpType = (dest->getType() == Type::FloatTy)? Type::IntTy : Type::LongTy; MachineInstr* store = new MachineInstr(ChooseStoreInstruction(tmpType)); store->SetMachineOperandVal(0, MachineOperand::MO_VirtualRegister, val); store->SetMachineOperandReg(1, target.getRegInfo().getFramePointer()); store->SetMachineOperandConst(2,MachineOperand::MO_SignExtendedImmed, offset); minstrVec.push_back(store); // Load instruction loads [%fp+offset] to `dest'. // MachineInstr* load =new MachineInstr(ChooseLoadInstruction(dest->getType())); load->SetMachineOperandReg(0, target.getRegInfo().getFramePointer()); load->SetMachineOperandConst(1, MachineOperand::MO_SignExtendedImmed,offset); load->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister, dest); minstrVec.push_back(load); } // Similarly, create an instruction sequence to copy an FP value // `val' to an integer value `dest' by copying to memory and back. // See the previous function for information about return values. // void UltraSparcInstrInfo::CreateCodeToCopyFloatToInt(Function *F, Value* val, Instruction* dest, std::vector& minstrVec, std::vector& tempVec, TargetMachine& target) const { assert((val->getType() ==Type::FloatTy || val->getType() ==Type::DoubleTy) && "Source type must be float/double"); assert((dest->getType()->isIntegral() || dest->getType()->isPointerType()) && "Dest type must be integral"); MachineCodeForMethod& mcinfo = MachineCodeForMethod::get(F); int offset = mcinfo.allocateLocalVar(target, val); // Store instruction stores `val' to [%fp+offset]. // The store and load opCodes are based on the value being copied, and // they use the integer type that matches the source type in size: // On SparcV9: int for float, long for double. // Type* tmpType = (val->getType() == Type::FloatTy)? Type::IntTy : Type::LongTy; MachineInstr* store=new MachineInstr(ChooseStoreInstruction(val->getType())); store->SetMachineOperandVal(0, MachineOperand::MO_VirtualRegister, val); store->SetMachineOperandReg(1, target.getRegInfo().getFramePointer()); store->SetMachineOperandConst(2,MachineOperand::MO_SignExtendedImmed,offset); minstrVec.push_back(store); // Load instruction loads [%fp+offset] to `dest'. // MachineInstr* load = new MachineInstr(ChooseLoadInstruction(tmpType)); load->SetMachineOperandReg(0, target.getRegInfo().getFramePointer()); load->SetMachineOperandConst(1, MachineOperand::MO_SignExtendedImmed, offset); load->SetMachineOperandVal(2, MachineOperand::MO_VirtualRegister, dest); minstrVec.push_back(load); }