diff options
author | Brian Gaeke <gaeke@uiuc.edu> | 2004-02-25 18:44:15 +0000 |
---|---|---|
committer | Brian Gaeke <gaeke@uiuc.edu> | 2004-02-25 18:44:15 +0000 |
commit | 94e95d2b3eaaf3404b9306c7f402a26beb18c9c4 (patch) | |
tree | 01a3a8922d75ff482e96b9905550c37715f16674 /llvm/lib/Target/Sparc | |
parent | 864c9014443c716da8851661d8e26c11b16bcca4 (diff) | |
download | bcm5719-llvm-94e95d2b3eaaf3404b9306c7f402a26beb18c9c4.tar.gz bcm5719-llvm-94e95d2b3eaaf3404b9306c7f402a26beb18c9c4.zip |
Great renaming: Sparc --> SparcV9
llvm-svn: 11826
Diffstat (limited to 'llvm/lib/Target/Sparc')
58 files changed, 0 insertions, 17669 deletions
diff --git a/llvm/lib/Target/Sparc/.cvsignore b/llvm/lib/Target/Sparc/.cvsignore deleted file mode 100644 index 2a06e93b553..00000000000 --- a/llvm/lib/Target/Sparc/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -*.inc diff --git a/llvm/lib/Target/Sparc/EmitAssembly.cpp b/llvm/lib/Target/Sparc/EmitAssembly.cpp deleted file mode 100644 index 40aa81cab00..00000000000 --- a/llvm/lib/Target/Sparc/EmitAssembly.cpp +++ /dev/null @@ -1,800 +0,0 @@ -//===-- EmitAssembly.cpp - Emit Sparc Specific .s File ---------------------==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements all of the stuff necessary to output a .s file from -// LLVM. The code in this file assumes that the specified module has already -// been compiled into the internal data structures of the Module. -// -// This code largely consists of two LLVM Pass's: a FunctionPass and a Pass. -// The FunctionPass is pipelined together with all of the rest of the code -// generation stages, and the Pass runs at the end to emit code for global -// variables and such. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/Assembly/Writer.h" -#include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Support/Mangler.h" -#include "Support/StringExtras.h" -#include "Support/Statistic.h" -#include "SparcInternals.h" -#include <string> -using namespace llvm; - -namespace { - Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); - - //===--------------------------------------------------------------------===// - // Utility functions - - /// getAsCString - Return the specified array as a C compatible string, only - /// if the predicate isString() is true. - /// - std::string getAsCString(const ConstantArray *CVA) { - assert(CVA->isString() && "Array is not string compatible!"); - - std::string Result = "\""; - for (unsigned i = 0; i != CVA->getNumOperands(); ++i) { - unsigned char C = cast<ConstantInt>(CVA->getOperand(i))->getRawValue(); - - if (C == '"') { - Result += "\\\""; - } else if (C == '\\') { - Result += "\\\\"; - } else if (isprint(C)) { - Result += C; - } else { - Result += '\\'; // print all other chars as octal value - // Convert C to octal representation - Result += ((C >> 6) & 7) + '0'; - Result += ((C >> 3) & 7) + '0'; - Result += ((C >> 0) & 7) + '0'; - } - } - Result += "\""; - - return Result; - } - - inline bool ArrayTypeIsString(const ArrayType* arrayType) { - return (arrayType->getElementType() == Type::UByteTy || - arrayType->getElementType() == Type::SByteTy); - } - - inline const std::string - TypeToDataDirective(const Type* type) { - switch(type->getPrimitiveID()) - { - case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: - return ".byte"; - case Type::UShortTyID: case Type::ShortTyID: - return ".half"; - case Type::UIntTyID: case Type::IntTyID: - return ".word"; - case Type::ULongTyID: case Type::LongTyID: case Type::PointerTyID: - return ".xword"; - case Type::FloatTyID: - return ".word"; - case Type::DoubleTyID: - return ".xword"; - case Type::ArrayTyID: - if (ArrayTypeIsString((ArrayType*) type)) - return ".ascii"; - else - return "<InvaliDataTypeForPrinting>"; - default: - return "<InvaliDataTypeForPrinting>"; - } - } - - /// Get the size of the constant for the given target. - /// If this is an unsized array, return 0. - /// - inline unsigned int - ConstantToSize(const Constant* CV, const TargetMachine& target) { - if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV)) { - const ArrayType *aty = cast<ArrayType>(CVA->getType()); - if (ArrayTypeIsString(aty)) - return 1 + CVA->getNumOperands(); - } - - return target.findOptimalStorageSize(CV->getType()); - } - - /// Align data larger than one L1 cache line on L1 cache line boundaries. - /// Align all smaller data on the next higher 2^x boundary (4, 8, ...). - /// - inline unsigned int - SizeToAlignment(unsigned int size, const TargetMachine& target) { - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); - if (size > (unsigned) cacheLineSize / 2) - return cacheLineSize; - else - for (unsigned sz=1; /*no condition*/; sz *= 2) - if (sz >= size) - return sz; - } - - /// Get the size of the type and then use SizeToAlignment. - /// - inline unsigned int - TypeToAlignment(const Type* type, const TargetMachine& target) { - return SizeToAlignment(target.findOptimalStorageSize(type), target); - } - - /// Get the size of the constant and then use SizeToAlignment. - /// Handles strings as a special case; - inline unsigned int - ConstantToAlignment(const Constant* CV, const TargetMachine& target) { - if (const ConstantArray* CVA = dyn_cast<ConstantArray>(CV)) - if (ArrayTypeIsString(cast<ArrayType>(CVA->getType()))) - return SizeToAlignment(1 + CVA->getNumOperands(), target); - - return TypeToAlignment(CV->getType(), target); - } - -} // End anonymous namespace - - - -//===---------------------------------------------------------------------===// -// Code abstracted away from the AsmPrinter -//===---------------------------------------------------------------------===// - -namespace { - class AsmPrinter { - // Mangle symbol names appropriately - Mangler *Mang; - - public: - std::ostream &toAsm; - const TargetMachine &Target; - - enum Sections { - Unknown, - Text, - ReadOnlyData, - InitRWData, - ZeroInitRWData, - } CurSection; - - AsmPrinter(std::ostream &os, const TargetMachine &T) - : /* idTable(0), */ toAsm(os), Target(T), CurSection(Unknown) {} - - ~AsmPrinter() { - delete Mang; - } - - // (start|end)(Module|Function) - Callback methods invoked by subclasses - void startModule(Module &M) { - Mang = new Mangler(M); - } - - void PrintZeroBytesToPad(int numBytes) { - // - // Always use single unsigned bytes for padding. We don't know upon - // what data size the beginning address is aligned, so using anything - // other than a byte may cause alignment errors in the assembler. - // - while (numBytes--) - printSingleConstantValue(Constant::getNullValue(Type::UByteTy)); - } - - /// Print a single constant value. - /// - void printSingleConstantValue(const Constant* CV); - - /// Print a constant value or values (it may be an aggregate). - /// Uses printSingleConstantValue() to print each individual value. - /// - void printConstantValueOnly(const Constant* CV, int numPadBytesAfter = 0); - - // Print a constant (which may be an aggregate) prefixed by all the - // appropriate directives. Uses printConstantValueOnly() to print the - // value or values. - void printConstant(const Constant* CV, std::string valID = "") { - if (valID.length() == 0) - valID = getID(CV); - - toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n"; - - // Print .size and .type only if it is not a string. - if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) - if (CVA->isString()) { - // print it as a string and return - toAsm << valID << ":\n"; - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; - return; - } - - toAsm << "\t.type" << "\t" << valID << ",#object\n"; - - unsigned int constSize = ConstantToSize(CV, Target); - if (constSize) - toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n"; - - toAsm << valID << ":\n"; - - printConstantValueOnly(CV); - } - - // enterSection - Use this method to enter a different section of the output - // executable. This is used to only output necessary section transitions. - // - void enterSection(enum Sections S) { - if (S == CurSection) return; // Only switch section if necessary - CurSection = S; - - toAsm << "\n\t.section "; - switch (S) - { - default: assert(0 && "Bad section name!"); - case Text: toAsm << "\".text\""; break; - case ReadOnlyData: toAsm << "\".rodata\",#alloc"; break; - case InitRWData: toAsm << "\".data\",#alloc,#write"; break; - case ZeroInitRWData: toAsm << "\".bss\",#alloc,#write"; break; - } - toAsm << "\n"; - } - - // getID Wrappers - Ensure consistent usage - // Symbol names in Sparc assembly language have these rules: - // (a) Must match { letter | _ | . | $ } { letter | _ | . | $ | digit }* - // (b) A name beginning in "." is treated as a local name. - std::string getID(const Function *F) { - return Mang->getValueName(F); - } - std::string getID(const BasicBlock *BB) { - return ".L_" + getID(BB->getParent()) + "_" + Mang->getValueName(BB); - } - std::string getID(const GlobalVariable *GV) { - return Mang->getValueName(GV); - } - std::string getID(const Constant *CV) { - return ".C_" + Mang->getValueName(CV); - } - std::string getID(const GlobalValue *GV) { - if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV)) - return getID(V); - else if (const Function *F = dyn_cast<Function>(GV)) - return getID(F); - assert(0 && "Unexpected type of GlobalValue!"); - return ""; - } - - // Combines expressions - inline std::string ConstantArithExprToString(const ConstantExpr* CE, - const TargetMachine &TM, - const std::string &op) { - return "(" + valToExprString(CE->getOperand(0), TM) + op - + valToExprString(CE->getOperand(1), TM) + ")"; - } - - /// ConstantExprToString() - Convert a ConstantExpr to an asm expression - /// and return this as a string. - /// - std::string ConstantExprToString(const ConstantExpr* CE, - const TargetMachine& target); - - /// valToExprString - Helper function for ConstantExprToString(). - /// Appends result to argument string S. - /// - std::string valToExprString(const Value* V, const TargetMachine& target); - }; -} // End anonymous namespace - - -/// Print a single constant value. -/// -void AsmPrinter::printSingleConstantValue(const Constant* CV) { - assert(CV->getType() != Type::VoidTy && - CV->getType() != Type::TypeTy && - CV->getType() != Type::LabelTy && - "Unexpected type for Constant"); - - assert((!isa<ConstantArray>(CV) && ! isa<ConstantStruct>(CV)) - && "Aggregate types should be handled outside this function"); - - toAsm << "\t" << TypeToDataDirective(CV->getType()) << "\t"; - - if (const ConstantPointerRef* CPR = dyn_cast<ConstantPointerRef>(CV)) { - // This is a constant address for a global variable or method. - // Use the name of the variable or method as the address value. - assert(isa<GlobalValue>(CPR->getValue()) && "Unexpected non-global"); - toAsm << getID(CPR->getValue()) << "\n"; - } else if (isa<ConstantPointerNull>(CV)) { - // Null pointer value - toAsm << "0\n"; - } else if (const ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) { - // Constant expression built from operators, constants, and symbolic addrs - toAsm << ConstantExprToString(CE, Target) << "\n"; - } else if (CV->getType()->isPrimitiveType()) { - // Check primitive types last - if (CV->getType()->isFloatingPoint()) { - // FP Constants are printed as integer constants to avoid losing - // precision... - double Val = cast<ConstantFP>(CV)->getValue(); - if (CV->getType() == Type::FloatTy) { - float FVal = (float)Val; - char *ProxyPtr = (char*)&FVal; // Abide by C TBAA rules - toAsm << *(unsigned int*)ProxyPtr; - } else if (CV->getType() == Type::DoubleTy) { - char *ProxyPtr = (char*)&Val; // Abide by C TBAA rules - toAsm << *(uint64_t*)ProxyPtr; - } else { - assert(0 && "Unknown floating point type!"); - } - - toAsm << "\t! " << CV->getType()->getDescription() - << " value: " << Val << "\n"; - } else if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) { - toAsm << (int)CB->getValue() << "\n"; - } else { - WriteAsOperand(toAsm, CV, false, false) << "\n"; - } - } else { - assert(0 && "Unknown elementary type for constant"); - } -} - -/// Print a constant value or values (it may be an aggregate). -/// Uses printSingleConstantValue() to print each individual value. -/// -void AsmPrinter::printConstantValueOnly(const Constant* CV, - int numPadBytesAfter) { - if (const ConstantArray *CVA = dyn_cast<ConstantArray>(CV)) { - if (CVA->isString()) { - // print the string alone and return - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; - } else { - // Not a string. Print the values in successive locations - const std::vector<Use> &constValues = CVA->getValues(); - for (unsigned i=0; i < constValues.size(); i++) - printConstantValueOnly(cast<Constant>(constValues[i].get())); - } - } else if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) { - // Print the fields in successive locations. Pad to align if needed! - const StructLayout *cvsLayout = - Target.getTargetData().getStructLayout(CVS->getType()); - const std::vector<Use>& constValues = CVS->getValues(); - unsigned sizeSoFar = 0; - for (unsigned i=0, N = constValues.size(); i < N; i++) { - const Constant* field = cast<Constant>(constValues[i].get()); - - // Check if padding is needed and insert one or more 0s. - unsigned fieldSize = - Target.getTargetData().getTypeSize(field->getType()); - int padSize = ((i == N-1? cvsLayout->StructSize - : cvsLayout->MemberOffsets[i+1]) - - cvsLayout->MemberOffsets[i]) - fieldSize; - sizeSoFar += (fieldSize + padSize); - - // Now print the actual field value - printConstantValueOnly(field, padSize); - } - assert(sizeSoFar == cvsLayout->StructSize && - "Layout of constant struct may be incorrect!"); - } else if (isa<ConstantAggregateZero>(CV)) { - PrintZeroBytesToPad(Target.getTargetData().getTypeSize(CV->getType())); - } else - printSingleConstantValue(CV); - - if (numPadBytesAfter) - PrintZeroBytesToPad(numPadBytesAfter); -} - -/// ConstantExprToString() - Convert a ConstantExpr to an asm expression -/// and return this as a string. -/// -std::string AsmPrinter::ConstantExprToString(const ConstantExpr* CE, - const TargetMachine& target) { - std::string S; - switch(CE->getOpcode()) { - case Instruction::GetElementPtr: - { // generate a symbolic expression for the byte address - const Value* ptrVal = CE->getOperand(0); - std::vector<Value*> idxVec(CE->op_begin()+1, CE->op_end()); - const TargetData &TD = target.getTargetData(); - S += "(" + valToExprString(ptrVal, target) + ") + (" - + utostr(TD.getIndexedOffset(ptrVal->getType(),idxVec)) + ")"; - break; - } - - case Instruction::Cast: - // Support only non-converting casts for now, i.e., a no-op. - // This assertion is not a complete check. - assert(target.getTargetData().getTypeSize(CE->getType()) == - target.getTargetData().getTypeSize(CE->getOperand(0)->getType())); - S += "(" + valToExprString(CE->getOperand(0), target) + ")"; - break; - - case Instruction::Add: - S += ConstantArithExprToString(CE, target, ") + ("); - break; - - case Instruction::Sub: - S += ConstantArithExprToString(CE, target, ") - ("); - break; - - case Instruction::Mul: - S += ConstantArithExprToString(CE, target, ") * ("); - break; - - case Instruction::Div: - S += ConstantArithExprToString(CE, target, ") / ("); - break; - - case Instruction::Rem: - S += ConstantArithExprToString(CE, target, ") % ("); - break; - - case Instruction::And: - // Logical && for booleans; bitwise & otherwise - S += ConstantArithExprToString(CE, target, - ((CE->getType() == Type::BoolTy)? ") && (" : ") & (")); - break; - - case Instruction::Or: - // Logical || for booleans; bitwise | otherwise - S += ConstantArithExprToString(CE, target, - ((CE->getType() == Type::BoolTy)? ") || (" : ") | (")); - break; - - case Instruction::Xor: - // Bitwise ^ for all types - S += ConstantArithExprToString(CE, target, ") ^ ("); - break; - - default: - assert(0 && "Unsupported operator in ConstantExprToString()"); - break; - } - - return S; -} - -/// valToExprString - Helper function for ConstantExprToString(). -/// Appends result to argument string S. -/// -std::string AsmPrinter::valToExprString(const Value* V, - const TargetMachine& target) { - std::string S; - bool failed = false; - if (const Constant* CV = dyn_cast<Constant>(V)) { // symbolic or known - if (const ConstantBool *CB = dyn_cast<ConstantBool>(CV)) - S += std::string(CB == ConstantBool::True ? "1" : "0"); - else if (const ConstantSInt *CI = dyn_cast<ConstantSInt>(CV)) - S += itostr(CI->getValue()); - else if (const ConstantUInt *CI = dyn_cast<ConstantUInt>(CV)) - S += utostr(CI->getValue()); - else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) - S += ftostr(CFP->getValue()); - else if (isa<ConstantPointerNull>(CV)) - S += "0"; - else if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(CV)) - S += valToExprString(CPR->getValue(), target); - else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(CV)) - S += ConstantExprToString(CE, target); - else - failed = true; - } else if (const GlobalValue* GV = dyn_cast<GlobalValue>(V)) { - S += getID(GV); - } else - failed = true; - - if (failed) { - assert(0 && "Cannot convert value to string"); - S += "<illegal-value>"; - } - return S; -} - - -//===----------------------------------------------------------------------===// -// SparcAsmPrinter Code -//===----------------------------------------------------------------------===// - -namespace { - - struct SparcAsmPrinter : public FunctionPass, public AsmPrinter { - inline SparcAsmPrinter(std::ostream &os, const TargetMachine &t) - : AsmPrinter(os, t) {} - - const Function *currFunction; - - const char *getPassName() const { - return "Output Sparc Assembly for Functions"; - } - - virtual bool doInitialization(Module &M) { - startModule(M); - return false; - } - - virtual bool runOnFunction(Function &F) { - currFunction = &F; - emitFunction(F); - return false; - } - - virtual bool doFinalization(Module &M) { - emitGlobals(M); - return false; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } - - void emitFunction(const Function &F); - private : - void emitBasicBlock(const MachineBasicBlock &MBB); - void emitMachineInst(const MachineInstr *MI); - - unsigned int printOperands(const MachineInstr *MI, unsigned int opNum); - void printOneOperand(const MachineOperand &Op, MachineOpCode opCode); - - bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum); - bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum); - - unsigned getOperandMask(unsigned Opcode) { - switch (Opcode) { - case V9::SUBccr: - case V9::SUBcci: return 1 << 3; // Remove CC argument - default: return 0; // By default, don't hack operands... - } - } - - void emitGlobals(const Module &M); - void printGlobalVariable(const GlobalVariable *GV); - }; - -} // End anonymous namespace - -inline bool -SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, - unsigned int opNum) { - switch (MI->getOpcode()) { - case V9::JMPLCALLr: - case V9::JMPLCALLi: - case V9::JMPLRETr: - case V9::JMPLRETi: - return (opNum == 0); - default: - return false; - } -} - -inline bool -SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, - unsigned int opNum) { - if (Target.getInstrInfo().isLoad(MI->getOpcode())) - return (opNum == 0); - else if (Target.getInstrInfo().isStore(MI->getOpcode())) - return (opNum == 1); - else - return false; -} - - -#define PrintOp1PlusOp2(mop1, mop2, opCode) \ - printOneOperand(mop1, opCode); \ - toAsm << "+"; \ - printOneOperand(mop2, opCode); - -unsigned int -SparcAsmPrinter::printOperands(const MachineInstr *MI, - unsigned int opNum) -{ - const MachineOperand& mop = MI->getOperand(opNum); - - if (OpIsBranchTargetLabel(MI, opNum)) { - PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); - return 2; - } else if (OpIsMemoryAddressBase(MI, opNum)) { - toAsm << "["; - PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); - toAsm << "]"; - return 2; - } else { - printOneOperand(mop, MI->getOpcode()); - return 1; - } -} - -void -SparcAsmPrinter::printOneOperand(const MachineOperand &mop, - MachineOpCode opCode) -{ - bool needBitsFlag = true; - - if (mop.isHiBits32()) - toAsm << "%lm("; - else if (mop.isLoBits32()) - toAsm << "%lo("; - else if (mop.isHiBits64()) - toAsm << "%hh("; - else if (mop.isLoBits64()) - toAsm << "%hm("; - else - needBitsFlag = false; - - switch (mop.getType()) - { - case MachineOperand::MO_VirtualRegister: - case MachineOperand::MO_CCRegister: - case MachineOperand::MO_MachineRegister: - { - int regNum = (int)mop.getReg(); - - if (regNum == Target.getRegInfo().getInvalidRegNum()) { - // better to print code with NULL registers than to die - toAsm << "<NULL VALUE>"; - } else { - toAsm << "%" << Target.getRegInfo().getUnifiedRegName(regNum); - } - break; - } - - case MachineOperand::MO_ConstantPoolIndex: - { - toAsm << ".CPI_" << currFunction->getName() - << "_" << mop.getConstantPoolIndex(); - break; - } - - case MachineOperand::MO_PCRelativeDisp: - { - const Value *Val = mop.getVRegValue(); - assert(Val && "\tNULL Value in SparcAsmPrinter"); - - if (const BasicBlock *BB = dyn_cast<BasicBlock>(Val)) - toAsm << getID(BB); - else if (const Function *M = dyn_cast<Function>(Val)) - toAsm << getID(M); - else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Val)) - toAsm << getID(GV); - else if (const Constant *CV = dyn_cast<Constant>(Val)) - toAsm << getID(CV); - else - assert(0 && "Unrecognized value in SparcAsmPrinter"); - break; - } - - case MachineOperand::MO_SignExtendedImmed: - toAsm << mop.getImmedValue(); - break; - - case MachineOperand::MO_UnextendedImmed: - toAsm << (uint64_t) mop.getImmedValue(); - break; - - default: - toAsm << mop; // use dump field - break; - } - - if (needBitsFlag) - toAsm << ")"; -} - -void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { - unsigned Opcode = MI->getOpcode(); - - if (Target.getInstrInfo().isDummyPhiInstr(Opcode)) - return; // IGNORE PHI NODES - - toAsm << "\t" << Target.getInstrInfo().getName(Opcode) << "\t"; - - unsigned Mask = getOperandMask(Opcode); - - bool NeedComma = false; - unsigned N = 1; - for (unsigned OpNum = 0; OpNum < MI->getNumOperands(); OpNum += N) - if (! ((1 << OpNum) & Mask)) { // Ignore this operand? - if (NeedComma) toAsm << ", "; // Handle comma outputting - NeedComma = true; - N = printOperands(MI, OpNum); - } else - N = 1; - - toAsm << "\n"; - ++EmittedInsts; -} - -void SparcAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) { - // Emit a label for the basic block - toAsm << getID(MBB.getBasicBlock()) << ":\n"; - - // Loop over all of the instructions in the basic block... - for (MachineBasicBlock::const_iterator MII = MBB.begin(), MIE = MBB.end(); - MII != MIE; ++MII) - emitMachineInst(MII); - toAsm << "\n"; // Separate BB's with newlines -} - -void SparcAsmPrinter::emitFunction(const Function &F) { - std::string methName = getID(&F); - toAsm << "!****** Outputing Function: " << methName << " ******\n"; - - // Emit constant pool for this function - const MachineConstantPool *MCP = MachineFunction::get(&F).getConstantPool(); - const std::vector<Constant*> &CP = MCP->getConstants(); - - enterSection(AsmPrinter::ReadOnlyData); - for (unsigned i = 0, e = CP.size(); i != e; ++i) { - std::string cpiName = ".CPI_" + F.getName() + "_" + utostr(i); - printConstant(CP[i], cpiName); - } - - enterSection(AsmPrinter::Text); - toAsm << "\t.align\t4\n\t.global\t" << methName << "\n"; - //toAsm << "\t.type\t" << methName << ",#function\n"; - toAsm << "\t.type\t" << methName << ", 2\n"; - toAsm << methName << ":\n"; - - // Output code for all of the basic blocks in the function... - MachineFunction &MF = MachineFunction::get(&F); - for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E;++I) - emitBasicBlock(*I); - - // Output a .size directive so the debugger knows the extents of the function - toAsm << ".EndOf_" << methName << ":\n\t.size " - << methName << ", .EndOf_" - << methName << "-" << methName << "\n"; - - // Put some spaces between the functions - toAsm << "\n\n"; -} - -void SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) { - if (GV->hasExternalLinkage()) - toAsm << "\t.global\t" << getID(GV) << "\n"; - - if (GV->hasInitializer() && ! GV->getInitializer()->isNullValue()) { - printConstant(GV->getInitializer(), getID(GV)); - } else { - toAsm << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(), - Target) << "\n"; - toAsm << "\t.type\t" << getID(GV) << ",#object\n"; - toAsm << "\t.reserve\t" << getID(GV) << "," - << Target.findOptimalStorageSize(GV->getType()->getElementType()) - << "\n"; - } -} - -void SparcAsmPrinter::emitGlobals(const Module &M) { - // Output global variables... - for (Module::const_giterator GI = M.gbegin(), GE = M.gend(); GI != GE; ++GI) - if (! GI->isExternal()) { - assert(GI->hasInitializer()); - if (GI->isConstant()) - enterSection(AsmPrinter::ReadOnlyData); // read-only, initialized data - else if (GI->getInitializer()->isNullValue()) - enterSection(AsmPrinter::ZeroInitRWData); // read-write zero data - else - enterSection(AsmPrinter::InitRWData); // read-write non-zero data - - printGlobalVariable(GI); - } - - toAsm << "\n"; -} - -FunctionPass *llvm::createAsmPrinterPass(std::ostream &Out, - const TargetMachine &TM) { - return new SparcAsmPrinter(Out, TM); -} diff --git a/llvm/lib/Target/Sparc/EmitBytecodeToAssembly.cpp b/llvm/lib/Target/Sparc/EmitBytecodeToAssembly.cpp deleted file mode 100644 index 40facf3fd99..00000000000 --- a/llvm/lib/Target/Sparc/EmitBytecodeToAssembly.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===-- EmitBytecodeToAssembly.cpp - Emit bytecode to Sparc .s File --------==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the pass that writes LLVM bytecode as data to a sparc -// assembly file. The bytecode gets assembled into a special bytecode section -// of the executable for use at runtime later. -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" -#include "llvm/Pass.h" -#include "llvm/Bytecode/Writer.h" -#include <iostream> - -namespace llvm { - -using std::ostream; - -namespace { - - // sparcasmbuf - stream buf for encoding output bytes as .byte directives for - // the sparc assembler. - // - class sparcasmbuf : public std::streambuf { - std::ostream &BaseStr; - public: - typedef char char_type; - typedef int int_type; - typedef std::streampos pos_type; - typedef std::streamoff off_type; - - sparcasmbuf(std::ostream &On) : BaseStr(On) {} - - virtual int_type overflow(int_type C) { - if (C != EOF) - BaseStr << "\t.byte " << C << "\n"; // Output C; - return C; - } - }; - - - // osparcasmstream - Define an ostream implementation that uses a sparcasmbuf - // as the underlying streambuf to write the data to. This streambuf formats - // the output as .byte directives for sparc output. - // - class osparcasmstream : public std::ostream { - sparcasmbuf sb; - public: - typedef char char_type; - typedef int int_type; - typedef std::streampos pos_type; - typedef std::streamoff off_type; - - explicit osparcasmstream(std::ostream &On) : std::ostream(&sb), sb(On) { } - - sparcasmbuf *rdbuf() const { - return const_cast<sparcasmbuf*>(&sb); - } - }; - - static void writePrologue (std::ostream &Out, const std::string &comment, - const std::string &symName) { - // Prologue: - // Output a comment describing the object. - Out << "!" << comment << "\n"; - // Switch the current section to .rodata in the assembly output: - Out << "\t.section \".rodata\"\n\t.align 8\n"; - // Output a global symbol naming the object: - Out << "\t.global " << symName << "\n"; - Out << "\t.type " << symName << ",#object\n"; - Out << symName << ":\n"; - } - - static void writeEpilogue (std::ostream &Out, const std::string &symName) { - // Epilogue: - // Output a local symbol marking the end of the object: - Out << ".end_" << symName << ":\n"; - // Output size directive giving the size of the object: - Out << "\t.size " << symName << ", .end_" << symName << "-" << symName - << "\n"; - } - - // SparcBytecodeWriter - Write bytecode out to a stream that is sparc'ified - class SparcBytecodeWriter : public Pass { - std::ostream &Out; - public: - SparcBytecodeWriter(std::ostream &out) : Out(out) {} - - const char *getPassName() const { return "Emit Bytecode to Sparc Assembly";} - - virtual bool run(Module &M) { - // Write an object containing the bytecode to the SPARC assembly stream - writePrologue (Out, "LLVM BYTECODE OUTPUT", "LLVMBytecode"); - osparcasmstream OS(Out); - WriteBytecodeToFile(&M, OS); - writeEpilogue (Out, "LLVMBytecode"); - - // Write an object containing its length as an integer to the - // SPARC assembly stream - writePrologue (Out, "LLVM BYTECODE LENGTH", "llvm_length"); - Out <<"\t.word\t.end_LLVMBytecode-LLVMBytecode\n"; - writeEpilogue (Out, "llvm_length"); - - return false; - } - }; -} // end anonymous namespace - -Pass *createBytecodeAsmPrinterPass(std::ostream &Out) { - return new SparcBytecodeWriter(Out); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/InstrSelection/InstrForest.cpp b/llvm/lib/Target/Sparc/InstrSelection/InstrForest.cpp deleted file mode 100644 index fd5056d22d7..00000000000 --- a/llvm/lib/Target/Sparc/InstrSelection/InstrForest.cpp +++ /dev/null @@ -1,336 +0,0 @@ -//===-- InstrForest.cpp - Build instruction forest for inst selection -----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The key goal is to group instructions into a single -// tree if one or more of them might be potentially combined into a single -// complex instruction in the target machine. -// Since this grouping is completely machine-independent, we do it as -// aggressive as possible to exploit any possible target instructions. -// In particular, we group two instructions O and I if: -// (1) Instruction O computes an operand used by instruction I, -// and (2) O and I are part of the same basic block, -// and (3) O has only a single use, viz., I. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constant.h" -#include "llvm/Function.h" -#include "llvm/iTerminators.h" -#include "llvm/iMemory.h" -#include "llvm/Type.h" -#include "llvm/CodeGen/InstrForest.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "Support/STLExtras.h" -#include "Config/alloca.h" - -namespace llvm { - -//------------------------------------------------------------------------ -// class InstrTreeNode -//------------------------------------------------------------------------ - -void -InstrTreeNode::dump(int dumpChildren, int indent) const { - dumpNode(indent); - - if (dumpChildren) { - if (LeftChild) - LeftChild->dump(dumpChildren, indent+1); - if (RightChild) - RightChild->dump(dumpChildren, indent+1); - } -} - - -InstructionNode::InstructionNode(Instruction* I) - : InstrTreeNode(NTInstructionNode, I), codeIsFoldedIntoParent(false) -{ - opLabel = I->getOpcode(); - - // Distinguish special cases of some instructions such as Ret and Br - // - if (opLabel == Instruction::Ret && cast<ReturnInst>(I)->getReturnValue()) { - opLabel = RetValueOp; // ret(value) operation - } - else if (opLabel ==Instruction::Br && !cast<BranchInst>(I)->isUnconditional()) - { - opLabel = BrCondOp; // br(cond) operation - } else if (opLabel >= Instruction::SetEQ && opLabel <= Instruction::SetGT) { - opLabel = SetCCOp; // common label for all SetCC ops - } else if (opLabel == Instruction::Alloca && I->getNumOperands() > 0) { - opLabel = AllocaN; // Alloca(ptr, N) operation - } else if (opLabel == Instruction::GetElementPtr && - cast<GetElementPtrInst>(I)->hasIndices()) { - opLabel = opLabel + 100; // getElem with index vector - } else if (opLabel == Instruction::Xor && - BinaryOperator::isNot(I)) { - opLabel = (I->getType() == Type::BoolTy)? NotOp // boolean Not operator - : BNotOp; // bitwise Not operator - } else if (opLabel == Instruction::And || opLabel == Instruction::Or || - opLabel == Instruction::Xor) { - // Distinguish bitwise operators from logical operators! - if (I->getType() != Type::BoolTy) - opLabel = opLabel + 100; // bitwise operator - } else if (opLabel == Instruction::Cast) { - const Type *ITy = I->getType(); - switch(ITy->getPrimitiveID()) - { - case Type::BoolTyID: opLabel = ToBoolTy; break; - case Type::UByteTyID: opLabel = ToUByteTy; break; - case Type::SByteTyID: opLabel = ToSByteTy; break; - case Type::UShortTyID: opLabel = ToUShortTy; break; - case Type::ShortTyID: opLabel = ToShortTy; break; - case Type::UIntTyID: opLabel = ToUIntTy; break; - case Type::IntTyID: opLabel = ToIntTy; break; - case Type::ULongTyID: opLabel = ToULongTy; break; - case Type::LongTyID: opLabel = ToLongTy; break; - case Type::FloatTyID: opLabel = ToFloatTy; break; - case Type::DoubleTyID: opLabel = ToDoubleTy; break; - case Type::ArrayTyID: opLabel = ToArrayTy; break; - case Type::PointerTyID: opLabel = ToPointerTy; break; - default: - // Just use `Cast' opcode otherwise. It's probably ignored. - break; - } - } -} - - -void -InstructionNode::dumpNode(int indent) const { - for (int i=0; i < indent; i++) - std::cerr << " "; - std::cerr << getInstruction()->getOpcodeName() - << " [label " << getOpLabel() << "]" << "\n"; -} - -void -VRegListNode::dumpNode(int indent) const { - for (int i=0; i < indent; i++) - std::cerr << " "; - - std::cerr << "List" << "\n"; -} - - -void -VRegNode::dumpNode(int indent) const { - for (int i=0; i < indent; i++) - std::cerr << " "; - - std::cerr << "VReg " << getValue() << "\t(type " - << (int) getValue()->getValueType() << ")" << "\n"; -} - -void -ConstantNode::dumpNode(int indent) const { - for (int i=0; i < indent; i++) - std::cerr << " "; - - std::cerr << "Constant " << getValue() << "\t(type " - << (int) getValue()->getValueType() << ")" << "\n"; -} - -void LabelNode::dumpNode(int indent) const { - for (int i=0; i < indent; i++) - std::cerr << " "; - - std::cerr << "Label " << getValue() << "\n"; -} - -//------------------------------------------------------------------------ -// class InstrForest -// -// A forest of instruction trees, usually for a single method. -//------------------------------------------------------------------------ - -InstrForest::InstrForest(Function *F) { - for (Function::iterator BB = F->begin(), FE = F->end(); BB != FE; ++BB) { - for(BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) - buildTreeForInstruction(I); - } -} - -InstrForest::~InstrForest() { - for_each(treeRoots.begin(), treeRoots.end(), deleter<InstructionNode>); -} - -void InstrForest::dump() const { - for (const_root_iterator I = roots_begin(); I != roots_end(); ++I) - (*I)->dump(/*dumpChildren*/ 1, /*indent*/ 0); -} - -inline void InstrForest::eraseRoot(InstructionNode* node) { - for (RootSet::reverse_iterator RI=treeRoots.rbegin(), RE=treeRoots.rend(); - RI != RE; ++RI) - if (*RI == node) - treeRoots.erase(RI.base()-1); -} - -inline void InstrForest::noteTreeNodeForInstr(Instruction *instr, - InstructionNode *treeNode) { - (*this)[instr] = treeNode; - treeRoots.push_back(treeNode); // mark node as root of a new tree -} - - -inline void InstrForest::setLeftChild(InstrTreeNode *parent, - InstrTreeNode *child) { - parent->LeftChild = child; - child->Parent = parent; - if (InstructionNode* instrNode = dyn_cast<InstructionNode>(child)) - eraseRoot(instrNode); // no longer a tree root -} - -inline void InstrForest::setRightChild(InstrTreeNode *parent, - InstrTreeNode *child) { - parent->RightChild = child; - child->Parent = parent; - if (InstructionNode* instrNode = dyn_cast<InstructionNode>(child)) - eraseRoot(instrNode); // no longer a tree root -} - - -InstructionNode* InstrForest::buildTreeForInstruction(Instruction *instr) { - InstructionNode *treeNode = getTreeNodeForInstr(instr); - if (treeNode) { - // treeNode has already been constructed for this instruction - assert(treeNode->getInstruction() == instr); - return treeNode; - } - - // Otherwise, create a new tree node for this instruction. - // - treeNode = new InstructionNode(instr); - noteTreeNodeForInstr(instr, treeNode); - - if (instr->getOpcode() == Instruction::Call) { - // Operands of call instruction - return treeNode; - } - - // If the instruction has more than 2 instruction operands, - // then we need to create artificial list nodes to hold them. - // (Note that we only count operands that get tree nodes, and not - // others such as branch labels for a branch or switch instruction.) - // - // To do this efficiently, we'll walk all operands, build treeNodes - // for all appropriate operands and save them in an array. We then - // insert children at the end, creating list nodes where needed. - // As a performance optimization, allocate a child array only - // if a fixed array is too small. - // - int numChildren = 0; - InstrTreeNode** childArray = new InstrTreeNode*[instr->getNumOperands()]; - - // - // Walk the operands of the instruction - // - for (Instruction::op_iterator O = instr->op_begin(); O!=instr->op_end(); ++O) - { - Value* operand = *O; - - // Check if the operand is a data value, not an branch label, type, - // method or module. If the operand is an address type (i.e., label - // or method) that is used in an non-branching operation, e.g., `add'. - // that should be considered a data value. - - // Check latter condition here just to simplify the next IF. - bool includeAddressOperand = - (isa<BasicBlock>(operand) || isa<Function>(operand)) - && !instr->isTerminator(); - - if (includeAddressOperand || isa<Instruction>(operand) || - isa<Constant>(operand) || isa<Argument>(operand) || - isa<GlobalVariable>(operand)) - { - // This operand is a data value - - // An instruction that computes the incoming value is added as a - // child of the current instruction if: - // the value has only a single use - // AND both instructions are in the same basic block. - // AND the current instruction is not a PHI (because the incoming - // value is conceptually in a predecessor block, - // even though it may be in the same static block) - // - // (Note that if the value has only a single use (viz., `instr'), - // the def of the value can be safely moved just before instr - // and therefore it is safe to combine these two instructions.) - // - // In all other cases, the virtual register holding the value - // is used directly, i.e., made a child of the instruction node. - // - InstrTreeNode* opTreeNode; - if (isa<Instruction>(operand) && operand->hasOneUse() && - cast<Instruction>(operand)->getParent() == instr->getParent() && - instr->getOpcode() != Instruction::PHI && - instr->getOpcode() != Instruction::Call) - { - // Recursively create a treeNode for it. - opTreeNode = buildTreeForInstruction((Instruction*)operand); - } else if (Constant *CPV = dyn_cast<Constant>(operand)) { - // Create a leaf node for a constant - opTreeNode = new ConstantNode(CPV); - } else { - // Create a leaf node for the virtual register - opTreeNode = new VRegNode(operand); - } - - childArray[numChildren++] = opTreeNode; - } - } - - //-------------------------------------------------------------------- - // Add any selected operands as children in the tree. - // Certain instructions can have more than 2 in some instances (viz., - // a CALL or a memory access -- LOAD, STORE, and GetElemPtr -- to an - // array or struct). Make the operands of every such instruction into - // a right-leaning binary tree with the operand nodes at the leaves - // and VRegList nodes as internal nodes. - //-------------------------------------------------------------------- - - InstrTreeNode *parent = treeNode; - - if (numChildren > 2) { - unsigned instrOpcode = treeNode->getInstruction()->getOpcode(); - assert(instrOpcode == Instruction::PHI || - instrOpcode == Instruction::Call || - instrOpcode == Instruction::Load || - instrOpcode == Instruction::Store || - instrOpcode == Instruction::GetElementPtr); - } - - // Insert the first child as a direct child - if (numChildren >= 1) - setLeftChild(parent, childArray[0]); - - int n; - - // Create a list node for children 2 .. N-1, if any - for (n = numChildren-1; n >= 2; n--) { - // We have more than two children - InstrTreeNode *listNode = new VRegListNode(); - setRightChild(parent, listNode); - setLeftChild(listNode, childArray[numChildren - n]); - parent = listNode; - } - - // Now insert the last remaining child (if any). - if (numChildren >= 2) { - assert(n == 1); - setRightChild(parent, childArray[numChildren - 1]); - } - - delete [] childArray; - return treeNode; -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/InstrSelection/InstrSelection.cpp b/llvm/lib/Target/Sparc/InstrSelection/InstrSelection.cpp deleted file mode 100644 index 4ddc4edfbb6..00000000000 --- a/llvm/lib/Target/Sparc/InstrSelection/InstrSelection.cpp +++ /dev/null @@ -1,414 +0,0 @@ -//===- InstrSelection.cpp - Machine Independent Inst Selection Driver -----===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Machine-independent driver file for instruction selection. This file -// constructs a forest of BURG instruction trees and then uses the -// BURG-generated tree grammar (BURM) to find the optimal instruction sequences -// for a given machine. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/Function.h" -#include "llvm/IntrinsicLowering.h" -#include "llvm/iPHINode.h" -#include "llvm/iOther.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/InstrForest.h" -#include "llvm/CodeGen/InstrSelectionSupport.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" -#include "Support/CommandLine.h" -#include "Support/LeakDetector.h" - -namespace llvm { - std::vector<MachineInstr*> - FixConstantOperandsForInstr(Instruction *I, MachineInstr *MI, - TargetMachine &TM); -} - -namespace { - //===--------------------------------------------------------------------===// - // SelectDebugLevel - Allow command line control over debugging. - // - enum SelectDebugLevel_t { - Select_NoDebugInfo, - Select_PrintMachineCode, - Select_DebugInstTrees, - Select_DebugBurgTrees, - }; - - // Enable Debug Options to be specified on the command line - cl::opt<SelectDebugLevel_t> - SelectDebugLevel("dselect", cl::Hidden, - cl::desc("enable instruction selection debug information"), - cl::values( - clEnumValN(Select_NoDebugInfo, "n", "disable debug output"), - clEnumValN(Select_PrintMachineCode, "y", "print generated machine code"), - clEnumValN(Select_DebugInstTrees, "i", - "print debugging info for instruction selection"), - clEnumValN(Select_DebugBurgTrees, "b", "print burg trees"), - 0)); - - - //===--------------------------------------------------------------------===// - // InstructionSelection Pass - // - // This is the actual pass object that drives the instruction selection - // process. - // - class InstructionSelection : public FunctionPass { - TargetMachine &Target; - void InsertCodeForPhis(Function &F); - void InsertPhiElimInstructions(BasicBlock *BB, - const std::vector<MachineInstr*>& CpVec); - void SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt); - void PostprocessMachineCodeForTree(InstructionNode* instrNode, - int ruleForNode, short* nts); - public: - InstructionSelection(TargetMachine &TM) : Target(TM) {} - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - } - - bool runOnFunction(Function &F); - virtual const char *getPassName() const { return "Instruction Selection"; } - }; -} - - -TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi, - Value *s1, Value *s2, const std::string &name) - : Instruction(s1->getType(), Instruction::UserOp1, name) -{ - mcfi.addTemp(this); - - Operands.push_back(Use(s1, this)); // s1 must be non-null - if (s2) - Operands.push_back(Use(s2, this)); - - // TmpInstructions should not be garbage checked. - LeakDetector::removeGarbageObject(this); -} - -// Constructor that requires the type of the temporary to be specified. -// Both S1 and S2 may be NULL.( -TmpInstruction::TmpInstruction(MachineCodeForInstruction& mcfi, - const Type *Ty, Value *s1, Value* s2, - const std::string &name) - : Instruction(Ty, Instruction::UserOp1, name) -{ - mcfi.addTemp(this); - - if (s1) - Operands.push_back(Use(s1, this)); - if (s2) - Operands.push_back(Use(s2, this)); - - // TmpInstructions should not be garbage checked. - LeakDetector::removeGarbageObject(this); -} - -bool InstructionSelection::runOnFunction(Function &F) { - // First pass - Walk the function, lowering any calls to intrinsic functions - // which the instruction selector cannot handle. - for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) - if (CallInst *CI = dyn_cast<CallInst>(I++)) - if (Function *F = CI->getCalledFunction()) - switch (F->getIntrinsicID()) { -#undef va_start -#undef va_copy -#undef va_end - case Intrinsic::not_intrinsic: - case Intrinsic::va_start: - case Intrinsic::va_copy: - case Intrinsic::va_end: - // We directly implement these intrinsics. Note that this knowledge - // is incestuously entangled with the code in - // SparcInstrSelection.cpp and must be updated when it is updated. - // Since ALL of the code in this library is incestuously intertwined - // with it already and sparc specific, we will live with this. - break; - default: - // All other intrinsic calls we must lower. - Instruction *Before = CI->getPrev(); - Target.getIntrinsicLowering().LowerIntrinsicCall(CI); - if (Before) { // Move iterator to instruction after call - I = Before; ++I; - } else { - I = BB->begin(); - } - } - - // - // Build the instruction trees to be given as inputs to BURG. - // - InstrForest instrForest(&F); - - if (SelectDebugLevel >= Select_DebugInstTrees) { - std::cerr << "\n\n*** Input to instruction selection for function " - << F.getName() << "\n\n" << F - << "\n\n*** Instruction trees for function " - << F.getName() << "\n\n"; - instrForest.dump(); - } - - // - // Invoke BURG instruction selection for each tree - // - for (InstrForest::const_root_iterator RI = instrForest.roots_begin(); - RI != instrForest.roots_end(); ++RI) { - InstructionNode* basicNode = *RI; - assert(basicNode->parent() == NULL && "A `root' node has a parent?"); - - // Invoke BURM to label each tree node with a state - burm_label(basicNode); - - if (SelectDebugLevel >= Select_DebugBurgTrees) { - printcover(basicNode, 1, 0); - std::cerr << "\nCover cost == " << treecost(basicNode, 1, 0) <<"\n\n"; - printMatches(basicNode); - } - - // Then recursively walk the tree to select instructions - SelectInstructionsForTree(basicNode, /*goalnt*/1); - } - - // - // Create the MachineBasicBlock records and add all of the MachineInstrs - // defined in the MachineCodeForInstruction objects to also live in the - // MachineBasicBlock objects. - // - MachineFunction &MF = MachineFunction::get(&F); - for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE; ++BI) { - MachineBasicBlock *MCBB = new MachineBasicBlock(BI); - MF.getBasicBlockList().push_back(MCBB); - - for (BasicBlock::iterator II = BI->begin(); II != BI->end(); ++II) { - MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(II); - MCBB->insert(MCBB->end(), mvec.begin(), mvec.end()); - } - } - - // Insert phi elimination code - InsertCodeForPhis(F); - - if (SelectDebugLevel >= Select_PrintMachineCode) { - std::cerr << "\n*** Machine instructions after INSTRUCTION SELECTION\n"; - MachineFunction::get(&F).dump(); - } - - return true; -} - - -//------------------------------------------------------------------------- -// This method inserts phi elimination code for all BBs in a method -//------------------------------------------------------------------------- - -void -InstructionSelection::InsertCodeForPhis(Function &F) { - // for all basic blocks in function - // - MachineFunction &MF = MachineFunction::get(&F); - for (MachineFunction::iterator BB = MF.begin(); BB != MF.end(); ++BB) { - for (BasicBlock::const_iterator IIt = BB->getBasicBlock()->begin(); - const PHINode *PN = dyn_cast<PHINode>(IIt); ++IIt) { - // FIXME: This is probably wrong... - Value *PhiCpRes = new PHINode(PN->getType(), "PhiCp:"); - - // The leak detector shouldn't track these nodes. They are not garbage, - // even though their parent field is never filled in. - // - LeakDetector::removeGarbageObject(PhiCpRes); - - // for each incoming value of the phi, insert phi elimination - // - for (unsigned i = 0; i < PN->getNumIncomingValues(); ++i) { - // insert the copy instruction to the predecessor BB - std::vector<MachineInstr*> mvec, CpVec; - Target.getRegInfo().cpValue2Value(PN->getIncomingValue(i), PhiCpRes, - mvec); - for (std::vector<MachineInstr*>::iterator MI=mvec.begin(); - MI != mvec.end(); ++MI) { - std::vector<MachineInstr*> CpVec2 = - FixConstantOperandsForInstr(const_cast<PHINode*>(PN), *MI, Target); - CpVec2.push_back(*MI); - CpVec.insert(CpVec.end(), CpVec2.begin(), CpVec2.end()); - } - - InsertPhiElimInstructions(PN->getIncomingBlock(i), CpVec); - } - - std::vector<MachineInstr*> mvec; - Target.getRegInfo().cpValue2Value(PhiCpRes, const_cast<PHINode*>(PN), - mvec); - BB->insert(BB->begin(), mvec.begin(), mvec.end()); - } // for each Phi Instr in BB - } // for all BBs in function -} - -//------------------------------------------------------------------------- -// Thid method inserts a copy instruction to a predecessor BB as a result -// of phi elimination. -//------------------------------------------------------------------------- - -void -InstructionSelection::InsertPhiElimInstructions(BasicBlock *BB, - const std::vector<MachineInstr*>& CpVec) -{ - Instruction *TermInst = (Instruction*)BB->getTerminator(); - MachineCodeForInstruction &MC4Term = MachineCodeForInstruction::get(TermInst); - MachineInstr *FirstMIOfTerm = MC4Term.front(); - assert (FirstMIOfTerm && "No Machine Instrs for terminator"); - - MachineFunction &MF = MachineFunction::get(BB->getParent()); - - // FIXME: if PHI instructions existed in the machine code, this would be - // unnecessary. - MachineBasicBlock *MBB = 0; - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - if (I->getBasicBlock() == BB) { - MBB = I; - break; - } - - MachineBasicBlock::iterator MCIt = FirstMIOfTerm; - - assert(MCIt != MBB->end() && "Start inst of terminator not found"); - - // insert the copy instructions just before the first machine instruction - // generated for the terminator - MBB->insert(MCIt, CpVec.begin(), CpVec.end()); -} - - -//--------------------------------------------------------------------------- -// Function SelectInstructionsForTree -// -// Recursively walk the tree to select instructions. -// Do this top-down so that child instructions can exploit decisions -// made at the child instructions. -// -// E.g., if br(setle(reg,const)) decides the constant is 0 and uses -// a branch-on-integer-register instruction, then the setle node -// can use that information to avoid generating the SUBcc instruction. -// -// Note that this cannot be done bottom-up because setle must do this -// only if it is a child of the branch (otherwise, the result of setle -// may be used by multiple instructions). -//--------------------------------------------------------------------------- - -void -InstructionSelection::SelectInstructionsForTree(InstrTreeNode* treeRoot, - int goalnt) -{ - // Get the rule that matches this node. - // - int ruleForNode = burm_rule(treeRoot->state, goalnt); - - if (ruleForNode == 0) { - std::cerr << "Could not match instruction tree for instr selection\n"; - abort(); - } - - // Get this rule's non-terminals and the corresponding child nodes (if any) - // - short *nts = burm_nts[ruleForNode]; - - // First, select instructions for the current node and rule. - // (If this is a list node, not an instruction, then skip this step). - // This function is specific to the target architecture. - // - if (treeRoot->opLabel != VRegListOp) { - std::vector<MachineInstr*> minstrVec; - - InstructionNode* instrNode = (InstructionNode*)treeRoot; - assert(instrNode->getNodeType() == InstrTreeNode::NTInstructionNode); - - GetInstructionsByRule(instrNode, ruleForNode, nts, Target, minstrVec); - - MachineCodeForInstruction &mvec = - MachineCodeForInstruction::get(instrNode->getInstruction()); - mvec.insert(mvec.end(), minstrVec.begin(), minstrVec.end()); - } - - // Then, recursively compile the child nodes, if any. - // - if (nts[0]) { - // i.e., there is at least one kid - InstrTreeNode* kids[2]; - int currentRule = ruleForNode; - burm_kids(treeRoot, currentRule, kids); - - // First skip over any chain rules so that we don't visit - // the current node again. - // - while (ThisIsAChainRule(currentRule)) { - currentRule = burm_rule(treeRoot->state, nts[0]); - nts = burm_nts[currentRule]; - burm_kids(treeRoot, currentRule, kids); - } - - // Now we have the first non-chain rule so we have found - // the actual child nodes. Recursively compile them. - // - for (unsigned i = 0; nts[i]; i++) { - assert(i < 2); - InstrTreeNode::InstrTreeNodeType nodeType = kids[i]->getNodeType(); - if (nodeType == InstrTreeNode::NTVRegListNode || - nodeType == InstrTreeNode::NTInstructionNode) - SelectInstructionsForTree(kids[i], nts[i]); - } - } - - // Finally, do any post-processing on this node after its children - // have been translated - // - if (treeRoot->opLabel != VRegListOp) - PostprocessMachineCodeForTree((InstructionNode*)treeRoot, ruleForNode, nts); -} - -//--------------------------------------------------------------------------- -// Function PostprocessMachineCodeForTree -// -// Apply any final cleanups to machine code for the root of a subtree -// after selection for all its children has been completed. -// -void -InstructionSelection::PostprocessMachineCodeForTree(InstructionNode* instrNode, - int ruleForNode, - short* nts) -{ - // Fix up any constant operands in the machine instructions to either - // use an immediate field or to load the constant into a register - // Walk backwards and use direct indexes to allow insertion before current - // - Instruction* vmInstr = instrNode->getInstruction(); - MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(vmInstr); - for (unsigned i = mvec.size(); i != 0; --i) { - std::vector<MachineInstr*> loadConstVec = - FixConstantOperandsForInstr(vmInstr, mvec[i-1], Target); - - mvec.insert(mvec.begin()+i-1, loadConstVec.begin(), loadConstVec.end()); - } -} - - -//===----------------------------------------------------------------------===// -// createInstructionSelectionPass - Public entrypoint for instruction selection -// and this file as a whole... -// -FunctionPass *llvm::createInstructionSelectionPass(TargetMachine &TM) { - return new InstructionSelection(TM); -} diff --git a/llvm/lib/Target/Sparc/InstrSelection/InstrSelectionSupport.cpp b/llvm/lib/Target/Sparc/InstrSelection/InstrSelectionSupport.cpp deleted file mode 100644 index a7923862cfa..00000000000 --- a/llvm/lib/Target/Sparc/InstrSelection/InstrSelectionSupport.cpp +++ /dev/null @@ -1,269 +0,0 @@ -//===-- InstrSelectionSupport.cpp -----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Target-independent instruction selection code. See SparcInstrSelection.cpp -// for usage. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/InstrSelectionSupport.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/InstrForest.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Constants.h" -#include "llvm/BasicBlock.h" -#include "llvm/DerivedTypes.h" -#include "../SparcInstrSelectionSupport.h" - -namespace llvm { - -// Generate code to load the constant into a TmpInstruction (virtual reg) and -// returns the virtual register. -// -static TmpInstruction* -InsertCodeToLoadConstant(Function *F, - Value* opValue, - Instruction* vmInstr, - std::vector<MachineInstr*>& loadConstVec, - TargetMachine& target) -{ - // Create a tmp virtual register to hold the constant. - MachineCodeForInstruction &mcfi = MachineCodeForInstruction::get(vmInstr); - TmpInstruction* tmpReg = new TmpInstruction(mcfi, opValue); - - target.getInstrInfo().CreateCodeToLoadConst(target, F, opValue, tmpReg, - loadConstVec, mcfi); - - // Record the mapping from the tmp VM instruction to machine instruction. - // Do this for all machine instructions that were not mapped to any - // other temp values created by - // tmpReg->addMachineInstruction(loadConstVec.back()); - - return tmpReg; -} - - -MachineOperand::MachineOperandType -ChooseRegOrImmed(int64_t intValue, - bool isSigned, - MachineOpCode opCode, - const TargetMachine& target, - bool canUseImmed, - unsigned int& getMachineRegNum, - int64_t& getImmedValue) -{ - MachineOperand::MachineOperandType opType=MachineOperand::MO_VirtualRegister; - getMachineRegNum = 0; - getImmedValue = 0; - - if (canUseImmed && - target.getInstrInfo().constantFitsInImmedField(opCode, intValue)) { - opType = isSigned? MachineOperand::MO_SignExtendedImmed - : MachineOperand::MO_UnextendedImmed; - getImmedValue = intValue; - } else if (intValue == 0 && - target.getRegInfo().getZeroRegNum() != (unsigned)-1) { - opType = MachineOperand::MO_MachineRegister; - getMachineRegNum = target.getRegInfo().getZeroRegNum(); - } - - return opType; -} - - -MachineOperand::MachineOperandType -ChooseRegOrImmed(Value* val, - MachineOpCode opCode, - const TargetMachine& target, - bool canUseImmed, - unsigned int& getMachineRegNum, - int64_t& getImmedValue) -{ - getMachineRegNum = 0; - getImmedValue = 0; - - // To use reg or immed, constant needs to be integer, bool, or a NULL pointer - // TargetInstrInfo::ConvertConstantToIntType() does the right conversions: - bool isValidConstant; - uint64_t valueToUse = - target.getInstrInfo().ConvertConstantToIntType(target, val, val->getType(), - isValidConstant); - if (! isValidConstant) - return MachineOperand::MO_VirtualRegister; - - // Now check if the constant value fits in the IMMED field. - // - return ChooseRegOrImmed((int64_t) valueToUse, val->getType()->isSigned(), - opCode, target, canUseImmed, - getMachineRegNum, getImmedValue); -} - -//--------------------------------------------------------------------------- -// Function: FixConstantOperandsForInstr -// -// Purpose: -// Special handling for constant operands of a machine instruction -// -- if the constant is 0, use the hardwired 0 register, if any; -// -- if the constant fits in the IMMEDIATE field, use that field; -// -- else create instructions to put the constant into a register, either -// directly or by loading explicitly from the constant pool. -// -// In the first 2 cases, the operand of `minstr' is modified in place. -// Returns a vector of machine instructions generated for operands that -// fall under case 3; these must be inserted before `minstr'. -//--------------------------------------------------------------------------- - -std::vector<MachineInstr*> -FixConstantOperandsForInstr(Instruction* vmInstr, - MachineInstr* minstr, - TargetMachine& target) -{ - std::vector<MachineInstr*> MVec; - - MachineOpCode opCode = minstr->getOpcode(); - const TargetInstrInfo& instrInfo = target.getInstrInfo(); - int resultPos = instrInfo.getResultPos(opCode); - int immedPos = instrInfo.getImmedConstantPos(opCode); - - Function *F = vmInstr->getParent()->getParent(); - - for (unsigned op=0; op < minstr->getNumOperands(); op++) - { - const MachineOperand& mop = minstr->getOperand(op); - - // Skip the result position, preallocated machine registers, or operands - // that cannot be constants (CC regs or PC-relative displacements) - if (resultPos == (int)op || - mop.getType() == MachineOperand::MO_MachineRegister || - mop.getType() == MachineOperand::MO_CCRegister || - mop.getType() == MachineOperand::MO_PCRelativeDisp) - continue; - - bool constantThatMustBeLoaded = false; - unsigned int machineRegNum = 0; - int64_t immedValue = 0; - Value* opValue = NULL; - MachineOperand::MachineOperandType opType = - MachineOperand::MO_VirtualRegister; - - // Operand may be a virtual register or a compile-time constant - if (mop.getType() == MachineOperand::MO_VirtualRegister) { - assert(mop.getVRegValue() != NULL); - opValue = mop.getVRegValue(); - if (Constant *opConst = dyn_cast<Constant>(opValue)) { - opType = ChooseRegOrImmed(opConst, opCode, target, - (immedPos == (int)op), machineRegNum, - immedValue); - if (opType == MachineOperand::MO_VirtualRegister) - constantThatMustBeLoaded = true; - } - } else { - // - // If the operand is from the constant pool, don't try to change it. - // - if (mop.getType() == MachineOperand::MO_ConstantPoolIndex) { - continue; - } - assert(mop.isImmediate()); - bool isSigned = mop.getType() == MachineOperand::MO_SignExtendedImmed; - - // Bit-selection flags indicate an instruction that is extracting - // bits from its operand so ignore this even if it is a big constant. - if (mop.isHiBits32() || mop.isLoBits32() || - mop.isHiBits64() || mop.isLoBits64()) - continue; - - opType = ChooseRegOrImmed(mop.getImmedValue(), isSigned, - opCode, target, (immedPos == (int)op), - machineRegNum, immedValue); - - if (opType == MachineOperand::MO_SignExtendedImmed || - opType == MachineOperand::MO_UnextendedImmed) { - // The optype is an immediate value - // This means we need to change the opcode, e.g. ADDr -> ADDi - unsigned newOpcode = convertOpcodeFromRegToImm(opCode); - minstr->setOpcode(newOpcode); - } - - if (opType == mop.getType()) - continue; // no change: this is the most common case - - if (opType == MachineOperand::MO_VirtualRegister) { - constantThatMustBeLoaded = true; - opValue = isSigned - ? (Value*)ConstantSInt::get(Type::LongTy, immedValue) - : (Value*)ConstantUInt::get(Type::ULongTy,(uint64_t)immedValue); - } - } - - if (opType == MachineOperand::MO_MachineRegister) - minstr->SetMachineOperandReg(op, machineRegNum); - else if (opType == MachineOperand::MO_SignExtendedImmed || - opType == MachineOperand::MO_UnextendedImmed) { - minstr->SetMachineOperandConst(op, opType, immedValue); - // The optype is or has become an immediate - // This means we need to change the opcode, e.g. ADDr -> ADDi - unsigned newOpcode = convertOpcodeFromRegToImm(opCode); - minstr->setOpcode(newOpcode); - } else if (constantThatMustBeLoaded || - (opValue && isa<GlobalValue>(opValue))) - { // opValue is a constant that must be explicitly loaded into a reg - assert(opValue); - TmpInstruction* tmpReg = InsertCodeToLoadConstant(F, opValue, vmInstr, - MVec, target); - minstr->SetMachineOperandVal(op, MachineOperand::MO_VirtualRegister, - tmpReg); - } - } - - // Also, check for implicit operands used by the machine instruction - // (no need to check those defined since they cannot be constants). - // These include: - // -- arguments to a Call - // -- return value of a Return - // Any such operand that is a constant value needs to be fixed also. - // The current instructions with implicit refs (viz., Call and Return) - // have no immediate fields, so the constant always needs to be loaded - // into a register. - // - bool isCall = instrInfo.isCall(opCode); - unsigned lastCallArgNum = 0; // unused if not a call - CallArgsDescriptor* argDesc = NULL; // unused if not a call - if (isCall) - argDesc = CallArgsDescriptor::get(minstr); - - for (unsigned i=0, N=minstr->getNumImplicitRefs(); i < N; ++i) - if (isa<Constant>(minstr->getImplicitRef(i)) || - isa<GlobalValue>(minstr->getImplicitRef(i))) - { - Value* oldVal = minstr->getImplicitRef(i); - TmpInstruction* tmpReg = - InsertCodeToLoadConstant(F, oldVal, vmInstr, MVec, target); - minstr->setImplicitRef(i, tmpReg); - - if (isCall) { - // find and replace the argument in the CallArgsDescriptor - unsigned i=lastCallArgNum; - while (argDesc->getArgInfo(i).getArgVal() != oldVal) - ++i; - assert(i < argDesc->getNumArgs() && - "Constant operands to a call *must* be in the arg list"); - lastCallArgNum = i; - argDesc->getArgInfo(i).replaceArgVal(tmpReg); - } - } - - return MVec; -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/InstrSelection/Makefile b/llvm/lib/Target/Sparc/InstrSelection/Makefile deleted file mode 100644 index ac44f3a7241..00000000000 --- a/llvm/lib/Target/Sparc/InstrSelection/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- Target/Sparc/InstrSelection/Makefile ----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -DIRS = -LIBRARYNAME = select - -include $(LEVEL)/Makefile.common diff --git a/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.cpp b/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.cpp deleted file mode 100644 index 9f9aaf5ddef..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.cpp +++ /dev/null @@ -1,232 +0,0 @@ -//===-- BBLiveVar.cpp - Live Variable Analysis for a BasicBlock -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a wrapper class for BasicBlock which is used by live var analysis. -// -//===----------------------------------------------------------------------===// - -#include "BBLiveVar.h" -#include "FunctionLiveVarInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Support/CFG.h" -#include "Support/SetOperations.h" -#include "../SparcInternals.h" - -namespace llvm { - -BBLiveVar::BBLiveVar(const BasicBlock &bb, - const MachineBasicBlock &mbb, - unsigned id) - : BB(bb), MBB(mbb), POID(id) { - InSetChanged = OutSetChanged = false; - - calcDefUseSets(); -} - -//----------------------------------------------------------------------------- -// calculates def and use sets for each BB -// There are two passes over operands of a machine instruction. This is -// because, we can have instructions like V = V + 1, since we no longer -// assume single definition. -//----------------------------------------------------------------------------- - -void BBLiveVar::calcDefUseSets() { - // iterate over all the machine instructions in BB - for (MachineBasicBlock::const_reverse_iterator MII = MBB.rbegin(), - MIE = MBB.rend(); MII != MIE; ++MII) { - const MachineInstr *MI = &*MII; - - if (DEBUG_LV >= LV_DEBUG_Verbose) { - std::cerr << " *Iterating over machine instr "; - MI->dump(); - std::cerr << "\n"; - } - - // iterate over MI operands to find defs - for (MachineInstr::const_val_op_iterator OpI = MI->begin(), OpE = MI->end(); - OpI != OpE; ++OpI) - if (OpI.isDef()) // add to Defs if this operand is a def - addDef(*OpI); - - // do for implicit operands as well - for (unsigned i = 0; i < MI->getNumImplicitRefs(); ++i) - if (MI->getImplicitOp(i).isDef()) - addDef(MI->getImplicitRef(i)); - - // iterate over MI operands to find uses - for (MachineInstr::const_val_op_iterator OpI = MI->begin(), OpE = MI->end(); - OpI != OpE; ++OpI) { - const Value *Op = *OpI; - - if (isa<BasicBlock>(Op)) - continue; // don't process labels - - if (OpI.isUse()) { // add to Uses only if this operand is a use - // - // *** WARNING: The following code for handling dummy PHI machine - // instructions is untested. The previous code was broken and I - // fixed it, but it turned out to be unused as long as Phi - // elimination is performed during instruction selection. - // - // Put Phi operands in UseSet for the incoming edge, not node. - // They must not "hide" later defs, and must be handled specially - // during set propagation over the CFG. - if (MI->getOpcode() == V9::PHI) { // for a phi node - const Value *ArgVal = Op; - const BasicBlock *PredBB = cast<BasicBlock>(*++OpI); // next ptr is BB - - PredToEdgeInSetMap[PredBB].insert(ArgVal); - - if (DEBUG_LV >= LV_DEBUG_Verbose) - std::cerr << " - phi operand " << RAV(ArgVal) << " came from BB " - << RAV(PredBB) << "\n"; - } // if( IsPhi ) - else { - // It is not a Phi use: add to regular use set and remove later defs. - addUse(Op); - } - } // if a use - } // for all operands - - // do for implicit operands as well - for (unsigned i = 0; i < MI->getNumImplicitRefs(); ++i) { - assert(MI->getOpcode() != V9::PHI && "Phi cannot have implicit operands"); - const Value *Op = MI->getImplicitRef(i); - - if (Op->getType() == Type::LabelTy) // don't process labels - continue; - - if (MI->getImplicitOp(i).isUse()) - addUse(Op); - } - } // for all machine instructions -} - - - -//----------------------------------------------------------------------------- -// To add an operand which is a def -//----------------------------------------------------------------------------- -void BBLiveVar::addDef(const Value *Op) { - DefSet.insert(Op); // operand is a def - so add to def set - InSet.erase(Op); // this definition kills any later uses - InSetChanged = true; - - if (DEBUG_LV >= LV_DEBUG_Verbose) std::cerr << " +Def: " << RAV(Op) << "\n"; -} - - -//----------------------------------------------------------------------------- -// To add an operand which is a use -//----------------------------------------------------------------------------- -void BBLiveVar::addUse(const Value *Op) { - InSet.insert(Op); // An operand is a use - so add to use set - DefSet.erase(Op); // remove if there is a def below this use - InSetChanged = true; - - if (DEBUG_LV >= LV_DEBUG_Verbose) std::cerr << " Use: " << RAV(Op) << "\n"; -} - - -//----------------------------------------------------------------------------- -// Applies the transfer function to a basic block to produce the InSet using -// the OutSet. -//----------------------------------------------------------------------------- - -bool BBLiveVar::applyTransferFunc() { - // IMPORTANT: caller should check whether the OutSet changed - // (else no point in calling) - - ValueSet OutMinusDef = set_difference(OutSet, DefSet); - InSetChanged = set_union(InSet, OutMinusDef); - - OutSetChanged = false; // no change to OutSet since transf func applied - return InSetChanged; -} - - -//----------------------------------------------------------------------------- -// calculates Out set using In sets of the successors -//----------------------------------------------------------------------------- - -bool BBLiveVar::setPropagate(ValueSet *OutSet, const ValueSet *InSet, - const BasicBlock *PredBB) { - bool Changed = false; - - // merge all members of InSet into OutSet of the predecessor - for (ValueSet::const_iterator InIt = InSet->begin(), InE = InSet->end(); - InIt != InE; ++InIt) - if ((OutSet->insert(*InIt)).second) - Changed = true; - - // - //**** WARNING: The following code for handling dummy PHI machine - // instructions is untested. See explanation above. - // - // then merge all members of the EdgeInSet for the predecessor into the OutSet - const ValueSet& EdgeInSet = PredToEdgeInSetMap[PredBB]; - for (ValueSet::const_iterator InIt = EdgeInSet.begin(), InE = EdgeInSet.end(); - InIt != InE; ++InIt) - if ((OutSet->insert(*InIt)).second) - Changed = true; - // - //**** - - return Changed; -} - - -//----------------------------------------------------------------------------- -// propagates in set to OutSets of PREDECESSORs -//----------------------------------------------------------------------------- - -bool BBLiveVar::applyFlowFunc(hash_map<const BasicBlock*, - BBLiveVar*> &BBLiveVarInfo) { - // IMPORTANT: caller should check whether inset changed - // (else no point in calling) - - // If this BB changed any OutSets of preds whose POID is lower, than we need - // another iteration... - // - bool needAnotherIt = false; - - for (pred_const_iterator PI = pred_begin(&BB), PE = pred_end(&BB); - PI != PE ; ++PI) { - BBLiveVar *PredLVBB = BBLiveVarInfo[*PI]; - - // do set union - if (setPropagate(&PredLVBB->OutSet, &InSet, *PI)) { - PredLVBB->OutSetChanged = true; - - // if the predec POID is lower than mine - if (PredLVBB->getPOId() <= POID) - needAnotherIt = true; - } - } // for - - return needAnotherIt; -} - - - -// ----------------- Methods For Debugging (Printing) ----------------- - -void BBLiveVar::printAllSets() const { - std::cerr << " Defs: "; printSet(DefSet); std::cerr << "\n"; - std::cerr << " In: "; printSet(InSet); std::cerr << "\n"; - std::cerr << " Out: "; printSet(OutSet); std::cerr << "\n"; -} - -void BBLiveVar::printInOutSets() const { - std::cerr << " In: "; printSet(InSet); std::cerr << "\n"; - std::cerr << " Out: "; printSet(OutSet); std::cerr << "\n"; -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.h b/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.h deleted file mode 100644 index 7e5c72e3e46..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/BBLiveVar.h +++ /dev/null @@ -1,90 +0,0 @@ -//===-- BBLiveVar.h - Live Variable Analysis for a BasicBlock ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is a BasicBlock annotation class that is used by live var analysis to -// hold data flow information for a basic block. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVE_VAR_BB_H -#define LIVE_VAR_BB_H - -#include "llvm/CodeGen/ValueSet.h" -#include "Support/hash_map" - -namespace llvm { - -class BasicBlock; -class Value; -class MachineBasicBlock; - -enum LiveVarDebugLevel_t { - LV_DEBUG_None, - LV_DEBUG_Normal, - LV_DEBUG_Instr, - LV_DEBUG_Verbose -}; - -extern LiveVarDebugLevel_t DEBUG_LV; - -class BBLiveVar { - const BasicBlock &BB; // pointer to BasicBlock - const MachineBasicBlock &MBB; // Pointer to MachineBasicBlock - unsigned POID; // Post-Order ID - - ValueSet DefSet; // Def set (with no preceding uses) for LV analysis - ValueSet InSet, OutSet; // In & Out for LV analysis - bool InSetChanged, OutSetChanged; // set if the InSet/OutSet is modified - - // map that contains PredBB -> Phi arguments - // coming in on that edge. such uses have to be - // treated differently from ordinary uses. - hash_map<const BasicBlock *, ValueSet> PredToEdgeInSetMap; - - // method to propagate an InSet to OutSet of a predecessor - bool setPropagate(ValueSet *OutSetOfPred, - const ValueSet *InSetOfThisBB, - const BasicBlock *PredBB); - - // To add an operand which is a def - void addDef(const Value *Op); - - // To add an operand which is a use - void addUse(const Value *Op); - - void calcDefUseSets(); // calculates the Def & Use sets for this BB -public: - - BBLiveVar(const BasicBlock &BB, const MachineBasicBlock &MBB, unsigned POID); - - inline bool isInSetChanged() const { return InSetChanged; } - inline bool isOutSetChanged() const { return OutSetChanged; } - - const MachineBasicBlock &getMachineBasicBlock() const { return MBB; } - - inline unsigned getPOId() const { return POID; } - - bool applyTransferFunc(); // calcultes the In in terms of Out - - // calculates Out set using In sets of the predecessors - bool applyFlowFunc(hash_map<const BasicBlock*, BBLiveVar*> &BBLiveVarInfo); - - inline const ValueSet &getOutSet() const { return OutSet; } - inline ValueSet &getOutSet() { return OutSet; } - - inline const ValueSet &getInSet() const { return InSet; } - inline ValueSet &getInSet() { return InSet; } - - void printAllSets() const; // for printing Def/In/Out sets - void printInOutSets() const; // for printing In/Out sets -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.cpp b/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.cpp deleted file mode 100644 index 9d5492371a7..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.cpp +++ /dev/null @@ -1,322 +0,0 @@ -//===-- FunctionLiveVarInfo.cpp - Live Variable Analysis for a Function ---===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the interface to function level live variable information that is -// provided by live variable analysis. -// -//===----------------------------------------------------------------------===// - -#include "FunctionLiveVarInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Support/CFG.h" -#include "Support/PostOrderIterator.h" -#include "Support/SetOperations.h" -#include "Support/CommandLine.h" -#include "BBLiveVar.h" - -namespace llvm { - -static RegisterAnalysis<FunctionLiveVarInfo> -X("livevar", "Live Variable Analysis"); - -LiveVarDebugLevel_t DEBUG_LV; - -static cl::opt<LiveVarDebugLevel_t, true> -DEBUG_LV_opt("dlivevar", cl::Hidden, cl::location(DEBUG_LV), - cl::desc("enable live-variable debugging information"), - cl::values( -clEnumValN(LV_DEBUG_None , "n", "disable debug output"), -clEnumValN(LV_DEBUG_Normal , "y", "enable debug output"), -clEnumValN(LV_DEBUG_Instr, "i", "print live-var sets before/after " - "every machine instrn"), -clEnumValN(LV_DEBUG_Verbose, "v", "print def, use sets for every instrn also"), - 0)); - - - -//----------------------------------------------------------------------------- -// Accessor Functions -//----------------------------------------------------------------------------- - -// gets OutSet of a BB -const ValueSet &FunctionLiveVarInfo::getOutSetOfBB(const BasicBlock *BB) const { - return BBLiveVarInfo.find(BB)->second->getOutSet(); -} - ValueSet &FunctionLiveVarInfo::getOutSetOfBB(const BasicBlock *BB) { - return BBLiveVarInfo[BB]->getOutSet(); -} - -// gets InSet of a BB -const ValueSet &FunctionLiveVarInfo::getInSetOfBB(const BasicBlock *BB) const { - return BBLiveVarInfo.find(BB)->second->getInSet(); -} -ValueSet &FunctionLiveVarInfo::getInSetOfBB(const BasicBlock *BB) { - return BBLiveVarInfo[BB]->getInSet(); -} - - -//----------------------------------------------------------------------------- -// Performs live var analysis for a function -//----------------------------------------------------------------------------- - -bool FunctionLiveVarInfo::runOnFunction(Function &F) { - M = &F; - if (DEBUG_LV) std::cerr << "Analysing live variables ...\n"; - - // create and initialize all the BBLiveVars of the CFG - constructBBs(M); - - unsigned int iter=0; - while (doSingleBackwardPass(M, iter++)) - ; // Iterate until we are done. - - if (DEBUG_LV) std::cerr << "Live Variable Analysis complete!\n"; - return false; -} - - -//----------------------------------------------------------------------------- -// constructs BBLiveVars and init Def and In sets -//----------------------------------------------------------------------------- - -void FunctionLiveVarInfo::constructBBs(const Function *F) { - unsigned POId = 0; // Reverse Depth-first Order ID - std::map<const BasicBlock*, unsigned> PONumbering; - - for (po_iterator<const Function*> BBI = po_begin(M), BBE = po_end(M); - BBI != BBE; ++BBI) - PONumbering[*BBI] = POId++; - - MachineFunction &MF = MachineFunction::get(F); - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { - const BasicBlock &BB = *I->getBasicBlock(); // get the current BB - if (DEBUG_LV) std::cerr << " For BB " << RAV(BB) << ":\n"; - - BBLiveVar *LVBB; - std::map<const BasicBlock*, unsigned>::iterator POI = PONumbering.find(&BB); - if (POI != PONumbering.end()) { - // create a new BBLiveVar - LVBB = new BBLiveVar(BB, *I, POId); - } else { - // The PO iterator does not discover unreachable blocks, but the random - // iterator later may access these blocks. We must make sure to - // initialize unreachable blocks as well. However, LV info is not correct - // for those blocks (they are not analyzed) - // - LVBB = new BBLiveVar(BB, *I, ++POId); - } - BBLiveVarInfo[&BB] = LVBB; - - if (DEBUG_LV) - LVBB->printAllSets(); - } -} - - -//----------------------------------------------------------------------------- -// do one backward pass over the CFG (for iterative analysis) -//----------------------------------------------------------------------------- - -bool FunctionLiveVarInfo::doSingleBackwardPass(const Function *M, - unsigned iter) { - if (DEBUG_LV) std::cerr << "\n After Backward Pass " << iter << "...\n"; - - bool NeedAnotherIteration = false; - for (po_iterator<const Function*> BBI = po_begin(M), BBE = po_end(M); - BBI != BBE; ++BBI) { - BBLiveVar *LVBB = BBLiveVarInfo[*BBI]; - assert(LVBB && "BasicBlock information not set for block!"); - - if (DEBUG_LV) std::cerr << " For BB " << (*BBI)->getName() << ":\n"; - - // InSets are initialized to "GenSet". Recompute only if OutSet changed. - if(LVBB->isOutSetChanged()) - LVBB->applyTransferFunc(); // apply the Tran Func to calc InSet - - // OutSets are initialized to EMPTY. Recompute on first iter or if InSet - // changed. - if (iter == 0 || LVBB->isInSetChanged()) // to calc Outsets of preds - NeedAnotherIteration |= LVBB->applyFlowFunc(BBLiveVarInfo); - - if (DEBUG_LV) LVBB->printInOutSets(); - } - - // true if we need to reiterate over the CFG - return NeedAnotherIteration; -} - - -void FunctionLiveVarInfo::releaseMemory() { - // First remove all BBLiveVars created in constructBBs(). - if (M) { - for (Function::const_iterator I = M->begin(), E = M->end(); I != E; ++I) - delete BBLiveVarInfo[I]; - BBLiveVarInfo.clear(); - } - M = 0; - - // Then delete all objects of type ValueSet created in calcLiveVarSetsForBB - // and entered into MInst2LVSetBI and MInst2LVSetAI (these are caches - // to return ValueSet's before/after a machine instruction quickly). - // We do not need to free up ValueSets in MInst2LVSetAI because it holds - // pointers to the same sets as in MInst2LVSetBI (for all instructions - // except the last one in a BB) or in BBLiveVar (for the last instruction). - // - for (hash_map<const MachineInstr*, ValueSet*>::iterator - MI = MInst2LVSetBI.begin(), - ME = MInst2LVSetBI.end(); MI != ME; ++MI) - delete MI->second; // delete all ValueSets in MInst2LVSetBI - - MInst2LVSetBI.clear(); - MInst2LVSetAI.clear(); -} - - - - -//----------------------------------------------------------------------------- -// Following functions will give the LiveVar info for any machine instr in -// a function. It should be called after a call to analyze(). -// -// These functions calculate live var info for all the machine instrs in a -// BB when LVInfo for one inst is requested. Hence, this function is useful -// when live var info is required for many (or all) instructions in a basic -// block. Also, the arguments to this function does not require specific -// iterators. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Gives live variable information before a machine instruction -//----------------------------------------------------------------------------- - -const ValueSet & -FunctionLiveVarInfo::getLiveVarSetBeforeMInst(const MachineInstr *MI, - const BasicBlock *BB) { - ValueSet* &LVSet = MInst2LVSetBI[MI]; // ref. to map entry - if (LVSet == NULL && BB != NULL) { // if not found and BB provided - calcLiveVarSetsForBB(BB); // calc LVSet for all instrs in BB - assert(LVSet != NULL); - } - return *LVSet; -} - - -//----------------------------------------------------------------------------- -// Gives live variable information after a machine instruction -//----------------------------------------------------------------------------- - -const ValueSet & -FunctionLiveVarInfo::getLiveVarSetAfterMInst(const MachineInstr *MI, - const BasicBlock *BB) { - - ValueSet* &LVSet = MInst2LVSetAI[MI]; // ref. to map entry - if (LVSet == NULL && BB != NULL) { // if not found and BB provided - calcLiveVarSetsForBB(BB); // calc LVSet for all instrs in BB - assert(LVSet != NULL); - } - return *LVSet; -} - -// This function applies a machine instr to a live var set (accepts OutSet) and -// makes necessary changes to it (produces InSet). Note that two for loops are -// used to first kill all defs and then to add all uses. This is because there -// can be instructions like Val = Val + 1 since we allow multiple defs to a -// machine instruction operand. -// -static void applyTranferFuncForMInst(ValueSet &LVS, const MachineInstr *MInst) { - for (MachineInstr::const_val_op_iterator OpI = MInst->begin(), - OpE = MInst->end(); OpI != OpE; ++OpI) { - if (OpI.isDef()) // kill if this operand is a def - LVS.erase(*OpI); // this definition kills any uses - } - - // do for implicit operands as well - for (unsigned i=0; i < MInst->getNumImplicitRefs(); ++i) { - if (MInst->getImplicitOp(i).isDef()) - LVS.erase(MInst->getImplicitRef(i)); - } - - for (MachineInstr::const_val_op_iterator OpI = MInst->begin(), - OpE = MInst->end(); OpI != OpE; ++OpI) { - if (!isa<BasicBlock>(*OpI)) // don't process labels - // add only if this operand is a use - if (OpI.isUse()) - LVS.insert(*OpI); // An operand is a use - so add to use set - } - - // do for implicit operands as well - for (unsigned i = 0, e = MInst->getNumImplicitRefs(); i != e; ++i) - if (MInst->getImplicitOp(i).isUse()) - LVS.insert(MInst->getImplicitRef(i)); -} - -//----------------------------------------------------------------------------- -// This method calculates the live variable information for all the -// instructions in a basic block and enter the newly constructed live -// variable sets into a the caches (MInst2LVSetAI, MInst2LVSetBI) -//----------------------------------------------------------------------------- - -void FunctionLiveVarInfo::calcLiveVarSetsForBB(const BasicBlock *BB) { - BBLiveVar *BBLV = BBLiveVarInfo[BB]; - assert(BBLV && "BBLiveVar annotation doesn't exist?"); - const MachineBasicBlock &MIVec = BBLV->getMachineBasicBlock(); - const MachineFunction &MF = MachineFunction::get(M); - const TargetMachine &TM = MF.getTarget(); - - if (DEBUG_LV >= LV_DEBUG_Instr) - std::cerr << "\n======For BB " << BB->getName() - << ": Live var sets for instructions======\n"; - - ValueSet *SetAI = &getOutSetOfBB(BB); // init SetAI with OutSet - ValueSet CurSet(*SetAI); // CurSet now contains OutSet - - // iterate over all the machine instructions in BB - for (MachineBasicBlock::const_reverse_iterator MII = MIVec.rbegin(), - MIE = MIVec.rend(); MII != MIE; ++MII) { - // MI is cur machine inst - const MachineInstr *MI = &*MII; - - MInst2LVSetAI[MI] = SetAI; // record in After Inst map - - applyTranferFuncForMInst(CurSet, MI); // apply the transfer Func - ValueSet *NewSet = new ValueSet(CurSet); // create a new set with a copy - // of the set after T/F - MInst2LVSetBI[MI] = NewSet; // record in Before Inst map - - // If the current machine instruction has delay slots, mark values - // used by this instruction as live before and after each delay slot - // instruction (After(MI) is the same as Before(MI+1) except for last MI). - if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(MI->getOpcode())) { - MachineBasicBlock::const_iterator fwdMII = MII.base(); // ptr to *next* MI - for (unsigned i = 0; i < DS; ++i, ++fwdMII) { - assert(fwdMII != MIVec.end() && "Missing instruction in delay slot?"); - const MachineInstr* DelaySlotMI = fwdMII; - if (! TM.getInstrInfo().isNop(DelaySlotMI->getOpcode())) { - set_union(*MInst2LVSetBI[DelaySlotMI], *NewSet); - if (i+1 == DS) - set_union(*MInst2LVSetAI[DelaySlotMI], *NewSet); - } - } - } - - if (DEBUG_LV >= LV_DEBUG_Instr) { - std::cerr << "\nLive var sets before/after instruction " << *MI; - std::cerr << " Before: "; printSet(*NewSet); std::cerr << "\n"; - std::cerr << " After : "; printSet(*SetAI); std::cerr << "\n"; - } - - // SetAI will be used in the next iteration - SetAI = NewSet; - } -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.h b/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.h deleted file mode 100644 index 23a9d93a6eb..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/FunctionLiveVarInfo.h +++ /dev/null @@ -1,111 +0,0 @@ -//===-- CodeGen/FunctionLiveVarInfo.h - LiveVar Analysis --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the interface for live variable info of a function that is required -// by any other part of the compiler -// -// After the analysis, getInSetOfBB or getOutSetofBB can be called to get -// live var info of a BB. -// -// The live var set before an instruction can be obtained in 2 ways: -// -// 1. Use the method getLiveVarSetAfterInst(Instruction *) to get the LV Info -// just after an instruction. (also exists getLiveVarSetBeforeInst(..)) -// -// This function caluclates the LV info for a BB only once and caches that -// info. If the cache does not contain the LV info of the instruction, it -// calculates the LV info for the whole BB and caches them. -// -// Getting liveVar info this way uses more memory since, LV info should be -// cached. However, if you need LV info of nearly all the instructions of a -// BB, this is the best and simplest interfrace. -// -// 2. Use the OutSet and applyTranferFuncForInst(const Instruction *const Inst) -// declared in LiveVarSet and traverse the instructions of a basic block in -// reverse (using const_reverse_iterator in the BB class). -// -//===----------------------------------------------------------------------===// - -#ifndef FUNCTION_LIVE_VAR_INFO_H -#define FUNCTION_LIVE_VAR_INFO_H - -#include "Support/hash_map" -#include "llvm/Pass.h" -#include "llvm/CodeGen/ValueSet.h" - -namespace llvm { - -class BBLiveVar; -class MachineInstr; - -class FunctionLiveVarInfo : public FunctionPass { - // Machine Instr to LiveVarSet Map for providing LVset BEFORE each inst - // These sets are owned by this map and will be freed in releaseMemory(). - hash_map<const MachineInstr *, ValueSet *> MInst2LVSetBI; - - // Machine Instr to LiveVarSet Map for providing LVset AFTER each inst. - // These sets are just pointers to sets in MInst2LVSetBI or BBLiveVar. - hash_map<const MachineInstr *, ValueSet *> MInst2LVSetAI; - - hash_map<const BasicBlock*, BBLiveVar*> BBLiveVarInfo; - - // Stored Function that the data is computed with respect to - const Function *M; - - // --------- private methods ----------------------------------------- - - // constructs BBLiveVars and init Def and In sets - void constructBBs(const Function *F); - - // do one backward pass over the CFG - bool doSingleBackwardPass(const Function *F, unsigned int iter); - - // calculates live var sets for instructions in a BB - void calcLiveVarSetsForBB(const BasicBlock *BB); - -public: - // --------- Implement the FunctionPass interface ---------------------- - - // runOnFunction - Perform analysis, update internal data structures. - virtual bool runOnFunction(Function &F); - - // releaseMemory - After LiveVariable analysis has been used, forget! - virtual void releaseMemory(); - - // getAnalysisUsage - Provide self! - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } - - // --------- Functions to access analysis results ------------------- - - // get OutSet of a BB - const ValueSet &getOutSetOfBB(const BasicBlock *BB) const; - ValueSet &getOutSetOfBB(const BasicBlock *BB) ; - - // get InSet of a BB - const ValueSet &getInSetOfBB(const BasicBlock *BB) const; - ValueSet &getInSetOfBB(const BasicBlock *BB) ; - - // gets the Live var set BEFORE an instruction. - // if BB is specified and the live var set has not yet been computed, - // it will be computed on demand. - const ValueSet &getLiveVarSetBeforeMInst(const MachineInstr *MI, - const BasicBlock *BB = 0); - - // gets the Live var set AFTER an instruction - // if BB is specified and the live var set has not yet been computed, - // it will be computed on demand. - const ValueSet &getLiveVarSetAfterMInst(const MachineInstr *MI, - const BasicBlock *BB = 0); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/LiveVar/Makefile b/llvm/lib/Target/Sparc/LiveVar/Makefile deleted file mode 100644 index 90a664e56ce..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- lib/Target/Sparc/LiveVar/Makefile -------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = livevar - -include $(LEVEL)/Makefile.common - diff --git a/llvm/lib/Target/Sparc/LiveVar/ValueSet.cpp b/llvm/lib/Target/Sparc/LiveVar/ValueSet.cpp deleted file mode 100644 index fd8289675a2..00000000000 --- a/llvm/lib/Target/Sparc/LiveVar/ValueSet.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// FIXME: Eliminate this file. - -#include "llvm/CodeGen/ValueSet.h" -#include "llvm/Value.h" -#include <iostream> - -namespace llvm { - -std::ostream &operator<<(std::ostream &O, RAV V) { // func to print a Value - const Value &v = V.V; - if (v.hasName()) - return O << (void*)&v << "(" << v.getName() << ") "; - else if (isa<Constant>(v)) - return O << (void*)&v << "(" << v << ") "; - else - return O << (void*)&v << " "; -} - -void printSet(const ValueSet &S) { - for (ValueSet::const_iterator I = S.begin(), E = S.end(); I != E; ++I) - std::cerr << RAV(*I); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/Makefile b/llvm/lib/Target/Sparc/Makefile deleted file mode 100644 index 619c9d02e7c..00000000000 --- a/llvm/lib/Target/Sparc/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -##===- lib/Target/Sparc/Makefile ---------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../.. -LIBRARYNAME = sparc -DIRS = InstrSelection RegAlloc LiveVar - -ExtraSource = Sparc.burm.cpp - -include $(LEVEL)/Makefile.common - -ifdef ENABLE_OPTIMIZED - DEBUG_FLAG = -else - DEBUG_FLAG = -D_DEBUG -endif - -Sparc.burg.in1 : $(SourceDir)/Sparc.burg.in - $(CXX) -E -I$(LLVM_SRC_ROOT)/include $(DEBUG_FLAG) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/Ydefine/#define/' > $@ - -Sparc.burm : Sparc.burg.in1 - $(CXX) -E -I$(LLVM_SRC_ROOT)/include $(DEBUG_FLAG) -x c++ $< | $(SED) '/^#/d' | $(SED) 's/^Xinclude/#include/' | $(SED) 's/^Xdefine/#define/' > $@ - -Sparc.burm.cpp: Sparc.burm - @echo "Burging `basename $<`" - $(RunBurg) $< -o $@ - -$(BUILD_OBJ_DIR)/Debug/Sparc.burm.lo: Sparc.burm.cpp - $(CompileG) $< -o $@ - -$(BUILD_OBJ_DIR)/Release/Sparc.burm.lo: Sparc.burm.cpp - $(CompileO) $< -o $@ - -$(BUILD_OBJ_DIR)/Profile/Sparc.burm.lo: Sparc.burm.cpp - $(CompileP) $< -o $@ - -$(BUILD_OBJ_DIR)/Depend/Sparc.burm.d: $(BUILD_OBJ_DIR)/Depend/.dir - touch $@ - -TARGET_NAME := SparcV9 - -TABLEGEN_FILES := $(notdir $(wildcard $(SourceDir)/*.td)) - -# Make sure that tblgen is run, first thing. -$(SourceDepend): $(TARGET_NAME)CodeEmitter.inc - -$(TARGET_NAME)CodeEmitter.cpp:: $(TARGET_NAME)CodeEmitter.inc - -$(TARGET_NAME)CodeEmitter.inc:: $(SourceDir)/$(TARGET_NAME).td $(TABLEGEN_FILES) $(TBLGEN) - @echo "Tblgen'ing `basename $<`" - $(TBLGEN) -I $(SourceDir) $< -gen-emitter -o $@ - -clean:: - $(RM) -f $(TARGET_NAME)CodeEmitter.inc Sparc.burg.in1 Sparc.burm Sparc.burm.cpp - diff --git a/llvm/lib/Target/Sparc/MappingInfo.cpp b/llvm/lib/Target/Sparc/MappingInfo.cpp deleted file mode 100644 index 4648c54e48e..00000000000 --- a/llvm/lib/Target/Sparc/MappingInfo.cpp +++ /dev/null @@ -1,299 +0,0 @@ -//===- MappingInfo.cpp - create LLVM info and output to .s file ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains a FunctionPass called MappingInfoAsmPrinter, -// which creates two maps: one between LLVM Instructions and MachineInstrs -// (the "LLVM I TO MI MAP"), and another between MachineBasicBlocks and -// MachineInstrs (the "BB TO MI MAP"). -// -// As a side effect, it outputs this information as .byte directives to -// the assembly file. The output is designed to survive the SPARC assembler, -// in order that the Reoptimizer may read it in from memory later when the -// binary is loaded. Therefore, it may contain some hidden SPARC-architecture -// dependencies. Currently this question is purely theoretical as the -// Reoptimizer works only on the SPARC. -// -// The LLVM I TO MI MAP consists of a set of information for each -// BasicBlock in a Function, ordered from begin() to end(). The information -// for a BasicBlock consists of -// 1) its (0-based) index in the Function, -// 2) the number of LLVM Instructions it contains, and -// 3) information for each Instruction, in sequence from the begin() -// to the end() of the BasicBlock. The information for an Instruction -// consists of -// 1) its (0-based) index in the BasicBlock, -// 2) the number of MachineInstrs that correspond to that Instruction -// (as reported by MachineCodeForInstruction), and -// 3) the MachineInstr number calculated by create_MI_to_number_Key, -// for each of the MachineInstrs that correspond to that Instruction. -// -// The BB TO MI MAP consists of a three-element tuple for each -// MachineBasicBlock in a function, ordered from begin() to end() of -// its MachineFunction: first, the index of the MachineBasicBlock in the -// function; second, the number of the MachineBasicBlock in the function -// as computed by create_BB_to_MInumber_Key; and third, the number of -// MachineInstrs in the MachineBasicBlock. -// -//===--------------------------------------------------------------------===// - -#include "MappingInfo.h" -#include "llvm/Pass.h" -#include "llvm/Module.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "Support/StringExtras.h" - -namespace llvm { - -namespace { - class MappingInfoAsmPrinter : public FunctionPass { - std::ostream &Out; - public: - MappingInfoAsmPrinter(std::ostream &out) : Out(out){} - const char *getPassName () const { return "Instr. Mapping Info Collector"; } - bool runOnFunction(Function &FI); - typedef std::map<const MachineInstr*, unsigned> InstructionKey; - private: - MappingInfo *currentOutputMap; - std::map<Function *, unsigned> Fkey; // Function # for all functions. - bool doInitialization(Module &M); - void create_BB_to_MInumber_Key(Function &FI, InstructionKey &key); - void create_MI_to_number_Key(Function &FI, InstructionKey &key); - void buildBBMIMap (Function &FI, MappingInfo &Map); - void buildLMIMap (Function &FI, MappingInfo &Map); - void writeNumber(unsigned X); - void selectOutputMap (MappingInfo &m) { currentOutputMap = &m; } - void outByte (unsigned char b) { currentOutputMap->outByte (b); } - bool doFinalization (Module &M); - }; -} - -/// getMappingInfoAsmPrinterPass - Static factory method: returns a new -/// MappingInfoAsmPrinter Pass object, which uses OUT as its output -/// stream for assembly output. -/// -Pass *getMappingInfoAsmPrinterPass(std::ostream &out){ - return (new MappingInfoAsmPrinter(out)); -} - -/// runOnFunction - Builds up the maps for the given function FI and then -/// writes them out as assembly code to the current output stream OUT. -/// This is an entry point to the pass, called by the PassManager. -/// -bool MappingInfoAsmPrinter::runOnFunction(Function &FI) { - unsigned num = Fkey[&FI]; // Function number for the current function. - - // Create objects to hold the maps. - MappingInfo LMIMap ("LLVM I TO MI MAP", "LMIMap", num); - MappingInfo BBMIMap ("BB TO MI MAP", "BBMIMap", num); - - // Now, build the maps. - buildLMIMap (FI, LMIMap); - buildBBMIMap (FI, BBMIMap); - - // Now, write out the maps. - LMIMap.dumpAssembly (Out); - BBMIMap.dumpAssembly (Out); - - return false; -} - -/// writeNumber - Write out the number X as a sequence of .byte -/// directives to the current output stream Out. This method performs a -/// run-length encoding of the unsigned integers X that are output. -/// -void MappingInfoAsmPrinter::writeNumber(unsigned X) { - unsigned i=0; - do { - unsigned tmp = X & 127; - X >>= 7; - if (X) tmp |= 128; - outByte (tmp); - ++i; - } while(X); -} - -/// doInitialization - Assign a number to each Function, as follows: -/// Functions are numbered starting at 0 at the begin() of each Module. -/// Functions which are External (and thus have 0 basic blocks) are not -/// inserted into the maps, and are not assigned a number. The side-effect -/// of this method is to fill in Fkey to contain the mapping from Functions -/// to numbers. (This method is called automatically by the PassManager.) -/// -bool MappingInfoAsmPrinter::doInitialization(Module &M) { - unsigned i = 0; - for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { - if (FI->isExternal()) continue; - Fkey[FI] = i; - ++i; - } - return false; // Success. -} - -/// create_BB_to_MInumber_Key -- Assign a number to each MachineBasicBlock -/// in the given Function, as follows: Numbering starts at zero in each -/// Function. MachineBasicBlocks are numbered from begin() to end() -/// in the Function's corresponding MachineFunction. Each successive -/// MachineBasicBlock increments the numbering by the number of instructions -/// it contains. The side-effect of this method is to fill in the parameter -/// KEY with the mapping of MachineBasicBlocks to numbers. KEY -/// is keyed on MachineInstrs, so each MachineBasicBlock is represented -/// therein by its first MachineInstr. -/// -void MappingInfoAsmPrinter::create_BB_to_MInumber_Key(Function &FI, - InstructionKey &key) { - unsigned i = 0; - MachineFunction &MF = MachineFunction::get(&FI); - for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); - BI != BE; ++BI) { - MachineBasicBlock &miBB = *BI; - key[&miBB.front()] = i; - i = i+(miBB.size()); - } -} - -/// create_MI_to_number_Key - Assign a number to each MachineInstr -/// in the given Function with respect to its enclosing MachineBasicBlock, as -/// follows: Numberings start at 0 in each MachineBasicBlock. MachineInstrs -/// are numbered from begin() to end() in their MachineBasicBlock. Each -/// MachineInstr is numbered, then the numbering is incremented by 1. The -/// side-effect of this method is to fill in the parameter KEY -/// with the mapping from MachineInstrs to numbers. -/// -void MappingInfoAsmPrinter::create_MI_to_number_Key(Function &FI, - InstructionKey &key) { - MachineFunction &MF = MachineFunction::get(&FI); - for (MachineFunction::iterator BI=MF.begin(), BE=MF.end(); BI != BE; ++BI) { - MachineBasicBlock &miBB = *BI; - unsigned j = 0; - for(MachineBasicBlock::iterator miI = miBB.begin(), miE = miBB.end(); - miI != miE; ++miI, ++j) { - key[miI] = j; - } - } -} - -/// buildBBMIMap - Build the BB TO MI MAP for the function FI, -/// and save it into the parameter MAP. -/// -void MappingInfoAsmPrinter::buildBBMIMap(Function &FI, MappingInfo &Map) { - unsigned bb = 0; - - // First build temporary table used to write out the map. - InstructionKey BBkey; - create_BB_to_MInumber_Key(FI, BBkey); - - selectOutputMap (Map); - MachineFunction &MF = MachineFunction::get(&FI); - for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); - BI != BE; ++BI, ++bb) { - MachineBasicBlock &miBB = *BI; - writeNumber(bb); - writeNumber(BBkey[&miBB.front()]); - writeNumber(miBB.size()); - } -} - -/// buildLMIMap - Build the LLVM I TO MI MAP for the function FI, -/// and save it into the parameter MAP. -/// -void MappingInfoAsmPrinter::buildLMIMap(Function &FI, MappingInfo &Map) { - unsigned bb = 0; - // First build temporary table used to write out the map. - InstructionKey MIkey; - create_MI_to_number_Key(FI, MIkey); - - selectOutputMap (Map); - for (Function::iterator BI = FI.begin(), BE = FI.end(); - BI != BE; ++BI, ++bb) { - unsigned li = 0; - writeNumber(bb); - writeNumber(BI->size()); - for (BasicBlock::iterator II = BI->begin(), IE = BI->end(); II != IE; - ++II, ++li) { - MachineCodeForInstruction& miI = MachineCodeForInstruction::get(II); - writeNumber(li); - writeNumber(miI.size()); - for (MachineCodeForInstruction::iterator miII = miI.begin(), - miIE = miI.end(); miII != miIE; ++miII) { - writeNumber(MIkey[*miII]); - } - } - } -} - -void MappingInfo::byteVector::dumpAssembly (std::ostream &Out) { - for (iterator i = begin (), e = end (); i != e; ++i) - Out << ".byte " << (int)*i << "\n"; -} - -static void writePrologue (std::ostream &Out, const std::string &comment, - const std::string &symName) { - // Prologue: - // Output a comment describing the object. - Out << "!" << comment << "\n"; - // Switch the current section to .rodata in the assembly output: - Out << "\t.section \".rodata\"\n\t.align 8\n"; - // Output a global symbol naming the object: - Out << "\t.global " << symName << "\n"; - Out << "\t.type " << symName << ",#object\n"; - Out << symName << ":\n"; -} - -static void writeEpilogue (std::ostream &Out, const std::string &symName) { - // Epilogue: - // Output a local symbol marking the end of the object: - Out << ".end_" << symName << ":\n"; - // Output size directive giving the size of the object: - Out << "\t.size " << symName << ", .end_" << symName << "-" << symName - << "\n"; -} - -void MappingInfo::dumpAssembly (std::ostream &Out) { - const std::string &name (symbolPrefix + utostr (functionNumber)); - writePrologue (Out, comment, name); - // The LMIMap and BBMIMap are supposed to start with a length word: - Out << "\t.word .end_" << name << "-" << name << "\n"; - bytes.dumpAssembly (Out); - writeEpilogue (Out, name); -} - -/// doFinalization - This method writes out two tables, named -/// FunctionBB and FunctionLI, which map Function numbers (as in -/// doInitialization) to the BBMIMap and LMIMap tables. (This used to -/// be the "FunctionInfo" pass.) -/// -bool MappingInfoAsmPrinter::doFinalization (Module &M) { - unsigned f; - - writePrologue(Out, "FUNCTION TO BB MAP", "FunctionBB"); - f=0; - for(Module::iterator FI = M.begin (), FE = M.end (); FE != FI; ++FI) { - if (FI->isExternal ()) - continue; - Out << "\t.xword BBMIMap" << f << "\n"; - ++f; - } - writeEpilogue(Out, "FunctionBB"); - - writePrologue(Out, "FUNCTION TO LI MAP", "FunctionLI"); - f=0; - for(Module::iterator FI = M.begin (), FE = M.end (); FE != FI; ++FI) { - if (FI->isExternal ()) - continue; - Out << "\t.xword LMIMap" << f << "\n"; - ++f; - } - writeEpilogue(Out, "FunctionLI"); - - return false; -} - -} // End llvm namespace - diff --git a/llvm/lib/Target/Sparc/MappingInfo.h b/llvm/lib/Target/Sparc/MappingInfo.h deleted file mode 100644 index 6af116a6da2..00000000000 --- a/llvm/lib/Target/Sparc/MappingInfo.h +++ /dev/null @@ -1,49 +0,0 @@ -//===- lib/Target/Sparc/MappingInfo.h ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Data structures to support the Reoptimizer's Instruction-to-MachineInstr -// mapping information gatherer. -// -//===----------------------------------------------------------------------===// - -#ifndef MAPPINGINFO_H -#define MAPPINGINFO_H - -#include <iosfwd> -#include <vector> -#include <string> - -namespace llvm { - -class Pass; - -Pass *getMappingInfoAsmPrinterPass(std::ostream &out); - -class MappingInfo { - struct byteVector : public std::vector <unsigned char> { - void dumpAssembly (std::ostream &Out); - }; - std::string comment; - std::string symbolPrefix; - unsigned functionNumber; - byteVector bytes; -public: - void outByte (unsigned char b) { bytes.push_back (b); } - MappingInfo (std::string Comment, std::string SymbolPrefix, - unsigned FunctionNumber) : comment(Comment), - symbolPrefix(SymbolPrefix), functionNumber(FunctionNumber) {} - void dumpAssembly (std::ostream &Out); - unsigned char *getBytes (unsigned &length) { - length = bytes.size(); return &bytes[0]; - } -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/PeepholeOpts.cpp b/llvm/lib/Target/Sparc/PeepholeOpts.cpp deleted file mode 100644 index dc56100a1eb..00000000000 --- a/llvm/lib/Target/Sparc/PeepholeOpts.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===-- PeepholeOpts.cpp --------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Support for performing several peephole opts in one or a few passes over the -// machine code of a method. -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" -#include "llvm/BasicBlock.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "Support/STLExtras.h" - -namespace llvm { - -//************************* Internal Functions *****************************/ - -static inline void -DeleteInstruction(MachineBasicBlock& mvec, - MachineBasicBlock::iterator& BBI, - const TargetMachine& target) { - // Check if this instruction is in a delay slot of its predecessor. - if (BBI != mvec.begin()) { - const TargetInstrInfo& mii = target.getInstrInfo(); - MachineBasicBlock::iterator predMI = prior(BBI); - if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpcode())) { - // This instruction is in a delay slot of its predecessor, so - // replace it with a nop. By replacing in place, we save having - // to update the I-I maps. - // - assert(ndelay == 1 && "Not yet handling multiple-delay-slot targets"); - BBI->replace(mii.getNOPOpCode(), 0); - return; - } - } - - // The instruction is not in a delay slot, so we can simply erase it. - mvec.erase(BBI); - BBI = mvec.end(); -} - -//******************* Individual Peephole Optimizations ********************/ - -//---------------------------------------------------------------------------- -// Function: IsUselessCopy -// Decide whether a machine instruction is a redundant copy: -// -- ADD with g0 and result and operand are identical, or -// -- OR with g0 and result and operand are identical, or -// -- FMOVS or FMOVD and result and operand are identical. -// Other cases are possible but very rare that they would be useless copies, -// so it's not worth analyzing them. -//---------------------------------------------------------------------------- - -static bool IsUselessCopy(const TargetMachine &target, const MachineInstr* MI) { - if (MI->getOpcode() == V9::FMOVS || MI->getOpcode() == V9::FMOVD) { - return (// both operands are allocated to the same register - MI->getOperand(0).getReg() == MI->getOperand(1).getReg()); - } else if (MI->getOpcode() == V9::ADDr || MI->getOpcode() == V9::ORr || - MI->getOpcode() == V9::ADDi || MI->getOpcode() == V9::ORi) { - unsigned srcWithDestReg; - - for (srcWithDestReg = 0; srcWithDestReg < 2; ++srcWithDestReg) - if (MI->getOperand(srcWithDestReg).hasAllocatedReg() && - MI->getOperand(srcWithDestReg).getReg() - == MI->getOperand(2).getReg()) - break; - - if (srcWithDestReg == 2) - return false; - else { - // else source and dest are allocated to the same register - unsigned otherOp = 1 - srcWithDestReg; - return (// either operand otherOp is register %g0 - (MI->getOperand(otherOp).hasAllocatedReg() && - MI->getOperand(otherOp).getReg() == - target.getRegInfo().getZeroRegNum()) || - - // or operand otherOp == 0 - (MI->getOperand(otherOp).getType() - == MachineOperand::MO_SignExtendedImmed && - MI->getOperand(otherOp).getImmedValue() == 0)); - } - } - else - return false; -} - -inline bool -RemoveUselessCopies(MachineBasicBlock& mvec, - MachineBasicBlock::iterator& BBI, - const TargetMachine& target) { - if (IsUselessCopy(target, BBI)) { - DeleteInstruction(mvec, BBI, target); - return true; - } - return false; -} - - -//************************ Class Implementations **************************/ - -class PeepholeOpts: public BasicBlockPass { - const TargetMachine ⌖ - bool visit(MachineBasicBlock& mvec, - MachineBasicBlock::iterator BBI) const; -public: - PeepholeOpts(const TargetMachine &TM): target(TM) { } - bool runOnBasicBlock(BasicBlock &BB); // apply this pass to each BB - virtual const char *getPassName() const { return "Peephole Optimization"; } - - // getAnalysisUsage - this pass preserves the CFG - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - } -}; - -// Apply a list of peephole optimizations to this machine instruction -// within its local context. They are allowed to delete MI or any -// instruction before MI, but not -// -bool PeepholeOpts::visit(MachineBasicBlock& mvec, - MachineBasicBlock::iterator BBI) const { - // Remove redundant copy instructions - return RemoveUselessCopies(mvec, BBI, target); -} - - -bool PeepholeOpts::runOnBasicBlock(BasicBlock &BB) { - // Get the machine instructions for this BB - // FIXME: MachineBasicBlock::get() is deprecated, hence inlining the function - const Function *F = BB.getParent(); - MachineFunction &MF = MachineFunction::get(F); - MachineBasicBlock *MBB = NULL; - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - if (I->getBasicBlock() == &BB) - MBB = I; - - assert(MBB && "MachineBasicBlock object not found for specified block!"); - MachineBasicBlock &mvec = *MBB; - - for (MachineBasicBlock::iterator I = mvec.begin(), E = mvec.end(); I != E; ) - visit(mvec, I++); - - return true; -} - -/// createPeepholeOptsPass - Public entry point for peephole optimization -/// -FunctionPass* createPeepholeOptsPass(const TargetMachine &TM) { - return new PeepholeOpts(TM); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/PreSelection.cpp b/llvm/lib/Target/Sparc/PreSelection.cpp deleted file mode 100644 index 5bb9b2b3619..00000000000 --- a/llvm/lib/Target/Sparc/PreSelection.cpp +++ /dev/null @@ -1,243 +0,0 @@ -//===- PreSelection.cpp - Specialize LLVM code for target machine ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PreSelection pass which specializes LLVM code for a -// target machine, while remaining in legal portable LLVM form and -// preserving type information and type safety. This is meant to enable -// dataflow optimizations on target-specific operations such as accesses to -// constants, globals, and array indexing. -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/iMemory.h" -#include "llvm/iPHINode.h" -#include "llvm/iOther.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/InstVisitor.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/Scalar.h" -#include <algorithm> - -namespace llvm { - -namespace { - - //===--------------------------------------------------------------------===// - // PreSelection Pass - Specialize LLVM code for the current target machine. - // - class PreSelection : public FunctionPass, public InstVisitor<PreSelection> { - const TargetInstrInfo &instrInfo; - - public: - PreSelection(const TargetMachine &T) - : instrInfo(T.getInstrInfo()) {} - - // runOnFunction - apply this pass to each Function - bool runOnFunction(Function &F) { - visit(F); - return true; - } - - // These methods do the actual work of specializing code - void visitInstruction(Instruction &I); // common work for every instr. - void visitGetElementPtrInst(GetElementPtrInst &I); - void visitCallInst(CallInst &I); - void visitPHINode(PHINode &PN); - - // Helper functions for visiting operands of every instruction - // - // visitOperands() works on every operand in [firstOp, lastOp-1]. - // If lastOp==0, lastOp defaults to #operands or #incoming Phi values. - // - // visitOneOperand() does all the work for one operand. - // - void visitOperands(Instruction &I, int firstOp=0); - void visitOneOperand(Instruction &I, Value* Op, unsigned opNum, - Instruction& insertBefore); - }; - -#if 0 - // Register the pass... - RegisterPass<PreSelection> X("preselect", - "Specialize LLVM code for a target machine" - createPreselectionPass); -#endif - -} // end anonymous namespace - - -//------------------------------------------------------------------------------ -// Helper functions used by methods of class PreSelection -//------------------------------------------------------------------------------ - - -// getGlobalAddr(): Put address of a global into a v. register. -static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) { - if (isa<ConstantPointerRef>(ptr)) - ptr = cast<ConstantPointerRef>(ptr)->getValue(); - - return (isa<GlobalVariable>(ptr)) - ? new GetElementPtrInst(ptr, - std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)), - "addrOfGlobal", &insertBefore) - : NULL; -} - -// Wrapper on Constant::classof to use in find_if -inline static bool nonConstant(const Use& U) { - return ! isa<Constant>(U); -} - -static Instruction* DecomposeConstantExpr(ConstantExpr* CE, - Instruction& insertBefore) -{ - Value *getArg1, *getArg2; - - switch(CE->getOpcode()) - { - case Instruction::Cast: - getArg1 = CE->getOperand(0); - if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore); - - case Instruction::GetElementPtr: - assert(find_if(CE->op_begin()+1, CE->op_end(),nonConstant) == CE->op_end() - && "All indices in ConstantExpr getelementptr must be constant!"); - getArg1 = CE->getOperand(0); - if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore)) - getArg1 = gep; - return new GetElementPtrInst(getArg1, - std::vector<Value*>(CE->op_begin()+1, CE->op_end()), - "constantGEP", &insertBefore); - - default: // must be a binary operator - assert(CE->getOpcode() >= Instruction::BinaryOpsBegin && - CE->getOpcode() < Instruction::BinaryOpsEnd && - "Unrecognized opcode in ConstantExpr"); - getArg1 = CE->getOperand(0); - if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1)) - getArg1 = DecomposeConstantExpr(CEarg, insertBefore); - getArg2 = CE->getOperand(1); - if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2)) - getArg2 = DecomposeConstantExpr(CEarg, insertBefore); - return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(), - getArg1, getArg2, - "constantBinaryOp", &insertBefore); - } -} - - -//------------------------------------------------------------------------------ -// Instruction visitor methods to perform instruction-specific operations -//------------------------------------------------------------------------------ -inline void -PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum, - Instruction& insertBefore) -{ - assert(&insertBefore != NULL && "Must have instruction to insert before."); - - if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) { - I.setOperand(opNum, gep); // replace global operand - return; // nothing more to do for this op. - } - - Constant* CV = dyn_cast<Constant>(Op); - if (CV == NULL) - return; - - if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) { - // load-time constant: factor it out so we optimize as best we can - Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore); - I.setOperand(opNum, computeConst); // replace expr operand with result - } else if (instrInfo.ConstantTypeMustBeLoaded(CV)) { - // load address of constant into a register, then load the constant - // this is now done during instruction selection - // the constant will live in the MachineConstantPool later on - } else if (instrInfo.ConstantMayNotFitInImmedField(CV, &I)) { - // put the constant into a virtual register using a cast - CastInst* castI = new CastInst(CV, CV->getType(), "copyConst", - &insertBefore); - I.setOperand(opNum, castI); // replace operand with copy in v.reg. - } -} - -/// visitOperands - transform individual operands of all instructions: -/// -- Load "large" int constants into a virtual register. What is large -/// depends on the type of instruction and on the target architecture. -/// -- For any constants that cannot be put in an immediate field, -/// load address into virtual register first, and then load the constant. -/// -/// firstOp and lastOp can be used to skip leading and trailing operands. -/// If lastOp is 0, it defaults to #operands or #incoming Phi values. -/// -inline void PreSelection::visitOperands(Instruction &I, int firstOp) { - // For any instruction other than PHI, copies go just before the instr. - for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i) - visitOneOperand(I, I.getOperand(i), i, I); -} - - -void PreSelection::visitPHINode(PHINode &PN) { - // For a PHI, operand copies must be before the terminator of the - // appropriate predecessor basic block. Remaining logic is simple - // so just handle PHIs and other instructions separately. - // - for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) - visitOneOperand(PN, PN.getIncomingValue(i), - PN.getOperandNumForIncomingValue(i), - *PN.getIncomingBlock(i)->getTerminator()); - // do not call visitOperands! -} - -// Common work for *all* instructions. This needs to be called explicitly -// by other visit<InstructionType> functions. -inline void PreSelection::visitInstruction(Instruction &I) { - visitOperands(I); // Perform operand transformations -} - -// GetElementPtr instructions: check if pointer is a global -void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) { - Instruction* curI = &I; - - // Decompose multidimensional array references - if (I.getNumIndices() >= 2) { - // DecomposeArrayRef() replaces I and deletes it, if successful, - // so remember predecessor in order to find the replacement instruction. - // Also remember the basic block in case there is no predecessor. - Instruction* prevI = I.getPrev(); - BasicBlock* bb = I.getParent(); - if (DecomposeArrayRef(&I)) - // first instr. replacing I - curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front()); - } - - // Perform other transformations common to all instructions - visitInstruction(*curI); -} - -void PreSelection::visitCallInst(CallInst &I) { - // Tell visitOperands to ignore the function name if this is a direct call. - visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0)); -} - -/// createPreSelectionPass - Public entry point for the PreSelection pass -/// -FunctionPass* createPreSelectionPass(const TargetMachine &TM) { - return new PreSelection(TM); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/PrologEpilogCodeInserter.cpp b/llvm/lib/Target/Sparc/PrologEpilogCodeInserter.cpp deleted file mode 100644 index 77aa098e311..00000000000 --- a/llvm/lib/Target/Sparc/PrologEpilogCodeInserter.cpp +++ /dev/null @@ -1,185 +0,0 @@ -//===-- PrologEpilogCodeInserter.cpp - Insert Prolog & Epilog code for fn -===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Insert SAVE/RESTORE instructions for the function -// -// Insert prolog code at the unique function entry point. -// Insert epilog code at each function exit point. -// InsertPrologEpilog invokes these only if the function is not compiled -// with the leaf function optimization. -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/Pass.h" -#include "llvm/Function.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Intrinsics.h" - -namespace llvm { - -namespace { - struct InsertPrologEpilogCode : public MachineFunctionPass { - const char *getPassName() const { return "Sparc Prolog/Epilog Inserter"; } - - bool runOnMachineFunction(MachineFunction &F) { - if (!F.getInfo()->isCompiledAsLeafMethod()) { - InsertPrologCode(F); - InsertEpilogCode(F); - } - return false; - } - - void InsertPrologCode(MachineFunction &F); - void InsertEpilogCode(MachineFunction &F); - }; - -} // End anonymous namespace - -//------------------------------------------------------------------------ -// Create prolog and epilog code for procedure entry and exit -//------------------------------------------------------------------------ - -void InsertPrologEpilogCode::InsertPrologCode(MachineFunction &MF) -{ - std::vector<MachineInstr*> mvec; - const TargetMachine &TM = MF.getTarget(); - const TargetFrameInfo& frameInfo = TM.getFrameInfo(); - - // The second operand is the stack size. If it does not fit in the - // immediate field, we have to use a free register to hold the size. - // See the comments below for the choice of this register. - // - unsigned staticStackSize = MF.getInfo()->getStaticStackSize(); - - if (staticStackSize < (unsigned) frameInfo.getMinStackFrameSize()) - staticStackSize = (unsigned) frameInfo.getMinStackFrameSize(); - - if (unsigned padsz = (staticStackSize % - (unsigned) frameInfo.getStackFrameSizeAlignment())) - staticStackSize += frameInfo.getStackFrameSizeAlignment() - padsz; - - int32_t C = - (int) staticStackSize; - int SP = TM.getRegInfo().getStackPointer(); - if (TM.getInstrInfo().constantFitsInImmedField(V9::SAVEi,staticStackSize)) { - mvec.push_back(BuildMI(V9::SAVEi, 3).addMReg(SP).addSImm(C) - .addMReg(SP, MachineOperand::Def)); - } else { - // We have to put the stack size value into a register before SAVE. - // Use register %g1 since it is volatile across calls. Note that the - // local (%l) and in (%i) registers cannot be used before the SAVE! - // Do this by creating a code sequence equivalent to: - // SETSW -(stackSize), %g1 - int uregNum = TM.getRegInfo().getUnifiedRegNum( - TM.getRegInfo().getRegClassIDOfType(Type::IntTy), - SparcIntRegClass::g1); - - MachineInstr* M = BuildMI(V9::SETHI, 2).addSImm(C) - .addMReg(uregNum, MachineOperand::Def); - M->setOperandHi32(0); - mvec.push_back(M); - - M = BuildMI(V9::ORi, 3).addMReg(uregNum).addSImm(C) - .addMReg(uregNum, MachineOperand::Def); - M->setOperandLo32(1); - mvec.push_back(M); - - M = BuildMI(V9::SRAi5, 3).addMReg(uregNum).addZImm(0) - .addMReg(uregNum, MachineOperand::Def); - mvec.push_back(M); - - // Now generate the SAVE using the value in register %g1 - M = BuildMI(V9::SAVEr,3).addMReg(SP).addMReg(uregNum) - .addMReg(SP,MachineOperand::Def); - mvec.push_back(M); - } - - // For varargs function bodies, insert instructions to copy incoming - // register arguments for the ... list to the stack. - // The first K=6 arguments are always received via int arg regs - // (%i0 ... %i5 if K=6) . - // By copying the varargs arguments to the stack, va_arg() then can - // simply assume that all vararg arguments are in an array on the stack. - // - if (MF.getFunction()->getFunctionType()->isVarArg()) { - int numFixedArgs = MF.getFunction()->getFunctionType()->getNumParams(); - int numArgRegs = TM.getRegInfo().getNumOfIntArgRegs(); - if (numFixedArgs < numArgRegs) { - bool ignore; - int firstArgReg = TM.getRegInfo().getUnifiedRegNum( - TM.getRegInfo().getRegClassIDOfType(Type::IntTy), - SparcIntRegClass::i0); - int fpReg = TM.getFrameInfo().getIncomingArgBaseRegNum(); - int argSize = TM.getFrameInfo().getSizeOfEachArgOnStack(); - int firstArgOffset=TM.getFrameInfo().getFirstIncomingArgOffset(MF,ignore); - int nextArgOffset = firstArgOffset + numFixedArgs * argSize; - - for (int i=numFixedArgs; i < numArgRegs; ++i) { - mvec.push_back(BuildMI(V9::STXi, 3).addMReg(firstArgReg+i). - addMReg(fpReg).addSImm(nextArgOffset)); - nextArgOffset += argSize; - } - } - } - - MF.front().insert(MF.front().begin(), mvec.begin(), mvec.end()); -} - -void InsertPrologEpilogCode::InsertEpilogCode(MachineFunction &MF) -{ - const TargetMachine &TM = MF.getTarget(); - const TargetInstrInfo &MII = TM.getInstrInfo(); - - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { - MachineBasicBlock &MBB = *I; - const BasicBlock &BB = *I->getBasicBlock(); - const Instruction *TermInst = (Instruction*)BB.getTerminator(); - if (TermInst->getOpcode() == Instruction::Ret) - { - int ZR = TM.getRegInfo().getZeroRegNum(); - MachineInstr *Restore = - BuildMI(V9::RESTOREi, 3).addMReg(ZR).addSImm(0) - .addMReg(ZR, MachineOperand::Def); - - MachineCodeForInstruction &termMvec = - MachineCodeForInstruction::get(TermInst); - - // Remove the NOPs in the delay slots of the return instruction - unsigned numNOPs = 0; - while (termMvec.back()->getOpcode() == V9::NOP) - { - assert( termMvec.back() == &MBB.back()); - termMvec.pop_back(); - MBB.erase(&MBB.back()); - ++numNOPs; - } - assert(termMvec.back() == &MBB.back()); - - // Check that we found the right number of NOPs and have the right - // number of instructions to replace them. - unsigned ndelays = MII.getNumDelaySlots(termMvec.back()->getOpcode()); - assert(numNOPs == ndelays && "Missing NOPs in delay slots?"); - assert(ndelays == 1 && "Cannot use epilog code for delay slots?"); - - // Append the epilog code to the end of the basic block. - MBB.push_back(Restore); - } - } -} - -FunctionPass *createPrologEpilogInsertionPass() { - return new InsertPrologEpilogCode(); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/AllocInfo.h b/llvm/lib/Target/Sparc/RegAlloc/AllocInfo.h deleted file mode 100644 index b4407523c4c..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/AllocInfo.h +++ /dev/null @@ -1,91 +0,0 @@ -//===-- AllocInfo.h - Store info about regalloc decisions -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file contains the data structure used to save the state -// of the global, graph-coloring register allocator. -// -//===----------------------------------------------------------------------===// - -#ifndef ALLOCINFO_H -#define ALLOCINFO_H - -#include "llvm/Type.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Constants.h" - -namespace llvm { - -/// AllocInfo - Structure representing one instruction's operand's-worth of -/// register allocation state. We create tables made out of these data -/// structures to generate mapping information for this register allocator. -/// -struct AllocInfo { - unsigned Instruction; - int Operand; // (-1 if Instruction, or 0...n-1 for an operand.) - enum AllocStateTy { NotAllocated = 0, Allocated, Spilled }; - AllocStateTy AllocState; - int Placement; - - AllocInfo (unsigned Instruction_, unsigned Operand_, - AllocStateTy AllocState_, int Placement_) : - Instruction (Instruction_), Operand (Operand_), - AllocState (AllocState_), Placement (Placement_) { } - - /// getConstantType - Return a StructType representing an AllocInfo object. - /// - static StructType *getConstantType () { - std::vector<const Type *> TV; - TV.push_back (Type::UIntTy); - TV.push_back (Type::IntTy); - TV.push_back (Type::UIntTy); - TV.push_back (Type::IntTy); - return StructType::get (TV); - } - - /// toConstant - Convert this AllocInfo into an LLVM Constant of type - /// getConstantType(), and return the Constant. - /// - Constant *toConstant () const { - StructType *ST = getConstantType (); - std::vector<Constant *> CV; - CV.push_back (ConstantUInt::get (Type::UIntTy, Instruction)); - CV.push_back (ConstantSInt::get (Type::IntTy, Operand)); - CV.push_back (ConstantUInt::get (Type::UIntTy, AllocState)); - CV.push_back (ConstantSInt::get (Type::IntTy, Placement)); - return ConstantStruct::get (ST, CV); - } - - /// AllocInfos compare equal if the allocation placements are equal - /// (i.e., they can be equal even if they refer to operands from two - /// different instructions.) - /// - bool operator== (const AllocInfo &X) const { - return (X.AllocState == AllocState) && (X.Placement == Placement); - } - bool operator!= (const AllocInfo &X) const { return !(*this == X); } - - /// Returns a human-readable string representation of the AllocState member. - /// - const std::string allocStateToString () const { - static const char *AllocStateNames[] = - { "NotAllocated", "Allocated", "Spilled" }; - return std::string (AllocStateNames[AllocState]); - } -}; - -static inline std::ostream &operator << (std::ostream &OS, AllocInfo &S) { - OS << "(Instruction " << S.Instruction << " Operand " << S.Operand - << " AllocState " << S.allocStateToString () << " Placement " - << S.Placement << ")"; - return OS; -} - -} // End llvm namespace - -#endif // ALLOCINFO_H diff --git a/llvm/lib/Target/Sparc/RegAlloc/IGNode.cpp b/llvm/lib/Target/Sparc/RegAlloc/IGNode.cpp deleted file mode 100644 index a76fdeaa037..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/IGNode.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- IGNode.cpp --------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements an Interference graph node for coloring-based register -// allocation. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include <algorithm> -#include <iostream> - -namespace llvm { - -//----------------------------------------------------------------------------- -// Sets this IGNode on stack and reduce the degree of neighbors -//----------------------------------------------------------------------------- - -void IGNode::pushOnStack() { - OnStack = true; - int neighs = AdjList.size(); - - if (neighs < 0) { - std::cerr << "\nAdj List size = " << neighs; - assert(0 && "Invalid adj list size"); - } - - for (int i=0; i < neighs; i++) - AdjList[i]->decCurDegree(); -} - -//----------------------------------------------------------------------------- -// Deletes an adjacency node. IGNodes are deleted when coalescing merges -// two IGNodes together. -//----------------------------------------------------------------------------- - -void IGNode::delAdjIGNode(const IGNode *Node) { - std::vector<IGNode *>::iterator It=find(AdjList.begin(), AdjList.end(), Node); - assert(It != AdjList.end() && "The node must be there!"); - AdjList.erase(It); -} - -//----------------------------------------------------------------------------- -// Get the number of unique neighbors if these two nodes are merged -//----------------------------------------------------------------------------- - -unsigned -IGNode::getCombinedDegree(const IGNode* otherNode) const { - std::vector<IGNode*> nbrs(AdjList); - nbrs.insert(nbrs.end(), otherNode->AdjList.begin(), otherNode->AdjList.end()); - sort(nbrs.begin(), nbrs.end()); - std::vector<IGNode*>::iterator new_end = unique(nbrs.begin(), nbrs.end()); - return new_end - nbrs.begin(); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/IGNode.h b/llvm/lib/Target/Sparc/RegAlloc/IGNode.h deleted file mode 100644 index 9fdc7a6ac07..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/IGNode.h +++ /dev/null @@ -1,123 +0,0 @@ -//===-- IGNode.h - Represent a node in an interference graph ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file represents a node in an interference graph. -// -// For efficiency, the AdjList is updated only once - ie. we can add but not -// remove nodes from AdjList. -// -// The removal of nodes from IG is simulated by decrementing the CurDegree. -// If this node is put on stack (that is removed from IG), the CurDegree of all -// the neighbors are decremented and this node is marked OnStack. Hence -// the effective neighbors in the AdjList are the ones that do not have the -// OnStack flag set (therefore, they are in the IG). -// -// The methods that modify/use the CurDegree must be called only -// after all modifications to the IG are over (i.e., all neighbors are fixed). -// -// The vector representation is the most efficient one for adj list. -// Though nodes are removed when coalescing is done, we access it in sequence -// for far many times when coloring (colorNode()). -// -//===----------------------------------------------------------------------===// - -#ifndef IGNODE_H -#define IGNODE_H - -#include "LiveRange.h" -#include <vector> - -namespace llvm { - -class RegClass; - -//---------------------------------------------------------------------------- -// Class IGNode -// -// Represents a node in an interference graph. -//---------------------------------------------------------------------------- - -class IGNode { - const unsigned Index; // index within IGNodeList - bool OnStack; // this has been pushed on to stack for coloring - std::vector<IGNode *> AdjList;// adjacency list for this live range - - int CurDegree; - // - // set by InterferenceGraph::setCurDegreeOfIGNodes() after calculating - // all adjacency lists. - // Decremented when a neighbor is pushed on to the stack. - // After that, never incremented/set again nor used. - - LiveRange *const ParentLR; -public: - - IGNode(LiveRange *LR, unsigned index) : Index(index), ParentLR(LR) { - OnStack = false; - CurDegree = -1; - ParentLR->setUserIGNode(this); - } - - inline unsigned int getIndex() const { return Index; } - - // adjLists must be updated only once. However, the CurDegree can be changed - // - inline void addAdjIGNode(IGNode *AdjNode) { AdjList.push_back(AdjNode); } - - inline IGNode *getAdjIGNode(unsigned ind) const - { assert ( ind < AdjList.size()); return AdjList[ind]; } - - // delete a node in AdjList - node must be in the list - // should not be called often - // - void delAdjIGNode(const IGNode *Node); - - inline unsigned getNumOfNeighbors() const { return AdjList.size(); } - - // Get the number of unique neighbors if these two nodes are merged - unsigned getCombinedDegree(const IGNode* otherNode) const; - - inline bool isOnStack() const { return OnStack; } - - // remove form IG and pushes on to stack (reduce the degree of neighbors) - // - void pushOnStack(); - - // CurDegree is the effective number of neighbors when neighbors are - // pushed on to the stack during the coloring phase. Must be called - // after all modifications to the IG are over (i.e., all neighbors are - // fixed). - // - inline void setCurDegree() { - assert(CurDegree == -1); - CurDegree = AdjList.size(); - } - - inline int getCurDegree() const { return CurDegree; } - - // called when a neigh is pushed on to stack - // - inline void decCurDegree() { assert(CurDegree > 0); --CurDegree; } - - // The following methods call the methods in ParentLR - // They are added to this class for convenience - // If many of these are called within a single scope, - // consider calling the methods directly on LR - inline bool hasColor() const { return ParentLR->hasColor(); } - - inline unsigned int getColor() const { return ParentLR->getColor(); } - - inline void setColor(unsigned Col) { ParentLR->setColor(Col); } - - inline LiveRange *getParentLR() const { return ParentLR; } -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.cpp b/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.cpp deleted file mode 100644 index 3cef19ea0e0..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.cpp +++ /dev/null @@ -1,252 +0,0 @@ -//===-- InterferenceGraph.cpp ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interference graph for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "InterferenceGraph.h" -#include "RegAllocCommon.h" -#include "Support/STLExtras.h" -#include <algorithm> - -namespace llvm { - -// for asserting this IG node is infact in the IGNodeList of this class -inline static void assertIGNode(const InterferenceGraph *IG, - const IGNode *Node) { - assert(IG->getIGNodeList()[Node->getIndex()] == Node); -} - -//----------------------------------------------------------------------------- -// Constructor: Records the RegClass and initalizes IGNodeList. -// The matrix is NOT yet created by the constructor. Call createGraph() -// to create it after adding all IGNodes to the IGNodeList. -//----------------------------------------------------------------------------- -InterferenceGraph::InterferenceGraph(RegClass *const RC) : RegCl(RC) { - IG = NULL; - Size = 0; - if( DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "Interference graph created!\n"; -} - - -//----------------------------------------------------------------------------- -// destructor. Deletes the bit matrix and all IGNodes -//----------------------------------------------------------------------------- -InterferenceGraph:: ~InterferenceGraph() { - // delete the matrix - for(unsigned int r=0; r < IGNodeList.size(); ++r) - delete[] IG[r]; - delete[] IG; - - // delete all IGNodes in the IGNodeList - for_each(IGNodeList.begin(), IGNodeList.end(), deleter<IGNode>); -} - - - -//----------------------------------------------------------------------------- -// Creates (dynamically allocates) the bit matrix necessary to hold the -// interference graph. -//----------------------------------------------------------------------------- -void InterferenceGraph::createGraph() -{ - Size = IGNodeList.size(); - IG = new char*[Size]; - for( unsigned int r=0; r < Size; ++r) - IG[r] = new char[Size]; - - // init IG matrix - for(unsigned int i=0; i < Size; i++) - for(unsigned int j=0; j < Size; j++) - IG[i][j] = 0; -} - -//----------------------------------------------------------------------------- -// creates a new IGNode for the given live range and add to IG -//----------------------------------------------------------------------------- -void InterferenceGraph::addLRToIG(LiveRange *const LR) -{ - IGNodeList.push_back(new IGNode(LR, IGNodeList.size())); -} - - -//----------------------------------------------------------------------------- -// set interference for two live ranges -// update both the matrix and AdjLists of nodes. -// If there is already an interference between LR1 and LR2, adj lists -// are not updated. LR1 and LR2 must be distinct since if not, it suggests -// that there is some wrong logic in some other method. -//----------------------------------------------------------------------------- -void InterferenceGraph::setInterference(const LiveRange *const LR1, - const LiveRange *const LR2 ) { - assert(LR1 != LR2); - - IGNode *IGNode1 = LR1->getUserIGNode(); - IGNode *IGNode2 = LR2->getUserIGNode(); - - assertIGNode(this, IGNode1); - assertIGNode(this, IGNode2); - - unsigned row = IGNode1->getIndex(); - unsigned col = IGNode2->getIndex(); - - char *val; - - if( DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "setting intf for: [" << row << "][" << col << "]\n"; - - ( row > col) ? val = &IG[row][col]: val = &IG[col][row]; - - if( ! (*val) ) { // if this interf is not previously set - *val = 1; // add edges between nodes - IGNode1->addAdjIGNode( IGNode2 ); - IGNode2->addAdjIGNode( IGNode1 ); - } - -} - - -//---------------------------------------------------------------------------- -// return whether two live ranges interfere -//---------------------------------------------------------------------------- -unsigned InterferenceGraph::getInterference(const LiveRange *const LR1, - const LiveRange *const LR2) const { - assert(LR1 != LR2); - assertIGNode(this, LR1->getUserIGNode()); - assertIGNode(this, LR2->getUserIGNode()); - - const unsigned int row = LR1->getUserIGNode()->getIndex(); - const unsigned int col = LR2->getUserIGNode()->getIndex(); - - char ret; - if (row > col) - ret = IG[row][col]; - else - ret = IG[col][row]; - return ret; - -} - - -//---------------------------------------------------------------------------- -// Merge 2 IGNodes. The neighbors of the SrcNode will be added to the DestNode. -// Then the IGNode2L will be deleted. Necessary for coalescing. -// IMPORTANT: The live ranges are NOT merged by this method. Use -// LiveRangeInfo::unionAndUpdateLRs for that purpose. -//---------------------------------------------------------------------------- - -void InterferenceGraph::mergeIGNodesOfLRs(const LiveRange *LR1, - LiveRange *LR2) { - - assert( LR1 != LR2); // cannot merge the same live range - - IGNode *const DestNode = LR1->getUserIGNode(); - IGNode *SrcNode = LR2->getUserIGNode(); - - assertIGNode(this, DestNode); - assertIGNode(this, SrcNode); - - if( DEBUG_RA >= RA_DEBUG_Interference) { - std::cerr << "Merging LRs: \""; printSet(*LR1); - std::cerr << "\" and \""; printSet(*LR2); - std::cerr << "\"\n"; - } - - unsigned SrcDegree = SrcNode->getNumOfNeighbors(); - const unsigned SrcInd = SrcNode->getIndex(); - - - // for all neighs of SrcNode - for(unsigned i=0; i < SrcDegree; i++) { - IGNode *NeighNode = SrcNode->getAdjIGNode(i); - - LiveRange *const LROfNeigh = NeighNode->getParentLR(); - - // delete edge between src and neigh - even neigh == dest - NeighNode->delAdjIGNode(SrcNode); - - // set the matrix posn to 0 betn src and neigh - even neigh == dest - const unsigned NInd = NeighNode->getIndex(); - ( SrcInd > NInd) ? (IG[SrcInd][NInd]=0) : (IG[NInd][SrcInd]=0) ; - - - if( LR1 != LROfNeigh) { // if the neigh != dest - - // add edge betwn Dest and Neigh - if there is no current edge - setInterference(LR1, LROfNeigh ); - } - - } - - IGNodeList[ SrcInd ] = NULL; - - // SrcNode is no longer necessary - LR2 must be deleted by the caller - delete( SrcNode ); - -} - - -//---------------------------------------------------------------------------- -// must be called after modifications to the graph are over but before -// pushing IGNodes on to the stack for coloring. -//---------------------------------------------------------------------------- -void InterferenceGraph::setCurDegreeOfIGNodes() -{ - unsigned Size = IGNodeList.size(); - - for( unsigned i=0; i < Size; i++) { - IGNode *Node = IGNodeList[i]; - if( Node ) - Node->setCurDegree(); - } -} - - - - - -//--------------------- debugging (Printing) methods ----------------------- - -//---------------------------------------------------------------------------- -// Print the IGnodes -//---------------------------------------------------------------------------- -void InterferenceGraph::printIG() const { - for(unsigned i=0; i < Size; i++) { - const IGNode *const Node = IGNodeList[i]; - if(Node) { - std::cerr << " [" << i << "] "; - - for( unsigned int j=0; j < Size; j++) - if(IG[i][j]) - std::cerr << "(" << i << "," << j << ") "; - std::cerr << "\n"; - } - } -} - -//---------------------------------------------------------------------------- -// Print the IGnodes in the IGNode List -//---------------------------------------------------------------------------- -void InterferenceGraph::printIGNodeList() const { - for(unsigned i=0; i < IGNodeList.size() ; ++i) { - const IGNode *const Node = IGNodeList[i]; - - if (Node) { - std::cerr << " [" << Node->getIndex() << "] "; - printSet(*Node->getParentLR()); - //int Deg = Node->getCurDegree(); - std::cerr << "\t <# of Neighs: " << Node->getNumOfNeighbors() << ">\n"; - } - } -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.h b/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.h deleted file mode 100644 index 79850c1fcf0..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/InterferenceGraph.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- InterferenceGraph.h - Interference graph for register coloring -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -/* Title: InterferenceGraph.h -*- C++ -*- - Author: Ruchira Sasanka - Date: July 20, 01 - Purpose: Interference Graph used for register coloring. - - Notes: - Adj Info is stored in the lower trangular matrix (i.e., row > col ) - - This class must be used in the following way: - - * Construct class - * call addLRToIG as many times to add ALL LRs to this IG - * call createGraph to create the actual matrix - * Then setInterference, getInterference, mergeIGNodesOfLRs can be - called as desired to modify the graph. - * Once the modifications to the graph are over, call - setCurDegreeOfIGNodes() before pushing IGNodes on to stack for coloring. -*/ - -#ifndef INTERFERENCEGRAPH_H -#define INTERFERENCEGRAPH_H - -#include <vector> - -namespace llvm { - -class LiveRange; -class RegClass; -class IGNode; - -class InterferenceGraph { - char **IG; // a poiner to the interference graph - unsigned int Size; // size of a side of the IG - RegClass *const RegCl; // RegCl contains this IG - std::vector<IGNode *> IGNodeList; // a list of all IGNodes in a reg class - - public: - // the matrix is not yet created by the constructor. Call createGraph() - // to create it after adding all IGNodes to the IGNodeList - InterferenceGraph(RegClass *RC); - ~InterferenceGraph(); - - void createGraph(); - - void addLRToIG(LiveRange *LR); - - void setInterference(const LiveRange *LR1, - const LiveRange *LR2); - - unsigned getInterference(const LiveRange *LR1, - const LiveRange *LR2) const ; - - void mergeIGNodesOfLRs(const LiveRange *LR1, LiveRange *LR2); - - std::vector<IGNode *> &getIGNodeList() { return IGNodeList; } - const std::vector<IGNode *> &getIGNodeList() const { return IGNodeList; } - - void setCurDegreeOfIGNodes(); - - void printIG() const; - void printIGNodeList() const; -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/LiveRange.h b/llvm/lib/Target/Sparc/RegAlloc/LiveRange.h deleted file mode 100644 index d6e2cf63072..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/LiveRange.h +++ /dev/null @@ -1,184 +0,0 @@ -//===-- LiveRange.h - Store info about a live range -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implements a live range using a ValueSet. A LiveRange is a simple set -// of Values. -// -// Since the Value pointed by a use is the same as of its def, it is sufficient -// to keep only defs in a LiveRange. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVERANGE_H -#define LIVERANGE_H - -#include "llvm/Value.h" -#include "llvm/CodeGen/ValueSet.h" - -namespace llvm { - -class RegClass; -class IGNode; - -class LiveRange : public ValueSet { - RegClass *MyRegClass; // register class (e.g., int, FP) for this LR - - /// doesSpanAcrossCalls - Does this live range span across calls? - /// This information is used by graph coloring algo to avoid allocating - /// volatile colors to live ranges that span across calls (since they have to - /// be saved/restored) - /// - bool doesSpanAcrossCalls; - - IGNode *UserIGNode; // IGNode which uses this LR - int Color; // color assigned to this live range - bool mustSpill; // whether this LR must be spilt - - /// mustSaveAcrossCalls - whether this LR must be saved accross calls - /// ***TODO REMOVE this - /// - bool mustSaveAcrossCalls; - - /// SuggestedColor - if this LR has a suggested color, can it be - /// really alloated? A suggested color cannot be allocated when the - /// suggested color is volatile and when there are call - /// interferences. - /// - int SuggestedColor; // The suggested color for this LR - - /// CanUseSuggestedCol - It is possible that a suggested color for - /// this live range is not available before graph coloring (e.g., it - /// can be allocated to another live range which interferes with - /// this) - /// - bool CanUseSuggestedCol; - - /// SpilledStackOffsetFromFP - If this LR is spilled, its stack - /// offset from *FP*. The spilled offsets must always be relative to - /// the FP. - /// - int SpilledStackOffsetFromFP; - - /// HasSpillOffset 0 Whether this live range has a spill offset - /// - bool HasSpillOffset; - - /// The spill cost of this live range. Calculated using loop depth of - /// each reference to each Value in the live range - /// - unsigned SpillCost; - -public: - LiveRange() { - Color = SuggestedColor = -1; // not yet colored - mustSpill = mustSaveAcrossCalls = false; - MyRegClass = 0; - UserIGNode = 0; - doesSpanAcrossCalls = false; - CanUseSuggestedCol = true; - HasSpillOffset = false; - SpillCost = 0; - } - - void setRegClass(RegClass *RC) { MyRegClass = RC; } - - RegClass *getRegClass() const { assert(MyRegClass); return MyRegClass; } - unsigned getRegClassID() const; - - bool hasColor() const { return Color != -1; } - - unsigned getColor() const { assert(Color != -1); return (unsigned)Color; } - - void setColor(unsigned Col) { Color = (int)Col; } - - inline void setCallInterference() { - doesSpanAcrossCalls = 1; - } - inline void clearCallInterference() { - doesSpanAcrossCalls = 0; - } - - inline bool isCallInterference() const { - return doesSpanAcrossCalls == 1; - } - - inline void markForSpill() { mustSpill = true; } - - inline bool isMarkedForSpill() const { return mustSpill; } - - inline void setSpillOffFromFP(int StackOffset) { - assert(mustSpill && "This LR is not spilled"); - SpilledStackOffsetFromFP = StackOffset; - HasSpillOffset = true; - } - - inline void modifySpillOffFromFP(int StackOffset) { - assert(mustSpill && "This LR is not spilled"); - SpilledStackOffsetFromFP = StackOffset; - HasSpillOffset = true; - } - - inline bool hasSpillOffset() const { - return HasSpillOffset; - } - - inline int getSpillOffFromFP() const { - assert(HasSpillOffset && "This LR is not spilled"); - return SpilledStackOffsetFromFP; - } - - inline void markForSaveAcrossCalls() { mustSaveAcrossCalls = true; } - - inline void setUserIGNode(IGNode *IGN) { - assert(!UserIGNode); UserIGNode = IGN; - } - - // getUserIGNode - NULL if the user is not allocated - inline IGNode *getUserIGNode() const { return UserIGNode; } - - inline const Type *getType() const { - return (*begin())->getType(); // set's don't have a front - } - - inline void setSuggestedColor(int Col) { - if (SuggestedColor == -1) - SuggestedColor = Col; - } - - inline unsigned getSuggestedColor() const { - assert(SuggestedColor != -1); // only a valid color is obtained - return (unsigned)SuggestedColor; - } - - inline bool hasSuggestedColor() const { - return SuggestedColor != -1; - } - - inline bool isSuggestedColorUsable() const { - assert(hasSuggestedColor() && "No suggested color"); - return CanUseSuggestedCol; - } - - inline void setSuggestedColorUsable(bool val) { - assert(hasSuggestedColor() && "No suggested color"); - CanUseSuggestedCol = val; - } - - inline void addSpillCost(unsigned cost) { - SpillCost += cost; - } - - inline unsigned getSpillCost() const { - return SpillCost; - } -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.cpp b/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.cpp deleted file mode 100644 index 100f9eb4c62..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.cpp +++ /dev/null @@ -1,415 +0,0 @@ -//===-- LiveRangeInfo.cpp -------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Live range construction for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "LiveRangeInfo.h" -#include "RegAllocCommon.h" -#include "RegClass.h" -#include "llvm/Function.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetRegInfo.h" -#include "Support/SetOperations.h" - -namespace llvm { - -unsigned LiveRange::getRegClassID() const { return getRegClass()->getID(); } - -LiveRangeInfo::LiveRangeInfo(const Function *F, const TargetMachine &tm, - std::vector<RegClass *> &RCL) - : Meth(F), TM(tm), RegClassList(RCL), MRI(tm.getRegInfo()) { } - - -LiveRangeInfo::~LiveRangeInfo() { - for (LiveRangeMapType::iterator MI = LiveRangeMap.begin(); - MI != LiveRangeMap.end(); ++MI) { - - if (MI->first && MI->second) { - LiveRange *LR = MI->second; - - // we need to be careful in deleting LiveRanges in LiveRangeMap - // since two/more Values in the live range map can point to the same - // live range. We have to make the other entries NULL when we delete - // a live range. - - for (LiveRange::iterator LI = LR->begin(); LI != LR->end(); ++LI) - LiveRangeMap[*LI] = 0; - - delete LR; - } - } -} - - -//--------------------------------------------------------------------------- -// union two live ranges into one. The 2nd LR is deleted. Used for coalescing. -// Note: the caller must make sure that L1 and L2 are distinct and both -// LRs don't have suggested colors -//--------------------------------------------------------------------------- - -void LiveRangeInfo::unionAndUpdateLRs(LiveRange *L1, LiveRange *L2) { - assert(L1 != L2 && (!L1->hasSuggestedColor() || !L2->hasSuggestedColor())); - assert(! (L1->hasColor() && L2->hasColor()) || - L1->getColor() == L2->getColor()); - - set_union(*L1, *L2); // add elements of L2 to L1 - - for(ValueSet::iterator L2It = L2->begin(); L2It != L2->end(); ++L2It) { - //assert(( L1->getTypeID() == L2->getTypeID()) && "Merge:Different types"); - - L1->insert(*L2It); // add the var in L2 to L1 - LiveRangeMap[*L2It] = L1; // now the elements in L2 should map - //to L1 - } - - // set call interference for L1 from L2 - if (L2->isCallInterference()) - L1->setCallInterference(); - - // add the spill costs - L1->addSpillCost(L2->getSpillCost()); - - // If L2 has a color, give L1 that color. Note that L1 may have had the same - // color or none, but would not have a different color as asserted above. - if (L2->hasColor()) - L1->setColor(L2->getColor()); - - // Similarly, if LROfUse(L2) has a suggested color, the new range - // must have the same color. - if (L2->hasSuggestedColor()) - L1->setSuggestedColor(L2->getSuggestedColor()); - - delete L2; // delete L2 as it is no longer needed -} - - -//--------------------------------------------------------------------------- -// Method for creating a single live range for a definition. -// The definition must be represented by a virtual register (a Value). -// Note: this function does *not* check that no live range exists for def. -//--------------------------------------------------------------------------- - -LiveRange* -LiveRangeInfo::createNewLiveRange(const Value* Def, bool isCC /* = false*/) -{ - LiveRange* DefRange = new LiveRange(); // Create a new live range, - DefRange->insert(Def); // add Def to it, - LiveRangeMap[Def] = DefRange; // and update the map. - - // set the register class of the new live range - DefRange->setRegClass(RegClassList[MRI.getRegClassIDOfType(Def->getType(), - isCC)]); - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) { - std::cerr << " Creating a LR for def "; - if (isCC) std::cerr << " (CC Register!)"; - std::cerr << " : " << RAV(Def) << "\n"; - } - return DefRange; -} - - -LiveRange* -LiveRangeInfo::createOrAddToLiveRange(const Value* Def, bool isCC /* = false*/) -{ - LiveRange *DefRange = LiveRangeMap[Def]; - - // check if the LR is already there (because of multiple defs) - if (!DefRange) { - DefRange = createNewLiveRange(Def, isCC); - } else { // live range already exists - DefRange->insert(Def); // add the operand to the range - LiveRangeMap[Def] = DefRange; // make operand point to merged set - if (DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << " Added to existing LR for def: " << RAV(Def) << "\n"; - } - return DefRange; -} - - -//--------------------------------------------------------------------------- -// Method for constructing all live ranges in a function. It creates live -// ranges for all values defined in the instruction stream. Also, it -// creates live ranges for all incoming arguments of the function. -//--------------------------------------------------------------------------- -void LiveRangeInfo::constructLiveRanges() { - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << "Constructing Live Ranges ...\n"; - - // first find the live ranges for all incoming args of the function since - // those LRs start from the start of the function - for (Function::const_aiterator AI = Meth->abegin(); AI != Meth->aend(); ++AI) - createNewLiveRange(AI, /*isCC*/ false); - - // Now suggest hardware registers for these function args - MRI.suggestRegs4MethodArgs(Meth, *this); - - // Now create LRs for machine instructions. A new LR will be created - // only for defs in the machine instr since, we assume that all Values are - // defined before they are used. However, there can be multiple defs for - // the same Value in machine instructions. - // - // Also, find CALL and RETURN instructions, which need extra work. - // - MachineFunction &MF = MachineFunction::get(Meth); - for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) { - MachineBasicBlock &MBB = *BBI; - - // iterate over all the machine instructions in BB - for(MachineBasicBlock::iterator MInstIterator = MBB.begin(); - MInstIterator != MBB.end(); ++MInstIterator) { - MachineInstr *MInst = MInstIterator; - - // If the machine instruction is a call/return instruction, add it to - // CallRetInstrList for processing its args, ret value, and ret addr. - // - if(TM.getInstrInfo().isReturn(MInst->getOpcode()) || - TM.getInstrInfo().isCall(MInst->getOpcode())) - CallRetInstrList.push_back(MInst); - - // iterate over explicit MI operands and create a new LR - // for each operand that is defined by the instruction - for (MachineInstr::val_op_iterator OpI = MInst->begin(), - OpE = MInst->end(); OpI != OpE; ++OpI) - if (OpI.isDef()) { - const Value *Def = *OpI; - bool isCC = (OpI.getMachineOperand().getType() - == MachineOperand::MO_CCRegister); - LiveRange* LR = createOrAddToLiveRange(Def, isCC); - - // If the operand has a pre-assigned register, - // set it directly in the LiveRange - if (OpI.getMachineOperand().hasAllocatedReg()) { - unsigned getClassId; - LR->setColor(MRI.getClassRegNum(OpI.getMachineOperand().getReg(), - getClassId)); - } - } - - // iterate over implicit MI operands and create a new LR - // for each operand that is defined by the instruction - for (unsigned i = 0; i < MInst->getNumImplicitRefs(); ++i) - if (MInst->getImplicitOp(i).isDef()) { - const Value *Def = MInst->getImplicitRef(i); - LiveRange* LR = createOrAddToLiveRange(Def, /*isCC*/ false); - - // If the implicit operand has a pre-assigned register, - // set it directly in the LiveRange - if (MInst->getImplicitOp(i).hasAllocatedReg()) { - unsigned getClassId; - LR->setColor(MRI.getClassRegNum( - MInst->getImplicitOp(i).getReg(), - getClassId)); - } - } - - } // for all machine instructions in the BB - } // for all BBs in function - - // Now we have to suggest clors for call and return arg live ranges. - // Also, if there are implicit defs (e.g., retun value of a call inst) - // they must be added to the live range list - // - suggestRegs4CallRets(); - - if( DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << "Initial Live Ranges constructed!\n"; -} - - -//--------------------------------------------------------------------------- -// If some live ranges must be colored with specific hardware registers -// (e.g., for outgoing call args), suggesting of colors for such live -// ranges is done using target specific function. Those functions are called -// from this function. The target specific methods must: -// 1) suggest colors for call and return args. -// 2) create new LRs for implicit defs in machine instructions -//--------------------------------------------------------------------------- -void LiveRangeInfo::suggestRegs4CallRets() { - std::vector<MachineInstr*>::iterator It = CallRetInstrList.begin(); - for( ; It != CallRetInstrList.end(); ++It) { - MachineInstr *MInst = *It; - MachineOpCode OpCode = MInst->getOpcode(); - - if ((TM.getInstrInfo()).isReturn(OpCode)) - MRI.suggestReg4RetValue(MInst, *this); - else if ((TM.getInstrInfo()).isCall(OpCode)) - MRI.suggestRegs4CallArgs(MInst, *this); - else - assert( 0 && "Non call/ret instr in CallRetInstrList" ); - } -} - - -//-------------------------------------------------------------------------- -// The following method coalesces live ranges when possible. This method -// must be called after the interference graph has been constructed. - - -/* Algorithm: - for each BB in function - for each machine instruction (inst) - for each definition (def) in inst - for each operand (op) of inst that is a use - if the def and op are of the same register type - if the def and op do not interfere //i.e., not simultaneously live - if (degree(LR of def) + degree(LR of op)) <= # avail regs - if both LRs do not have suggested colors - merge2IGNodes(def, op) // i.e., merge 2 LRs - -*/ -//--------------------------------------------------------------------------- - - -// Checks if live range LR interferes with any node assigned or suggested to -// be assigned the specified color -// -inline bool InterferesWithColor(const LiveRange& LR, unsigned color) { - IGNode* lrNode = LR.getUserIGNode(); - for (unsigned n=0, NN = lrNode->getNumOfNeighbors(); n < NN; n++) { - LiveRange *neighLR = lrNode->getAdjIGNode(n)->getParentLR(); - if (neighLR->hasColor() && neighLR->getColor() == color) - return true; - if (neighLR->hasSuggestedColor() && neighLR->getSuggestedColor() == color) - return true; - } - return false; -} - -// Cannot coalesce if any of the following is true: -// (1) Both LRs have suggested colors (should be "different suggested colors"?) -// (2) Both LR1 and LR2 have colors and the colors are different -// (but if the colors are the same, it is definitely safe to coalesce) -// (3) LR1 has color and LR2 interferes with any LR that has the same color -// (4) LR2 has color and LR1 interferes with any LR that has the same color -// -inline bool InterfsPreventCoalescing(const LiveRange& LROfDef, - const LiveRange& LROfUse) { - // (4) if they have different suggested colors, cannot coalesce - if (LROfDef.hasSuggestedColor() && LROfUse.hasSuggestedColor()) - return true; - - // if neither has a color, nothing more to do. - if (! LROfDef.hasColor() && ! LROfUse.hasColor()) - return false; - - // (2, 3) if L1 has color... - if (LROfDef.hasColor()) { - if (LROfUse.hasColor()) - return (LROfUse.getColor() != LROfDef.getColor()); - return InterferesWithColor(LROfUse, LROfDef.getColor()); - } - - // (4) else only LROfUse has a color: check if that could interfere - return InterferesWithColor(LROfDef, LROfUse.getColor()); -} - - -void LiveRangeInfo::coalesceLRs() -{ - if(DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << "\nCoalescing LRs ...\n"; - - MachineFunction &MF = MachineFunction::get(Meth); - for (MachineFunction::iterator BBI = MF.begin(); BBI != MF.end(); ++BBI) { - MachineBasicBlock &MBB = *BBI; - - // iterate over all the machine instructions in BB - for(MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII){ - const MachineInstr *MI = MII; - - if( DEBUG_RA >= RA_DEBUG_LiveRanges) { - std::cerr << " *Iterating over machine instr "; - MI->dump(); - std::cerr << "\n"; - } - - // iterate over MI operands to find defs - for(MachineInstr::const_val_op_iterator DefI = MI->begin(), - DefE = MI->end(); DefI != DefE; ++DefI) { - if (DefI.isDef()) { // this operand is modified - LiveRange *LROfDef = getLiveRangeForValue( *DefI ); - RegClass *RCOfDef = LROfDef->getRegClass(); - - MachineInstr::const_val_op_iterator UseI = MI->begin(), - UseE = MI->end(); - for( ; UseI != UseE; ++UseI) { // for all uses - LiveRange *LROfUse = getLiveRangeForValue( *UseI ); - if (!LROfUse) { // if LR of use is not found - //don't warn about labels - if (!isa<BasicBlock>(*UseI) && DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << " !! Warning: No LR for use " << RAV(*UseI)<< "\n"; - continue; // ignore and continue - } - - if (LROfUse == LROfDef) // nothing to merge if they are same - continue; - - if (MRI.getRegTypeForLR(LROfDef) == - MRI.getRegTypeForLR(LROfUse)) { - // If the two RegTypes are the same - if (!RCOfDef->getInterference(LROfDef, LROfUse) ) { - - unsigned CombinedDegree = - LROfDef->getUserIGNode()->getNumOfNeighbors() + - LROfUse->getUserIGNode()->getNumOfNeighbors(); - - if (CombinedDegree > RCOfDef->getNumOfAvailRegs()) { - // get more precise estimate of combined degree - CombinedDegree = LROfDef->getUserIGNode()-> - getCombinedDegree(LROfUse->getUserIGNode()); - } - - if (CombinedDegree <= RCOfDef->getNumOfAvailRegs()) { - // if both LRs do not have different pre-assigned colors - // and both LRs do not have suggested colors - if (! InterfsPreventCoalescing(*LROfDef, *LROfUse)) { - RCOfDef->mergeIGNodesOfLRs(LROfDef, LROfUse); - unionAndUpdateLRs(LROfDef, LROfUse); - } - - } // if combined degree is less than # of regs - } // if def and use do not interfere - }// if reg classes are the same - } // for all uses - } // if def - } // for all defs - } // for all machine instructions - } // for all BBs - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) - std::cerr << "\nCoalescing Done!\n"; -} - -/*--------------------------- Debug code for printing ---------------*/ - - -void LiveRangeInfo::printLiveRanges() { - LiveRangeMapType::iterator HMI = LiveRangeMap.begin(); // hash map iterator - std::cerr << "\nPrinting Live Ranges from Hash Map:\n"; - for( ; HMI != LiveRangeMap.end(); ++HMI) { - if (HMI->first && HMI->second) { - std::cerr << " Value* " << RAV(HMI->first) << "\t: "; - if (IGNode* igNode = HMI->second->getUserIGNode()) - std::cerr << "LR# " << igNode->getIndex(); - else - std::cerr << "LR# " << "<no-IGNode>"; - std::cerr << "\t:Values = "; printSet(*HMI->second); std::cerr << "\n"; - } - } -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.h b/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.h deleted file mode 100644 index a8d0e7152f1..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/LiveRangeInfo.h +++ /dev/null @@ -1,128 +0,0 @@ -//===-- LiveRangeInfo.h - Track all LiveRanges for a Function ----*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the class LiveRangeInfo which constructs and keeps -// the LiveRangeMap which contains all the live ranges used in a method. -// -// Assumptions: -// -// All variables (llvm Values) are defined before they are used. However, a -// constant may not be defined in the machine instruction stream if it can be -// used as an immediate value within a machine instruction. However, register -// allocation does not have to worry about immediate constants since they -// do not require registers. -// -// Since an llvm Value has a list of uses associated, it is sufficient to -// record only the defs in a Live Range. -// -//===----------------------------------------------------------------------===// - -#ifndef LIVERANGEINFO_H -#define LIVERANGEINFO_H - -#include "llvm/CodeGen/ValueSet.h" -#include "Support/hash_map" - -namespace llvm { - -class LiveRange; -class MachineInstr; -class RegClass; -class TargetRegInfo; -class TargetMachine; -class Value; -class Function; -class Instruction; - -typedef hash_map<const Value*, LiveRange*> LiveRangeMapType; - -//---------------------------------------------------------------------------- -// Class LiveRangeInfo -// -// Constructs and keeps the LiveRangeMap which contains all the live -// ranges used in a method. Also contain methods to coalesce live ranges. -//---------------------------------------------------------------------------- - -class LiveRangeInfo { - const Function *const Meth; // Func for which live range info is held - LiveRangeMapType LiveRangeMap; // A map from Value * to LiveRange * to - // record all live ranges in a method - // created by constructLiveRanges - - const TargetMachine& TM; // target machine description - - std::vector<RegClass *> & RegClassList;// vector containing register classess - - const TargetRegInfo& MRI; // machine reg info - - std::vector<MachineInstr*> CallRetInstrList; // a list of all call/ret instrs - - - //------------ Private methods (see LiveRangeInfo.cpp for description)------- - - LiveRange* createNewLiveRange (const Value* Def, - bool isCC = false); - - LiveRange* createOrAddToLiveRange (const Value* Def, - bool isCC = false); - - void unionAndUpdateLRs (LiveRange *L1, - LiveRange *L2); - - void addInterference (const Instruction *Inst, - const ValueSet *LVSet); - - void suggestRegs4CallRets (); - - const Function *getMethod () const { return Meth; } - -public: - - LiveRangeInfo(const Function *F, - const TargetMachine& tm, - std::vector<RegClass *> & RCList); - - - /// Destructor to destroy all LiveRanges in the LiveRange Map - /// - ~LiveRangeInfo(); - - // Main entry point for live range construction - // - void constructLiveRanges(); - - /// return the common live range map for this method - /// - inline const LiveRangeMapType *getLiveRangeMap() const - { return &LiveRangeMap; } - - /// Method used to get the live range containing a Value. - /// This may return NULL if no live range exists for a Value (eg, some consts) - /// - inline LiveRange *getLiveRangeForValue(const Value *Val) { - return LiveRangeMap[Val]; - } - inline const LiveRange *getLiveRangeForValue(const Value *Val) const { - LiveRangeMapType::const_iterator I = LiveRangeMap.find(Val); - return I->second; - } - - /// Method for coalescing live ranges. Called only after interference info - /// is calculated. - /// - void coalesceLRs(); - - /// debugging method to print the live ranges - /// - void printLiveRanges(); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/Makefile b/llvm/lib/Target/Sparc/RegAlloc/Makefile deleted file mode 100644 index 374c70f08a0..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -##===- lib/CodeGen/RegAlloc/Makefile -----------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file was developed by the LLVM research group and is distributed under -# the University of Illinois Open Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../../.. - -DIRS = - -LIBRARYNAME = regalloc - -BUILD_ARCHIVE = 1 - -include $(LEVEL)/Makefile.common diff --git a/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.cpp b/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.cpp deleted file mode 100644 index 7b224119cef..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.cpp +++ /dev/null @@ -1,1379 +0,0 @@ -//===-- PhyRegAlloc.cpp ---------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Traditional graph-coloring global register allocator currently used -// by the SPARC back-end. -// -// NOTE: This register allocator has some special support -// for the Reoptimizer, such as not saving some registers on calls to -// the first-level instrumentation function. -// -// NOTE 2: This register allocator can save its state in a global -// variable in the module it's working on. This feature is not -// thread-safe; if you have doubts, leave it turned off. -// -//===----------------------------------------------------------------------===// - -#include "AllocInfo.h" -#include "IGNode.h" -#include "PhyRegAlloc.h" -#include "RegAllocCommon.h" -#include "RegClass.h" -#include "../LiveVar/FunctionLiveVarInfo.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/iOther.h" -#include "llvm/Module.h" -#include "llvm/Type.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "Support/CommandLine.h" -#include "Support/SetOperations.h" -#include "Support/STLExtras.h" -#include <cmath> - -namespace llvm { - -RegAllocDebugLevel_t DEBUG_RA; - -/// The reoptimizer wants to be able to grovel through the register -/// allocator's state after it has done its job. This is a hack. -/// -PhyRegAlloc::SavedStateMapTy ExportedFnAllocState; -const bool SaveStateToModule = true; - -static cl::opt<RegAllocDebugLevel_t, true> -DRA_opt("dregalloc", cl::Hidden, cl::location(DEBUG_RA), - cl::desc("enable register allocation debugging information"), - cl::values( - clEnumValN(RA_DEBUG_None , "n", "disable debug output"), - clEnumValN(RA_DEBUG_Results, "y", "debug output for allocation results"), - clEnumValN(RA_DEBUG_Coloring, "c", "debug output for graph coloring step"), - clEnumValN(RA_DEBUG_Interference,"ig","debug output for interference graphs"), - clEnumValN(RA_DEBUG_LiveRanges , "lr","debug output for live ranges"), - clEnumValN(RA_DEBUG_Verbose, "v", "extra debug output"), - 0)); - -static cl::opt<bool> -SaveRegAllocState("save-ra-state", cl::Hidden, - cl::desc("write reg. allocator state into module")); - -FunctionPass *getRegisterAllocator(TargetMachine &T) { - return new PhyRegAlloc (T); -} - -void PhyRegAlloc::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<LoopInfo> (); - AU.addRequired<FunctionLiveVarInfo> (); -} - - -/// Initialize interference graphs (one in each reg class) and IGNodeLists -/// (one in each IG). The actual nodes will be pushed later. -/// -void PhyRegAlloc::createIGNodeListsAndIGs() { - if (DEBUG_RA >= RA_DEBUG_LiveRanges) std::cerr << "Creating LR lists ...\n"; - - LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap()->begin(); - LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap()->end(); - - for (; HMI != HMIEnd ; ++HMI ) { - if (HMI->first) { - LiveRange *L = HMI->second; // get the LiveRange - if (!L) { - if (DEBUG_RA) - std::cerr << "\n**** ?!?WARNING: NULL LIVE RANGE FOUND FOR: " - << RAV(HMI->first) << "****\n"; - continue; - } - - // if the Value * is not null, and LR is not yet written to the IGNodeList - if (!(L->getUserIGNode()) ) { - RegClass *const RC = // RegClass of first value in the LR - RegClassList[ L->getRegClassID() ]; - RC->addLRToIG(L); // add this LR to an IG - } - } - } - - // init RegClassList - for ( unsigned rc=0; rc < NumOfRegClasses ; rc++) - RegClassList[rc]->createInterferenceGraph(); - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) std::cerr << "LRLists Created!\n"; -} - - -/// Add all interferences for a given instruction. Interference occurs only -/// if the LR of Def (Inst or Arg) is of the same reg class as that of live -/// var. The live var passed to this function is the LVset AFTER the -/// instruction. -/// -void PhyRegAlloc::addInterference(const Value *Def, const ValueSet *LVSet, - bool isCallInst) { - ValueSet::const_iterator LIt = LVSet->begin(); - - // get the live range of instruction - const LiveRange *const LROfDef = LRI->getLiveRangeForValue( Def ); - - IGNode *const IGNodeOfDef = LROfDef->getUserIGNode(); - assert( IGNodeOfDef ); - - RegClass *const RCOfDef = LROfDef->getRegClass(); - - // for each live var in live variable set - for ( ; LIt != LVSet->end(); ++LIt) { - - if (DEBUG_RA >= RA_DEBUG_Verbose) - std::cerr << "< Def=" << RAV(Def) << ", Lvar=" << RAV(*LIt) << "> "; - - // get the live range corresponding to live var - LiveRange *LROfVar = LRI->getLiveRangeForValue(*LIt); - - // LROfVar can be null if it is a const since a const - // doesn't have a dominating def - see Assumptions above - if (LROfVar) - if (LROfDef != LROfVar) // do not set interf for same LR - if (RCOfDef == LROfVar->getRegClass()) // 2 reg classes are the same - RCOfDef->setInterference( LROfDef, LROfVar); - } -} - - -/// For a call instruction, this method sets the CallInterference flag in -/// the LR of each variable live in the Live Variable Set live after the -/// call instruction (except the return value of the call instruction - since -/// the return value does not interfere with that call itself). -/// -void PhyRegAlloc::setCallInterferences(const MachineInstr *MInst, - const ValueSet *LVSetAft) { - if (DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "\n For call inst: " << *MInst; - - // for each live var in live variable set after machine inst - for (ValueSet::const_iterator LIt = LVSetAft->begin(), LEnd = LVSetAft->end(); - LIt != LEnd; ++LIt) { - - // get the live range corresponding to live var - LiveRange *const LR = LRI->getLiveRangeForValue(*LIt ); - - // LR can be null if it is a const since a const - // doesn't have a dominating def - see Assumptions above - if (LR ) { - if (DEBUG_RA >= RA_DEBUG_Interference) { - std::cerr << "\n\tLR after Call: "; - printSet(*LR); - } - LR->setCallInterference(); - if (DEBUG_RA >= RA_DEBUG_Interference) { - std::cerr << "\n ++After adding call interference for LR: " ; - printSet(*LR); - } - } - - } - - // Now find the LR of the return value of the call - // We do this because, we look at the LV set *after* the instruction - // to determine, which LRs must be saved across calls. The return value - // of the call is live in this set - but it does not interfere with call - // (i.e., we can allocate a volatile register to the return value) - CallArgsDescriptor* argDesc = CallArgsDescriptor::get(MInst); - - if (const Value *RetVal = argDesc->getReturnValue()) { - LiveRange *RetValLR = LRI->getLiveRangeForValue( RetVal ); - assert( RetValLR && "No LR for RetValue of call"); - RetValLR->clearCallInterference(); - } - - // If the CALL is an indirect call, find the LR of the function pointer. - // That has a call interference because it conflicts with outgoing args. - if (const Value *AddrVal = argDesc->getIndirectFuncPtr()) { - LiveRange *AddrValLR = LRI->getLiveRangeForValue( AddrVal ); - assert( AddrValLR && "No LR for indirect addr val of call"); - AddrValLR->setCallInterference(); - } -} - - -/// Create interferences in the IG of each RegClass, and calculate the spill -/// cost of each Live Range (it is done in this method to save another pass -/// over the code). -/// -void PhyRegAlloc::buildInterferenceGraphs() { - if (DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "Creating interference graphs ...\n"; - - unsigned BBLoopDepthCost; - for (MachineFunction::iterator BBI = MF->begin(), BBE = MF->end(); - BBI != BBE; ++BBI) { - const MachineBasicBlock &MBB = *BBI; - const BasicBlock *BB = MBB.getBasicBlock(); - - // find the 10^(loop_depth) of this BB - BBLoopDepthCost = (unsigned)pow(10.0, LoopDepthCalc->getLoopDepth(BB)); - - // get the iterator for machine instructions - MachineBasicBlock::const_iterator MII = MBB.begin(); - - // iterate over all the machine instructions in BB - for ( ; MII != MBB.end(); ++MII) { - const MachineInstr *MInst = MII; - - // get the LV set after the instruction - const ValueSet &LVSetAI = LVI->getLiveVarSetAfterMInst(MInst, BB); - bool isCallInst = TM.getInstrInfo().isCall(MInst->getOpcode()); - - if (isCallInst) { - // set the isCallInterference flag of each live range which extends - // across this call instruction. This information is used by graph - // coloring algorithm to avoid allocating volatile colors to live ranges - // that span across calls (since they have to be saved/restored) - setCallInterferences(MInst, &LVSetAI); - } - - // iterate over all MI operands to find defs - for (MachineInstr::const_val_op_iterator OpI = MInst->begin(), - OpE = MInst->end(); OpI != OpE; ++OpI) { - if (OpI.isDef()) // create a new LR since def - addInterference(*OpI, &LVSetAI, isCallInst); - - // Calculate the spill cost of each live range - LiveRange *LR = LRI->getLiveRangeForValue(*OpI); - if (LR) LR->addSpillCost(BBLoopDepthCost); - } - - // Mark all operands of pseudo-instructions as interfering with one - // another. This must be done because pseudo-instructions may be - // expanded to multiple instructions by the assembler, so all the - // operands must get distinct registers. - if (TM.getInstrInfo().isPseudoInstr(MInst->getOpcode())) - addInterf4PseudoInstr(MInst); - - // Also add interference for any implicit definitions in a machine - // instr (currently, only calls have this). - unsigned NumOfImpRefs = MInst->getNumImplicitRefs(); - for (unsigned z=0; z < NumOfImpRefs; z++) - if (MInst->getImplicitOp(z).isDef()) - addInterference( MInst->getImplicitRef(z), &LVSetAI, isCallInst ); - - } // for all machine instructions in BB - } // for all BBs in function - - // add interferences for function arguments. Since there are no explicit - // defs in the function for args, we have to add them manually - addInterferencesForArgs(); - - if (DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "Interference graphs calculated!\n"; -} - - -/// Mark all operands of the given MachineInstr as interfering with one -/// another. -/// -void PhyRegAlloc::addInterf4PseudoInstr(const MachineInstr *MInst) { - bool setInterf = false; - - // iterate over MI operands to find defs - for (MachineInstr::const_val_op_iterator It1 = MInst->begin(), - ItE = MInst->end(); It1 != ItE; ++It1) { - const LiveRange *LROfOp1 = LRI->getLiveRangeForValue(*It1); - assert((LROfOp1 || It1.isDef()) && "No LR for Def in PSEUDO insruction"); - - MachineInstr::const_val_op_iterator It2 = It1; - for (++It2; It2 != ItE; ++It2) { - const LiveRange *LROfOp2 = LRI->getLiveRangeForValue(*It2); - - if (LROfOp2) { - RegClass *RCOfOp1 = LROfOp1->getRegClass(); - RegClass *RCOfOp2 = LROfOp2->getRegClass(); - - if (RCOfOp1 == RCOfOp2 ){ - RCOfOp1->setInterference( LROfOp1, LROfOp2 ); - setInterf = true; - } - } // if Op2 has a LR - } // for all other defs in machine instr - } // for all operands in an instruction - - if (!setInterf && MInst->getNumOperands() > 2) { - std::cerr << "\nInterf not set for any operand in pseudo instr:\n"; - std::cerr << *MInst; - assert(0 && "Interf not set for pseudo instr with > 2 operands" ); - } -} - - -/// Add interferences for incoming arguments to a function. -/// -void PhyRegAlloc::addInterferencesForArgs() { - // get the InSet of root BB - const ValueSet &InSet = LVI->getInSetOfBB(&Fn->front()); - - for (Function::const_aiterator AI = Fn->abegin(); AI != Fn->aend(); ++AI) { - // add interferences between args and LVars at start - addInterference(AI, &InSet, false); - - if (DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << " - %% adding interference for argument " << RAV(AI) << "\n"; - } -} - - -/// The following are utility functions used solely by updateMachineCode and -/// the functions that it calls. They should probably be folded back into -/// updateMachineCode at some point. -/// - -// used by: updateMachineCode (1 time), PrependInstructions (1 time) -inline void InsertBefore(MachineInstr* newMI, MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII) { - MII = MBB.insert(MII, newMI); - ++MII; -} - -// used by: AppendInstructions (1 time) -inline void InsertAfter(MachineInstr* newMI, MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII) { - ++MII; // insert before the next instruction - MII = MBB.insert(MII, newMI); -} - -// used by: updateMachineCode (2 times) -inline void PrependInstructions(std::vector<MachineInstr *> &IBef, - MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII, - const std::string& msg) { - if (!IBef.empty()) { - MachineInstr* OrigMI = MII; - std::vector<MachineInstr *>::iterator AdIt; - for (AdIt = IBef.begin(); AdIt != IBef.end() ; ++AdIt) { - if (DEBUG_RA) { - if (OrigMI) std::cerr << "For MInst:\n " << *OrigMI; - std::cerr << msg << "PREPENDed instr:\n " << **AdIt << "\n"; - } - InsertBefore(*AdIt, MBB, MII); - } - } -} - -// used by: updateMachineCode (1 time) -inline void AppendInstructions(std::vector<MachineInstr *> &IAft, - MachineBasicBlock& MBB, - MachineBasicBlock::iterator& MII, - const std::string& msg) { - if (!IAft.empty()) { - MachineInstr* OrigMI = MII; - std::vector<MachineInstr *>::iterator AdIt; - for ( AdIt = IAft.begin(); AdIt != IAft.end() ; ++AdIt ) { - if (DEBUG_RA) { - if (OrigMI) std::cerr << "For MInst:\n " << *OrigMI; - std::cerr << msg << "APPENDed instr:\n " << **AdIt << "\n"; - } - InsertAfter(*AdIt, MBB, MII); - } - } -} - -/// Set the registers for operands in the given MachineInstr, if a register was -/// successfully allocated. Return true if any of its operands has been marked -/// for spill. -/// -bool PhyRegAlloc::markAllocatedRegs(MachineInstr* MInst) -{ - bool instrNeedsSpills = false; - - // First, set the registers for operands in the machine instruction - // if a register was successfully allocated. Do this first because we - // will need to know which registers are already used by this instr'n. - for (unsigned OpNum=0; OpNum < MInst->getNumOperands(); ++OpNum) { - MachineOperand& Op = MInst->getOperand(OpNum); - if (Op.getType() == MachineOperand::MO_VirtualRegister || - Op.getType() == MachineOperand::MO_CCRegister) { - const Value *const Val = Op.getVRegValue(); - if (const LiveRange* LR = LRI->getLiveRangeForValue(Val)) { - // Remember if any operand needs spilling - instrNeedsSpills |= LR->isMarkedForSpill(); - - // An operand may have a color whether or not it needs spilling - if (LR->hasColor()) - MInst->SetRegForOperand(OpNum, - MRI.getUnifiedRegNum(LR->getRegClassID(), - LR->getColor())); - } - } - } // for each operand - - return instrNeedsSpills; -} - -/// Mark allocated registers (using markAllocatedRegs()) on the instruction -/// that MII points to. Then, if it's a call instruction, insert caller-saving -/// code before and after it. Finally, insert spill code before and after it, -/// using insertCode4SpilledLR(). -/// -void PhyRegAlloc::updateInstruction(MachineBasicBlock::iterator& MII, - MachineBasicBlock &MBB) { - MachineInstr* MInst = MII; - unsigned Opcode = MInst->getOpcode(); - - // Reset tmp stack positions so they can be reused for each machine instr. - MF->getInfo()->popAllTempValues(); - - // Mark the operands for which regs have been allocated. - bool instrNeedsSpills = markAllocatedRegs(MII); - -#ifndef NDEBUG - // Mark that the operands have been updated. Later, - // setRelRegsUsedByThisInst() is called to find registers used by each - // MachineInst, and it should not be used for an instruction until - // this is done. This flag just serves as a sanity check. - OperandsColoredMap[MInst] = true; -#endif - - // Now insert caller-saving code before/after the call. - // Do this before inserting spill code since some registers must be - // used by save/restore and spill code should not use those registers. - if (TM.getInstrInfo().isCall(Opcode)) { - AddedInstrns &AI = AddedInstrMap[MInst]; - insertCallerSavingCode(AI.InstrnsBefore, AI.InstrnsAfter, MInst, - MBB.getBasicBlock()); - } - - // Now insert spill code for remaining operands not allocated to - // registers. This must be done even for call return instructions - // since those are not handled by the special code above. - if (instrNeedsSpills) - for (unsigned OpNum=0; OpNum < MInst->getNumOperands(); ++OpNum) { - MachineOperand& Op = MInst->getOperand(OpNum); - if (Op.getType() == MachineOperand::MO_VirtualRegister || - Op.getType() == MachineOperand::MO_CCRegister) { - const Value* Val = Op.getVRegValue(); - if (const LiveRange *LR = LRI->getLiveRangeForValue(Val)) - if (LR->isMarkedForSpill()) - insertCode4SpilledLR(LR, MII, MBB, OpNum); - } - } // for each operand -} - -/// Iterate over all the MachineBasicBlocks in the current function and set -/// the allocated registers for each instruction (using updateInstruction()), -/// after register allocation is complete. Then move code out of delay slots. -/// -void PhyRegAlloc::updateMachineCode() -{ - // Insert any instructions needed at method entry - MachineBasicBlock::iterator MII = MF->front().begin(); - PrependInstructions(AddedInstrAtEntry.InstrnsBefore, MF->front(), MII, - "At function entry: \n"); - assert(AddedInstrAtEntry.InstrnsAfter.empty() && - "InstrsAfter should be unnecessary since we are just inserting at " - "the function entry point here."); - - for (MachineFunction::iterator BBI = MF->begin(), BBE = MF->end(); - BBI != BBE; ++BBI) { - MachineBasicBlock &MBB = *BBI; - - // Iterate over all machine instructions in BB and mark operands with - // their assigned registers or insert spill code, as appropriate. - // Also, fix operands of call/return instructions. - for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII) - if (! TM.getInstrInfo().isDummyPhiInstr(MII->getOpcode())) - updateInstruction(MII, MBB); - - // Now, move code out of delay slots of branches and returns if needed. - // (Also, move "after" code from calls to the last delay slot instruction.) - // Moving code out of delay slots is needed in 2 situations: - // (1) If this is a branch and it needs instructions inserted after it, - // move any existing instructions out of the delay slot so that the - // instructions can go into the delay slot. This only supports the - // case that #instrsAfter <= #delay slots. - // - // (2) If any instruction in the delay slot needs - // instructions inserted, move it out of the delay slot and before the - // branch because putting code before or after it would be VERY BAD! - // - // If the annul bit of the branch is set, neither of these is legal! - // If so, we need to handle spill differently but annulling is not yet used. - for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end(); ++MII) - if (unsigned delaySlots = - TM.getInstrInfo().getNumDelaySlots(MII->getOpcode())) { - MachineBasicBlock::iterator DelaySlotMI = next(MII); - assert(DelaySlotMI != MBB.end() && "no instruction for delay slot"); - - // Check the 2 conditions above: - // (1) Does a branch need instructions added after it? - // (2) O/w does delay slot instr. need instrns before or after? - bool isBranch = (TM.getInstrInfo().isBranch(MII->getOpcode()) || - TM.getInstrInfo().isReturn(MII->getOpcode())); - bool cond1 = (isBranch && - AddedInstrMap.count(MII) && - AddedInstrMap[MII].InstrnsAfter.size() > 0); - bool cond2 = (AddedInstrMap.count(DelaySlotMI) && - (AddedInstrMap[DelaySlotMI].InstrnsBefore.size() > 0 || - AddedInstrMap[DelaySlotMI].InstrnsAfter.size() > 0)); - - if (cond1 || cond2) { - assert(delaySlots==1 && - "InsertBefore does not yet handle >1 delay slots!"); - - if (DEBUG_RA) { - std::cerr << "\nRegAlloc: Moved instr. with added code: " - << *DelaySlotMI - << " out of delay slots of instr: " << *MII; - } - - // move instruction before branch - MBB.insert(MII, MBB.remove(DelaySlotMI)); - - // On cond1 we are done (we already moved the - // instruction out of the delay slot). On cond2 we need - // to insert a nop in place of the moved instruction - if (cond2) { - MBB.insert(MII, BuildMI(TM.getInstrInfo().getNOPOpCode(),1)); - } - } - else { - // For non-branch instr with delay slots (probably a call), move - // InstrAfter to the instr. in the last delay slot. - MachineBasicBlock::iterator tmp = next(MII, delaySlots); - move2DelayedInstr(MII, tmp); - } - } - - // Finally iterate over all instructions in BB and insert before/after - for (MachineBasicBlock::iterator MII=MBB.begin(); MII != MBB.end(); ++MII) { - MachineInstr *MInst = MII; - - // do not process Phis - if (TM.getInstrInfo().isDummyPhiInstr(MInst->getOpcode())) - continue; - - // if there are any added instructions... - if (AddedInstrMap.count(MInst)) { - AddedInstrns &CallAI = AddedInstrMap[MInst]; - -#ifndef NDEBUG - bool isBranch = (TM.getInstrInfo().isBranch(MInst->getOpcode()) || - TM.getInstrInfo().isReturn(MInst->getOpcode())); - assert((!isBranch || - AddedInstrMap[MInst].InstrnsAfter.size() <= - TM.getInstrInfo().getNumDelaySlots(MInst->getOpcode())) && - "Cannot put more than #delaySlots instrns after " - "branch or return! Need to handle temps differently."); -#endif - -#ifndef NDEBUG - // Temporary sanity checking code to detect whether the same machine - // instruction is ever inserted twice before/after a call. - // I suspect this is happening but am not sure. --Vikram, 7/1/03. - std::set<const MachineInstr*> instrsSeen; - for (int i = 0, N = CallAI.InstrnsBefore.size(); i < N; ++i) { - assert(instrsSeen.count(CallAI.InstrnsBefore[i]) == 0 && - "Duplicate machine instruction in InstrnsBefore!"); - instrsSeen.insert(CallAI.InstrnsBefore[i]); - } - for (int i = 0, N = CallAI.InstrnsAfter.size(); i < N; ++i) { - assert(instrsSeen.count(CallAI.InstrnsAfter[i]) == 0 && - "Duplicate machine instruction in InstrnsBefore/After!"); - instrsSeen.insert(CallAI.InstrnsAfter[i]); - } -#endif - - // Now add the instructions before/after this MI. - // We do this here to ensure that spill for an instruction is inserted - // as close as possible to an instruction (see above insertCode4Spill) - if (! CallAI.InstrnsBefore.empty()) - PrependInstructions(CallAI.InstrnsBefore, MBB, MII,""); - - if (! CallAI.InstrnsAfter.empty()) - AppendInstructions(CallAI.InstrnsAfter, MBB, MII,""); - - } // if there are any added instructions - } // for each machine instruction - } -} - - -/// Insert spill code for AN operand whose LR was spilled. May be called -/// repeatedly for a single MachineInstr if it has many spilled operands. On -/// each call, it finds a register which is not live at that instruction and -/// also which is not used by other spilled operands of the same -/// instruction. Then it uses this register temporarily to accommodate the -/// spilled value. -/// -void PhyRegAlloc::insertCode4SpilledLR(const LiveRange *LR, - MachineBasicBlock::iterator& MII, - MachineBasicBlock &MBB, - const unsigned OpNum) { - MachineInstr *MInst = MII; - const BasicBlock *BB = MBB.getBasicBlock(); - - assert((! TM.getInstrInfo().isCall(MInst->getOpcode()) || OpNum == 0) && - "Outgoing arg of a call must be handled elsewhere (func arg ok)"); - assert(! TM.getInstrInfo().isReturn(MInst->getOpcode()) && - "Return value of a ret must be handled elsewhere"); - - MachineOperand& Op = MInst->getOperand(OpNum); - bool isDef = Op.isDef(); - bool isUse = Op.isUse(); - unsigned RegType = MRI.getRegTypeForLR(LR); - int SpillOff = LR->getSpillOffFromFP(); - RegClass *RC = LR->getRegClass(); - - // Get the live-variable set to find registers free before this instr. - const ValueSet &LVSetBef = LVI->getLiveVarSetBeforeMInst(MInst, BB); - -#ifndef NDEBUG - // If this instr. is in the delay slot of a branch or return, we need to - // include all live variables before that branch or return -- we don't want to - // trample those! Verify that the set is included in the LV set before MInst. - if (MII != MBB.begin()) { - MachineBasicBlock::iterator PredMI = prior(MII); - if (unsigned DS = TM.getInstrInfo().getNumDelaySlots(PredMI->getOpcode())) - assert(set_difference(LVI->getLiveVarSetBeforeMInst(PredMI), LVSetBef) - .empty() && "Live-var set before branch should be included in " - "live-var set of each delay slot instruction!"); - } -#endif - - MF->getInfo()->pushTempValue(MRI.getSpilledRegSize(RegType)); - - std::vector<MachineInstr*> MIBef, MIAft; - std::vector<MachineInstr*> AdIMid; - - // Choose a register to hold the spilled value, if one was not preallocated. - // This may insert code before and after MInst to free up the value. If so, - // this code should be first/last in the spill sequence before/after MInst. - int TmpRegU=(LR->hasColor() - ? MRI.getUnifiedRegNum(LR->getRegClassID(),LR->getColor()) - : getUsableUniRegAtMI(RegType, &LVSetBef, MInst, MIBef,MIAft)); - - // Set the operand first so that it this register does not get used - // as a scratch register for later calls to getUsableUniRegAtMI below - MInst->SetRegForOperand(OpNum, TmpRegU); - - // get the added instructions for this instruction - AddedInstrns &AI = AddedInstrMap[MInst]; - - // We may need a scratch register to copy the spilled value to/from memory. - // This may itself have to insert code to free up a scratch register. - // Any such code should go before (after) the spill code for a load (store). - // The scratch reg is not marked as used because it is only used - // for the copy and not used across MInst. - int scratchRegType = -1; - int scratchReg = -1; - if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) { - scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetBef, - MInst, MIBef, MIAft); - assert(scratchReg != MRI.getInvalidRegNum()); - } - - if (isUse) { - // for a USE, we have to load the value of LR from stack to a TmpReg - // and use the TmpReg as one operand of instruction - - // actual loading instruction(s) - MRI.cpMem2RegMI(AdIMid, MRI.getFramePointer(), SpillOff, TmpRegU, - RegType, scratchReg); - - // the actual load should be after the instructions to free up TmpRegU - MIBef.insert(MIBef.end(), AdIMid.begin(), AdIMid.end()); - AdIMid.clear(); - } - - if (isDef) { // if this is a Def - // for a DEF, we have to store the value produced by this instruction - // on the stack position allocated for this LR - - // actual storing instruction(s) - MRI.cpReg2MemMI(AdIMid, TmpRegU, MRI.getFramePointer(), SpillOff, - RegType, scratchReg); - - MIAft.insert(MIAft.begin(), AdIMid.begin(), AdIMid.end()); - } // if !DEF - - // Finally, insert the entire spill code sequences before/after MInst - AI.InstrnsBefore.insert(AI.InstrnsBefore.end(), MIBef.begin(), MIBef.end()); - AI.InstrnsAfter.insert(AI.InstrnsAfter.begin(), MIAft.begin(), MIAft.end()); - - if (DEBUG_RA) { - std::cerr << "\nFor Inst:\n " << *MInst; - std::cerr << "SPILLED LR# " << LR->getUserIGNode()->getIndex(); - std::cerr << "; added Instructions:"; - for_each(MIBef.begin(), MIBef.end(), std::mem_fun(&MachineInstr::dump)); - for_each(MIAft.begin(), MIAft.end(), std::mem_fun(&MachineInstr::dump)); - } -} - - -/// Insert caller saving/restoring instructions before/after a call machine -/// instruction (before or after any other instructions that were inserted for -/// the call). -/// -void -PhyRegAlloc::insertCallerSavingCode(std::vector<MachineInstr*> &instrnsBefore, - std::vector<MachineInstr*> &instrnsAfter, - MachineInstr *CallMI, - const BasicBlock *BB) { - assert(TM.getInstrInfo().isCall(CallMI->getOpcode())); - - // hash set to record which registers were saved/restored - hash_set<unsigned> PushedRegSet; - - CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI); - - // if the call is to a instrumentation function, do not insert save and - // restore instructions the instrumentation function takes care of save - // restore for volatile regs. - // - // FIXME: this should be made general, not specific to the reoptimizer! - const Function *Callee = argDesc->getCallInst()->getCalledFunction(); - bool isLLVMFirstTrigger = Callee && Callee->getName() == "llvm_first_trigger"; - - // Now check if the call has a return value (using argDesc) and if so, - // find the LR of the TmpInstruction representing the return value register. - // (using the last or second-last *implicit operand* of the call MI). - // Insert it to to the PushedRegSet since we must not save that register - // and restore it after the call. - // We do this because, we look at the LV set *after* the instruction - // to determine, which LRs must be saved across calls. The return value - // of the call is live in this set - but we must not save/restore it. - if (const Value *origRetVal = argDesc->getReturnValue()) { - unsigned retValRefNum = (CallMI->getNumImplicitRefs() - - (argDesc->getIndirectFuncPtr()? 1 : 2)); - const TmpInstruction* tmpRetVal = - cast<TmpInstruction>(CallMI->getImplicitRef(retValRefNum)); - assert(tmpRetVal->getOperand(0) == origRetVal && - tmpRetVal->getType() == origRetVal->getType() && - "Wrong implicit ref?"); - LiveRange *RetValLR = LRI->getLiveRangeForValue(tmpRetVal); - assert(RetValLR && "No LR for RetValue of call"); - - if (! RetValLR->isMarkedForSpill()) - PushedRegSet.insert(MRI.getUnifiedRegNum(RetValLR->getRegClassID(), - RetValLR->getColor())); - } - - const ValueSet &LVSetAft = LVI->getLiveVarSetAfterMInst(CallMI, BB); - ValueSet::const_iterator LIt = LVSetAft.begin(); - - // for each live var in live variable set after machine inst - for( ; LIt != LVSetAft.end(); ++LIt) { - // get the live range corresponding to live var - LiveRange *const LR = LRI->getLiveRangeForValue(*LIt); - - // LR can be null if it is a const since a const - // doesn't have a dominating def - see Assumptions above - if (LR) { - if (! LR->isMarkedForSpill()) { - assert(LR->hasColor() && "LR is neither spilled nor colored?"); - unsigned RCID = LR->getRegClassID(); - unsigned Color = LR->getColor(); - - if (MRI.isRegVolatile(RCID, Color) ) { - // if this is a call to the first-level reoptimizer - // instrumentation entry point, and the register is not - // modified by call, don't save and restore it. - if (isLLVMFirstTrigger && !MRI.modifiedByCall(RCID, Color)) - continue; - - // if the value is in both LV sets (i.e., live before and after - // the call machine instruction) - unsigned Reg = MRI.getUnifiedRegNum(RCID, Color); - - // if we haven't already pushed this register... - if( PushedRegSet.find(Reg) == PushedRegSet.end() ) { - unsigned RegType = MRI.getRegTypeForLR(LR); - - // Now get two instructions - to push on stack and pop from stack - // and add them to InstrnsBefore and InstrnsAfter of the - // call instruction - int StackOff = - MF->getInfo()->pushTempValue(MRI.getSpilledRegSize(RegType)); - - //---- Insert code for pushing the reg on stack ---------- - - std::vector<MachineInstr*> AdIBef, AdIAft; - - // We may need a scratch register to copy the saved value - // to/from memory. This may itself have to insert code to - // free up a scratch register. Any such code should go before - // the save code. The scratch register, if any, is by default - // temporary and not "used" by the instruction unless the - // copy code itself decides to keep the value in the scratch reg. - int scratchRegType = -1; - int scratchReg = -1; - if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) - { // Find a register not live in the LVSet before CallMI - const ValueSet &LVSetBef = - LVI->getLiveVarSetBeforeMInst(CallMI, BB); - scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetBef, - CallMI, AdIBef, AdIAft); - assert(scratchReg != MRI.getInvalidRegNum()); - } - - if (AdIBef.size() > 0) - instrnsBefore.insert(instrnsBefore.end(), - AdIBef.begin(), AdIBef.end()); - - MRI.cpReg2MemMI(instrnsBefore, Reg, MRI.getFramePointer(), - StackOff, RegType, scratchReg); - - if (AdIAft.size() > 0) - instrnsBefore.insert(instrnsBefore.end(), - AdIAft.begin(), AdIAft.end()); - - //---- Insert code for popping the reg from the stack ---------- - AdIBef.clear(); - AdIAft.clear(); - - // We may need a scratch register to copy the saved value - // from memory. This may itself have to insert code to - // free up a scratch register. Any such code should go - // after the save code. As above, scratch is not marked "used". - scratchRegType = -1; - scratchReg = -1; - if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) - { // Find a register not live in the LVSet after CallMI - scratchReg = getUsableUniRegAtMI(scratchRegType, &LVSetAft, - CallMI, AdIBef, AdIAft); - assert(scratchReg != MRI.getInvalidRegNum()); - } - - if (AdIBef.size() > 0) - instrnsAfter.insert(instrnsAfter.end(), - AdIBef.begin(), AdIBef.end()); - - MRI.cpMem2RegMI(instrnsAfter, MRI.getFramePointer(), StackOff, - Reg, RegType, scratchReg); - - if (AdIAft.size() > 0) - instrnsAfter.insert(instrnsAfter.end(), - AdIAft.begin(), AdIAft.end()); - - PushedRegSet.insert(Reg); - - if(DEBUG_RA) { - std::cerr << "\nFor call inst:" << *CallMI; - std::cerr << " -inserted caller saving instrs: Before:\n\t "; - for_each(instrnsBefore.begin(), instrnsBefore.end(), - std::mem_fun(&MachineInstr::dump)); - std::cerr << " -and After:\n\t "; - for_each(instrnsAfter.begin(), instrnsAfter.end(), - std::mem_fun(&MachineInstr::dump)); - } - } // if not already pushed - } // if LR has a volatile color - } // if LR has color - } // if there is a LR for Var - } // for each value in the LV set after instruction -} - - -/// Returns the unified register number of a temporary register to be used -/// BEFORE MInst. If no register is available, it will pick one and modify -/// MIBef and MIAft to contain instructions used to free up this returned -/// register. -/// -int PhyRegAlloc::getUsableUniRegAtMI(const int RegType, - const ValueSet *LVSetBef, - MachineInstr *MInst, - std::vector<MachineInstr*>& MIBef, - std::vector<MachineInstr*>& MIAft) { - RegClass* RC = getRegClassByID(MRI.getRegClassIDOfRegType(RegType)); - - int RegU = getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef); - - if (RegU == -1) { - // we couldn't find an unused register. Generate code to free up a reg by - // saving it on stack and restoring after the instruction - - int TmpOff = MF->getInfo()->pushTempValue(MRI.getSpilledRegSize(RegType)); - - RegU = getUniRegNotUsedByThisInst(RC, RegType, MInst); - - // Check if we need a scratch register to copy this register to memory. - int scratchRegType = -1; - if (MRI.regTypeNeedsScratchReg(RegType, scratchRegType)) { - int scratchReg = getUsableUniRegAtMI(scratchRegType, LVSetBef, - MInst, MIBef, MIAft); - assert(scratchReg != MRI.getInvalidRegNum()); - - // We may as well hold the value in the scratch register instead - // of copying it to memory and back. But we have to mark the - // register as used by this instruction, so it does not get used - // as a scratch reg. by another operand or anyone else. - ScratchRegsUsed.insert(std::make_pair(MInst, scratchReg)); - MRI.cpReg2RegMI(MIBef, RegU, scratchReg, RegType); - MRI.cpReg2RegMI(MIAft, scratchReg, RegU, RegType); - } else { // the register can be copied directly to/from memory so do it. - MRI.cpReg2MemMI(MIBef, RegU, MRI.getFramePointer(), TmpOff, RegType); - MRI.cpMem2RegMI(MIAft, MRI.getFramePointer(), TmpOff, RegU, RegType); - } - } - - return RegU; -} - - -/// Returns the register-class register number of a new unused register that -/// can be used to accommodate a temporary value. May be called repeatedly -/// for a single MachineInstr. On each call, it finds a register which is not -/// live at that instruction and which is not used by any spilled operands of -/// that instruction. -/// -int PhyRegAlloc::getUnusedUniRegAtMI(RegClass *RC, const int RegType, - const MachineInstr *MInst, - const ValueSet* LVSetBef) { - RC->clearColorsUsed(); // Reset array - - if (LVSetBef == NULL) { - LVSetBef = &LVI->getLiveVarSetBeforeMInst(MInst); - assert(LVSetBef != NULL && "Unable to get live-var set before MInst?"); - } - - ValueSet::const_iterator LIt = LVSetBef->begin(); - - // for each live var in live variable set after machine inst - for ( ; LIt != LVSetBef->end(); ++LIt) { - // Get the live range corresponding to live var, and its RegClass - LiveRange *const LRofLV = LRI->getLiveRangeForValue(*LIt ); - - // LR can be null if it is a const since a const - // doesn't have a dominating def - see Assumptions above - if (LRofLV && LRofLV->getRegClass() == RC && LRofLV->hasColor()) - RC->markColorsUsed(LRofLV->getColor(), - MRI.getRegTypeForLR(LRofLV), RegType); - } - - // It is possible that one operand of this MInst was already spilled - // and it received some register temporarily. If that's the case, - // it is recorded in machine operand. We must skip such registers. - setRelRegsUsedByThisInst(RC, RegType, MInst); - - int unusedReg = RC->getUnusedColor(RegType); // find first unused color - if (unusedReg >= 0) - return MRI.getUnifiedRegNum(RC->getID(), unusedReg); - - return -1; -} - - -/// Return the unified register number of a register in class RC which is not -/// used by any operands of MInst. -/// -int PhyRegAlloc::getUniRegNotUsedByThisInst(RegClass *RC, - const int RegType, - const MachineInstr *MInst) { - RC->clearColorsUsed(); - - setRelRegsUsedByThisInst(RC, RegType, MInst); - - // find the first unused color - int unusedReg = RC->getUnusedColor(RegType); - assert(unusedReg >= 0 && - "FATAL: No free register could be found in reg class!!"); - - return MRI.getUnifiedRegNum(RC->getID(), unusedReg); -} - - -/// Modify the IsColorUsedArr of register class RC, by setting the bits -/// corresponding to register RegNo. This is a helper method of -/// setRelRegsUsedByThisInst(). -/// -static void markRegisterUsed(int RegNo, RegClass *RC, int RegType, - const TargetRegInfo &TRI) { - unsigned classId = 0; - int classRegNum = TRI.getClassRegNum(RegNo, classId); - if (RC->getID() == classId) - RC->markColorsUsed(classRegNum, RegType, RegType); -} - -void PhyRegAlloc::setRelRegsUsedByThisInst(RegClass *RC, int RegType, - const MachineInstr *MI) { - assert(OperandsColoredMap[MI] == true && - "Illegal to call setRelRegsUsedByThisInst() until colored operands " - "are marked for an instruction."); - - // Add the registers already marked as used by the instruction. Both - // explicit and implicit operands are set. - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).hasAllocatedReg()) - markRegisterUsed(MI->getOperand(i).getReg(), RC, RegType,MRI); - - for (unsigned i = 0, e = MI->getNumImplicitRefs(); i != e; ++i) - if (MI->getImplicitOp(i).hasAllocatedReg()) - markRegisterUsed(MI->getImplicitOp(i).getReg(), RC, RegType,MRI); - - // Add all of the scratch registers that are used to save values across the - // instruction (e.g., for saving state register values). - std::pair<ScratchRegsUsedTy::iterator, ScratchRegsUsedTy::iterator> - IR = ScratchRegsUsed.equal_range(MI); - for (ScratchRegsUsedTy::iterator I = IR.first; I != IR.second; ++I) - markRegisterUsed(I->second, RC, RegType, MRI); - - // If there are implicit references, mark their allocated regs as well - for (unsigned z=0; z < MI->getNumImplicitRefs(); z++) - if (const LiveRange* - LRofImpRef = LRI->getLiveRangeForValue(MI->getImplicitRef(z))) - if (LRofImpRef->hasColor()) - // this implicit reference is in a LR that received a color - RC->markColorsUsed(LRofImpRef->getColor(), - MRI.getRegTypeForLR(LRofImpRef), RegType); -} - - -/// If there are delay slots for an instruction, the instructions added after -/// it must really go after the delayed instruction(s). So, we Move the -/// InstrAfter of that instruction to the corresponding delayed instruction -/// using the following method. -/// -void PhyRegAlloc::move2DelayedInstr(const MachineInstr *OrigMI, - const MachineInstr *DelayedMI) -{ - // "added after" instructions of the original instr - std::vector<MachineInstr *> &OrigAft = AddedInstrMap[OrigMI].InstrnsAfter; - - if (DEBUG_RA && OrigAft.size() > 0) { - std::cerr << "\nRegAlloc: Moved InstrnsAfter for: " << *OrigMI; - std::cerr << " to last delay slot instrn: " << *DelayedMI; - } - - // "added after" instructions of the delayed instr - std::vector<MachineInstr *> &DelayedAft=AddedInstrMap[DelayedMI].InstrnsAfter; - - // go thru all the "added after instructions" of the original instruction - // and append them to the "added after instructions" of the delayed - // instructions - DelayedAft.insert(DelayedAft.end(), OrigAft.begin(), OrigAft.end()); - - // empty the "added after instructions" of the original instruction - OrigAft.clear(); -} - - -void PhyRegAlloc::colorIncomingArgs() -{ - MRI.colorMethodArgs(Fn, *LRI, AddedInstrAtEntry.InstrnsBefore, - AddedInstrAtEntry.InstrnsAfter); -} - - -/// Determine whether the suggested color of each live range is really usable, -/// and then call its setSuggestedColorUsable() method to record the answer. A -/// suggested color is NOT usable when the suggested color is volatile AND -/// when there are call interferences. -/// -void PhyRegAlloc::markUnusableSugColors() -{ - LiveRangeMapType::const_iterator HMI = (LRI->getLiveRangeMap())->begin(); - LiveRangeMapType::const_iterator HMIEnd = (LRI->getLiveRangeMap())->end(); - - for (; HMI != HMIEnd ; ++HMI ) { - if (HMI->first) { - LiveRange *L = HMI->second; // get the LiveRange - if (L && L->hasSuggestedColor ()) - L->setSuggestedColorUsable - (!(MRI.isRegVolatile (L->getRegClassID (), L->getSuggestedColor ()) - && L->isCallInterference ())); - } - } // for all LR's in hash map -} - - -/// For each live range that is spilled, allocates a new spill position on the -/// stack, and set the stack offsets of the live range that will be spilled to -/// that position. This must be called just after coloring the LRs. -/// -void PhyRegAlloc::allocateStackSpace4SpilledLRs() { - if (DEBUG_RA) std::cerr << "\nSetting LR stack offsets for spills...\n"; - - LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap()->begin(); - LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap()->end(); - - for ( ; HMI != HMIEnd ; ++HMI) { - if (HMI->first && HMI->second) { - LiveRange *L = HMI->second; // get the LiveRange - if (L->isMarkedForSpill()) { // NOTE: allocating size of long Type ** - int stackOffset = MF->getInfo()->allocateSpilledValue(Type::LongTy); - L->setSpillOffFromFP(stackOffset); - if (DEBUG_RA) - std::cerr << " LR# " << L->getUserIGNode()->getIndex() - << ": stack-offset = " << stackOffset << "\n"; - } - } - } // for all LR's in hash map -} - - -void PhyRegAlloc::saveStateForValue (std::vector<AllocInfo> &state, - const Value *V, unsigned Insn, int Opnd) { - LiveRangeMapType::const_iterator HMI = LRI->getLiveRangeMap ()->find (V); - LiveRangeMapType::const_iterator HMIEnd = LRI->getLiveRangeMap ()->end (); - AllocInfo::AllocStateTy AllocState = AllocInfo::NotAllocated; - int Placement = -1; - if ((HMI != HMIEnd) && HMI->second) { - LiveRange *L = HMI->second; - assert ((L->hasColor () || L->isMarkedForSpill ()) - && "Live range exists but not colored or spilled"); - if (L->hasColor ()) { - AllocState = AllocInfo::Allocated; - Placement = MRI.getUnifiedRegNum (L->getRegClassID (), - L->getColor ()); - } else if (L->isMarkedForSpill ()) { - AllocState = AllocInfo::Spilled; - assert (L->hasSpillOffset () - && "Live range marked for spill but has no spill offset"); - Placement = L->getSpillOffFromFP (); - } - } - state.push_back (AllocInfo (Insn, Opnd, AllocState, Placement)); -} - - -/// Save the global register allocation decisions made by the register -/// allocator so that they can be accessed later (sort of like "poor man's -/// debug info"). -/// -void PhyRegAlloc::saveState () { - std::vector<AllocInfo> &state = FnAllocState[Fn]; - unsigned Insn = 0; - for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II!=IE; ++II){ - saveStateForValue (state, (*II), Insn, -1); - for (unsigned i = 0; i < (*II)->getNumOperands (); ++i) { - const Value *V = (*II)->getOperand (i); - // Don't worry about it unless it's something whose reg. we'll need. - if (!isa<Argument> (V) && !isa<Instruction> (V)) - continue; - saveStateForValue (state, V, Insn, i); - } - ++Insn; - } -} - - -/// Check the saved state filled in by saveState(), and abort if it looks -/// wrong. Only used when debugging. FIXME: Currently it just prints out -/// the state, which isn't quite as useful. -/// -void PhyRegAlloc::verifySavedState () { - std::vector<AllocInfo> &state = FnAllocState[Fn]; - unsigned Insn = 0; - for (const_inst_iterator II=inst_begin (Fn), IE=inst_end (Fn); II!=IE; ++II) { - const Instruction *I = *II; - MachineCodeForInstruction &Instrs = MachineCodeForInstruction::get (I); - std::cerr << "Instruction:\n" << " " << *I << "\n" - << "MachineCodeForInstruction:\n"; - for (unsigned i = 0, n = Instrs.size (); i != n; ++i) - std::cerr << " " << *Instrs[i] << "\n"; - std::cerr << "FnAllocState:\n"; - for (unsigned i = 0; i < state.size (); ++i) { - AllocInfo &S = state[i]; - if (Insn == S.Instruction) - std::cerr << " " << S << "\n"; - } - std::cerr << "----------\n"; - ++Insn; - } -} - - -/// Finish the job of saveState(), by collapsing FnAllocState into an LLVM -/// Constant and stuffing it inside the Module. (NOTE: Soon, there will be -/// other, better ways of storing the saved state; this one is cumbersome and -/// does not work well with the JIT.) -/// -bool PhyRegAlloc::doFinalization (Module &M) { - if (!SaveRegAllocState) - return false; // Nothing to do here, unless we're saving state. - - // If saving state into the module, just copy new elements to the - // correct global. - if (!SaveStateToModule) { - ExportedFnAllocState = FnAllocState; - // FIXME: should ONLY copy new elements in FnAllocState - return false; - } - - // Convert FnAllocState to a single Constant array and add it - // to the Module. - ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), 0); - std::vector<const Type *> TV; - TV.push_back (Type::UIntTy); - TV.push_back (AT); - PointerType *PT = PointerType::get (StructType::get (TV)); - - std::vector<Constant *> allstate; - for (Module::iterator I = M.begin (), E = M.end (); I != E; ++I) { - Function *F = I; - if (F->isExternal ()) continue; - if (FnAllocState.find (F) == FnAllocState.end ()) { - allstate.push_back (ConstantPointerNull::get (PT)); - } else { - std::vector<AllocInfo> &state = FnAllocState[F]; - - // Convert state into an LLVM ConstantArray, and put it in a - // ConstantStruct (named S) along with its size. - std::vector<Constant *> stateConstants; - for (unsigned i = 0, s = state.size (); i != s; ++i) - stateConstants.push_back (state[i].toConstant ()); - unsigned Size = stateConstants.size (); - ArrayType *AT = ArrayType::get (AllocInfo::getConstantType (), Size); - std::vector<const Type *> TV; - TV.push_back (Type::UIntTy); - TV.push_back (AT); - StructType *ST = StructType::get (TV); - std::vector<Constant *> CV; - CV.push_back (ConstantUInt::get (Type::UIntTy, Size)); - CV.push_back (ConstantArray::get (AT, stateConstants)); - Constant *S = ConstantStruct::get (ST, CV); - - GlobalVariable *GV = - new GlobalVariable (ST, true, - GlobalValue::InternalLinkage, S, - F->getName () + ".regAllocState", &M); - - // Have: { uint, [Size x { uint, int, uint, int }] } * - // Cast it to: { uint, [0 x { uint, int, uint, int }] } * - Constant *CE = ConstantExpr::getCast (ConstantPointerRef::get (GV), PT); - allstate.push_back (CE); - } - } - - unsigned Size = allstate.size (); - // Final structure type is: - // { uint, [Size x { uint, [0 x { uint, int, uint, int }] } *] } - std::vector<const Type *> TV2; - TV2.push_back (Type::UIntTy); - ArrayType *AT2 = ArrayType::get (PT, Size); - TV2.push_back (AT2); - StructType *ST2 = StructType::get (TV2); - std::vector<Constant *> CV2; - CV2.push_back (ConstantUInt::get (Type::UIntTy, Size)); - CV2.push_back (ConstantArray::get (AT2, allstate)); - new GlobalVariable (ST2, true, GlobalValue::ExternalLinkage, - ConstantStruct::get (ST2, CV2), "_llvm_regAllocState", - &M); - return false; // No error. -} - - -/// Allocate registers for the machine code previously generated for F using -/// the graph-coloring algorithm. -/// -bool PhyRegAlloc::runOnFunction (Function &F) { - if (DEBUG_RA) - std::cerr << "\n********* Function "<< F.getName () << " ***********\n"; - - Fn = &F; - MF = &MachineFunction::get (Fn); - LVI = &getAnalysis<FunctionLiveVarInfo> (); - LRI = new LiveRangeInfo (Fn, TM, RegClassList); - LoopDepthCalc = &getAnalysis<LoopInfo> (); - - // Create each RegClass for the target machine and add it to the - // RegClassList. This must be done before calling constructLiveRanges(). - for (unsigned rc = 0; rc != NumOfRegClasses; ++rc) - RegClassList.push_back (new RegClass (Fn, &TM.getRegInfo (), - MRI.getMachineRegClass (rc))); - - LRI->constructLiveRanges(); // create LR info - if (DEBUG_RA >= RA_DEBUG_LiveRanges) - LRI->printLiveRanges(); - - createIGNodeListsAndIGs(); // create IGNode list and IGs - - buildInterferenceGraphs(); // build IGs in all reg classes - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) { - // print all LRs in all reg classes - for ( unsigned rc=0; rc < NumOfRegClasses ; rc++) - RegClassList[rc]->printIGNodeList(); - - // print IGs in all register classes - for ( unsigned rc=0; rc < NumOfRegClasses ; rc++) - RegClassList[rc]->printIG(); - } - - LRI->coalesceLRs(); // coalesce all live ranges - - if (DEBUG_RA >= RA_DEBUG_LiveRanges) { - // print all LRs in all reg classes - for (unsigned rc=0; rc < NumOfRegClasses; rc++) - RegClassList[rc]->printIGNodeList(); - - // print IGs in all register classes - for (unsigned rc=0; rc < NumOfRegClasses; rc++) - RegClassList[rc]->printIG(); - } - - // mark un-usable suggested color before graph coloring algorithm. - // When this is done, the graph coloring algo will not reserve - // suggested color unnecessarily - they can be used by another LR - markUnusableSugColors(); - - // color all register classes using the graph coloring algo - for (unsigned rc=0; rc < NumOfRegClasses ; rc++) - RegClassList[rc]->colorAllRegs(); - - // After graph coloring, if some LRs did not receive a color (i.e, spilled) - // a position for such spilled LRs - allocateStackSpace4SpilledLRs(); - - // Reset the temp. area on the stack before use by the first instruction. - // This will also happen after updating each instruction. - MF->getInfo()->popAllTempValues(); - - // color incoming args - if the correct color was not received - // insert code to copy to the correct register - colorIncomingArgs(); - - // Save register allocation state for this function in a Constant. - if (SaveRegAllocState) - saveState(); - if (DEBUG_RA) { // Check our work. - verifySavedState (); - } - - // Now update the machine code with register names and add any additional - // code inserted by the register allocator to the instruction stream. - updateMachineCode(); - - if (DEBUG_RA) { - std::cerr << "\n**** Machine Code After Register Allocation:\n\n"; - MF->dump(); - } - - // Tear down temporary data structures - for (unsigned rc = 0; rc < NumOfRegClasses; ++rc) - delete RegClassList[rc]; - RegClassList.clear (); - AddedInstrMap.clear (); - OperandsColoredMap.clear (); - ScratchRegsUsed.clear (); - AddedInstrAtEntry.clear (); - delete LRI; - - if (DEBUG_RA) std::cerr << "\nRegister allocation complete!\n"; - return false; // Function was not modified -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.h b/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.h deleted file mode 100644 index 4ec083c8ea3..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/PhyRegAlloc.h +++ /dev/null @@ -1,186 +0,0 @@ -//===-- PhyRegAlloc.h - Graph Coloring Register Allocator -------*- c++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This is the main entry point for register allocation. -// -// Notes: -// * RegisterClasses: Each RegClass accepts a -// TargetRegClass which contains machine specific info about that register -// class. The code in the RegClass is machine independent and they use -// access functions in the TargetRegClass object passed into it to get -// machine specific info. -// -// * Machine dependent work: All parts of the register coloring algorithm -// except coloring of an individual node are machine independent. -// -//===----------------------------------------------------------------------===// - -#ifndef PHYREGALLOC_H -#define PHYREGALLOC_H - -#include "LiveRangeInfo.h" -#include "llvm/Pass.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" -#include <map> - -namespace llvm { - -class MachineFunction; -class FunctionLiveVarInfo; -class MachineInstr; -class LoopInfo; -class RegClass; -class Constant; - -//---------------------------------------------------------------------------- -// Class AddedInstrns: -// When register allocator inserts new instructions in to the existing -// instruction stream, it does NOT directly modify the instruction stream. -// Rather, it creates an object of AddedInstrns and stick it in the -// AddedInstrMap for an existing instruction. This class contains two vectors -// to store such instructions added before and after an existing instruction. -//---------------------------------------------------------------------------- - -struct AddedInstrns { - std::vector<MachineInstr*> InstrnsBefore;//Insts added BEFORE an existing inst - std::vector<MachineInstr*> InstrnsAfter; //Insts added AFTER an existing inst - inline void clear () { InstrnsBefore.clear (); InstrnsAfter.clear (); } -}; - -//---------------------------------------------------------------------------- -// class PhyRegAlloc: -// Main class the register allocator. Call runOnFunction() to allocate -// registers for a Function. -//---------------------------------------------------------------------------- - -class PhyRegAlloc : public FunctionPass { - std::vector<RegClass *> RegClassList; // vector of register classes - const TargetMachine &TM; // target machine - const Function *Fn; // name of the function we work on - MachineFunction *MF; // descriptor for method's native code - FunctionLiveVarInfo *LVI; // LV information for this method - // (already computed for BBs) - LiveRangeInfo *LRI; // LR info (will be computed) - const TargetRegInfo &MRI; // Machine Register information - const unsigned NumOfRegClasses; // recorded here for efficiency - - // Map to indicate whether operands of each MachineInstr have been - // updated according to their assigned colors. This is only used in - // assertion checking (debug builds). - std::map<const MachineInstr *, bool> OperandsColoredMap; - - // AddedInstrMap - Used to store instrns added in this phase - std::map<const MachineInstr *, AddedInstrns> AddedInstrMap; - - // ScratchRegsUsed - Contains scratch register uses for a particular MI. - typedef std::multimap<const MachineInstr*, int> ScratchRegsUsedTy; - ScratchRegsUsedTy ScratchRegsUsed; - - AddedInstrns AddedInstrAtEntry; // to store instrns added at entry - const LoopInfo *LoopDepthCalc; // to calculate loop depths - - PhyRegAlloc(const PhyRegAlloc&); // DO NOT IMPLEMENT - void operator=(const PhyRegAlloc&); // DO NOT IMPLEMENT -public: - typedef std::map<const Function *, std::vector<AllocInfo> > SavedStateMapTy; - - inline PhyRegAlloc (const TargetMachine &TM_) : - TM (TM_), MRI (TM.getRegInfo ()), - NumOfRegClasses (MRI.getNumOfRegClasses ()) { } - virtual ~PhyRegAlloc() { } - - /// runOnFunction - Main method called for allocating registers. - /// - virtual bool runOnFunction (Function &F); - - virtual bool doFinalization (Module &M); - - virtual void getAnalysisUsage (AnalysisUsage &AU) const; - - const char *getPassName () const { - return "Traditional graph-coloring reg. allocator"; - } - - inline const RegClass* getRegClassByID(unsigned id) const { - return RegClassList[id]; - } - inline RegClass *getRegClassByID(unsigned id) { return RegClassList[id]; } - -private: - SavedStateMapTy FnAllocState; - - void addInterference(const Value *Def, const ValueSet *LVSet, - bool isCallInst); - bool markAllocatedRegs(MachineInstr* MInst); - - void addInterferencesForArgs(); - void createIGNodeListsAndIGs(); - void buildInterferenceGraphs(); - - void saveStateForValue (std::vector<AllocInfo> &state, - const Value *V, unsigned Insn, int Opnd); - void saveState(); - void verifySavedState(); - - void setCallInterferences(const MachineInstr *MI, - const ValueSet *LVSetAft); - - void move2DelayedInstr(const MachineInstr *OrigMI, - const MachineInstr *DelayedMI); - - void markUnusableSugColors(); - void allocateStackSpace4SpilledLRs(); - - void insertCode4SpilledLR(const LiveRange *LR, - MachineBasicBlock::iterator& MII, - MachineBasicBlock &MBB, unsigned OpNum); - - /// Method for inserting caller saving code. The caller must save all the - /// volatile registers live across a call. - /// - void insertCallerSavingCode(std::vector<MachineInstr*>& instrnsBefore, - std::vector<MachineInstr*>& instrnsAfter, - MachineInstr *CallMI, - const BasicBlock *BB); - - void colorIncomingArgs(); - void colorCallRetArgs(); - void updateMachineCode(); - void updateInstruction(MachineBasicBlock::iterator& MII, - MachineBasicBlock &MBB); - - int getUsableUniRegAtMI(int RegType, const ValueSet *LVSetBef, - MachineInstr *MI, - std::vector<MachineInstr*>& MIBef, - std::vector<MachineInstr*>& MIAft); - - /// Callback method used to find unused registers. - /// LVSetBef is the live variable set to search for an unused register. - /// If it is not specified, the LV set before the current MI is used. - /// This is sufficient as long as no new copy instructions are generated - /// to copy the free register to memory. - /// - int getUnusedUniRegAtMI(RegClass *RC, int RegType, - const MachineInstr *MI, - const ValueSet *LVSetBef = 0); - - void setRelRegsUsedByThisInst(RegClass *RC, int RegType, - const MachineInstr *MI); - - int getUniRegNotUsedByThisInst(RegClass *RC, int RegType, - const MachineInstr *MI); - - void addInterf4PseudoInstr(const MachineInstr *MI); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/RegAllocCommon.h b/llvm/lib/Target/Sparc/RegAlloc/RegAllocCommon.h deleted file mode 100644 index 7dd86b205af..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/RegAllocCommon.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- RegAllocCommon.h --------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Shared declarations for register allocation. -// -//===----------------------------------------------------------------------===// - -#ifndef REGALLOCCOMMON_H -#define REGALLOCCOMMON_H - -namespace llvm { - -enum RegAllocDebugLevel_t { - RA_DEBUG_None = 0, - RA_DEBUG_Results = 1, - RA_DEBUG_Coloring = 2, - RA_DEBUG_Interference = 3, - RA_DEBUG_LiveRanges = 4, - RA_DEBUG_Verbose = 5 -}; - -extern RegAllocDebugLevel_t DEBUG_RA; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/RegAlloc/RegClass.cpp b/llvm/lib/Target/Sparc/RegAlloc/RegClass.cpp deleted file mode 100644 index 9af87ba0e86..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/RegClass.cpp +++ /dev/null @@ -1,250 +0,0 @@ -//===-- RegClass.cpp -----------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// class RegClass for coloring-based register allocation for LLVM. -// -//===----------------------------------------------------------------------===// - -#include "IGNode.h" -#include "RegAllocCommon.h" -#include "RegClass.h" -#include "llvm/Target/TargetRegInfo.h" - -namespace llvm { - -//---------------------------------------------------------------------------- -// This constructor inits IG. The actual matrix is created by a call to -// createInterferenceGraph() above. -//---------------------------------------------------------------------------- -RegClass::RegClass(const Function *M, - const TargetRegInfo *_MRI_, - const TargetRegClassInfo *_MRC_) - : Meth(M), MRI(_MRI_), MRC(_MRC_), - RegClassID( _MRC_->getRegClassID() ), - IG(this), IGNodeStack() { - if (DEBUG_RA >= RA_DEBUG_Interference) - std::cerr << "Created Reg Class: " << RegClassID << "\n"; - - IsColorUsedArr.resize(MRC->getNumOfAllRegs()); -} - - - -//---------------------------------------------------------------------------- -// Main entry point for coloring a register class. -//---------------------------------------------------------------------------- -void RegClass::colorAllRegs() -{ - if (DEBUG_RA >= RA_DEBUG_Coloring) - std::cerr << "Coloring IG of reg class " << RegClassID << " ...\n"; - // pre-color IGNodes - pushAllIGNodes(); // push all IG Nodes - - unsigned int StackSize = IGNodeStack.size(); - IGNode *CurIGNode; - // for all LRs on stack - for (unsigned int IGN=0; IGN < StackSize; IGN++) { - CurIGNode = IGNodeStack.top(); // pop the IGNode on top of stack - IGNodeStack.pop(); - colorIGNode (CurIGNode); // color it - } -} - - - -//---------------------------------------------------------------------------- -// The method for pushing all IGNodes on to the stack. -//---------------------------------------------------------------------------- -void RegClass::pushAllIGNodes() -{ - bool NeedMoreSpills; - - - IG.setCurDegreeOfIGNodes(); // calculate degree of IGNodes - - // push non-constrained IGNodes - bool PushedAll = pushUnconstrainedIGNodes(); - - if (DEBUG_RA >= RA_DEBUG_Coloring) { - std::cerr << " Puhsed all-unconstrained IGNodes. "; - if( PushedAll ) std::cerr << " No constrained nodes left."; - std::cerr << "\n"; - } - - if (PushedAll) // if NO constrained nodes left - return; - - - // now, we have constrained nodes. So, push one of them (the one with min - // spill cost) and try to push the others as unConstrained nodes. - // Repeat this. - - do { - //get node with min spill cost - IGNode *IGNodeSpill = getIGNodeWithMinSpillCost(); - // push that node on to stack - IGNodeStack.push(IGNodeSpill); - // set its OnStack flag and decrement degree of neighs - IGNodeSpill->pushOnStack(); - // now push NON-constrained ones, if any - NeedMoreSpills = !pushUnconstrainedIGNodes(); - if (DEBUG_RA >= RA_DEBUG_Coloring) - std::cerr << "\nConstrained IG Node found !@!" << IGNodeSpill->getIndex(); - } while(NeedMoreSpills); // repeat until we have pushed all - -} - - - - -//-------------------------------------------------------------------------- -// This method goes thru all IG nodes in the IGNodeList of an IG of a -// register class and push any unconstrained IG node left (that is not -// already pushed) -//-------------------------------------------------------------------------- - -bool RegClass::pushUnconstrainedIGNodes() -{ - // # of LRs for this reg class - unsigned int IGNodeListSize = IG.getIGNodeList().size(); - bool pushedall = true; - - // a pass over IGNodeList - for (unsigned i =0; i < IGNodeListSize; i++) { - - // get IGNode i from IGNodeList - IGNode *IGNode = IG.getIGNodeList()[i]; - - if (!IGNode ) // can be null due to merging - continue; - - // if already pushed on stack, continue. This can happen since this - // method can be called repeatedly until all constrained nodes are - // pushed - if (IGNode->isOnStack() ) - continue; - // if the degree of IGNode is lower - if ((unsigned) IGNode->getCurDegree() < MRC->getNumOfAvailRegs()) { - IGNodeStack.push( IGNode ); // push IGNode on to the stack - IGNode->pushOnStack(); // set OnStack and dec deg of neighs - - if (DEBUG_RA >= RA_DEBUG_Coloring) { - std::cerr << " pushed un-constrained IGNode " << IGNode->getIndex() - << " on to stack\n"; - } - } - else pushedall = false; // we didn't push all live ranges - - } // for - - // returns true if we pushed all live ranges - else false - return pushedall; -} - - - -//---------------------------------------------------------------------------- -// Get the IGNode with the minimum spill cost -//---------------------------------------------------------------------------- -IGNode * RegClass::getIGNodeWithMinSpillCost() { - unsigned int IGNodeListSize = IG.getIGNodeList().size(); - double MinSpillCost = 0; - IGNode *MinCostIGNode = NULL; - bool isFirstNode = true; - - // pass over IGNodeList to find the IGNode with minimum spill cost - // among all IGNodes that are not yet pushed on to the stack - for (unsigned int i =0; i < IGNodeListSize; i++) { - IGNode *IGNode = IG.getIGNodeList()[i]; - - if (!IGNode) // can be null due to merging - continue; - - if (!IGNode->isOnStack()) { - double SpillCost = (double) IGNode->getParentLR()->getSpillCost() / - (double) (IGNode->getCurDegree() + 1); - - if (isFirstNode) { // for the first IG node - MinSpillCost = SpillCost; - MinCostIGNode = IGNode; - isFirstNode = false; - } else if (MinSpillCost > SpillCost) { - MinSpillCost = SpillCost; - MinCostIGNode = IGNode; - } - } - } - - assert (MinCostIGNode && "No IGNode to spill"); - return MinCostIGNode; -} - - -//---------------------------------------------------------------------------- -// Color the IGNode using the machine specific code. -//---------------------------------------------------------------------------- -void RegClass::colorIGNode(IGNode *const Node) { - if (! Node->hasColor()) { // not colored as an arg etc. - - // init all elements of to IsColorUsedAr false; - clearColorsUsed(); - - // initialize all colors used by neighbors of this node to true - LiveRange *LR = Node->getParentLR(); - unsigned NumNeighbors = Node->getNumOfNeighbors(); - for (unsigned n=0; n < NumNeighbors; n++) { - IGNode *NeighIGNode = Node->getAdjIGNode(n); - LiveRange *NeighLR = NeighIGNode->getParentLR(); - - // Don't use a color if it is in use by the neighbor, - // or is suggested for use by the neighbor, - // markColorsUsed() should be given the color and the reg type for - // LR, not for NeighLR, because it should mark registers used based on - // the type we are looking for, not on the regType for the neighbour. - if (NeighLR->hasColor()) - this->markColorsUsed(NeighLR->getColor(), - MRI->getRegTypeForLR(NeighLR), - MRI->getRegTypeForLR(LR)); // use LR, not NeighLR - else if (NeighLR->hasSuggestedColor() && - NeighLR->isSuggestedColorUsable()) - this->markColorsUsed(NeighLR->getSuggestedColor(), - MRI->getRegTypeForLR(NeighLR), - MRI->getRegTypeForLR(LR)); // use LR, not NeighLR - } - - // call the target specific code for coloring - // - MRC->colorIGNode(Node, IsColorUsedArr); - } else { - if (DEBUG_RA >= RA_DEBUG_Coloring) { - std::cerr << " Node " << Node->getIndex(); - std::cerr << " already colored with color " << Node->getColor() << "\n"; - } - } - - - if (!Node->hasColor() ) { - if (DEBUG_RA >= RA_DEBUG_Coloring) { - std::cerr << " Node " << Node->getIndex(); - std::cerr << " - could not find a color (needs spilling)\n"; - } - } -} - -void RegClass::printIGNodeList() const { - std::cerr << "IG Nodes for Register Class " << RegClassID << ":" << "\n"; - IG.printIGNodeList(); -} - -void RegClass::printIG() { - std::cerr << "IG for Register Class " << RegClassID << ":" << "\n"; - IG.printIG(); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/RegAlloc/RegClass.h b/llvm/lib/Target/Sparc/RegAlloc/RegClass.h deleted file mode 100644 index 0071f7c2129..00000000000 --- a/llvm/lib/Target/Sparc/RegAlloc/RegClass.h +++ /dev/null @@ -1,147 +0,0 @@ -//===-- RegClass.h - Machine Independent register coloring ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -/* Title: RegClass.h -*- C++ -*- - Author: Ruchira Sasanka - Date: Aug 20, 01 - Purpose: Contains machine independent methods for register coloring. - -*/ - -#ifndef REGCLASS_H -#define REGCLASS_H - -#include "llvm/Target/TargetRegInfo.h" -#include "InterferenceGraph.h" -#include <stack> - -namespace llvm { - -class TargetRegClassInfo; - - -//----------------------------------------------------------------------------- -// Class RegClass -// -// Implements a machine independent register class. -// -// This is the class that contains all data structures and common algos -// for coloring a particular register class (e.g., int class, fp class). -// This class is hardware independent. This class accepts a hardware -// dependent description of machine registers (TargetRegInfo class) to -// get hardware specific info and to color an individual IG node. -// -// This class contains the InterferenceGraph (IG). -// Also it contains an IGNode stack that can be used for coloring. -// The class provides some easy access methods to the IG methods, since these -// methods are called thru a register class. -// -//----------------------------------------------------------------------------- -class RegClass { - const Function *const Meth; // Function we are working on - const TargetRegInfo *MRI; // Machine register information - const TargetRegClassInfo *const MRC; // Machine reg. class for this RegClass - const unsigned RegClassID; // my int ID - - InterferenceGraph IG; // Interference graph - constructed by - // buildInterferenceGraph - std::stack<IGNode *> IGNodeStack; // the stack used for coloring - - // IsColorUsedArr - An array used for coloring each node. This array must be - // of size MRC->getNumOfAllRegs(). Allocated once in the constructor for - // efficiency. - // - std::vector<bool> IsColorUsedArr; - - - - //--------------------------- private methods ------------------------------ - - void pushAllIGNodes(); - - bool pushUnconstrainedIGNodes(); - - IGNode * getIGNodeWithMinSpillCost(); - - void colorIGNode(IGNode *const Node); - - // This directly marks the colors used by a particular register number - // within the register class. External users should use the public - // versions of this function below. - inline void markColorUsed(unsigned classRegNum) { - assert(classRegNum < IsColorUsedArr.size() && "Invalid register used?"); - IsColorUsedArr[classRegNum] = true; - } - - inline bool isColorUsed(unsigned regNum) const { - assert(regNum < IsColorUsedArr.size() && "Invalid register used?"); - return IsColorUsedArr[regNum]; - } - - public: - - RegClass(const Function *M, - const TargetRegInfo *_MRI_, - const TargetRegClassInfo *_MRC_); - - inline void createInterferenceGraph() { IG.createGraph(); } - - inline InterferenceGraph &getIG() { return IG; } - - inline const unsigned getID() const { return RegClassID; } - - inline const TargetRegClassInfo* getTargetRegClass() const { return MRC; } - - // main method called for coloring regs - // - void colorAllRegs(); - - inline unsigned getNumOfAvailRegs() const - { return MRC->getNumOfAvailRegs(); } - - - // --- following methods are provided to access the IG contained within this - // ---- RegClass easilly. - - inline void addLRToIG(LiveRange *const LR) - { IG.addLRToIG(LR); } - - inline void setInterference(const LiveRange *const LR1, - const LiveRange *const LR2) - { IG.setInterference(LR1, LR2); } - - inline unsigned getInterference(const LiveRange *const LR1, - const LiveRange *const LR2) const - { return IG.getInterference(LR1, LR2); } - - inline void mergeIGNodesOfLRs(const LiveRange *const LR1, - LiveRange *const LR2) - { IG.mergeIGNodesOfLRs(LR1, LR2); } - - - inline void clearColorsUsed() { - IsColorUsedArr.clear(); - IsColorUsedArr.resize(MRC->getNumOfAllRegs()); - } - inline void markColorsUsed(unsigned ClassRegNum, - int UserRegType, - int RegTypeWanted) { - MRC->markColorsUsed(ClassRegNum, UserRegType, RegTypeWanted,IsColorUsedArr); - } - inline int getUnusedColor(int machineRegType) const { - return MRC->findUnusedColor(machineRegType, IsColorUsedArr); - } - - void printIGNodeList() const; - void printIG(); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/Sparc.burg.in b/llvm/lib/Target/Sparc/Sparc.burg.in deleted file mode 100644 index 38dc2439ce8..00000000000 --- a/llvm/lib/Target/Sparc/Sparc.burg.in +++ /dev/null @@ -1,351 +0,0 @@ -%{ // -*- C++ -*- -/* ===----------------------------------------------------------------------=== -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===*/ - -Xinclude <cstdio> -Xinclude <llvm/CodeGen/InstrForest.h> - -typedef llvm::InstrTreeNode* NODEPTR_TYPE; -Xdefine OP_LABEL(p) ((p)->opLabel) -Xdefine LEFT_CHILD(p) ((p)->LeftChild) -Xdefine RIGHT_CHILD(p) ((p)->RightChild) -Xdefine STATE_LABEL(p) ((p)->state) -Xdefine PANIC printf - -// Get definitions for various instruction values that we will need... -#define HANDLE_TERM_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N -#define HANDLE_UNARY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N -#define HANDLE_BINARY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N -#define HANDLE_MEMORY_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N -#define HANDLE_OTHER_INST(N, OPC, CLASS) Ydefine OPC##OPCODE N - -#include "llvm/Instruction.def" - -%} - -%start stmt - -%term Ret=RetOPCODE /* return void from a function */ -%term RetValue=101 /* return a value from a function */ -%term BrUncond=BrOPCODE -%term BrCond=102 -%term Switch=SwitchOPCODE - /* 4 is unused */ -%term Add=AddOPCODE -%term Sub=SubOPCODE -%term Mul=MulOPCODE -%term Div=DivOPCODE -%term Rem=RemOPCODE -%term And=AndOPCODE -%term Or=OrOPCODE -%term Xor=XorOPCODE - /* Use the next 4 to distinguish bitwise operators from - * logical operators. This is no longer used for Sparc, - * but may be useful for other target machines. - * The last one is the bitwise Not(val) == XOR val, 11..1. - * Note that it is also a binary operator, not unary. - */ -%term BAnd=111 -%term BOr=112 -%term BXor=113 -%term BNot=213 - /* The next one is the boolean Not(val) == bool XOR val, true - * Note that it is also a binary operator, not unary. - */ -%term Not=313 - -%term SetCC=114 /* use this to match all SetCC instructions */ - /* %term SetEQ=13 */ - /* %term SetNE=14 */ - /* %term SetLE=15 */ - /* %term SetGE=16 */ - /* %term SetLT=17 */ - /* %term SetGT=18 */ -%term Malloc=MallocOPCODE -%term Free=FreeOPCODE -%term Alloca=AllocaOPCODE -%term AllocaN=122 /* alloca with arg N */ -%term Load=LoadOPCODE -%term Store=StoreOPCODE -%term GetElemPtr=GetElementPtrOPCODE -%term GetElemPtrIdx=125 /* getElemPtr with index vector */ - -%term Phi=PHIOPCODE - -%term Cast=CastOPCODE /* cast that will be ignored. others are made explicit */ -%term ToBoolTy=127 -%term ToUByteTy=128 -%term ToSByteTy=129 -%term ToUShortTy=130 -%term ToShortTy=131 -%term ToUIntTy=132 -%term ToIntTy=133 -%term ToULongTy=134 -%term ToLongTy=135 -%term ToFloatTy=136 -%term ToDoubleTy=137 -%term ToArrayTy=138 -%term ToPointerTy=139 - -%term Call=CallOPCODE -%term Shl=ShlOPCODE -%term Shr=ShrOPCODE -%term VANext=VANextOPCODE -%term VAArg=VAArgOPCODE - /* 33...46 are unused */ - /* - * The foll. values should match the constants in InstrForest.h - */ -%term VRegList=97 -%term VReg=98 -%term Constant=99 -%term Label=100 - /* 50+i is a variant of i, as defined above */ - - -%% -/*-----------------------------------------------------------------------* - * The productions of the grammar. - * Note that all chain rules are numbered 101 and above. - * Also, a special case of production X is numbered 100+X, 200+X, etc. - * The cost of a 1-cycle operation is represented as 10, to allow - * finer comparisons of costs (effectively, fractions of 1/10). - *-----------------------------------------------------------------------*/ - - /* - * The top-level statements - */ -stmt: Ret = 1 (30); -stmt: RetValue(reg) = 2 (30); -stmt: Store(reg,reg) = 3 (10); -stmt: Store(reg,ptrreg) = 4 (10); -stmt: BrUncond = 5 (20); -stmt: BrCond(setCC) = 6 (20); /* branch on cond. code */ -stmt: BrCond(setCCconst) = 206 (10); /* may save one instruction */ -stmt: BrCond(reg) = 8 (20); /* may avoid an extra instr */ -stmt: BrCond(Constant) = 208 (20); /* may avoid an extra instr */ -stmt: Switch(reg) = 9 (30); /* cost = load + branch */ - -stmt: reg = 111 (0); - - /* - * List node used for nodes with more than 2 children - */ -reg: VRegList(reg,reg) = 10 (0); - - /* - * Special case non-terminals to help combine unary instructions. - * Eg1: zdouble <- todouble(xfloat) * todouble(yfloat) - * Eg2: c <- a AND (NOT b). - * Note that the costs are counted for the special non-terminals here, - * and should not be counted again for the reg productions later. - */ -not: Not(reg,reg) = 21 (10); -tobool: ToBoolTy(reg) = 22 (10); -not: Not(tobool, reg) = 322 (10); // fold cast-to-bool into not -toubyte: ToUByteTy(reg) = 23 (10); -tosbyte: ToSByteTy(reg) = 24 (10); -toushort: ToUShortTy(reg) = 25 (10); -toshort: ToShortTy(reg) = 26 (10); -touint: ToUIntTy(reg) = 27 (10); -toint: ToIntTy(reg) = 28 (10); -toulong: ToULongTy(reg) = 29 (10); -tolong: ToLongTy(reg) = 30 (10); -tofloat: ToFloatTy(reg) = 31 (10); -todouble: ToDoubleTy(reg) = 32 (10); -todoubleConst: ToDoubleTy(Constant) = 232 (10); - - /* - * All the ways to produce a boolean value (Not and ToBoolTy are above): - * -- boolean operators: Not, And, Or, ..., ToBoolTy, SetCC - * -- an existing boolean register not in the same tree - * -- a boolean constant - * - * For And, Or, Xor, we add special cases for when: - * (a) one operand is a constant. - * (b) one operand is a NOT, to use the ANDN, ORN, and XORN instrns. - * We do not need the cases when both operands are constant - * because constant folding should take care of that beforehand. - */ -reg: And(reg,reg) = 38 (10); -reg: And(reg,not) = 138 (0); /* cost is counted for not */ -reg: And(reg,Constant) = 238 (10); -reg: Or (reg,reg) = 39 (10); -reg: Or (reg,not) = 139 (0); /* cost is counted for not */ -reg: Or (reg,Constant) = 239 (10); -reg: Xor(reg,reg) = 40 (10); -reg: Xor(reg,not) = 140 (0); /* cost is counted for not */ -reg: Xor(reg,Constant) = 240 (10); - - /* Special case non-terms for BrCond(setCC) and BrCond(setCCconst) */ -setCCconst: SetCC(reg,Constant) = 41 (5); -setCC: SetCC(reg,reg) = 42 (10); - -reg: not = 221 (0); -reg: tobool = 222 (0); -reg: setCCconst = 241 (0); -reg: setCC = 242 (0); - - /* - * Special case non-terminals for the unary cast operators. - * Some of these can be folded into other operations (e.g., todouble). - * The rest are just for uniformity. - */ -reg: toubyte = 123 (0); -reg: tosbyte = 124 (0); -reg: toushort = 125 (0); -reg: toshort = 126 (0); -reg: touint = 127 (0); -reg: toint = 128 (0); -reg: toulong = 129 (0); -reg: tolong = 130 (0); -reg: tofloat = 131 (0); -reg: todouble = 132 (0); -reg: todoubleConst = 133 (0); - -reg: ToArrayTy(reg) = 19 (10); -reg: ToPointerTy(reg) = 20 (10); - - /* - * The binary arithmetic operators. - */ -reg: Add(reg,reg) = 33 (10); -reg: Sub(reg,reg) = 34 (10); -reg: Mul(reg,reg) = 35 (30); -reg: Mul(todouble,todouble) = 135 (20); /* avoids 1-2 type converts */ -reg: Div(reg,reg) = 36 (60); -reg: Rem(reg,reg) = 37 (60); - - /* - * The binary bitwise logical operators. - */ -reg: BAnd(reg,reg) = 338 (10); -reg: BAnd(reg,bnot) = 438 ( 0); /* cost is counted for not */ -reg: BOr( reg,reg) = 339 (10); -reg: BOr( reg,bnot) = 439 ( 0); /* cost is counted for not */ -reg: BXor(reg,reg) = 340 (10); -reg: BXor(reg,bnot) = 440 ( 0); /* cost is counted for not */ - -reg: bnot = 321 ( 0); -bnot: BNot(reg,reg) = 421 (10); - - /* - * Special cases for the binary operators with one constant argument. - * Not and BNot are effectively just one argument, so not needed here. - */ -reg: Add(reg,Constant) = 233 (10); -reg: Sub(reg,Constant) = 234 (10); -reg: Mul(reg,Constant) = 235 (30); -reg: Mul(todouble,todoubleConst) = 335 (20); /* avoids 1-2 type converts */ -reg: Div(reg,Constant) = 236 (60); -reg: Rem(reg,Constant) = 237 (60); - -reg: BAnd(reg,Constant) = 538 (0); -reg: BOr( reg,Constant) = 539 (0); -reg: BXor(reg,Constant) = 540 (0); - - /* - * Memory access instructions - */ -reg: Load(reg) = 51 (30); -reg: Load(ptrreg) = 52 (20); /* 1 counted for ptrreg */ -reg: ptrreg = 155 (0); -ptrreg: GetElemPtr(reg) = 55 (10); -ptrreg: GetElemPtrIdx(reg,reg) = 56 (10); -reg: Alloca = 57 (10); -reg: AllocaN(reg) = 58 (10); - - /* - * Other operators producing register values - */ -reg: Call = 61 (20); /* just ignore the operands! */ -reg: Shl(reg,reg) = 62 (20); /* 1 for issue restrictions */ -reg: Shr(reg,reg) = 63 (20); /* 1 for issue restrictions */ -reg: Phi(reg,reg) = 64 (0); -reg: VANext(reg) = 65 (40); /* incr stack slot pointer */ -reg: VAArg(reg) = 66 (40); /* get a vararg */ - - /* - * Finally, leaf nodes of expression trees. - */ -reg: VReg = 71 (0); -reg: Constant = 72 (3); /* prefer direct use */ - - - -%% -/*-----------------------------------------------------------------------* - * The rest of this file provides code to print the cover produced - * by BURG and information about computed tree cost and matches. - * This code was taken from sample.gr provided with BURG. - *-----------------------------------------------------------------------*/ - -void printcover(NODEPTR_TYPE p, int goalnt, int indent) { - int eruleno = burm_rule(STATE_LABEL(p), goalnt); - short *nts = burm_nts[eruleno]; - NODEPTR_TYPE kids[10]; - int i; - - if (eruleno == 0) { - printf("no cover\n"); - return; - } - for (i = 0; i < indent; i++) - printf("."); - printf("%s\n", burm_string[eruleno]); - burm_kids(p, eruleno, kids); - for (i = 0; nts[i]; i++) - printcover(kids[i], nts[i], indent+1); -} - -void printtree(NODEPTR_TYPE p) { - int op = burm_op_label(p); - - printf("%s", burm_opname[op]); - switch (burm_arity[op]) { - case 0: - break; - case 1: - printf("("); - printtree(burm_child(p, 0)); - printf(")"); - break; - case 2: - printf("("); - printtree(burm_child(p, 0)); - printf(", "); - printtree(burm_child(p, 1)); - printf(")"); - break; - } -} - -int treecost(NODEPTR_TYPE p, int goalnt, int costindex) { - int eruleno = burm_rule(STATE_LABEL(p), goalnt); - int cost = burm_cost[eruleno][costindex], i; - short *nts = burm_nts[eruleno]; - NODEPTR_TYPE kids[10]; - - burm_kids(p, eruleno, kids); - for (i = 0; nts[i]; i++) - cost += treecost(kids[i], nts[i], costindex); - return cost; -} - -void printMatches(NODEPTR_TYPE p) { - int nt; - int eruleno; - - printf("Node 0x%lx= ", (unsigned long)p); - printtree(p); - printf(" matched rules:\n"); - for (nt = 1; burm_ntname[nt] != (char*)NULL; nt++) - if ((eruleno = burm_rule(STATE_LABEL(p), nt)) != 0) - printf("\t%s\n", burm_string[eruleno]); -} diff --git a/llvm/lib/Target/Sparc/Sparc.cpp b/llvm/lib/Target/Sparc/Sparc.cpp deleted file mode 100644 index 2b4c3cb1801..00000000000 --- a/llvm/lib/Target/Sparc/Sparc.cpp +++ /dev/null @@ -1,238 +0,0 @@ -//===-- Sparc.cpp - General implementation file for the Sparc Target ------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Primary interface to machine description for the UltraSPARC. Primarily just -// initializes machine-dependent parameters in class TargetMachine, and creates -// machine-dependent subclasses for classes such as TargetInstrInfo. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Function.h" -#include "llvm/IntrinsicLowering.h" -#include "llvm/PassManager.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/InstrScheduling.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Target/TargetMachineImpls.h" -#include "llvm/Transforms/Scalar.h" -#include "MappingInfo.h" -#include "SparcInternals.h" -#include "SparcTargetMachine.h" -#include "Support/CommandLine.h" - -using namespace llvm; - -static const unsigned ImplicitRegUseList[] = { 0 }; /* not used yet */ -// Build the MachineInstruction Description Array... -const TargetInstrDescriptor llvm::SparcMachineInstrDesc[] = { -#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ - { OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS, 0, \ - ImplicitRegUseList, ImplicitRegUseList }, -#include "SparcInstr.def" -}; - -//--------------------------------------------------------------------------- -// Command line options to control choice of code generation passes. -//--------------------------------------------------------------------------- - -namespace { - cl::opt<bool> DisableSched("disable-sched", - cl::desc("Disable local scheduling pass")); - - cl::opt<bool> DisablePeephole("disable-peephole", - cl::desc("Disable peephole optimization pass")); - - cl::opt<bool> EmitMappingInfo("enable-maps", - cl::desc("Emit LLVM-to-MachineCode mapping info to assembly")); - - cl::opt<bool> DisableStrip("disable-strip", - cl::desc("Do not strip the LLVM bytecode in executable")); -} - -//===---------------------------------------------------------------------===// -// Code generation/destruction passes -//===---------------------------------------------------------------------===// - -namespace { - class ConstructMachineFunction : public FunctionPass { - TargetMachine &Target; - public: - ConstructMachineFunction(TargetMachine &T) : Target(T) {} - - const char *getPassName() const { - return "ConstructMachineFunction"; - } - - bool runOnFunction(Function &F) { - MachineFunction::construct(&F, Target).getInfo()->CalculateArgSize(); - return false; - } - }; - - struct DestroyMachineFunction : public FunctionPass { - const char *getPassName() const { return "FreeMachineFunction"; } - - static void freeMachineCode(Instruction &I) { - MachineCodeForInstruction::destroy(&I); - } - - bool runOnFunction(Function &F) { - for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) - for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E; ++I) - MachineCodeForInstruction::get(I).dropAllReferences(); - - for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) - for_each(FI->begin(), FI->end(), freeMachineCode); - - MachineFunction::destruct(&F); - return false; - } - }; - - FunctionPass *createMachineCodeConstructionPass(TargetMachine &Target) { - return new ConstructMachineFunction(Target); - } -} - -FunctionPass *llvm::createSparcMachineCodeDestructionPass() { - return new DestroyMachineFunction(); -} - - -SparcTargetMachine::SparcTargetMachine(IntrinsicLowering *il) - : TargetMachine("UltraSparc-Native", il, false), - schedInfo(*this), - regInfo(*this), - frameInfo(*this), - cacheInfo(*this), - jitInfo(*this) { -} - -/// addPassesToEmitAssembly - This method controls the entire code generation -/// process for the ultra sparc. -/// -bool -SparcTargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) -{ - // The following 3 passes used to be inserted specially by llc. - // Replace malloc and free instructions with library calls. - PM.add(createLowerAllocationsPass()); - - // Strip all of the symbols from the bytecode so that it will be smaller... - if (!DisableStrip) - PM.add(createSymbolStrippingPass()); - - // FIXME: implement the switch instruction in the instruction selector. - PM.add(createLowerSwitchPass()); - - // FIXME: implement the invoke/unwind instructions! - PM.add(createLowerInvokePass()); - - // decompose multi-dimensional array references into single-dim refs - PM.add(createDecomposeMultiDimRefsPass()); - - // Construct and initialize the MachineFunction object for this fn. - PM.add(createMachineCodeConstructionPass(*this)); - - //Insert empty stackslots in the stack frame of each function - //so %fp+offset-8 and %fp+offset-16 are empty slots now! - PM.add(createStackSlotsPass(*this)); - - // Specialize LLVM code for this target machine and then - // run basic dataflow optimizations on LLVM code. - PM.add(createPreSelectionPass(*this)); - PM.add(createReassociatePass()); - PM.add(createLICMPass()); - PM.add(createGCSEPass()); - - PM.add(createInstructionSelectionPass(*this)); - - if (!DisableSched) - PM.add(createInstructionSchedulingWithSSAPass(*this)); - - PM.add(getRegisterAllocator(*this)); - PM.add(createPrologEpilogInsertionPass()); - - if (!DisablePeephole) - PM.add(createPeepholeOptsPass(*this)); - - if (EmitMappingInfo) - PM.add(getMappingInfoAsmPrinterPass(Out)); - - // Output assembly language to the .s file. Assembly emission is split into - // two parts: Function output and Global value output. This is because - // function output is pipelined with all of the rest of code generation stuff, - // allowing machine code representations for functions to be free'd after the - // function has been emitted. - PM.add(createAsmPrinterPass(Out, *this)); - PM.add(createSparcMachineCodeDestructionPass()); // Free mem no longer needed - - // Emit bytecode to the assembly file into its special section next - if (EmitMappingInfo) - PM.add(createBytecodeAsmPrinterPass(Out)); - - return false; -} - -/// addPassesToJITCompile - This method controls the JIT method of code -/// generation for the UltraSparc. -/// -void SparcJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { - const TargetData &TD = TM.getTargetData(); - - PM.add(new TargetData("lli", TD.isLittleEndian(), TD.getPointerSize(), - TD.getPointerAlignment(), TD.getDoubleAlignment())); - - // Replace malloc and free instructions with library calls. - // Do this after tracing until lli implements these lib calls. - // For now, it will emulate malloc and free internally. - PM.add(createLowerAllocationsPass()); - - // FIXME: implement the switch instruction in the instruction selector. - PM.add(createLowerSwitchPass()); - - // FIXME: implement the invoke/unwind instructions! - PM.add(createLowerInvokePass()); - - // decompose multi-dimensional array references into single-dim refs - PM.add(createDecomposeMultiDimRefsPass()); - - // Construct and initialize the MachineFunction object for this fn. - PM.add(createMachineCodeConstructionPass(TM)); - - // Specialize LLVM code for this target machine and then - // run basic dataflow optimizations on LLVM code. - PM.add(createPreSelectionPass(TM)); - PM.add(createReassociatePass()); - // FIXME: these passes crash the FunctionPassManager when being added... - //PM.add(createLICMPass()); - //PM.add(createGCSEPass()); - - PM.add(createInstructionSelectionPass(TM)); - - PM.add(getRegisterAllocator(TM)); - PM.add(createPrologEpilogInsertionPass()); - - if (!DisablePeephole) - PM.add(createPeepholeOptsPass(TM)); -} - -/// allocateSparcTargetMachine - Allocate and return a subclass of TargetMachine -/// that implements the Sparc backend. (the llvm/CodeGen/Sparc.h interface) -/// -TargetMachine *llvm::allocateSparcTargetMachine(const Module &M, - IntrinsicLowering *IL) { - return new SparcTargetMachine(IL); -} diff --git a/llvm/lib/Target/Sparc/SparcInstr.def b/llvm/lib/Target/Sparc/SparcInstr.def deleted file mode 100644 index 8c7c7c749e9..00000000000 --- a/llvm/lib/Target/Sparc/SparcInstr.def +++ /dev/null @@ -1,553 +0,0 @@ -//===-- SparcInstr.def - Sparc Instruction Information -----------*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file describes all of the instructions that the sparc backend uses. It -// relys on an external 'I' macro being defined that takes the arguments -// specified below, and is used to make all of the information relevant to an -// instruction be in one place. -// -//===----------------------------------------------------------------------===// - -// NOTE: No include guards desired - -#ifndef I -#errror "Must define I macro before including SparcInstr.def!" -#endif - -// Constants for defining the maximum constant size field. -// One #define per bit size -// -#define B5 ((1 << 5) - 1) -#define B6 ((1 << 6) - 1) -#define B12 ((1 << 12) - 1) -#define B15 ((1 << 15) - 1) -#define B18 ((1 << 18) - 1) -#define B21 ((1 << 21) - 1) -#define B22 ((1 << 22) - 1) -#define B29 ((1 << 29) - 1) - -// Arguments passed into the I macro -// enum name, -// opCodeString, -// numOperands, -// resultPosition (0-based; -1 if no result), -// maxImmedConst, -// immedIsSignExtended, -// numDelaySlots (in cycles) -// latency (in cycles) -// instr sched class (defined above) -// instr class flags (defined in TargetInstrInfo.h) - - - -I(NOP, "nop", 0, -1, 0, false, 0, 1, SPARC_NONE, M_NOP_FLAG) - -// Synthetic SPARC assembly opcodes for setting a register to a constant. -// Max immediate constant should be ignored for both these instructions. -// Use a latency > 1 since this may generate as many as 3 instructions. -I(SETSW, "setsw", 2, 1, 0, true , 0, 2, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) -I(SETUW, "setuw", 2, 1, 0, false, 0, 2, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) -I(SETX, "setx", 3, 2, 0, true, 0, 2, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG | M_PSEUDO_FLAG ) - -// Set high-order bits of register and clear low-order bits -I(SETHI, "sethi", 2, 1, B22, false, 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG | M_ARITH_FLAG) - -// Add or add with carry. -I(ADDr , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDi , "add", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDccr, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDcci, "addcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDCr , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDCi , "addc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(ADDCccr, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(ADDCcci, "addccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) - -// Subtract or subtract with carry. -I(SUBr , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBi , "sub", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBccr , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBcci , "subcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBCr , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBCi , "subc", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SUBCccr, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(SUBCcci, "subccc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) - -// Integer multiply, signed divide, unsigned divide. -// Note that the deprecated 32-bit multiply and multiply-step are not used. -I(MULXr , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(MULXi , "mulx", 3, 2, B12, true , 0, 3, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SDIVXr, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(SDIVXi, "sdivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(UDIVXr, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) -I(UDIVXi, "udivx", 3, 2, B12, true , 0, 6, SPARC_IEUN, M_INT_FLAG | M_ARITH_FLAG) - - // Floating point add, subtract, compare. - // Note that destination of FCMP* instructions is operand 0, not operand 2. -I(FADDS, "fadds", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FADDD, "faddd", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FADDQ, "faddq", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBS, "fsubs", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBD, "fsubd", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSUBQ, "fsubq", 3, 2, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FCMPS, "fcmps", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(FCMPD, "fcmpd", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -I(FCMPQ, "fcmpq", 3, 0, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG | M_CC_FLAG ) -// NOTE: FCMPE{S,D,Q}: FP Compare With Exception are currently unused! - -// Floating point multiply or divide. -I(FMULS , "fmuls", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FMULD , "fmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FMULQ , "fmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSMULD, "fsmuld", 3, 2, 0, false, 0, 3, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDMULQ, "fdmulq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVS , "fdivs", 3, 2, 0, false, 0, 12, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVD , "fdivd", 3, 2, 0, false, 0, 22, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDIVQ , "fdivq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTS, "fsqrts", 3, 2, 0, false, 0, 12, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTD, "fsqrtd", 3, 2, 0, false, 0, 22, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSQRTQ, "fsqrtq", 3, 2, 0, false, 0, 0, SPARC_FPM, M_FLOAT_FLAG | M_ARITH_FLAG) - -// Logical operations -I(ANDr , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDi , "and", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDccr , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDcci , "andcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNr , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNi , "andn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNccr, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ANDNcci, "andncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) - -I(ORr , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORi , "or", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORccr , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORcci , "orcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNr , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNi , "orn", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNccr, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(ORNcci, "orncc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) - -I(XORr , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORi , "xor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORccr , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XORcci , "xorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORr , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORi , "xnor", 3, 2, B12, true , 0, 1, SPARC_IEUN, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORccr, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) -I(XNORcci, "xnorcc", 4, 2, B12, true , 0, 1, SPARC_IEU1, M_INT_FLAG | M_LOGICAL_FLAG) - -// Shift operations -I(SLLr5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SLLi5 , "sll", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLr5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLi5 , "srl", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRAr5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SRAi5 , "sra", 3, 2, B5, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SLLXr6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SLLXi6, "sllx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLXr6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRLXi6, "srlx", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_LOGICAL_FLAG) -I(SRAXr6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) -I(SRAXi6, "srax", 3, 2, B6, true , 0, 1, SPARC_IEU0, M_INT_FLAG | M_ARITH_FLAG) - -// Floating point move, negate, and abs instructions -I(FMOVS, "fmovs", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FMOVD, "fmovd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FMOVQ, "fmovq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) -I(FNEGS, "fnegs", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FNEGD, "fnegd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FNEGQ, "fnegq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) -I(FABSS, "fabss", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -I(FABSD, "fabsd", 2, 1, 0, false, 0, 1, SPARC_FPA, M_FLOAT_FLAG) -//I(FABSQ, "fabsq", 2, 1, 0, false, 0, ?, SPARC_FPA, M_FLOAT_FLAG) - -// Convert from floating point to floating point formats -I(FSTOD, "fstod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FSTOQ, "fstoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDTOS, "fdtos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FDTOQ, "fdtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FQTOS, "fqtos", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) -I(FQTOD, "fqtod", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_ARITH_FLAG) - -// Convert from floating point to integer formats. -// Note that this accesses both integer and floating point registers. -I(FSTOX, "fstox", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FDTOX, "fdtox", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FQTOX, "fqtox", 2, 1, 0, false, 0, 2, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FSTOI, "fstoi", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FDTOI, "fdtoi", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FQTOI, "fqtoi", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) - -// Convert from integer to floating point formats -// Note that this accesses both integer and floating point registers. -I(FXTOS, "fxtos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FXTOD, "fxtod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FXTOQ, "fxtoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOS, "fitos", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOD, "fitod", 2, 1, 0, false, 0, 3, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) -I(FITOQ, "fitoq", 2, 1, 0, false, 0, 0, SPARC_FPA, M_FLOAT_FLAG | M_INT_FLAG | M_ARITH_FLAG) - -// Branch on integer comparison with zero. -// Latency excludes the delay slot since it can be issued in same cycle. -I(BRZ , "brz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRLEZ, "brlez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRLZ , "brlz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRNZ , "brnz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRGZ , "brgz", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) -I(BRGEZ, "brgez", 2, -1, B15, true , 1, 1, SPARC_CTI, M_INT_FLAG | M_BRANCH_FLAG) - -// Branch on integer condition code. -// The first argument specifies the ICC register: %icc or %xcc -// Latency includes the delay slot. -I(BA , "ba", 1, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BN , "bn", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BNE , "bne", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BE , "be", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BG , "bg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BLE , "ble", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BGE , "bge", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BL , "bl", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BGU , "bgu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BLEU, "bleu", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BCC , "bcc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BCS , "bcs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BPOS, "bpos", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BNEG, "bneg", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BVC , "bvc", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(BVS , "bvs", 2, -1, B21, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) - -// Branch on floating point condition code. -// The first argument is the FCCn register (0 <= n <= 3). -// Latency includes the delay slot. -I(FBA , "fba", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBN , "fbn", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBU , "fbu", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBG , "fbg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBUG , "fbug", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBL , "fbl", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBUL , "fbul", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBLG , "fblg", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBNE , "fbne", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBE , "fbe", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBUE , "fbue", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBGE , "fbge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBUGE, "fbuge", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBLE , "fble", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBULE, "fbule", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) -I(FBO , "fbo", 2, -1, B18, true , 1, 2, SPARC_CTI, M_CC_FLAG | M_BRANCH_FLAG) - -// Conditional move on integer comparison with zero. -I(MOVRZr , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRZi , "movrz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLEZr, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLEZi, "movrlez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLZr , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRLZi , "movrlz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRNZr , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRNZi , "movrnz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGZr , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGZi , "movrgz", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGEZr, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) -I(MOVRGEZi, "movrgez", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_INT_FLAG) - -// Conditional move on integer condition code. -// The first argument specifies the ICC register: %icc or %xcc -I(MOVAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGUr , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVGUi , "movgu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEUr, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVLEUi, "movleu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCCr , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCCi , "movcc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCSr , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVCSi , "movcs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVPOSr, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVPOSi, "movpos", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEGr, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVNEGi, "movneg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVCr , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVCi , "movvc", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVSr , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVVSi , "movvs", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) - -// Conditional move (of integer register) on floating point condition code. -// The first argument is the FCCn register (0 <= n <= 3). -// Note that the enum name above is not the same as the assembly mnemonic -// because some of the assembly mnemonics are the same as the move on -// integer CC (e.g., MOVG), and we cannot have the same enum entry twice. -I(MOVFAr , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFAi , "mova", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNr , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNi , "movn", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUr , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUi , "movu", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGr , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGi , "movg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGr , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGi , "movug", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLr , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLi , "movl", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULr , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULi , "movul", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLGr , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLGi , "movlg", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNEr , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFNEi , "movne", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFEr , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFEi , "move", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUEr , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUEi , "movue", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGEr , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFGEi , "movge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGEr, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFUGEi, "movuge", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLEr , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFLEi , "movle", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULEr, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFULEi, "movule", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFOr , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) -I(MOVFOi , "movo", 3, 2, B12, true , 0, 2, SPARC_SINGLE, M_CC_FLAG | M_INT_FLAG) - -// Conditional move of floating point register on each of the above: -// i. on integer comparison with zero. -// ii. on integer condition code -// iii. on floating point condition code -// Note that the same set is repeated for S,D,Q register classes. -I(FMOVRSZ ,"fmovrsz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSLEZ,"fmovrslez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSLZ ,"fmovrslz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSNZ ,"fmovrsnz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSGZ ,"fmovrsgz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRSGEZ,"fmovrsgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVSA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSGU , "fmovsgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSLEU, "fmovsleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSCC , "fmovscc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSCS , "fmovscs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSPOS, "fmovspos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSNEG, "fmovsneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSVC , "fmovsvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSVS , "fmovsvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVSFA , "fmovsa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFN , "fmovsn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFU , "fmovsu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFG , "fmovsg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUG , "fmovsug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFL , "fmovsl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUL , "fmovsul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFLG , "fmovslg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFNE , "fmovsne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFE , "fmovse", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUE , "fmovsue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFGE , "fmovsge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFUGE, "fmovsuge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFLE , "fmovsle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFULE, "fmovslue",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVSFO , "fmovso", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVRDZ , "fmovrdz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDLEZ, "fmovrdlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDLZ , "fmovrdlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDNZ , "fmovrdnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDGZ , "fmovrdgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRDGEZ, "fmovrdgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVDA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDGU , "fmovdgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDLEU, "fmovdleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDCC , "fmovdcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDCS , "fmovdcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDPOS, "fmovdpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDNEG, "fmovdneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDVC , "fmovdvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDVS , "fmovdvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVDFA , "fmovda", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFN , "fmovdn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFU , "fmovdu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFG , "fmovdg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUG , "fmovdug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFL , "fmovdl", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUL , "fmovdul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFLG , "fmovdlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFNE , "fmovdne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFE , "fmovde", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUE , "fmovdue", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFGE , "fmovdge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFUGE, "fmovduge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFLE , "fmovdle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFULE, "fmovdule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVDFO , "fmovdo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVRQZ , "fmovrqz", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQLEZ, "fmovrqlez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQLZ , "fmovrqlz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQNZ , "fmovrqnz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQGZ , "fmovrqgz",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) -I(FMOVRQGEZ, "fmovrqgez",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CONDL_FLAG | M_FLOAT_FLAG | M_INT_FLAG) - -I(FMOVQA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQGU , "fmovqgu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQLEU, "fmovqleu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQCC , "fmovqcc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQCS , "fmovqcs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQPOS, "fmovqpos", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQNEG, "fmovqneg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQVC , "fmovqvc", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQVS , "fmovqvs", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -I(FMOVQFA , "fmovqa", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFN , "fmovqn", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFU , "fmovqu", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFG , "fmovqg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUG , "fmovqug", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFL , "fmovql", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUL , "fmovqul", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFLG , "fmovqlg", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFNE , "fmovqne", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFE , "fmovqe", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUE , "fmovque", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFGE , "fmovqge", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFUGE, "fmovquge",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFLE , "fmovqle", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFULE, "fmovqule",3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) -I(FMOVQFO , "fmovqo", 3, 2, 0, false, 0, 2, SPARC_SINGLE, M_CC_FLAG | M_FLOAT_FLAG) - -// Load integer instructions -// Latency includes 1 cycle for address generation (Sparc IIi), -// plus 3 cycles assumed for average miss penalty (bias towards L1 hits). -// Signed loads of less than 64 bits need an extra cycle for sign-extension. -// -// Not reflected here: After a 3-cycle loads, all subsequent consecutive -// loads also require 3 cycles to avoid contention for the load return -// stage. Latency returns to 2 cycles after the first cycle with no load. -I(LDSBr, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSBi, "ldsb", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSHr, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSHi, "ldsh", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSWr, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDSWi, "ldsw", 3, 2, B12, true , 0, 6, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUBr, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUBi, "ldub", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUHr, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUHi, "lduh", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUWr, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDUWi, "lduw", 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDXr , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) -I(LDXi , "ldx" , 3, 2, B12, true , 0, 5, SPARC_LD, M_INT_FLAG | M_LOAD_FLAG) - -// Load floating-point instructions -// Latency includes 1 cycle for address generation (Sparc IIi) -I(LDFr , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFi , "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDDFr, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDDFi, "ldd", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDQFr, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDQFi, "ldq", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFSRr, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDFSRi, "ld", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDXFSRr, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) -I(LDXFSRi, "ldx", 3, 2, B12, true , 0, 5, SPARC_LD, M_FLOAT_FLAG | M_LOAD_FLAG) - -// Store integer instructions. -// Requires 1 cycle for address generation (Sparc IIi). -// Default latency is 0 because value is not explicitly used. -I(STBr, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STBi, "stb", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STHr, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STHi, "sth", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STWr, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STWi, "stw", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STXr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) -I(STXi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_INT_FLAG | M_STORE_FLAG) - -// Store floating-point instructions (Sparc IIi) -I(STFr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STDFr, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STDFi, "std", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFSRr, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STFSRi, "st", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STXFSRr, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) -I(STXFSRi, "stx", 3, -1, B12, true , 0, 0, SPARC_ST, M_FLOAT_FLAG | M_STORE_FLAG) - -// Call, Return and "Jump and link". Operand (2) for JMPL is marked as -// a "result" because JMPL stores the return address for the call in it. -// Latency includes the delay slot. -I(CALL, "call", 1, -1, B29, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLCALLr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLCALLi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_CALL_FLAG) -I(JMPLRETr, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_RET_FLAG) -I(JMPLRETi, "jmpl", 3, 2, B12, true , 1, 2, SPARC_CTI, M_RET_FLAG) -I(RETURNr, "return", 2, -1, 0, false, 1, 2, SPARC_CTI, M_RET_FLAG) -I(RETURNi, "return", 2, -1, 0, false, 1, 2, SPARC_CTI, M_RET_FLAG) - -// SAVE and restore instructions -I(SAVEr, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(SAVEi, "save", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(RESTOREr, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) -I(RESTOREi, "restore", 3, 2, B12, true , 0, 1, SPARC_SINGLE, M_INT_FLAG | M_ARITH_FLAG) - -// Read and Write CCR register from/to an int reg -I(RDCCR, "rd", 2, 1, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) -I(WRCCRr, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) -I(WRCCRi, "wr", 3, 2, 0, false, 0, 1, SPARC_SINGLE, M_INT_FLAG | M_CC_FLAG) - -// Synthetic phi operation for near-SSA form of machine code -// Number of operands is variable, indicated by -1. Result is the first op. -I(PHI, "<phi>", -1, 0, 0, false, 0, 0, SPARC_INV, M_DUMMY_PHI_FLAG) - - -#undef B5 -#undef B6 -#undef B12 -#undef B15 -#undef B18 -#undef B21 -#undef B22 -#undef B29 - -#undef I diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp deleted file mode 100644 index af458ea0399..00000000000 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ /dev/null @@ -1,799 +0,0 @@ -//===-- SparcInstrInfo.cpp ------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/iTerminators.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/InstrSelectionSupport.h" -#include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "SparcInternals.h" -#include "SparcInstrSelectionSupport.h" -#include "SparcInstrInfo.h" - -namespace llvm { - -static const uint32_t MAXLO = (1 << 10) - 1; // set bits set by %lo(*) -static const uint32_t MAXSIMM = (1 << 12) - 1; // set bits in simm13 field of OR - -//--------------------------------------------------------------------------- -// Function ConvertConstantToIntType -// -// Function to get the value of an integral constant in the form -// that must be put into the machine register. The specified constant is -// interpreted as (i.e., converted if necessary to) the specified destination -// type. The result is always returned as an uint64_t, since the representation -// of int64_t and uint64_t are identical. The argument can be any known const. -// -// isValidConstant is set to true if a valid constant was found. -//--------------------------------------------------------------------------- - -uint64_t -SparcInstrInfo::ConvertConstantToIntType(const TargetMachine &target, - const Value *V, - const Type *destType, - bool &isValidConstant) const -{ - isValidConstant = false; - uint64_t C = 0; - - if (! destType->isIntegral() && ! isa<PointerType>(destType)) - return C; - - if (! isa<Constant>(V)) - return C; - - // ConstantPointerRef: no conversions needed: get value and return it - if (const ConstantPointerRef* CPR = dyn_cast<ConstantPointerRef>(V)) { - // A ConstantPointerRef is just a reference to GlobalValue. - isValidConstant = true; // may be overwritten by recursive call - return (CPR->isNullValue()? 0 - : ConvertConstantToIntType(target, CPR->getValue(), destType, - isValidConstant)); - } - - // ConstantBool: no conversions needed: get value and return it - if (const ConstantBool *CB = dyn_cast<ConstantBool>(V)) { - isValidConstant = true; - return (uint64_t) CB->getValue(); - } - - // For other types of constants, some conversion may be needed. - // First, extract the constant operand according to its own type - if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) - switch(CE->getOpcode()) { - case Instruction::Cast: // recursively get the value as cast - C = ConvertConstantToIntType(target, CE->getOperand(0), CE->getType(), - isValidConstant); - break; - default: // not simplifying other ConstantExprs - break; - } - else if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) { - isValidConstant = true; - C = CI->getRawValue(); - } - else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(V)) { - isValidConstant = true; - double fC = CFP->getValue(); - C = (destType->isSigned()? (uint64_t) (int64_t) fC - : (uint64_t) fC); - } - - // Now if a valid value was found, convert it to destType. - if (isValidConstant) { - unsigned opSize = target.getTargetData().getTypeSize(V->getType()); - unsigned destSize = target.getTargetData().getTypeSize(destType); - uint64_t maskHi = (destSize < 8)? (1U << 8*destSize) - 1 : ~0; - assert(opSize <= 8 && destSize <= 8 && ">8-byte int type unexpected"); - - if (destType->isSigned()) { - if (opSize > destSize) // operand is larger than dest: - C = C & maskHi; // mask high bits - - if (opSize > destSize || - (opSize == destSize && ! V->getType()->isSigned())) - if (C & (1U << (8*destSize - 1))) - C = C | ~maskHi; // sign-extend from destSize to 64 bits - } - else { - if (opSize > destSize || (V->getType()->isSigned() && destSize < 8)) { - // operand is larger than dest, - // OR both are equal but smaller than the full register size - // AND operand is signed, so it may have extra sign bits: - // mask high bits - C = C & maskHi; - } - } - } - - return C; -} - - -//---------------------------------------------------------------------------- -// Function: CreateSETUWConst -// -// Set a 32-bit unsigned constant in the register `dest', using -// SETHI, OR in the worst case. This function correctly emulates -// the SETUW pseudo-op for SPARC v9 (if argument isSigned == false). -// -// The isSigned=true case is used to implement SETSW without duplicating code. -// -// Optimize some common cases: -// (1) Small value that fits in simm13 field of OR: don't need SETHI. -// (2) isSigned = true and C is a small negative signed value, i.e., -// high bits are 1, and the remaining bits fit in simm13(OR). -//---------------------------------------------------------------------------- - -static inline void -CreateSETUWConst(const TargetMachine& target, uint32_t C, - Instruction* dest, std::vector<MachineInstr*>& mvec, - bool isSigned = false) -{ - MachineInstr *miSETHI = NULL, *miOR = NULL; - - // In order to get efficient code, we should not generate the SETHI if - // all high bits are 1 (i.e., this is a small signed value that fits in - // the simm13 field of OR). So we check for and handle that case specially. - // NOTE: The value C = 0x80000000 is bad: sC < 0 *and* -sC < 0. - // In fact, sC == -sC, so we have to check for this explicitly. - int32_t sC = (int32_t) C; - bool smallNegValue =isSigned && sC < 0 && sC != -sC && -sC < (int32_t)MAXSIMM; - - // Set the high 22 bits in dest if non-zero and simm13 field of OR not enough - if (!smallNegValue && (C & ~MAXLO) && C > MAXSIMM) { - miSETHI = BuildMI(V9::SETHI, 2).addZImm(C).addRegDef(dest); - miSETHI->setOperandHi32(0); - mvec.push_back(miSETHI); - } - - // Set the low 10 or 12 bits in dest. This is necessary if no SETHI - // was generated, or if the low 10 bits are non-zero. - if (miSETHI==NULL || C & MAXLO) { - if (miSETHI) { - // unsigned value with high-order bits set using SETHI - miOR = BuildMI(V9::ORi,3).addReg(dest).addZImm(C).addRegDef(dest); - miOR->setOperandLo32(1); - } else { - // unsigned or small signed value that fits in simm13 field of OR - assert(smallNegValue || (C & ~MAXSIMM) == 0); - miOR = BuildMI(V9::ORi, 3).addMReg(target.getRegInfo() - .getZeroRegNum()) - .addSImm(sC).addRegDef(dest); - } - mvec.push_back(miOR); - } - - assert((miSETHI || miOR) && "Oops, no code was generated!"); -} - - -//---------------------------------------------------------------------------- -// Function: CreateSETSWConst -// -// Set a 32-bit signed constant in the register `dest', with sign-extension -// to 64 bits. This uses SETHI, OR, SRA in the worst case. -// This function correctly emulates the SETSW pseudo-op for SPARC v9. -// -// Optimize the same cases as SETUWConst, plus: -// (1) SRA is not needed for positive or small negative values. -//---------------------------------------------------------------------------- - -static inline void -CreateSETSWConst(const TargetMachine& target, int32_t C, - Instruction* dest, std::vector<MachineInstr*>& mvec) -{ - // Set the low 32 bits of dest - CreateSETUWConst(target, (uint32_t) C, dest, mvec, /*isSigned*/true); - - // Sign-extend to the high 32 bits if needed. - // NOTE: The value C = 0x80000000 is bad: -C == C and so -C is < MAXSIMM - if (C < 0 && (C == -C || -C > (int32_t) MAXSIMM)) - mvec.push_back(BuildMI(V9::SRAi5,3).addReg(dest).addZImm(0).addRegDef(dest)); -} - - -//---------------------------------------------------------------------------- -// Function: CreateSETXConst -// -// Set a 64-bit signed or unsigned constant in the register `dest'. -// Use SETUWConst for each 32 bit word, plus a left-shift-by-32 in between. -// This function correctly emulates the SETX pseudo-op for SPARC v9. -// -// Optimize the same cases as SETUWConst for each 32 bit word. -//---------------------------------------------------------------------------- - -static inline void -CreateSETXConst(const TargetMachine& target, uint64_t C, - Instruction* tmpReg, Instruction* dest, - std::vector<MachineInstr*>& mvec) -{ - assert(C > (unsigned int) ~0 && "Use SETUW/SETSW for 32-bit values!"); - - MachineInstr* MI; - - // Code to set the upper 32 bits of the value in register `tmpReg' - CreateSETUWConst(target, (C >> 32), tmpReg, mvec); - - // Shift tmpReg left by 32 bits - mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg).addZImm(32) - .addRegDef(tmpReg)); - - // Code to set the low 32 bits of the value in register `dest' - CreateSETUWConst(target, C, dest, mvec); - - // dest = OR(tmpReg, dest) - mvec.push_back(BuildMI(V9::ORr,3).addReg(dest).addReg(tmpReg).addRegDef(dest)); -} - - -//---------------------------------------------------------------------------- -// Function: CreateSETUWLabel -// -// Set a 32-bit constant (given by a symbolic label) in the register `dest'. -//---------------------------------------------------------------------------- - -static inline void -CreateSETUWLabel(const TargetMachine& target, Value* val, - Instruction* dest, std::vector<MachineInstr*>& mvec) -{ - MachineInstr* MI; - - // Set the high 22 bits in dest - MI = BuildMI(V9::SETHI, 2).addReg(val).addRegDef(dest); - MI->setOperandHi32(0); - mvec.push_back(MI); - - // Set the low 10 bits in dest - MI = BuildMI(V9::ORr, 3).addReg(dest).addReg(val).addRegDef(dest); - MI->setOperandLo32(1); - mvec.push_back(MI); -} - - -//---------------------------------------------------------------------------- -// Function: CreateSETXLabel -// -// Set a 64-bit constant (given by a symbolic label) in the register `dest'. -//---------------------------------------------------------------------------- - -static inline void -CreateSETXLabel(const TargetMachine& target, - Value* val, Instruction* tmpReg, Instruction* dest, - std::vector<MachineInstr*>& mvec) -{ - assert(isa<Constant>(val) || isa<GlobalValue>(val) && - "I only know about constant values and global addresses"); - - MachineInstr* MI; - - MI = BuildMI(V9::SETHI, 2).addPCDisp(val).addRegDef(tmpReg); - MI->setOperandHi64(0); - mvec.push_back(MI); - - MI = BuildMI(V9::ORi, 3).addReg(tmpReg).addPCDisp(val).addRegDef(tmpReg); - MI->setOperandLo64(1); - mvec.push_back(MI); - - mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg).addZImm(32) - .addRegDef(tmpReg)); - MI = BuildMI(V9::SETHI, 2).addPCDisp(val).addRegDef(dest); - MI->setOperandHi32(0); - mvec.push_back(MI); - - MI = BuildMI(V9::ORr, 3).addReg(dest).addReg(tmpReg).addRegDef(dest); - mvec.push_back(MI); - - MI = BuildMI(V9::ORi, 3).addReg(dest).addPCDisp(val).addRegDef(dest); - MI->setOperandLo32(1); - mvec.push_back(MI); -} - - -//---------------------------------------------------------------------------- -// Function: CreateUIntSetInstruction -// -// Create code to Set an unsigned constant in the register `dest'. -// Uses CreateSETUWConst, CreateSETSWConst or CreateSETXConst as needed. -// CreateSETSWConst is an optimization for the case that the unsigned value -// has all ones in the 33 high bits (so that sign-extension sets them all). -//---------------------------------------------------------------------------- - -static inline void -CreateUIntSetInstruction(const TargetMachine& target, - uint64_t C, Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - static const uint64_t lo32 = (uint32_t) ~0; - if (C <= lo32) // High 32 bits are 0. Set low 32 bits. - CreateSETUWConst(target, (uint32_t) C, dest, mvec); - else if ((C & ~lo32) == ~lo32 && (C & (1U << 31))) { - // All high 33 (not 32) bits are 1s: sign-extension will take care - // of high 32 bits, so use the sequence for signed int - CreateSETSWConst(target, (int32_t) C, dest, mvec); - } else if (C > lo32) { - // C does not fit in 32 bits - TmpInstruction* tmpReg = new TmpInstruction(mcfi, Type::IntTy); - CreateSETXConst(target, C, tmpReg, dest, mvec); - } -} - - -//---------------------------------------------------------------------------- -// Function: CreateIntSetInstruction -// -// Create code to Set a signed constant in the register `dest'. -// Really the same as CreateUIntSetInstruction. -//---------------------------------------------------------------------------- - -static inline void -CreateIntSetInstruction(const TargetMachine& target, - int64_t C, Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - CreateUIntSetInstruction(target, (uint64_t) C, dest, mvec, mcfi); -} - - -//--------------------------------------------------------------------------- -// Create a table of LLVM opcode -> max. immediate constant likely to -// be usable for that operation. -//--------------------------------------------------------------------------- - -// Entry == 0 ==> no immediate constant field exists at all. -// Entry > 0 ==> abs(immediate constant) <= Entry -// -std::vector<int> MaxConstantsTable(Instruction::OtherOpsEnd); - -static int -MaxConstantForInstr(unsigned llvmOpCode) -{ - int modelOpCode = -1; - - if (llvmOpCode >= Instruction::BinaryOpsBegin && - llvmOpCode < Instruction::BinaryOpsEnd) - modelOpCode = V9::ADDi; - else - switch(llvmOpCode) { - case Instruction::Ret: modelOpCode = V9::JMPLCALLi; break; - - case Instruction::Malloc: - case Instruction::Alloca: - case Instruction::GetElementPtr: - case Instruction::PHI: - case Instruction::Cast: - case Instruction::Call: modelOpCode = V9::ADDi; break; - - case Instruction::Shl: - case Instruction::Shr: modelOpCode = V9::SLLXi6; break; - - default: break; - }; - - return (modelOpCode < 0)? 0: SparcMachineInstrDesc[modelOpCode].maxImmedConst; -} - -static void -InitializeMaxConstantsTable() -{ - unsigned op; - assert(MaxConstantsTable.size() == Instruction::OtherOpsEnd && - "assignments below will be illegal!"); - for (op = Instruction::TermOpsBegin; op < Instruction::TermOpsEnd; ++op) - MaxConstantsTable[op] = MaxConstantForInstr(op); - for (op = Instruction::BinaryOpsBegin; op < Instruction::BinaryOpsEnd; ++op) - MaxConstantsTable[op] = MaxConstantForInstr(op); - for (op = Instruction::MemoryOpsBegin; op < Instruction::MemoryOpsEnd; ++op) - MaxConstantsTable[op] = MaxConstantForInstr(op); - for (op = Instruction::OtherOpsBegin; op < Instruction::OtherOpsEnd; ++op) - MaxConstantsTable[op] = MaxConstantForInstr(op); -} - - -//--------------------------------------------------------------------------- -// class SparcInstrInfo -// -// 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 TargetInstrInfo. -//--------------------------------------------------------------------------- - -/*ctor*/ -SparcInstrInfo::SparcInstrInfo() - : TargetInstrInfo(SparcMachineInstrDesc, - /*descSize = */ V9::NUM_TOTAL_OPCODES, - /*numRealOpCodes = */ V9::NUM_REAL_OPCODES) -{ - InitializeMaxConstantsTable(); -} - -bool -SparcInstrInfo::ConstantMayNotFitInImmedField(const Constant* CV, - const Instruction* I) const -{ - if (I->getOpcode() >= MaxConstantsTable.size()) // user-defined op (or bug!) - return true; - - if (isa<ConstantPointerNull>(CV)) // can always use %g0 - return false; - - if (isa<SwitchInst>(I)) // Switch instructions will be lowered! - return false; - - if (const ConstantInt* CI = dyn_cast<ConstantInt>(CV)) - return labs((int64_t)CI->getRawValue()) > MaxConstantsTable[I->getOpcode()]; - - if (isa<ConstantBool>(CV)) - return 1 > MaxConstantsTable[I->getOpcode()]; - - return true; -} - -// -// 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 `mvec'. -// Any temp. registers (TmpInstruction) created are recorded in mcfi. -// Any stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateCodeToLoadConst(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - assert(isa<Constant>(val) || isa<GlobalValue>(val) && - "I only know about constant values and global addresses"); - - // Use a "set" instruction for known constants or symbolic constants (labels) - // that can go in an integer reg. - // We have to use a "load" instruction for all other constants, - // in particular, floating point constants. - // - const Type* valType = val->getType(); - - // A ConstantPointerRef is just a reference to GlobalValue. - while (isa<ConstantPointerRef>(val)) - val = cast<ConstantPointerRef>(val)->getValue(); - - if (isa<GlobalValue>(val)) { - TmpInstruction* tmpReg = - new TmpInstruction(mcfi, PointerType::get(val->getType()), val); - CreateSETXLabel(target, val, tmpReg, dest, mvec); - return; - } - - bool isValid; - uint64_t C = ConvertConstantToIntType(target, val, dest->getType(), isValid); - if (isValid) { - if (dest->getType()->isSigned()) - CreateUIntSetInstruction(target, C, dest, mvec, mcfi); - else - CreateIntSetInstruction(target, (int64_t) C, dest, mvec, mcfi); - - } else { - // Make an instruction sequence to load the constant, viz: - // SETX <addr-of-constant>, tmpReg, addrReg - // LOAD /*addr*/ addrReg, /*offset*/ 0, dest - - // First, create a tmp register to be used by the SETX sequence. - TmpInstruction* tmpReg = - new TmpInstruction(mcfi, PointerType::get(val->getType())); - - // Create another TmpInstruction for the address register - TmpInstruction* addrReg = - new TmpInstruction(mcfi, PointerType::get(val->getType())); - - // Get the constant pool index for this constant - MachineConstantPool *CP = MachineFunction::get(F).getConstantPool(); - Constant *C = cast<Constant>(val); - unsigned CPI = CP->getConstantPoolIndex(C); - - // Put the address of the constant into a register - MachineInstr* MI; - - MI = BuildMI(V9::SETHI, 2).addConstantPoolIndex(CPI).addRegDef(tmpReg); - MI->setOperandHi64(0); - mvec.push_back(MI); - - MI = BuildMI(V9::ORi, 3).addReg(tmpReg).addConstantPoolIndex(CPI) - .addRegDef(tmpReg); - MI->setOperandLo64(1); - mvec.push_back(MI); - - mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpReg).addZImm(32) - .addRegDef(tmpReg)); - MI = BuildMI(V9::SETHI, 2).addConstantPoolIndex(CPI).addRegDef(addrReg); - MI->setOperandHi32(0); - mvec.push_back(MI); - - MI = BuildMI(V9::ORr, 3).addReg(addrReg).addReg(tmpReg).addRegDef(addrReg); - mvec.push_back(MI); - - MI = BuildMI(V9::ORi, 3).addReg(addrReg).addConstantPoolIndex(CPI) - .addRegDef(addrReg); - MI->setOperandLo32(1); - mvec.push_back(MI); - - // Now load the constant from out ConstantPool label - unsigned Opcode = ChooseLoadInstruction(val->getType()); - Opcode = convertOpcodeFromRegToImm(Opcode); - mvec.push_back(BuildMI(Opcode, 3) - .addReg(addrReg).addSImm((int64_t)0).addRegDef(dest)); - } -} - - -// Create an instruction sequence to copy an integer register `val' -// to a floating point register `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 `mvec'. -// Any temp. registers (TmpInstruction) created are recorded in mcfi. -// Any stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateCodeToCopyIntToFloat(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - assert((val->getType()->isIntegral() || isa<PointerType>(val->getType())) - && "Source type must be integral (integer or bool) or pointer"); - assert(dest->getType()->isFloatingPoint() - && "Dest type must be float/double"); - - // Get a stack slot to use for the copy - int offset = MachineFunction::get(F).getInfo()->allocateLocalVar(val); - - // Get the size of the source value being copied. - size_t srcSize = target.getTargetData().getTypeSize(val->getType()); - - // Store instruction stores `val' to [%fp+offset]. - // The store and load opCodes are based on the size of the source value. - // If the value is smaller than 32 bits, we must sign- or zero-extend it - // to 32 bits since the load-float will load 32 bits. - // Note that the store instruction is the same for signed and unsigned ints. - const Type* storeType = (srcSize <= 4)? Type::IntTy : Type::LongTy; - Value* storeVal = val; - if (srcSize < target.getTargetData().getTypeSize(Type::FloatTy)) { - // sign- or zero-extend respectively - storeVal = new TmpInstruction(mcfi, storeType, val); - if (val->getType()->isSigned()) - CreateSignExtensionInstructions(target, F, val, storeVal, 8*srcSize, - mvec, mcfi); - else - CreateZeroExtensionInstructions(target, F, val, storeVal, 8*srcSize, - mvec, mcfi); - } - - unsigned FPReg = target.getRegInfo().getFramePointer(); - unsigned StoreOpcode = ChooseStoreInstruction(storeType); - StoreOpcode = convertOpcodeFromRegToImm(StoreOpcode); - mvec.push_back(BuildMI(StoreOpcode, 3) - .addReg(storeVal).addMReg(FPReg).addSImm(offset)); - - // Load instruction loads [%fp+offset] to `dest'. - // The type of the load opCode is the floating point type that matches the - // stored type in size: - // On SparcV9: float for int or smaller, double for long. - // - const Type* loadType = (srcSize <= 4)? Type::FloatTy : Type::DoubleTy; - unsigned LoadOpcode = ChooseLoadInstruction(loadType); - LoadOpcode = convertOpcodeFromRegToImm(LoadOpcode); - mvec.push_back(BuildMI(LoadOpcode, 3) - .addMReg(FPReg).addSImm(offset).addRegDef(dest)); -} - -// Similarly, create an instruction sequence to copy an FP register -// `val' to an integer register `dest' by copying to memory and back. -// The generated instructions are returned in `mvec'. -// Any temp. virtual registers (TmpInstruction) created are recorded in mcfi. -// Temporary stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateCodeToCopyFloatToInt(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - const Type* opTy = val->getType(); - const Type* destTy = dest->getType(); - - assert(opTy->isFloatingPoint() && "Source type must be float/double"); - assert((destTy->isIntegral() || isa<PointerType>(destTy)) - && "Dest type must be integer, bool or pointer"); - - // FIXME: For now, we allocate permanent space because the stack frame - // manager does not allow locals to be allocated (e.g., for alloca) after - // a temp is allocated! - // - int offset = MachineFunction::get(F).getInfo()->allocateLocalVar(val); - - unsigned FPReg = target.getRegInfo().getFramePointer(); - - // Store instruction stores `val' to [%fp+offset]. - // The store opCode is based only the source value being copied. - // - unsigned StoreOpcode = ChooseStoreInstruction(opTy); - StoreOpcode = convertOpcodeFromRegToImm(StoreOpcode); - mvec.push_back(BuildMI(StoreOpcode, 3) - .addReg(val).addMReg(FPReg).addSImm(offset)); - - // Load instruction loads [%fp+offset] to `dest'. - // The type of the load opCode is the integer type that matches the - // source type in size: - // On SparcV9: int for float, long for double. - // Note that we *must* use signed loads even for unsigned dest types, to - // ensure correct sign-extension for UByte, UShort or UInt: - // - const Type* loadTy = (opTy == Type::FloatTy)? Type::IntTy : Type::LongTy; - unsigned LoadOpcode = ChooseLoadInstruction(loadTy); - LoadOpcode = convertOpcodeFromRegToImm(LoadOpcode); - mvec.push_back(BuildMI(LoadOpcode, 3).addMReg(FPReg) - .addSImm(offset).addRegDef(dest)); -} - - -// Create instruction(s) to copy src to dest, for arbitrary types -// The generated instructions are returned in `mvec'. -// Any temp. registers (TmpInstruction) created are recorded in mcfi. -// Any stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateCopyInstructionsByType(const TargetMachine& target, - Function *F, - Value* src, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - bool loadConstantToReg = false; - - const Type* resultType = dest->getType(); - - MachineOpCode opCode = ChooseAddInstructionByType(resultType); - if (opCode == V9::INVALID_OPCODE) { - assert(0 && "Unsupported result type in CreateCopyInstructionsByType()"); - return; - } - - // if `src' is a constant that doesn't fit in the immed field or if it is - // a global variable (i.e., a constant address), generate a load - // instruction instead of an add - // - if (isa<Constant>(src)) { - unsigned int machineRegNum; - int64_t immedValue; - MachineOperand::MachineOperandType opType = - ChooseRegOrImmed(src, opCode, target, /*canUseImmed*/ true, - machineRegNum, immedValue); - - if (opType == MachineOperand::MO_VirtualRegister) - loadConstantToReg = true; - } - else if (isa<GlobalValue>(src)) - loadConstantToReg = true; - - if (loadConstantToReg) { - // `src' is constant and cannot fit in immed field for the ADD - // Insert instructions to "load" the constant into a register - target.getInstrInfo().CreateCodeToLoadConst(target, F, src, dest, - mvec, mcfi); - } else { - // Create a reg-to-reg copy instruction for the given type: - // -- For FP values, create a FMOVS or FMOVD instruction - // -- For non-FP values, create an add-with-0 instruction (opCode as above) - // Make `src' the second operand, in case it is a small constant! - // - MachineInstr* MI; - if (resultType->isFloatingPoint()) - MI = (BuildMI(resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD, 2) - .addReg(src).addRegDef(dest)); - else { - const Type* Ty =isa<PointerType>(resultType)? Type::ULongTy :resultType; - MI = (BuildMI(opCode, 3) - .addSImm((int64_t) 0).addReg(src).addRegDef(dest)); - } - mvec.push_back(MI); - } -} - - -// Helper function for sign-extension and zero-extension. -// For SPARC v9, we sign-extend the given operand using SLL; SRA/SRL. -inline void -CreateBitExtensionInstructions(bool signExtend, - const TargetMachine& target, - Function* F, - Value* srcVal, - Value* destVal, - unsigned int numLowBits, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - MachineInstr* M; - - assert(numLowBits <= 32 && "Otherwise, nothing should be done here!"); - - if (numLowBits < 32) { - // SLL is needed since operand size is < 32 bits. - TmpInstruction *tmpI = new TmpInstruction(mcfi, destVal->getType(), - srcVal, destVal, "make32"); - mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(srcVal) - .addZImm(32-numLowBits).addRegDef(tmpI)); - srcVal = tmpI; - } - - mvec.push_back(BuildMI(signExtend? V9::SRAi5 : V9::SRLi5, 3) - .addReg(srcVal).addZImm(32-numLowBits).addRegDef(destVal)); -} - - -// Create instruction sequence to produce a sign-extended register value -// from an arbitrary-sized integer value (sized in bits, not bytes). -// The generated instructions are returned in `mvec'. -// Any temp. registers (TmpInstruction) created are recorded in mcfi. -// Any stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateSignExtensionInstructions( - const TargetMachine& target, - Function* F, - Value* srcVal, - Value* destVal, - unsigned int numLowBits, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - CreateBitExtensionInstructions(/*signExtend*/ true, target, F, srcVal, - destVal, numLowBits, mvec, mcfi); -} - - -// Create instruction sequence to produce a zero-extended register value -// from an arbitrary-sized integer value (sized in bits, not bytes). -// For SPARC v9, we sign-extend the given operand using SLL; SRL. -// The generated instructions are returned in `mvec'. -// Any temp. registers (TmpInstruction) created are recorded in mcfi. -// Any stack space required is allocated via MachineFunction. -// -void -SparcInstrInfo::CreateZeroExtensionInstructions( - const TargetMachine& target, - Function* F, - Value* srcVal, - Value* destVal, - unsigned int numLowBits, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const -{ - CreateBitExtensionInstructions(/*signExtend*/ false, target, F, srcVal, - destVal, numLowBits, mvec, mcfi); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/SparcInstrSelection.cpp b/llvm/lib/Target/Sparc/SparcInstrSelection.cpp deleted file mode 100644 index 57f1251af73..00000000000 --- a/llvm/lib/Target/Sparc/SparcInstrSelection.cpp +++ /dev/null @@ -1,2898 +0,0 @@ -//===-- SparcInstrSelection.cpp -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// BURS instruction selection for SPARC V9 architecture. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" -#include "llvm/Intrinsics.h" -#include "llvm/Module.h" -#include "llvm/CodeGen/InstrForest.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/InstrSelectionSupport.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" -#include "SparcInstrSelectionSupport.h" -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" -#include "SparcRegInfo.h" -#include "Support/MathExtras.h" -#include <algorithm> -#include <cmath> - -namespace llvm { - -static inline void Add3OperandInstr(unsigned Opcode, InstructionNode* Node, - std::vector<MachineInstr*>& mvec) { - mvec.push_back(BuildMI(Opcode, 3).addReg(Node->leftChild()->getValue()) - .addReg(Node->rightChild()->getValue()) - .addRegDef(Node->getValue())); -} - - -//--------------------------------------------------------------------------- -// Function: FoldGetElemChain -// -// Purpose: -// Fold a chain of GetElementPtr instructions containing only -// constant offsets into an equivalent (Pointer, IndexVector) pair. -// Returns the pointer Value, and stores the resulting IndexVector -// in argument chainIdxVec. This is a helper function for -// FoldConstantIndices that does the actual folding. -//--------------------------------------------------------------------------- - - -// Check for a constant 0. -static inline bool -IsZero(Value* idx) -{ - return (idx == ConstantSInt::getNullValue(idx->getType())); -} - -static Value* -FoldGetElemChain(InstrTreeNode* ptrNode, std::vector<Value*>& chainIdxVec, - bool lastInstHasLeadingNonZero) -{ - InstructionNode* gepNode = dyn_cast<InstructionNode>(ptrNode); - GetElementPtrInst* gepInst = - dyn_cast_or_null<GetElementPtrInst>(gepNode ? gepNode->getInstruction() :0); - - // ptr value is not computed in this tree or ptr value does not come from GEP - // instruction - if (gepInst == NULL) - return NULL; - - // Return NULL if we don't fold any instructions in. - Value* ptrVal = NULL; - - // Now chase the chain of getElementInstr instructions, if any. - // Check for any non-constant indices and stop there. - // Also, stop if the first index of child is a non-zero array index - // and the last index of the current node is a non-array index: - // in that case, a non-array declared type is being accessed as an array - // which is not type-safe, but could be legal. - // - InstructionNode* ptrChild = gepNode; - while (ptrChild && (ptrChild->getOpLabel() == Instruction::GetElementPtr || - ptrChild->getOpLabel() == GetElemPtrIdx)) - { - // Child is a GetElemPtr instruction - gepInst = cast<GetElementPtrInst>(ptrChild->getValue()); - User::op_iterator OI, firstIdx = gepInst->idx_begin(); - User::op_iterator lastIdx = gepInst->idx_end(); - bool allConstantOffsets = true; - - // The first index of every GEP must be an array index. - assert((*firstIdx)->getType() == Type::LongTy && - "INTERNAL ERROR: Structure index for a pointer type!"); - - // If the last instruction had a leading non-zero index, check if the - // current one references a sequential (i.e., indexable) type. - // If not, the code is not type-safe and we would create an illegal GEP - // by folding them, so don't fold any more instructions. - // - if (lastInstHasLeadingNonZero) - if (! isa<SequentialType>(gepInst->getType()->getElementType())) - break; // cannot fold in any preceding getElementPtr instrs. - - // Check that all offsets are constant for this instruction - for (OI = firstIdx; allConstantOffsets && OI != lastIdx; ++OI) - allConstantOffsets = isa<ConstantInt>(*OI); - - if (allConstantOffsets) { - // Get pointer value out of ptrChild. - ptrVal = gepInst->getPointerOperand(); - - // Insert its index vector at the start, skipping any leading [0] - // Remember the old size to check if anything was inserted. - unsigned oldSize = chainIdxVec.size(); - int firstIsZero = IsZero(*firstIdx); - chainIdxVec.insert(chainIdxVec.begin(), firstIdx + firstIsZero, lastIdx); - - // Remember if it has leading zero index: it will be discarded later. - if (oldSize < chainIdxVec.size()) - lastInstHasLeadingNonZero = !firstIsZero; - - // Mark the folded node so no code is generated for it. - ((InstructionNode*) ptrChild)->markFoldedIntoParent(); - - // Get the previous GEP instruction and continue trying to fold - ptrChild = dyn_cast<InstructionNode>(ptrChild->leftChild()); - } else // cannot fold this getElementPtr instr. or any preceding ones - break; - } - - // If the first getElementPtr instruction had a leading [0], add it back. - // Note that this instruction is the *last* one that was successfully - // folded *and* contributed any indices, in the loop above. - // - if (ptrVal && ! lastInstHasLeadingNonZero) - chainIdxVec.insert(chainIdxVec.begin(), ConstantSInt::get(Type::LongTy,0)); - - return ptrVal; -} - - -//--------------------------------------------------------------------------- -// Function: GetGEPInstArgs -// -// Purpose: -// Helper function for GetMemInstArgs that handles the final getElementPtr -// instruction used by (or same as) the memory operation. -// Extracts the indices of the current instruction and tries to fold in -// preceding ones if all indices of the current one are constant. -//--------------------------------------------------------------------------- - -static Value * -GetGEPInstArgs(InstructionNode* gepNode, - std::vector<Value*>& idxVec, - bool& allConstantIndices) -{ - allConstantIndices = true; - GetElementPtrInst* gepI = cast<GetElementPtrInst>(gepNode->getInstruction()); - - // Default pointer is the one from the current instruction. - Value* ptrVal = gepI->getPointerOperand(); - InstrTreeNode* ptrChild = gepNode->leftChild(); - - // Extract the index vector of the GEP instruction. - // If all indices are constant and first index is zero, try to fold - // in preceding GEPs with all constant indices. - for (User::op_iterator OI=gepI->idx_begin(), OE=gepI->idx_end(); - allConstantIndices && OI != OE; ++OI) - if (! isa<Constant>(*OI)) - allConstantIndices = false; // note: this also terminates loop! - - // If we have only constant indices, fold chains of constant indices - // in this and any preceding GetElemPtr instructions. - bool foldedGEPs = false; - bool leadingNonZeroIdx = gepI && ! IsZero(*gepI->idx_begin()); - if (allConstantIndices) - if (Value* newPtr = FoldGetElemChain(ptrChild, idxVec, leadingNonZeroIdx)) { - ptrVal = newPtr; - foldedGEPs = true; - } - - // Append the index vector of the current instruction. - // Skip the leading [0] index if preceding GEPs were folded into this. - idxVec.insert(idxVec.end(), - gepI->idx_begin() + (foldedGEPs && !leadingNonZeroIdx), - gepI->idx_end()); - - return ptrVal; -} - -//--------------------------------------------------------------------------- -// Function: GetMemInstArgs -// -// Purpose: -// Get the pointer value and the index vector for a memory operation -// (GetElementPtr, Load, or Store). If all indices of the given memory -// operation are constant, fold in constant indices in a chain of -// preceding GetElementPtr instructions (if any), and return the -// pointer value of the first instruction in the chain. -// All folded instructions are marked so no code is generated for them. -// -// Return values: -// Returns the pointer Value to use. -// Returns the resulting IndexVector in idxVec. -// Returns true/false in allConstantIndices if all indices are/aren't const. -//--------------------------------------------------------------------------- - -static Value* -GetMemInstArgs(InstructionNode* memInstrNode, - std::vector<Value*>& idxVec, - bool& allConstantIndices) -{ - allConstantIndices = false; - Instruction* memInst = memInstrNode->getInstruction(); - assert(idxVec.size() == 0 && "Need empty vector to return indices"); - - // If there is a GetElemPtr instruction to fold in to this instr, - // it must be in the left child for Load and GetElemPtr, and in the - // right child for Store instructions. - InstrTreeNode* ptrChild = (memInst->getOpcode() == Instruction::Store - ? memInstrNode->rightChild() - : memInstrNode->leftChild()); - - // Default pointer is the one from the current instruction. - Value* ptrVal = ptrChild->getValue(); - - // Find the "last" GetElemPtr instruction: this one or the immediate child. - // There will be none if this is a load or a store from a scalar pointer. - InstructionNode* gepNode = NULL; - if (isa<GetElementPtrInst>(memInst)) - gepNode = memInstrNode; - else if (isa<InstructionNode>(ptrChild) && isa<GetElementPtrInst>(ptrVal)) { - // Child of load/store is a GEP and memInst is its only use. - // Use its indices and mark it as folded. - gepNode = cast<InstructionNode>(ptrChild); - gepNode->markFoldedIntoParent(); - } - - // If there are no indices, return the current pointer. - // Else extract the pointer from the GEP and fold the indices. - return gepNode ? GetGEPInstArgs(gepNode, idxVec, allConstantIndices) - : ptrVal; -} - - -//************************ Internal Functions ******************************/ - - -static inline MachineOpCode -ChooseBprInstruction(const InstructionNode* instrNode) -{ - MachineOpCode opCode; - - Instruction* setCCInstr = - ((InstructionNode*) instrNode->leftChild())->getInstruction(); - - switch(setCCInstr->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::BRZ; break; - case Instruction::SetNE: opCode = V9::BRNZ; break; - case Instruction::SetLE: opCode = V9::BRLEZ; break; - case Instruction::SetGE: opCode = V9::BRGEZ; break; - case Instruction::SetLT: opCode = V9::BRLZ; break; - case Instruction::SetGT: opCode = V9::BRGZ; break; - default: - assert(0 && "Unrecognized VM instruction!"); - opCode = V9::INVALID_OPCODE; - break; - } - - return opCode; -} - - -static inline MachineOpCode -ChooseBpccInstruction(const InstructionNode* instrNode, - const BinaryOperator* setCCInstr) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - bool isSigned = setCCInstr->getOperand(0)->getType()->isSigned(); - - if (isSigned) { - switch(setCCInstr->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::BE; break; - case Instruction::SetNE: opCode = V9::BNE; break; - case Instruction::SetLE: opCode = V9::BLE; break; - case Instruction::SetGE: opCode = V9::BGE; break; - case Instruction::SetLT: opCode = V9::BL; break; - case Instruction::SetGT: opCode = V9::BG; break; - default: - assert(0 && "Unrecognized VM instruction!"); - break; - } - } else { - switch(setCCInstr->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::BE; break; - case Instruction::SetNE: opCode = V9::BNE; break; - case Instruction::SetLE: opCode = V9::BLEU; break; - case Instruction::SetGE: opCode = V9::BCC; break; - case Instruction::SetLT: opCode = V9::BCS; break; - case Instruction::SetGT: opCode = V9::BGU; break; - default: - assert(0 && "Unrecognized VM instruction!"); - break; - } - } - - return opCode; -} - -static inline MachineOpCode -ChooseBFpccInstruction(const InstructionNode* instrNode, - const BinaryOperator* setCCInstr) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - switch(setCCInstr->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::FBE; break; - case Instruction::SetNE: opCode = V9::FBNE; break; - case Instruction::SetLE: opCode = V9::FBLE; break; - case Instruction::SetGE: opCode = V9::FBGE; break; - case Instruction::SetLT: opCode = V9::FBL; break; - case Instruction::SetGT: opCode = V9::FBG; break; - default: - assert(0 && "Unrecognized VM instruction!"); - break; - } - - return opCode; -} - - -// Create a unique TmpInstruction for a boolean value, -// representing the CC register used by a branch on that value. -// For now, hack this using a little static cache of TmpInstructions. -// Eventually the entire BURG instruction selection should be put -// into a separate class that can hold such information. -// The static cache is not too bad because the memory for these -// TmpInstructions will be freed along with the rest of the Function anyway. -// -static TmpInstruction* -GetTmpForCC(Value* boolVal, const Function *F, const Type* ccType, - MachineCodeForInstruction& mcfi) -{ - typedef hash_map<const Value*, TmpInstruction*> BoolTmpCache; - static BoolTmpCache boolToTmpCache; // Map boolVal -> TmpInstruction* - static const Function *lastFunction = 0;// Use to flush cache between funcs - - assert(boolVal->getType() == Type::BoolTy && "Weird but ok! Delete assert"); - - if (lastFunction != F) { - lastFunction = F; - boolToTmpCache.clear(); - } - - // Look for tmpI and create a new one otherwise. The new value is - // directly written to map using the ref returned by operator[]. - TmpInstruction*& tmpI = boolToTmpCache[boolVal]; - if (tmpI == NULL) - tmpI = new TmpInstruction(mcfi, ccType, boolVal); - - return tmpI; -} - - -static inline MachineOpCode -ChooseBccInstruction(const InstructionNode* instrNode, - const Type*& setCCType) -{ - InstructionNode* setCCNode = (InstructionNode*) instrNode->leftChild(); - assert(setCCNode->getOpLabel() == SetCCOp); - BinaryOperator* setCCInstr =cast<BinaryOperator>(setCCNode->getInstruction()); - setCCType = setCCInstr->getOperand(0)->getType(); - - if (setCCType->isFloatingPoint()) - return ChooseBFpccInstruction(instrNode, setCCInstr); - else - return ChooseBpccInstruction(instrNode, setCCInstr); -} - - -// WARNING: since this function has only one caller, it always returns -// the opcode that expects an immediate and a register. If this function -// is ever used in cases where an opcode that takes two registers is required, -// then modify this function and use convertOpcodeFromRegToImm() where required. -// -// It will be necessary to expand convertOpcodeFromRegToImm() to handle the -// new cases of opcodes. -static inline MachineOpCode -ChooseMovFpcciInstruction(const InstructionNode* instrNode) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - switch(instrNode->getInstruction()->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::MOVFEi; break; - case Instruction::SetNE: opCode = V9::MOVFNEi; break; - case Instruction::SetLE: opCode = V9::MOVFLEi; break; - case Instruction::SetGE: opCode = V9::MOVFGEi; break; - case Instruction::SetLT: opCode = V9::MOVFLi; break; - case Instruction::SetGT: opCode = V9::MOVFGi; break; - default: - assert(0 && "Unrecognized VM instruction!"); - break; - } - - return opCode; -} - - -// ChooseMovpcciForSetCC -- Choose a conditional-move instruction -// based on the type of SetCC operation. -// -// WARNING: since this function has only one caller, it always returns -// the opcode that expects an immediate and a register. If this function -// is ever used in cases where an opcode that takes two registers is required, -// then modify this function and use convertOpcodeFromRegToImm() where required. -// -// It will be necessary to expand convertOpcodeFromRegToImm() to handle the -// new cases of opcodes. -// -static MachineOpCode -ChooseMovpcciForSetCC(const InstructionNode* instrNode) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - const Type* opType = instrNode->leftChild()->getValue()->getType(); - assert(opType->isIntegral() || isa<PointerType>(opType)); - bool noSign = opType->isUnsigned() || isa<PointerType>(opType); - - switch(instrNode->getInstruction()->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::MOVEi; break; - case Instruction::SetLE: opCode = noSign? V9::MOVLEUi : V9::MOVLEi; break; - case Instruction::SetGE: opCode = noSign? V9::MOVCCi : V9::MOVGEi; break; - case Instruction::SetLT: opCode = noSign? V9::MOVCSi : V9::MOVLi; break; - case Instruction::SetGT: opCode = noSign? V9::MOVGUi : V9::MOVGi; break; - case Instruction::SetNE: opCode = V9::MOVNEi; break; - default: assert(0 && "Unrecognized LLVM instr!"); break; - } - - return opCode; -} - - -// ChooseMovpregiForSetCC -- Choose a conditional-move-on-register-value -// instruction based on the type of SetCC operation. These instructions -// compare a register with 0 and perform the move is the comparison is true. -// -// WARNING: like the previous function, this function it always returns -// the opcode that expects an immediate and a register. See above. -// -static MachineOpCode -ChooseMovpregiForSetCC(const InstructionNode* instrNode) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - switch(instrNode->getInstruction()->getOpcode()) - { - case Instruction::SetEQ: opCode = V9::MOVRZi; break; - case Instruction::SetLE: opCode = V9::MOVRLEZi; break; - case Instruction::SetGE: opCode = V9::MOVRGEZi; break; - case Instruction::SetLT: opCode = V9::MOVRLZi; break; - case Instruction::SetGT: opCode = V9::MOVRGZi; break; - case Instruction::SetNE: opCode = V9::MOVRNZi; break; - default: assert(0 && "Unrecognized VM instr!"); break; - } - - return opCode; -} - - -static inline MachineOpCode -ChooseConvertToFloatInstr(const TargetMachine& target, - OpLabel vopCode, const Type* opType) -{ - assert((vopCode == ToFloatTy || vopCode == ToDoubleTy) && - "Unrecognized convert-to-float opcode!"); - assert((opType->isIntegral() || opType->isFloatingPoint() || - isa<PointerType>(opType)) - && "Trying to convert a non-scalar type to FLOAT/DOUBLE?"); - - MachineOpCode opCode = V9::INVALID_OPCODE; - - unsigned opSize = target.getTargetData().getTypeSize(opType); - - if (opType == Type::FloatTy) - opCode = (vopCode == ToFloatTy? V9::NOP : V9::FSTOD); - else if (opType == Type::DoubleTy) - opCode = (vopCode == ToFloatTy? V9::FDTOS : V9::NOP); - else if (opSize <= 4) - opCode = (vopCode == ToFloatTy? V9::FITOS : V9::FITOD); - else { - assert(opSize == 8 && "Unrecognized type size > 4 and < 8!"); - opCode = (vopCode == ToFloatTy? V9::FXTOS : V9::FXTOD); - } - - return opCode; -} - -static inline MachineOpCode -ChooseConvertFPToIntInstr(const TargetMachine& target, - const Type* destType, const Type* opType) -{ - assert((opType == Type::FloatTy || opType == Type::DoubleTy) - && "This function should only be called for FLOAT or DOUBLE"); - assert((destType->isIntegral() || isa<PointerType>(destType)) - && "Trying to convert FLOAT/DOUBLE to a non-scalar type?"); - - MachineOpCode opCode = V9::INVALID_OPCODE; - - unsigned destSize = target.getTargetData().getTypeSize(destType); - - if (destType == Type::UIntTy) - assert(destType != Type::UIntTy && "Expand FP-to-uint beforehand."); - else if (destSize <= 4) - opCode = (opType == Type::FloatTy)? V9::FSTOI : V9::FDTOI; - else { - assert(destSize == 8 && "Unrecognized type size > 4 and < 8!"); - opCode = (opType == Type::FloatTy)? V9::FSTOX : V9::FDTOX; - } - - return opCode; -} - -static MachineInstr* -CreateConvertFPToIntInstr(const TargetMachine& target, - Value* srcVal, - Value* destVal, - const Type* destType) -{ - MachineOpCode opCode = ChooseConvertFPToIntInstr(target, destType, - srcVal->getType()); - assert(opCode != V9::INVALID_OPCODE && "Expected to need conversion!"); - return BuildMI(opCode, 2).addReg(srcVal).addRegDef(destVal); -} - -// CreateCodeToConvertFloatToInt: Convert FP value to signed or unsigned integer -// The FP value must be converted to the dest type in an FP register, -// and the result is then copied from FP to int register via memory. -// SPARC does not have a float-to-uint conversion, only a float-to-int (fdtoi). -// Since fdtoi converts to signed integers, any FP value V between MAXINT+1 -// and MAXUNSIGNED (i.e., 2^31 <= V <= 2^32-1) would be converted incorrectly. -// Therefore, for converting an FP value to uint32_t, we first need to convert -// to uint64_t and then to uint32_t. -// -static void -CreateCodeToConvertFloatToInt(const TargetMachine& target, - Value* opVal, - Instruction* destI, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - Function* F = destI->getParent()->getParent(); - - // Create a temporary to represent the FP register into which the - // int value will placed after conversion. The type of this temporary - // depends on the type of FP register to use: single-prec for a 32-bit - // int or smaller; double-prec for a 64-bit int. - // - size_t destSize = target.getTargetData().getTypeSize(destI->getType()); - - const Type* castDestType = destI->getType(); // type for the cast instr result - const Type* castDestRegType; // type for cast instruction result reg - TmpInstruction* destForCast; // dest for cast instruction - Instruction* fpToIntCopyDest = destI; // dest for fp-reg-to-int-reg copy instr - - // For converting an FP value to uint32_t, we first need to convert to - // uint64_t and then to uint32_t, as explained above. - if (destI->getType() == Type::UIntTy) { - castDestType = Type::ULongTy; // use this instead of type of destI - castDestRegType = Type::DoubleTy; // uint64_t needs 64-bit FP register. - destForCast = new TmpInstruction(mcfi, castDestRegType, opVal); - fpToIntCopyDest = new TmpInstruction(mcfi, castDestType, destForCast); - } - else { - castDestRegType = (destSize > 4)? Type::DoubleTy : Type::FloatTy; - destForCast = new TmpInstruction(mcfi, castDestRegType, opVal); - } - - // Create the fp-to-int conversion instruction (src and dest regs are FP regs) - mvec.push_back(CreateConvertFPToIntInstr(target, opVal, destForCast, - castDestType)); - - // Create the fpreg-to-intreg copy code - target.getInstrInfo().CreateCodeToCopyFloatToInt(target, F, destForCast, - fpToIntCopyDest, mvec, mcfi); - - // Create the uint64_t to uint32_t conversion, if needed - if (destI->getType() == Type::UIntTy) - target.getInstrInfo(). - CreateZeroExtensionInstructions(target, F, fpToIntCopyDest, destI, - /*numLowBits*/ 32, mvec, mcfi); -} - - -static inline MachineOpCode -ChooseAddInstruction(const InstructionNode* instrNode) -{ - return ChooseAddInstructionByType(instrNode->getInstruction()->getType()); -} - - -static inline MachineInstr* -CreateMovFloatInstruction(const InstructionNode* instrNode, - const Type* resultType) -{ - return BuildMI((resultType == Type::FloatTy) ? V9::FMOVS : V9::FMOVD, 2) - .addReg(instrNode->leftChild()->getValue()) - .addRegDef(instrNode->getValue()); -} - -static inline MachineInstr* -CreateAddConstInstruction(const InstructionNode* instrNode) -{ - MachineInstr* minstr = NULL; - - Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); - assert(isa<Constant>(constOp)); - - // Cases worth optimizing are: - // (1) Add with 0 for float or double: use an FMOV of appropriate type, - // instead of an FADD (1 vs 3 cycles). There is no integer MOV. - // - if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) { - double dval = FPC->getValue(); - if (dval == 0.0) - minstr = CreateMovFloatInstruction(instrNode, - instrNode->getInstruction()->getType()); - } - - return minstr; -} - - -static inline MachineOpCode -ChooseSubInstructionByType(const Type* resultType) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - if (resultType->isInteger() || isa<PointerType>(resultType)) { - opCode = V9::SUBr; - } else { - switch(resultType->getPrimitiveID()) - { - case Type::FloatTyID: opCode = V9::FSUBS; break; - case Type::DoubleTyID: opCode = V9::FSUBD; break; - default: assert(0 && "Invalid type for SUB instruction"); break; - } - } - - return opCode; -} - - -static inline MachineInstr* -CreateSubConstInstruction(const InstructionNode* instrNode) -{ - MachineInstr* minstr = NULL; - - Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); - assert(isa<Constant>(constOp)); - - // Cases worth optimizing are: - // (1) Sub with 0 for float or double: use an FMOV of appropriate type, - // instead of an FSUB (1 vs 3 cycles). There is no integer MOV. - // - if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) { - double dval = FPC->getValue(); - if (dval == 0.0) - minstr = CreateMovFloatInstruction(instrNode, - instrNode->getInstruction()->getType()); - } - - return minstr; -} - - -static inline MachineOpCode -ChooseFcmpInstruction(const InstructionNode* instrNode) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue(); - switch(operand->getType()->getPrimitiveID()) { - case Type::FloatTyID: opCode = V9::FCMPS; break; - case Type::DoubleTyID: opCode = V9::FCMPD; break; - default: assert(0 && "Invalid type for FCMP instruction"); break; - } - - return opCode; -} - - -// Assumes that leftArg and rightArg are both cast instructions. -// -static inline bool -BothFloatToDouble(const InstructionNode* instrNode) -{ - InstrTreeNode* leftArg = instrNode->leftChild(); - InstrTreeNode* rightArg = instrNode->rightChild(); - InstrTreeNode* leftArgArg = leftArg->leftChild(); - InstrTreeNode* rightArgArg = rightArg->leftChild(); - assert(leftArg->getValue()->getType() == rightArg->getValue()->getType()); - - // Check if both arguments are floats cast to double - return (leftArg->getValue()->getType() == Type::DoubleTy && - leftArgArg->getValue()->getType() == Type::FloatTy && - rightArgArg->getValue()->getType() == Type::FloatTy); -} - - -static inline MachineOpCode -ChooseMulInstructionByType(const Type* resultType) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - if (resultType->isInteger()) - opCode = V9::MULXr; - else - switch(resultType->getPrimitiveID()) - { - case Type::FloatTyID: opCode = V9::FMULS; break; - case Type::DoubleTyID: opCode = V9::FMULD; break; - default: assert(0 && "Invalid type for MUL instruction"); break; - } - - return opCode; -} - - - -static inline MachineInstr* -CreateIntNegInstruction(const TargetMachine& target, - Value* vreg) -{ - return BuildMI(V9::SUBr, 3).addMReg(target.getRegInfo().getZeroRegNum()) - .addReg(vreg).addRegDef(vreg); -} - - -// Create instruction sequence for any shift operation. -// SLL or SLLX on an operand smaller than the integer reg. size (64bits) -// requires a second instruction for explicit sign-extension. -// Note that we only have to worry about a sign-bit appearing in the -// most significant bit of the operand after shifting (e.g., bit 32 of -// Int or bit 16 of Short), so we do not have to worry about results -// that are as large as a normal integer register. -// -static inline void -CreateShiftInstructions(const TargetMachine& target, - Function* F, - MachineOpCode shiftOpCode, - Value* argVal1, - Value* optArgVal2, /* Use optArgVal2 if not NULL */ - unsigned optShiftNum, /* else use optShiftNum */ - Instruction* destVal, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - assert((optArgVal2 != NULL || optShiftNum <= 64) && - "Large shift sizes unexpected, but can be handled below: " - "You need to check whether or not it fits in immed field below"); - - // If this is a logical left shift of a type smaller than the standard - // integer reg. size, we have to extend the sign-bit into upper bits - // of dest, so we need to put the result of the SLL into a temporary. - // - Value* shiftDest = destVal; - unsigned opSize = target.getTargetData().getTypeSize(argVal1->getType()); - - if ((shiftOpCode == V9::SLLr5 || shiftOpCode == V9::SLLXr6) && opSize < 8) { - // put SLL result into a temporary - shiftDest = new TmpInstruction(mcfi, argVal1, optArgVal2, "sllTmp"); - } - - MachineInstr* M = (optArgVal2 != NULL) - ? BuildMI(shiftOpCode, 3).addReg(argVal1).addReg(optArgVal2) - .addReg(shiftDest, MachineOperand::Def) - : BuildMI(shiftOpCode, 3).addReg(argVal1).addZImm(optShiftNum) - .addReg(shiftDest, MachineOperand::Def); - mvec.push_back(M); - - if (shiftDest != destVal) { - // extend the sign-bit of the result into all upper bits of dest - assert(8*opSize <= 32 && "Unexpected type size > 4 and < IntRegSize?"); - target.getInstrInfo(). - CreateSignExtensionInstructions(target, F, shiftDest, destVal, - 8*opSize, mvec, mcfi); - } -} - - -// Does not create any instructions if we cannot exploit constant to -// create a cheaper instruction. -// This returns the approximate cost of the instructions generated, -// which is used to pick the cheapest when both operands are constant. -static unsigned -CreateMulConstInstruction(const TargetMachine &target, Function* F, - Value* lval, Value* rval, Instruction* destVal, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - /* Use max. multiply cost, viz., cost of MULX */ - unsigned cost = target.getInstrInfo().minLatency(V9::MULXr); - unsigned firstNewInstr = mvec.size(); - - Value* constOp = rval; - if (! isa<Constant>(constOp)) - return cost; - - // Cases worth optimizing are: - // (1) Multiply by 0 or 1 for any type: replace with copy (ADD or FMOV) - // (2) Multiply by 2^x for integer types: replace with Shift - // - const Type* resultType = destVal->getType(); - - if (resultType->isInteger() || isa<PointerType>(resultType)) { - bool isValidConst; - int64_t C = (int64_t) target.getInstrInfo().ConvertConstantToIntType(target, - constOp, constOp->getType(), isValidConst); - if (isValidConst) { - unsigned pow; - bool needNeg = false; - if (C < 0) { - needNeg = true; - C = -C; - } - - if (C == 0 || C == 1) { - cost = target.getInstrInfo().minLatency(V9::ADDr); - unsigned Zero = target.getRegInfo().getZeroRegNum(); - MachineInstr* M; - if (C == 0) - M =BuildMI(V9::ADDr,3).addMReg(Zero).addMReg(Zero).addRegDef(destVal); - else - M = BuildMI(V9::ADDr,3).addReg(lval).addMReg(Zero).addRegDef(destVal); - mvec.push_back(M); - } else if (isPowerOf2(C, pow)) { - unsigned opSize = target.getTargetData().getTypeSize(resultType); - MachineOpCode opCode = (opSize <= 32)? V9::SLLr5 : V9::SLLXr6; - CreateShiftInstructions(target, F, opCode, lval, NULL, pow, - destVal, mvec, mcfi); - } - - if (mvec.size() > 0 && needNeg) { - // insert <reg = SUB 0, reg> after the instr to flip the sign - MachineInstr* M = CreateIntNegInstruction(target, destVal); - mvec.push_back(M); - } - } - } else { - if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) { - double dval = FPC->getValue(); - if (fabs(dval) == 1) { - MachineOpCode opCode = (dval < 0) - ? (resultType == Type::FloatTy? V9::FNEGS : V9::FNEGD) - : (resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD); - mvec.push_back(BuildMI(opCode,2).addReg(lval).addRegDef(destVal)); - } - } - } - - if (firstNewInstr < mvec.size()) { - cost = 0; - for (unsigned i=firstNewInstr; i < mvec.size(); ++i) - cost += target.getInstrInfo().minLatency(mvec[i]->getOpcode()); - } - - return cost; -} - - -// Does not create any instructions if we cannot exploit constant to -// create a cheaper instruction. -// -static inline void -CreateCheapestMulConstInstruction(const TargetMachine &target, - Function* F, - Value* lval, Value* rval, - Instruction* destVal, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) -{ - Value* constOp; - if (isa<Constant>(lval) && isa<Constant>(rval)) { - // both operands are constant: evaluate and "set" in dest - Constant* P = ConstantExpr::get(Instruction::Mul, - cast<Constant>(lval), - cast<Constant>(rval)); - target.getInstrInfo().CreateCodeToLoadConst(target,F,P,destVal,mvec,mcfi); - } - else if (isa<Constant>(rval)) // rval is constant, but not lval - CreateMulConstInstruction(target, F, lval, rval, destVal, mvec, mcfi); - else if (isa<Constant>(lval)) // lval is constant, but not rval - CreateMulConstInstruction(target, F, lval, rval, destVal, mvec, mcfi); - - // else neither is constant - return; -} - -// Return NULL if we cannot exploit constant to create a cheaper instruction -static inline void -CreateMulInstruction(const TargetMachine &target, Function* F, - Value* lval, Value* rval, Instruction* destVal, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi, - MachineOpCode forceMulOp = INVALID_MACHINE_OPCODE) -{ - unsigned L = mvec.size(); - CreateCheapestMulConstInstruction(target,F, lval, rval, destVal, mvec, mcfi); - if (mvec.size() == L) { - // no instructions were added so create MUL reg, reg, reg. - // Use FSMULD if both operands are actually floats cast to doubles. - // Otherwise, use the default opcode for the appropriate type. - MachineOpCode mulOp = ((forceMulOp != INVALID_MACHINE_OPCODE) - ? forceMulOp - : ChooseMulInstructionByType(destVal->getType())); - mvec.push_back(BuildMI(mulOp, 3).addReg(lval).addReg(rval) - .addRegDef(destVal)); - } -} - - -// Generate a divide instruction for Div or Rem. -// For Rem, this assumes that the operand type will be signed if the result -// type is signed. This is correct because they must have the same sign. -// -static inline MachineOpCode -ChooseDivInstruction(TargetMachine &target, - const InstructionNode* instrNode) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - const Type* resultType = instrNode->getInstruction()->getType(); - - if (resultType->isInteger()) - opCode = resultType->isSigned()? V9::SDIVXr : V9::UDIVXr; - else - switch(resultType->getPrimitiveID()) - { - case Type::FloatTyID: opCode = V9::FDIVS; break; - case Type::DoubleTyID: opCode = V9::FDIVD; break; - default: assert(0 && "Invalid type for DIV instruction"); break; - } - - return opCode; -} - - -// Return if we cannot exploit constant to create a cheaper instruction -static void -CreateDivConstInstruction(TargetMachine &target, - const InstructionNode* instrNode, - std::vector<MachineInstr*>& mvec) -{ - Value* LHS = instrNode->leftChild()->getValue(); - Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); - if (!isa<Constant>(constOp)) - return; - - Instruction* destVal = instrNode->getInstruction(); - unsigned ZeroReg = target.getRegInfo().getZeroRegNum(); - - // Cases worth optimizing are: - // (1) Divide by 1 for any type: replace with copy (ADD or FMOV) - // (2) Divide by 2^x for integer types: replace with SR[L or A]{X} - // - const Type* resultType = instrNode->getInstruction()->getType(); - - if (resultType->isInteger()) { - unsigned pow; - bool isValidConst; - int64_t C = (int64_t) target.getInstrInfo().ConvertConstantToIntType(target, - constOp, constOp->getType(), isValidConst); - if (isValidConst) { - bool needNeg = false; - if (C < 0) { - needNeg = true; - C = -C; - } - - if (C == 1) { - mvec.push_back(BuildMI(V9::ADDr, 3).addReg(LHS).addMReg(ZeroReg) - .addRegDef(destVal)); - } else if (isPowerOf2(C, pow)) { - unsigned opCode; - Value* shiftOperand; - unsigned opSize = target.getTargetData().getTypeSize(resultType); - - if (resultType->isSigned()) { - // For N / 2^k, if the operand N is negative, - // we need to add (2^k - 1) before right-shifting by k, i.e., - // - // (N / 2^k) = N >> k, if N >= 0; - // (N + 2^k - 1) >> k, if N < 0 - // - // If N is <= 32 bits, use: - // sra N, 31, t1 // t1 = ~0, if N < 0, 0 else - // srl t1, 32-k, t2 // t2 = 2^k - 1, if N < 0, 0 else - // add t2, N, t3 // t3 = N + 2^k -1, if N < 0, N else - // sra t3, k, result // result = N / 2^k - // - // If N is 64 bits, use: - // srax N, k-1, t1 // t1 = sign bit in high k positions - // srlx t1, 64-k, t2 // t2 = 2^k - 1, if N < 0, 0 else - // add t2, N, t3 // t3 = N + 2^k -1, if N < 0, N else - // sra t3, k, result // result = N / 2^k - // - TmpInstruction *sraTmp, *srlTmp, *addTmp; - MachineCodeForInstruction& mcfi - = MachineCodeForInstruction::get(destVal); - sraTmp = new TmpInstruction(mcfi, resultType, LHS, 0, "getSign"); - srlTmp = new TmpInstruction(mcfi, resultType, LHS, 0, "getPlus2km1"); - addTmp = new TmpInstruction(mcfi, resultType, LHS, srlTmp,"incIfNeg"); - - // Create the SRA or SRAX instruction to get the sign bit - mvec.push_back(BuildMI((opSize > 4)? V9::SRAXi6 : V9::SRAi5, 3) - .addReg(LHS) - .addSImm((resultType==Type::LongTy)? pow-1 : 31) - .addRegDef(sraTmp)); - - // Create the SRL or SRLX instruction to get the sign bit - mvec.push_back(BuildMI((opSize > 4)? V9::SRLXi6 : V9::SRLi5, 3) - .addReg(sraTmp) - .addSImm((resultType==Type::LongTy)? 64-pow : 32-pow) - .addRegDef(srlTmp)); - - // Create the ADD instruction to add 2^pow-1 for negative values - mvec.push_back(BuildMI(V9::ADDr, 3).addReg(LHS).addReg(srlTmp) - .addRegDef(addTmp)); - - // Get the shift operand and "right-shift" opcode to do the divide - shiftOperand = addTmp; - opCode = (opSize > 4)? V9::SRAXi6 : V9::SRAi5; - } else { - // Get the shift operand and "right-shift" opcode to do the divide - shiftOperand = LHS; - opCode = (opSize > 4)? V9::SRLXi6 : V9::SRLi5; - } - - // Now do the actual shift! - mvec.push_back(BuildMI(opCode, 3).addReg(shiftOperand).addZImm(pow) - .addRegDef(destVal)); - } - - if (needNeg && (C == 1 || isPowerOf2(C, pow))) { - // insert <reg = SUB 0, reg> after the instr to flip the sign - mvec.push_back(CreateIntNegInstruction(target, destVal)); - } - } - } else { - if (ConstantFP *FPC = dyn_cast<ConstantFP>(constOp)) { - double dval = FPC->getValue(); - if (fabs(dval) == 1) { - unsigned opCode = - (dval < 0) ? (resultType == Type::FloatTy? V9::FNEGS : V9::FNEGD) - : (resultType == Type::FloatTy? V9::FMOVS : V9::FMOVD); - - mvec.push_back(BuildMI(opCode, 2).addReg(LHS).addRegDef(destVal)); - } - } - } -} - - -static void -CreateCodeForVariableSizeAlloca(const TargetMachine& target, - Instruction* result, - unsigned tsize, - Value* numElementsVal, - std::vector<MachineInstr*>& getMvec) -{ - Value* totalSizeVal; - MachineInstr* M; - MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(result); - Function *F = result->getParent()->getParent(); - - // Enforce the alignment constraints on the stack pointer at - // compile time if the total size is a known constant. - if (isa<Constant>(numElementsVal)) { - bool isValid; - int64_t numElem = (int64_t) target.getInstrInfo(). - ConvertConstantToIntType(target, numElementsVal, - numElementsVal->getType(), isValid); - assert(isValid && "Unexpectedly large array dimension in alloca!"); - int64_t total = numElem * tsize; - if (int extra= total % target.getFrameInfo().getStackFrameSizeAlignment()) - total += target.getFrameInfo().getStackFrameSizeAlignment() - extra; - totalSizeVal = ConstantSInt::get(Type::IntTy, total); - } else { - // The size is not a constant. Generate code to compute it and - // code to pad the size for stack alignment. - // Create a Value to hold the (constant) element size - Value* tsizeVal = ConstantSInt::get(Type::IntTy, tsize); - - // Create temporary values to hold the result of MUL, SLL, SRL - // To pad `size' to next smallest multiple of 16: - // size = (size + 15) & (-16 = 0xfffffffffffffff0) - // - TmpInstruction* tmpProd = new TmpInstruction(mcfi,numElementsVal, tsizeVal); - TmpInstruction* tmpAdd15= new TmpInstruction(mcfi,numElementsVal, tmpProd); - TmpInstruction* tmpAndf0= new TmpInstruction(mcfi,numElementsVal, tmpAdd15); - - // Instruction 1: mul numElements, typeSize -> tmpProd - // This will optimize the MUL as far as possible. - CreateMulInstruction(target, F, numElementsVal, tsizeVal, tmpProd, getMvec, - mcfi, INVALID_MACHINE_OPCODE); - - // Instruction 2: andn tmpProd, 0x0f -> tmpAndn - getMvec.push_back(BuildMI(V9::ADDi, 3).addReg(tmpProd).addSImm(15) - .addReg(tmpAdd15, MachineOperand::Def)); - - // Instruction 3: add tmpAndn, 0x10 -> tmpAdd16 - getMvec.push_back(BuildMI(V9::ANDi, 3).addReg(tmpAdd15).addSImm(-16) - .addReg(tmpAndf0, MachineOperand::Def)); - - totalSizeVal = tmpAndf0; - } - - // Get the constant offset from SP for dynamically allocated storage - // and create a temporary Value to hold it. - MachineFunction& mcInfo = MachineFunction::get(F); - bool growUp; - ConstantSInt* dynamicAreaOffset = - ConstantSInt::get(Type::IntTy, - target.getFrameInfo().getDynamicAreaOffset(mcInfo,growUp)); - assert(! growUp && "Has SPARC v9 stack frame convention changed?"); - - unsigned SPReg = target.getRegInfo().getStackPointer(); - - // Instruction 2: sub %sp, totalSizeVal -> %sp - getMvec.push_back(BuildMI(V9::SUBr, 3).addMReg(SPReg).addReg(totalSizeVal) - .addMReg(SPReg,MachineOperand::Def)); - - // Instruction 3: add %sp, frameSizeBelowDynamicArea -> result - getMvec.push_back(BuildMI(V9::ADDr,3).addMReg(SPReg).addReg(dynamicAreaOffset) - .addRegDef(result)); -} - - -static void -CreateCodeForFixedSizeAlloca(const TargetMachine& target, - Instruction* result, - unsigned tsize, - unsigned numElements, - std::vector<MachineInstr*>& getMvec) -{ - assert(tsize > 0 && "Illegal (zero) type size for alloca"); - assert(result && result->getParent() && - "Result value is not part of a function?"); - Function *F = result->getParent()->getParent(); - MachineFunction &mcInfo = MachineFunction::get(F); - - // Put the variable in the dynamically sized area of the frame if either: - // (a) The offset is too large to use as an immediate in load/stores - // (check LDX because all load/stores have the same-size immed. field). - // (b) The object is "large", so it could cause many other locals, - // spills, and temporaries to have large offsets. - // NOTE: We use LARGE = 8 * argSlotSize = 64 bytes. - // You've gotta love having only 13 bits for constant offset values :-|. - // - unsigned paddedSize; - int offsetFromFP = mcInfo.getInfo()->computeOffsetforLocalVar(result, - paddedSize, - tsize * numElements); - - if (((int)paddedSize) > 8 * target.getFrameInfo().getSizeOfEachArgOnStack() || - ! target.getInstrInfo().constantFitsInImmedField(V9::LDXi,offsetFromFP)) { - CreateCodeForVariableSizeAlloca(target, result, tsize, - ConstantSInt::get(Type::IntTy,numElements), - getMvec); - return; - } - - // else offset fits in immediate field so go ahead and allocate it. - offsetFromFP = mcInfo.getInfo()->allocateLocalVar(result, tsize *numElements); - - // Create a temporary Value to hold the constant offset. - // This is needed because it may not fit in the immediate field. - ConstantSInt* offsetVal = ConstantSInt::get(Type::IntTy, offsetFromFP); - - // Instruction 1: add %fp, offsetFromFP -> result - unsigned FPReg = target.getRegInfo().getFramePointer(); - getMvec.push_back(BuildMI(V9::ADDr, 3).addMReg(FPReg).addReg(offsetVal) - .addRegDef(result)); -} - - -//------------------------------------------------------------------------ -// Function SetOperandsForMemInstr -// -// Choose addressing mode for the given load or store instruction. -// Use [reg+reg] if it is an indexed reference, and the index offset is -// not a constant or if it cannot fit in the offset field. -// Use [reg+offset] in all other cases. -// -// This assumes that all array refs are "lowered" to one of these forms: -// %x = load (subarray*) ptr, constant ; single constant offset -// %x = load (subarray*) ptr, offsetVal ; single non-constant offset -// Generally, this should happen via strength reduction + LICM. -// Also, strength reduction should take care of using the same register for -// the loop index variable and an array index, when that is profitable. -//------------------------------------------------------------------------ - -static void -SetOperandsForMemInstr(unsigned Opcode, - std::vector<MachineInstr*>& mvec, - InstructionNode* vmInstrNode, - const TargetMachine& target) -{ - Instruction* memInst = vmInstrNode->getInstruction(); - // Index vector, ptr value, and flag if all indices are const. - std::vector<Value*> idxVec; - bool allConstantIndices; - Value* ptrVal = GetMemInstArgs(vmInstrNode, idxVec, allConstantIndices); - - // Now create the appropriate operands for the machine instruction. - // First, initialize so we default to storing the offset in a register. - int64_t smallConstOffset = 0; - Value* valueForRegOffset = NULL; - MachineOperand::MachineOperandType offsetOpType = - MachineOperand::MO_VirtualRegister; - - // Check if there is an index vector and if so, compute the - // right offset for structures and for arrays - // - if (!idxVec.empty()) { - const PointerType* ptrType = cast<PointerType>(ptrVal->getType()); - - // If all indices are constant, compute the combined offset directly. - if (allConstantIndices) { - // Compute the offset value using the index vector. Create a - // virtual reg. for it since it may not fit in the immed field. - uint64_t offset = target.getTargetData().getIndexedOffset(ptrType,idxVec); - valueForRegOffset = ConstantSInt::get(Type::LongTy, offset); - } else { - // There is at least one non-constant offset. Therefore, this must - // be an array ref, and must have been lowered to a single non-zero - // offset. (An extra leading zero offset, if any, can be ignored.) - // Generate code sequence to compute address from index. - // - bool firstIdxIsZero = IsZero(idxVec[0]); - assert(idxVec.size() == 1U + firstIdxIsZero - && "Array refs must be lowered before Instruction Selection"); - - Value* idxVal = idxVec[firstIdxIsZero]; - - std::vector<MachineInstr*> mulVec; - Instruction* addr = - new TmpInstruction(MachineCodeForInstruction::get(memInst), - Type::ULongTy, memInst); - - // Get the array type indexed by idxVal, and compute its element size. - // The call to getTypeSize() will fail if size is not constant. - const Type* vecType = (firstIdxIsZero - ? GetElementPtrInst::getIndexedType(ptrType, - std::vector<Value*>(1U, idxVec[0]), - /*AllowCompositeLeaf*/ true) - : ptrType); - const Type* eltType = cast<SequentialType>(vecType)->getElementType(); - ConstantUInt* eltSizeVal = ConstantUInt::get(Type::ULongTy, - target.getTargetData().getTypeSize(eltType)); - - // CreateMulInstruction() folds constants intelligently enough. - CreateMulInstruction(target, memInst->getParent()->getParent(), - idxVal, /* lval, not likely to be const*/ - eltSizeVal, /* rval, likely to be constant */ - addr, /* result */ - mulVec, MachineCodeForInstruction::get(memInst), - INVALID_MACHINE_OPCODE); - - assert(mulVec.size() > 0 && "No multiply code created?"); - mvec.insert(mvec.end(), mulVec.begin(), mulVec.end()); - - valueForRegOffset = addr; - } - } else { - offsetOpType = MachineOperand::MO_SignExtendedImmed; - smallConstOffset = 0; - } - - // For STORE: - // Operand 0 is value, operand 1 is ptr, operand 2 is offset - // For LOAD or GET_ELEMENT_PTR, - // Operand 0 is ptr, operand 1 is offset, operand 2 is result. - // - unsigned offsetOpNum, ptrOpNum; - MachineInstr *MI; - if (memInst->getOpcode() == Instruction::Store) { - if (offsetOpType == MachineOperand::MO_VirtualRegister) { - MI = BuildMI(Opcode, 3).addReg(vmInstrNode->leftChild()->getValue()) - .addReg(ptrVal).addReg(valueForRegOffset); - } else { - Opcode = convertOpcodeFromRegToImm(Opcode); - MI = BuildMI(Opcode, 3).addReg(vmInstrNode->leftChild()->getValue()) - .addReg(ptrVal).addSImm(smallConstOffset); - } - } else { - if (offsetOpType == MachineOperand::MO_VirtualRegister) { - MI = BuildMI(Opcode, 3).addReg(ptrVal).addReg(valueForRegOffset) - .addRegDef(memInst); - } else { - Opcode = convertOpcodeFromRegToImm(Opcode); - MI = BuildMI(Opcode, 3).addReg(ptrVal).addSImm(smallConstOffset) - .addRegDef(memInst); - } - } - mvec.push_back(MI); -} - - -// -// Substitute operand `operandNum' of the instruction in node `treeNode' -// in place of the use(s) of that instruction in node `parent'. -// Check both explicit and implicit operands! -// Also make sure to skip over a parent who: -// (1) is a list node in the Burg tree, or -// (2) itself had its results forwarded to its parent -// -static void -ForwardOperand(InstructionNode* treeNode, - InstrTreeNode* parent, - int operandNum) -{ - assert(treeNode && parent && "Invalid invocation of ForwardOperand"); - - Instruction* unusedOp = treeNode->getInstruction(); - Value* fwdOp = unusedOp->getOperand(operandNum); - - // The parent itself may be a list node, so find the real parent instruction - while (parent->getNodeType() != InstrTreeNode::NTInstructionNode) - { - parent = parent->parent(); - assert(parent && "ERROR: Non-instruction node has no parent in tree."); - } - InstructionNode* parentInstrNode = (InstructionNode*) parent; - - Instruction* userInstr = parentInstrNode->getInstruction(); - MachineCodeForInstruction &mvec = MachineCodeForInstruction::get(userInstr); - - // The parent's mvec would be empty if it was itself forwarded. - // Recursively call ForwardOperand in that case... - // - if (mvec.size() == 0) { - assert(parent->parent() != NULL && - "Parent could not have been forwarded, yet has no instructions?"); - ForwardOperand(treeNode, parent->parent(), operandNum); - } else { - for (unsigned i=0, N=mvec.size(); i < N; i++) { - MachineInstr* minstr = mvec[i]; - for (unsigned i=0, numOps=minstr->getNumOperands(); i < numOps; ++i) { - const MachineOperand& mop = minstr->getOperand(i); - if (mop.getType() == MachineOperand::MO_VirtualRegister && - mop.getVRegValue() == unusedOp) - { - minstr->SetMachineOperandVal(i, MachineOperand::MO_VirtualRegister, - fwdOp); - } - } - - for (unsigned i=0,numOps=minstr->getNumImplicitRefs(); i<numOps; ++i) - if (minstr->getImplicitRef(i) == unusedOp) - minstr->setImplicitRef(i, fwdOp); - } - } -} - - -inline bool -AllUsesAreBranches(const Instruction* setccI) -{ - for (Value::use_const_iterator UI=setccI->use_begin(), UE=setccI->use_end(); - UI != UE; ++UI) - if (! isa<TmpInstruction>(*UI) // ignore tmp instructions here - && cast<Instruction>(*UI)->getOpcode() != Instruction::Br) - return false; - return true; -} - -// Generate code for any intrinsic that needs a special code sequence -// instead of a regular call. If not that kind of intrinsic, do nothing. -// Returns true if code was generated, otherwise false. -// -static bool CodeGenIntrinsic(Intrinsic::ID iid, CallInst &callInstr, - TargetMachine &target, - std::vector<MachineInstr*>& mvec) { - switch (iid) { - default: - assert(0 && "Unknown intrinsic function call should have been lowered!"); - case Intrinsic::va_start: { - // Get the address of the first incoming vararg argument on the stack - bool ignore; - Function* func = cast<Function>(callInstr.getParent()->getParent()); - int numFixedArgs = func->getFunctionType()->getNumParams(); - int fpReg = target.getFrameInfo().getIncomingArgBaseRegNum(); - int argSize = target.getFrameInfo().getSizeOfEachArgOnStack(); - int firstVarArgOff = numFixedArgs * argSize + target.getFrameInfo(). - getFirstIncomingArgOffset(MachineFunction::get(func), ignore); - mvec.push_back(BuildMI(V9::ADDi, 3).addMReg(fpReg).addSImm(firstVarArgOff). - addRegDef(&callInstr)); - return true; - } - - case Intrinsic::va_end: - return true; // no-op on Sparc - - case Intrinsic::va_copy: - // Simple copy of current va_list (arg1) to new va_list (result) - mvec.push_back(BuildMI(V9::ORr, 3). - addMReg(target.getRegInfo().getZeroRegNum()). - addReg(callInstr.getOperand(1)). - addRegDef(&callInstr)); - return true; - } -} - -//******************* Externally Visible Functions *************************/ - -//------------------------------------------------------------------------ -// External Function: ThisIsAChainRule -// -// Purpose: -// Check if a given BURG rule is a chain rule. -//------------------------------------------------------------------------ - -extern bool -ThisIsAChainRule(int eruleno) -{ - switch(eruleno) - { - case 111: // stmt: reg - case 123: - case 124: - case 125: - case 126: - case 127: - case 128: - case 129: - case 130: - case 131: - case 132: - case 133: - case 155: - case 221: - case 222: - case 241: - case 242: - case 243: - case 244: - case 245: - case 321: - return true; break; - - default: - return false; break; - } -} - - -//------------------------------------------------------------------------ -// External Function: GetInstructionsByRule -// -// Purpose: -// Choose machine instructions for the SPARC according to the -// patterns chosen by the BURG-generated parser. -//------------------------------------------------------------------------ - -void -GetInstructionsByRule(InstructionNode* subtreeRoot, - int ruleForNode, - short* nts, - TargetMachine &target, - std::vector<MachineInstr*>& mvec) -{ - bool checkCast = false; // initialize here to use fall-through - bool maskUnsignedResult = false; - int nextRule; - int forwardOperandNum = -1; - unsigned allocaSize = 0; - MachineInstr* M, *M2; - unsigned L; - bool foldCase = false; - - mvec.clear(); - - // If the code for this instruction was folded into the parent (user), - // then do nothing! - if (subtreeRoot->isFoldedIntoParent()) - return; - - // - // Let's check for chain rules outside the switch so that we don't have - // to duplicate the list of chain rule production numbers here again - // - if (ThisIsAChainRule(ruleForNode)) { - // Chain rules have a single nonterminal on the RHS. - // Get the rule that matches the RHS non-terminal and use that instead. - // - assert(nts[0] && ! nts[1] - && "A chain rule should have only one RHS non-terminal!"); - nextRule = burm_rule(subtreeRoot->state, nts[0]); - nts = burm_nts[nextRule]; - GetInstructionsByRule(subtreeRoot, nextRule, nts, target, mvec); - } else { - switch(ruleForNode) { - case 1: // stmt: Ret - case 2: // stmt: RetValue(reg) - { // NOTE: Prepass of register allocation is responsible - // for moving return value to appropriate register. - // Copy the return value to the required return register. - // Mark the return Value as an implicit ref of the RET instr.. - // Mark the return-address register as a hidden virtual reg. - // Finally put a NOP in the delay slot. - ReturnInst *returnInstr=cast<ReturnInst>(subtreeRoot->getInstruction()); - Value* retVal = returnInstr->getReturnValue(); - MachineCodeForInstruction& mcfi = - MachineCodeForInstruction::get(returnInstr); - - // Create a hidden virtual reg to represent the return address register - // used by the machine instruction but not represented in LLVM. - // - Instruction* returnAddrTmp = new TmpInstruction(mcfi, returnInstr); - - MachineInstr* retMI = - BuildMI(V9::JMPLRETi, 3).addReg(returnAddrTmp).addSImm(8) - .addMReg(target.getRegInfo().getZeroRegNum(), MachineOperand::Def); - - // If there is a value to return, we need to: - // (a) Sign-extend the value if it is smaller than 8 bytes (reg size) - // (b) Insert a copy to copy the return value to the appropriate reg. - // -- For FP values, create a FMOVS or FMOVD instruction - // -- For non-FP values, create an add-with-0 instruction - // - if (retVal != NULL) { - const SparcRegInfo& regInfo = - (SparcRegInfo&) target.getRegInfo(); - const Type* retType = retVal->getType(); - unsigned regClassID = regInfo.getRegClassIDOfType(retType); - unsigned retRegNum = (retType->isFloatingPoint() - ? (unsigned) SparcFloatRegClass::f0 - : (unsigned) SparcIntRegClass::i0); - retRegNum = regInfo.getUnifiedRegNum(regClassID, retRegNum); - - // () Insert sign-extension instructions for small signed values. - // - Value* retValToUse = retVal; - if (retType->isIntegral() && retType->isSigned()) { - unsigned retSize = target.getTargetData().getTypeSize(retType); - if (retSize <= 4) { - // create a temporary virtual reg. to hold the sign-extension - retValToUse = new TmpInstruction(mcfi, retVal); - - // sign-extend retVal and put the result in the temporary reg. - target.getInstrInfo().CreateSignExtensionInstructions - (target, returnInstr->getParent()->getParent(), - retVal, retValToUse, 8*retSize, mvec, mcfi); - } - } - - // (b) Now, insert a copy to to the appropriate register: - // -- For FP values, create a FMOVS or FMOVD instruction - // -- For non-FP values, create an add-with-0 instruction - // - // First, create a virtual register to represent the register and - // mark this vreg as being an implicit operand of the ret MI. - TmpInstruction* retVReg = - new TmpInstruction(mcfi, retValToUse, NULL, "argReg"); - - retMI->addImplicitRef(retVReg); - - if (retType->isFloatingPoint()) - M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2) - .addReg(retValToUse).addReg(retVReg, MachineOperand::Def)); - else - M = (BuildMI(ChooseAddInstructionByType(retType), 3) - .addReg(retValToUse).addSImm((int64_t) 0) - .addReg(retVReg, MachineOperand::Def)); - - // Mark the operand with the register it should be assigned - M->SetRegForOperand(M->getNumOperands()-1, retRegNum); - retMI->SetRegForImplicitRef(retMI->getNumImplicitRefs()-1, retRegNum); - - mvec.push_back(M); - } - - // Now insert the RET instruction and a NOP for the delay slot - mvec.push_back(retMI); - mvec.push_back(BuildMI(V9::NOP, 0)); - - break; - } - - case 3: // stmt: Store(reg,reg) - case 4: // stmt: Store(reg,ptrreg) - SetOperandsForMemInstr(ChooseStoreInstruction( - subtreeRoot->leftChild()->getValue()->getType()), - mvec, subtreeRoot, target); - break; - - case 5: // stmt: BrUncond - { - BranchInst *BI = cast<BranchInst>(subtreeRoot->getInstruction()); - mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(BI->getSuccessor(0))); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - break; - } - - case 206: // stmt: BrCond(setCCconst) - { // setCCconst => boolean was computed with `%b = setCC type reg1 const' - // If the constant is ZERO, we can use the branch-on-integer-register - // instructions and avoid the SUBcc instruction entirely. - // Otherwise this is just the same as case 5, so just fall through. - // - InstrTreeNode* constNode = subtreeRoot->leftChild()->rightChild(); - assert(constNode && - constNode->getNodeType() ==InstrTreeNode::NTConstNode); - Constant *constVal = cast<Constant>(constNode->getValue()); - bool isValidConst; - - if ((constVal->getType()->isInteger() - || isa<PointerType>(constVal->getType())) - && target.getInstrInfo().ConvertConstantToIntType(target, - constVal, constVal->getType(), isValidConst) == 0 - && isValidConst) - { - // That constant is a zero after all... - // Use the left child of setCC as the first argument! - // Mark the setCC node so that no code is generated for it. - InstructionNode* setCCNode = (InstructionNode*) - subtreeRoot->leftChild(); - assert(setCCNode->getOpLabel() == SetCCOp); - setCCNode->markFoldedIntoParent(); - - BranchInst* brInst=cast<BranchInst>(subtreeRoot->getInstruction()); - - M = BuildMI(ChooseBprInstruction(subtreeRoot), 2) - .addReg(setCCNode->leftChild()->getValue()) - .addPCDisp(brInst->getSuccessor(0)); - mvec.push_back(M); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - - // false branch - mvec.push_back(BuildMI(V9::BA, 1) - .addPCDisp(brInst->getSuccessor(1))); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - break; - } - // ELSE FALL THROUGH - } - - case 6: // stmt: BrCond(setCC) - { // bool => boolean was computed with SetCC. - // The branch to use depends on whether it is FP, signed, or unsigned. - // If it is an integer CC, we also need to find the unique - // TmpInstruction representing that CC. - // - BranchInst* brInst = cast<BranchInst>(subtreeRoot->getInstruction()); - const Type* setCCType; - unsigned Opcode = ChooseBccInstruction(subtreeRoot, setCCType); - Value* ccValue = GetTmpForCC(subtreeRoot->leftChild()->getValue(), - brInst->getParent()->getParent(), - setCCType, - MachineCodeForInstruction::get(brInst)); - M = BuildMI(Opcode, 2).addCCReg(ccValue) - .addPCDisp(brInst->getSuccessor(0)); - mvec.push_back(M); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - - // false branch - mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(brInst->getSuccessor(1))); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - break; - } - - case 208: // stmt: BrCond(boolconst) - { - // boolconst => boolean is a constant; use BA to first or second label - Constant* constVal = - cast<Constant>(subtreeRoot->leftChild()->getValue()); - unsigned dest = cast<ConstantBool>(constVal)->getValue()? 0 : 1; - - M = BuildMI(V9::BA, 1).addPCDisp( - cast<BranchInst>(subtreeRoot->getInstruction())->getSuccessor(dest)); - mvec.push_back(M); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - break; - } - - case 8: // stmt: BrCond(boolreg) - { // boolreg => boolean is recorded in an integer register. - // Use branch-on-integer-register instruction. - // - BranchInst *BI = cast<BranchInst>(subtreeRoot->getInstruction()); - M = BuildMI(V9::BRNZ, 2).addReg(subtreeRoot->leftChild()->getValue()) - .addPCDisp(BI->getSuccessor(0)); - mvec.push_back(M); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - - // false branch - mvec.push_back(BuildMI(V9::BA, 1).addPCDisp(BI->getSuccessor(1))); - - // delay slot - mvec.push_back(BuildMI(V9::NOP, 0)); - break; - } - - case 9: // stmt: Switch(reg) - assert(0 && "*** SWITCH instruction is not implemented yet."); - break; - - case 10: // reg: VRegList(reg, reg) - assert(0 && "VRegList should never be the topmost non-chain rule"); - break; - - case 21: // bool: Not(bool,reg): Compute with a conditional-move-on-reg - { // First find the unary operand. It may be left or right, usually right. - Instruction* notI = subtreeRoot->getInstruction(); - Value* notArg = BinaryOperator::getNotArgument( - cast<BinaryOperator>(subtreeRoot->getInstruction())); - unsigned ZeroReg = target.getRegInfo().getZeroRegNum(); - - // Unconditionally set register to 0 - mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(notI)); - - // Now conditionally move 1 into the register. - // Mark the register as a use (as well as a def) because the old - // value will be retained if the condition is false. - mvec.push_back(BuildMI(V9::MOVRZi, 3).addReg(notArg).addZImm(1) - .addReg(notI, MachineOperand::UseAndDef)); - - break; - } - - case 421: // reg: BNot(reg,reg): Compute as reg = reg XOR-NOT 0 - { // First find the unary operand. It may be left or right, usually right. - Value* notArg = BinaryOperator::getNotArgument( - cast<BinaryOperator>(subtreeRoot->getInstruction())); - unsigned ZeroReg = target.getRegInfo().getZeroRegNum(); - mvec.push_back(BuildMI(V9::XNORr, 3).addReg(notArg).addMReg(ZeroReg) - .addRegDef(subtreeRoot->getValue())); - break; - } - - case 322: // reg: Not(tobool, reg): - // Fold CAST-TO-BOOL with NOT by inverting the sense of cast-to-bool - foldCase = true; - // Just fall through! - - case 22: // reg: ToBoolTy(reg): - { - Instruction* castI = subtreeRoot->getInstruction(); - Value* opVal = subtreeRoot->leftChild()->getValue(); - assert(opVal->getType()->isIntegral() || - isa<PointerType>(opVal->getType())); - - // Unconditionally set register to 0 - mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(castI)); - - // Now conditionally move 1 into the register. - // Mark the register as a use (as well as a def) because the old - // value will be retained if the condition is false. - MachineOpCode opCode = foldCase? V9::MOVRZi : V9::MOVRNZi; - mvec.push_back(BuildMI(opCode, 3).addReg(opVal).addZImm(1) - .addReg(castI, MachineOperand::UseAndDef)); - - break; - } - - case 23: // reg: ToUByteTy(reg) - case 24: // reg: ToSByteTy(reg) - case 25: // reg: ToUShortTy(reg) - case 26: // reg: ToShortTy(reg) - case 27: // reg: ToUIntTy(reg) - case 28: // reg: ToIntTy(reg) - case 29: // reg: ToULongTy(reg) - case 30: // reg: ToLongTy(reg) - { - //====================================================================== - // Rules for integer conversions: - // - //-------- - // From ISO 1998 C++ Standard, Sec. 4.7: - // - // 2. If the destination type is unsigned, the resulting value is - // the least unsigned integer congruent to the source integer - // (modulo 2n where n is the number of bits used to represent the - // unsigned type). [Note: In a two s complement representation, - // this conversion is conceptual and there is no change in the - // bit pattern (if there is no truncation). ] - // - // 3. If the destination type is signed, the value is unchanged if - // it can be represented in the destination type (and bitfield width); - // otherwise, the value is implementation-defined. - //-------- - // - // Since we assume 2s complement representations, this implies: - // - // -- If operand is smaller than destination, zero-extend or sign-extend - // according to the signedness of the *operand*: source decides: - // (1) If operand is signed, sign-extend it. - // If dest is unsigned, zero-ext the result! - // (2) If operand is unsigned, our current invariant is that - // it's high bits are correct, so zero-extension is not needed. - // - // -- If operand is same size as or larger than destination, - // zero-extend or sign-extend according to the signedness of - // the *destination*: destination decides: - // (1) If destination is signed, sign-extend (truncating if needed) - // This choice is implementation defined. We sign-extend the - // operand, which matches both Sun's cc and gcc3.2. - // (2) If destination is unsigned, zero-extend (truncating if needed) - //====================================================================== - - Instruction* destI = subtreeRoot->getInstruction(); - Function* currentFunc = destI->getParent()->getParent(); - MachineCodeForInstruction& mcfi=MachineCodeForInstruction::get(destI); - - Value* opVal = subtreeRoot->leftChild()->getValue(); - const Type* opType = opVal->getType(); - const Type* destType = destI->getType(); - unsigned opSize = target.getTargetData().getTypeSize(opType); - unsigned destSize = target.getTargetData().getTypeSize(destType); - - bool isIntegral = opType->isIntegral() || isa<PointerType>(opType); - - if (opType == Type::BoolTy || - opType == destType || - isIntegral && opSize == destSize && opSize == 8) { - // nothing to do in all these cases - forwardOperandNum = 0; // forward first operand to user - - } else if (opType->isFloatingPoint()) { - - CreateCodeToConvertFloatToInt(target, opVal, destI, mvec, mcfi); - if (destI->getType()->isUnsigned() && destI->getType() !=Type::UIntTy) - maskUnsignedResult = true; // not handled by fp->int code - - } else if (isIntegral) { - - bool opSigned = opType->isSigned(); - bool destSigned = destType->isSigned(); - unsigned extSourceInBits = 8 * std::min<unsigned>(opSize, destSize); - - assert(! (opSize == destSize && opSigned == destSigned) && - "How can different int types have same size and signedness?"); - - bool signExtend = (opSize < destSize && opSigned || - opSize >= destSize && destSigned); - - bool signAndZeroExtend = (opSize < destSize && destSize < 8u && - opSigned && !destSigned); - assert(!signAndZeroExtend || signExtend); - - bool zeroExtendOnly = opSize >= destSize && !destSigned; - assert(!zeroExtendOnly || !signExtend); - - if (signExtend) { - Value* signExtDest = (signAndZeroExtend - ? new TmpInstruction(mcfi, destType, opVal) - : destI); - - target.getInstrInfo().CreateSignExtensionInstructions - (target, currentFunc,opVal,signExtDest,extSourceInBits,mvec,mcfi); - - if (signAndZeroExtend) - target.getInstrInfo().CreateZeroExtensionInstructions - (target, currentFunc, signExtDest, destI, 8*destSize, mvec, mcfi); - } - else if (zeroExtendOnly) { - target.getInstrInfo().CreateZeroExtensionInstructions - (target, currentFunc, opVal, destI, extSourceInBits, mvec, mcfi); - } - else - forwardOperandNum = 0; // forward first operand to user - - } else - assert(0 && "Unrecognized operand type for convert-to-integer"); - - break; - } - - case 31: // reg: ToFloatTy(reg): - case 32: // reg: ToDoubleTy(reg): - case 232: // reg: ToDoubleTy(Constant): - - // If this instruction has a parent (a user) in the tree - // and the user is translated as an FsMULd instruction, - // then the cast is unnecessary. So check that first. - // In the future, we'll want to do the same for the FdMULq instruction, - // so do the check here instead of only for ToFloatTy(reg). - // - if (subtreeRoot->parent() != NULL) { - const MachineCodeForInstruction& mcfi = - MachineCodeForInstruction::get( - cast<InstructionNode>(subtreeRoot->parent())->getInstruction()); - if (mcfi.size() == 0 || mcfi.front()->getOpcode() == V9::FSMULD) - forwardOperandNum = 0; // forward first operand to user - } - - if (forwardOperandNum != 0) { // we do need the cast - Value* leftVal = subtreeRoot->leftChild()->getValue(); - const Type* opType = leftVal->getType(); - MachineOpCode opCode=ChooseConvertToFloatInstr(target, - subtreeRoot->getOpLabel(), opType); - if (opCode == V9::NOP) { // no conversion needed - forwardOperandNum = 0; // forward first operand to user - } else { - // If the source operand is a non-FP type it must be - // first copied from int to float register via memory! - Instruction *dest = subtreeRoot->getInstruction(); - Value* srcForCast; - int n = 0; - if (! opType->isFloatingPoint()) { - // Create a temporary to represent the FP register - // into which the integer will be copied via memory. - // The type of this temporary will determine the FP - // register used: single-prec for a 32-bit int or smaller, - // double-prec for a 64-bit int. - // - uint64_t srcSize = - target.getTargetData().getTypeSize(leftVal->getType()); - Type* tmpTypeToUse = - (srcSize <= 4)? Type::FloatTy : Type::DoubleTy; - MachineCodeForInstruction &destMCFI = - MachineCodeForInstruction::get(dest); - srcForCast = new TmpInstruction(destMCFI, tmpTypeToUse, dest); - - target.getInstrInfo().CreateCodeToCopyIntToFloat(target, - dest->getParent()->getParent(), - leftVal, cast<Instruction>(srcForCast), - mvec, destMCFI); - } else - srcForCast = leftVal; - - M = BuildMI(opCode, 2).addReg(srcForCast).addRegDef(dest); - mvec.push_back(M); - } - } - break; - - case 19: // reg: ToArrayTy(reg): - case 20: // reg: ToPointerTy(reg): - forwardOperandNum = 0; // forward first operand to user - break; - - case 233: // reg: Add(reg, Constant) - maskUnsignedResult = true; - M = CreateAddConstInstruction(subtreeRoot); - if (M != NULL) { - mvec.push_back(M); - break; - } - // ELSE FALL THROUGH - - case 33: // reg: Add(reg, reg) - maskUnsignedResult = true; - Add3OperandInstr(ChooseAddInstruction(subtreeRoot), subtreeRoot, mvec); - break; - - case 234: // reg: Sub(reg, Constant) - maskUnsignedResult = true; - M = CreateSubConstInstruction(subtreeRoot); - if (M != NULL) { - mvec.push_back(M); - break; - } - // ELSE FALL THROUGH - - case 34: // reg: Sub(reg, reg) - maskUnsignedResult = true; - Add3OperandInstr(ChooseSubInstructionByType( - subtreeRoot->getInstruction()->getType()), - subtreeRoot, mvec); - break; - - case 135: // reg: Mul(todouble, todouble) - checkCast = true; - // FALL THROUGH - - case 35: // reg: Mul(reg, reg) - { - maskUnsignedResult = true; - MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot)) - ? (MachineOpCode)V9::FSMULD - : INVALID_MACHINE_OPCODE); - Instruction* mulInstr = subtreeRoot->getInstruction(); - CreateMulInstruction(target, mulInstr->getParent()->getParent(), - subtreeRoot->leftChild()->getValue(), - subtreeRoot->rightChild()->getValue(), - mulInstr, mvec, - MachineCodeForInstruction::get(mulInstr),forceOp); - break; - } - case 335: // reg: Mul(todouble, todoubleConst) - checkCast = true; - // FALL THROUGH - - case 235: // reg: Mul(reg, Constant) - { - maskUnsignedResult = true; - MachineOpCode forceOp = ((checkCast && BothFloatToDouble(subtreeRoot)) - ? (MachineOpCode)V9::FSMULD - : INVALID_MACHINE_OPCODE); - Instruction* mulInstr = subtreeRoot->getInstruction(); - CreateMulInstruction(target, mulInstr->getParent()->getParent(), - subtreeRoot->leftChild()->getValue(), - subtreeRoot->rightChild()->getValue(), - mulInstr, mvec, - MachineCodeForInstruction::get(mulInstr), - forceOp); - break; - } - case 236: // reg: Div(reg, Constant) - maskUnsignedResult = true; - L = mvec.size(); - CreateDivConstInstruction(target, subtreeRoot, mvec); - if (mvec.size() > L) - break; - // ELSE FALL THROUGH - - case 36: // reg: Div(reg, reg) - { - maskUnsignedResult = true; - - // If either operand of divide is smaller than 64 bits, we have - // to make sure the unused top bits are correct because they affect - // the result. These bits are already correct for unsigned values. - // They may be incorrect for signed values, so sign extend to fill in. - Instruction* divI = subtreeRoot->getInstruction(); - Value* divOp1 = subtreeRoot->leftChild()->getValue(); - Value* divOp2 = subtreeRoot->rightChild()->getValue(); - Value* divOp1ToUse = divOp1; - Value* divOp2ToUse = divOp2; - if (divI->getType()->isSigned()) { - unsigned opSize=target.getTargetData().getTypeSize(divI->getType()); - if (opSize < 8) { - MachineCodeForInstruction& mcfi=MachineCodeForInstruction::get(divI); - divOp1ToUse = new TmpInstruction(mcfi, divOp1); - divOp2ToUse = new TmpInstruction(mcfi, divOp2); - target.getInstrInfo(). - CreateSignExtensionInstructions(target, - divI->getParent()->getParent(), - divOp1, divOp1ToUse, - 8*opSize, mvec, mcfi); - target.getInstrInfo(). - CreateSignExtensionInstructions(target, - divI->getParent()->getParent(), - divOp2, divOp2ToUse, - 8*opSize, mvec, mcfi); - } - } - - mvec.push_back(BuildMI(ChooseDivInstruction(target, subtreeRoot), 3) - .addReg(divOp1ToUse) - .addReg(divOp2ToUse) - .addRegDef(divI)); - - break; - } - - case 37: // reg: Rem(reg, reg) - case 237: // reg: Rem(reg, Constant) - { - maskUnsignedResult = true; - - Instruction* remI = subtreeRoot->getInstruction(); - Value* divOp1 = subtreeRoot->leftChild()->getValue(); - Value* divOp2 = subtreeRoot->rightChild()->getValue(); - - MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(remI); - - // If second operand of divide is smaller than 64 bits, we have - // to make sure the unused top bits are correct because they affect - // the result. These bits are already correct for unsigned values. - // They may be incorrect for signed values, so sign extend to fill in. - // - Value* divOpToUse = divOp2; - if (divOp2->getType()->isSigned()) { - unsigned opSize=target.getTargetData().getTypeSize(divOp2->getType()); - if (opSize < 8) { - divOpToUse = new TmpInstruction(mcfi, divOp2); - target.getInstrInfo(). - CreateSignExtensionInstructions(target, - remI->getParent()->getParent(), - divOp2, divOpToUse, - 8*opSize, mvec, mcfi); - } - } - - // Now compute: result = rem V1, V2 as: - // result = V1 - (V1 / signExtend(V2)) * signExtend(V2) - // - TmpInstruction* quot = new TmpInstruction(mcfi, divOp1, divOpToUse); - TmpInstruction* prod = new TmpInstruction(mcfi, quot, divOpToUse); - - mvec.push_back(BuildMI(ChooseDivInstruction(target, subtreeRoot), 3) - .addReg(divOp1).addReg(divOpToUse).addRegDef(quot)); - - mvec.push_back(BuildMI(ChooseMulInstructionByType(remI->getType()), 3) - .addReg(quot).addReg(divOpToUse).addRegDef(prod)); - - mvec.push_back(BuildMI(ChooseSubInstructionByType(remI->getType()), 3) - .addReg(divOp1).addReg(prod).addRegDef(remI)); - - break; - } - - case 38: // bool: And(bool, bool) - case 138: // bool: And(bool, not) - case 238: // bool: And(bool, boolconst) - case 338: // reg : BAnd(reg, reg) - case 538: // reg : BAnd(reg, Constant) - Add3OperandInstr(V9::ANDr, subtreeRoot, mvec); - break; - - case 438: // bool: BAnd(bool, bnot) - { // Use the argument of NOT as the second argument! - // Mark the NOT node so that no code is generated for it. - // If the type is boolean, set 1 or 0 in the result register. - InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild(); - Value* notArg = BinaryOperator::getNotArgument( - cast<BinaryOperator>(notNode->getInstruction())); - notNode->markFoldedIntoParent(); - Value *lhs = subtreeRoot->leftChild()->getValue(); - Value *dest = subtreeRoot->getValue(); - mvec.push_back(BuildMI(V9::ANDNr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MachineOperand::Def)); - - if (notArg->getType() == Type::BoolTy) { - // set 1 in result register if result of above is non-zero - mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MachineOperand::UseAndDef)); - } - - break; - } - - case 39: // bool: Or(bool, bool) - case 139: // bool: Or(bool, not) - case 239: // bool: Or(bool, boolconst) - case 339: // reg : BOr(reg, reg) - case 539: // reg : BOr(reg, Constant) - Add3OperandInstr(V9::ORr, subtreeRoot, mvec); - break; - - case 439: // bool: BOr(bool, bnot) - { // Use the argument of NOT as the second argument! - // Mark the NOT node so that no code is generated for it. - // If the type is boolean, set 1 or 0 in the result register. - InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild(); - Value* notArg = BinaryOperator::getNotArgument( - cast<BinaryOperator>(notNode->getInstruction())); - notNode->markFoldedIntoParent(); - Value *lhs = subtreeRoot->leftChild()->getValue(); - Value *dest = subtreeRoot->getValue(); - - mvec.push_back(BuildMI(V9::ORNr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MachineOperand::Def)); - - if (notArg->getType() == Type::BoolTy) { - // set 1 in result register if result of above is non-zero - mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MachineOperand::UseAndDef)); - } - - break; - } - - case 40: // bool: Xor(bool, bool) - case 140: // bool: Xor(bool, not) - case 240: // bool: Xor(bool, boolconst) - case 340: // reg : BXor(reg, reg) - case 540: // reg : BXor(reg, Constant) - Add3OperandInstr(V9::XORr, subtreeRoot, mvec); - break; - - case 440: // bool: BXor(bool, bnot) - { // Use the argument of NOT as the second argument! - // Mark the NOT node so that no code is generated for it. - // If the type is boolean, set 1 or 0 in the result register. - InstructionNode* notNode = (InstructionNode*) subtreeRoot->rightChild(); - Value* notArg = BinaryOperator::getNotArgument( - cast<BinaryOperator>(notNode->getInstruction())); - notNode->markFoldedIntoParent(); - Value *lhs = subtreeRoot->leftChild()->getValue(); - Value *dest = subtreeRoot->getValue(); - mvec.push_back(BuildMI(V9::XNORr, 3).addReg(lhs).addReg(notArg) - .addReg(dest, MachineOperand::Def)); - - if (notArg->getType() == Type::BoolTy) { - // set 1 in result register if result of above is non-zero - mvec.push_back(BuildMI(V9::MOVRNZi, 3).addReg(dest).addZImm(1) - .addReg(dest, MachineOperand::UseAndDef)); - } - break; - } - - case 41: // setCCconst: SetCC(reg, Constant) - { // Comparison is with a constant: - // - // If the bool result must be computed into a register (see below), - // and the constant is int ZERO, we can use the MOVR[op] instructions - // and avoid the SUBcc instruction entirely. - // Otherwise this is just the same as case 42, so just fall through. - // - // The result of the SetCC must be computed and stored in a register if - // it is used outside the current basic block (so it must be computed - // as a boolreg) or it is used by anything other than a branch. - // We will use a conditional move to do this. - // - Instruction* setCCInstr = subtreeRoot->getInstruction(); - bool computeBoolVal = (subtreeRoot->parent() == NULL || - ! AllUsesAreBranches(setCCInstr)); - - if (computeBoolVal) { - InstrTreeNode* constNode = subtreeRoot->rightChild(); - assert(constNode && - constNode->getNodeType() ==InstrTreeNode::NTConstNode); - Constant *constVal = cast<Constant>(constNode->getValue()); - bool isValidConst; - - if ((constVal->getType()->isInteger() - || isa<PointerType>(constVal->getType())) - && target.getInstrInfo().ConvertConstantToIntType(target, - constVal, constVal->getType(), isValidConst) == 0 - && isValidConst) - { - // That constant is an integer zero after all... - // Use a MOVR[op] to compute the boolean result - // Unconditionally set register to 0 - mvec.push_back(BuildMI(V9::SETHI, 2).addZImm(0) - .addRegDef(setCCInstr)); - - // Now conditionally move 1 into the register. - // Mark the register as a use (as well as a def) because the old - // value will be retained if the condition is false. - MachineOpCode movOpCode = ChooseMovpregiForSetCC(subtreeRoot); - mvec.push_back(BuildMI(movOpCode, 3) - .addReg(subtreeRoot->leftChild()->getValue()) - .addZImm(1) - .addReg(setCCInstr, MachineOperand::UseAndDef)); - - break; - } - } - // ELSE FALL THROUGH - } - - case 42: // bool: SetCC(reg, reg): - { - // This generates a SUBCC instruction, putting the difference in a - // result reg. if needed, and/or setting a condition code if needed. - // - Instruction* setCCInstr = subtreeRoot->getInstruction(); - Value* leftVal = subtreeRoot->leftChild()->getValue(); - Value* rightVal = subtreeRoot->rightChild()->getValue(); - const Type* opType = leftVal->getType(); - bool isFPCompare = opType->isFloatingPoint(); - - // If the boolean result of the SetCC is used outside the current basic - // block (so it must be computed as a boolreg) or is used by anything - // other than a branch, the boolean must be computed and stored - // in a result register. We will use a conditional move to do this. - // - bool computeBoolVal = (subtreeRoot->parent() == NULL || - ! AllUsesAreBranches(setCCInstr)); - - // A TmpInstruction is created to represent the CC "result". - // Unlike other instances of TmpInstruction, this one is used - // by machine code of multiple LLVM instructions, viz., - // the SetCC and the branch. Make sure to get the same one! - // Note that we do this even for FP CC registers even though they - // are explicit operands, because the type of the operand - // needs to be a floating point condition code, not an integer - // condition code. Think of this as casting the bool result to - // a FP condition code register. - // Later, we mark the 4th operand as being a CC register, and as a def. - // - TmpInstruction* tmpForCC = GetTmpForCC(setCCInstr, - setCCInstr->getParent()->getParent(), - leftVal->getType(), - MachineCodeForInstruction::get(setCCInstr)); - - // If the operands are signed values smaller than 4 bytes, then they - // must be sign-extended in order to do a valid 32-bit comparison - // and get the right result in the 32-bit CC register (%icc). - // - Value* leftOpToUse = leftVal; - Value* rightOpToUse = rightVal; - if (opType->isIntegral() && opType->isSigned()) { - unsigned opSize = target.getTargetData().getTypeSize(opType); - if (opSize < 4) { - MachineCodeForInstruction& mcfi = - MachineCodeForInstruction::get(setCCInstr); - - // create temporary virtual regs. to hold the sign-extensions - leftOpToUse = new TmpInstruction(mcfi, leftVal); - rightOpToUse = new TmpInstruction(mcfi, rightVal); - - // sign-extend each operand and put the result in the temporary reg. - target.getInstrInfo().CreateSignExtensionInstructions - (target, setCCInstr->getParent()->getParent(), - leftVal, leftOpToUse, 8*opSize, mvec, mcfi); - target.getInstrInfo().CreateSignExtensionInstructions - (target, setCCInstr->getParent()->getParent(), - rightVal, rightOpToUse, 8*opSize, mvec, mcfi); - } - } - - if (! isFPCompare) { - // Integer condition: set CC and discard result. - mvec.push_back(BuildMI(V9::SUBccr, 4) - .addReg(leftOpToUse) - .addReg(rightOpToUse) - .addMReg(target.getRegInfo() - .getZeroRegNum(), MachineOperand::Def) - .addCCReg(tmpForCC, MachineOperand::Def)); - } else { - // FP condition: dest of FCMP should be some FCCn register - mvec.push_back(BuildMI(ChooseFcmpInstruction(subtreeRoot), 3) - .addCCReg(tmpForCC, MachineOperand::Def) - .addReg(leftOpToUse) - .addReg(rightOpToUse)); - } - - if (computeBoolVal) { - MachineOpCode movOpCode = (isFPCompare - ? ChooseMovFpcciInstruction(subtreeRoot) - : ChooseMovpcciForSetCC(subtreeRoot)); - - // Unconditionally set register to 0 - M = BuildMI(V9::SETHI, 2).addZImm(0).addRegDef(setCCInstr); - mvec.push_back(M); - - // Now conditionally move 1 into the register. - // Mark the register as a use (as well as a def) because the old - // value will be retained if the condition is false. - M = (BuildMI(movOpCode, 3).addCCReg(tmpForCC).addZImm(1) - .addReg(setCCInstr, MachineOperand::UseAndDef)); - mvec.push_back(M); - } - break; - } - - case 51: // reg: Load(reg) - case 52: // reg: Load(ptrreg) - SetOperandsForMemInstr(ChooseLoadInstruction( - subtreeRoot->getValue()->getType()), - mvec, subtreeRoot, target); - break; - - case 55: // reg: GetElemPtr(reg) - case 56: // reg: GetElemPtrIdx(reg,reg) - // If the GetElemPtr was folded into the user (parent), it will be - // caught above. For other cases, we have to compute the address. - SetOperandsForMemInstr(V9::ADDr, mvec, subtreeRoot, target); - break; - - case 57: // reg: Alloca: Implement as 1 instruction: - { // add %fp, offsetFromFP -> result - AllocationInst* instr = - cast<AllocationInst>(subtreeRoot->getInstruction()); - unsigned tsize = - target.getTargetData().getTypeSize(instr->getAllocatedType()); - assert(tsize != 0); - CreateCodeForFixedSizeAlloca(target, instr, tsize, 1, mvec); - break; - } - - case 58: // reg: Alloca(reg): Implement as 3 instructions: - // mul num, typeSz -> tmp - // sub %sp, tmp -> %sp - { // add %sp, frameSizeBelowDynamicArea -> result - AllocationInst* instr = - cast<AllocationInst>(subtreeRoot->getInstruction()); - const Type* eltType = instr->getAllocatedType(); - - // If #elements is constant, use simpler code for fixed-size allocas - int tsize = (int) target.getTargetData().getTypeSize(eltType); - Value* numElementsVal = NULL; - bool isArray = instr->isArrayAllocation(); - - if (!isArray || isa<Constant>(numElementsVal = instr->getArraySize())) { - // total size is constant: generate code for fixed-size alloca - unsigned numElements = isArray? - cast<ConstantUInt>(numElementsVal)->getValue() : 1; - CreateCodeForFixedSizeAlloca(target, instr, tsize, - numElements, mvec); - } else { - // total size is not constant. - CreateCodeForVariableSizeAlloca(target, instr, tsize, - numElementsVal, mvec); - } - break; - } - - case 61: // reg: Call - { // Generate a direct (CALL) or indirect (JMPL) call. - // Mark the return-address register, the indirection - // register (for indirect calls), the operands of the Call, - // and the return value (if any) as implicit operands - // of the machine instruction. - // - // If this is a varargs function, floating point arguments - // have to passed in integer registers so insert - // copy-float-to-int instructions for each float operand. - // - CallInst *callInstr = cast<CallInst>(subtreeRoot->getInstruction()); - Value *callee = callInstr->getCalledValue(); - Function* calledFunc = dyn_cast<Function>(callee); - - // Check if this is an intrinsic function that needs a special code - // sequence (e.g., va_start). Indirect calls cannot be special. - // - bool specialIntrinsic = false; - Intrinsic::ID iid; - if (calledFunc && (iid=(Intrinsic::ID)calledFunc->getIntrinsicID())) - specialIntrinsic = CodeGenIntrinsic(iid, *callInstr, target, mvec); - - // If not, generate the normal call sequence for the function. - // This can also handle any intrinsics that are just function calls. - // - if (! specialIntrinsic) { - Function* currentFunc = callInstr->getParent()->getParent(); - MachineFunction& MF = MachineFunction::get(currentFunc); - MachineCodeForInstruction& mcfi = - MachineCodeForInstruction::get(callInstr); - const SparcRegInfo& regInfo = - (SparcRegInfo&) target.getRegInfo(); - const TargetFrameInfo& frameInfo = target.getFrameInfo(); - - // Create hidden virtual register for return address with type void* - TmpInstruction* retAddrReg = - new TmpInstruction(mcfi, PointerType::get(Type::VoidTy), callInstr); - - // Generate the machine instruction and its operands. - // Use CALL for direct function calls; this optimistically assumes - // the PC-relative address fits in the CALL address field (22 bits). - // Use JMPL for indirect calls. - // This will be added to mvec later, after operand copies. - // - MachineInstr* callMI; - if (calledFunc) // direct function call - callMI = BuildMI(V9::CALL, 1).addPCDisp(callee); - else // indirect function call - callMI = (BuildMI(V9::JMPLCALLi,3).addReg(callee) - .addSImm((int64_t)0).addRegDef(retAddrReg)); - - const FunctionType* funcType = - cast<FunctionType>(cast<PointerType>(callee->getType()) - ->getElementType()); - bool isVarArgs = funcType->isVarArg(); - bool noPrototype = isVarArgs && funcType->getNumParams() == 0; - - // Use a descriptor to pass information about call arguments - // to the register allocator. This descriptor will be "owned" - // and freed automatically when the MachineCodeForInstruction - // object for the callInstr goes away. - CallArgsDescriptor* argDesc = - new CallArgsDescriptor(callInstr, retAddrReg,isVarArgs,noPrototype); - assert(callInstr->getOperand(0) == callee - && "This is assumed in the loop below!"); - - // Insert sign-extension instructions for small signed values, - // if this is an unknown function (i.e., called via a funcptr) - // or an external one (i.e., which may not be compiled by llc). - // - if (calledFunc == NULL || calledFunc->isExternal()) { - for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i) { - Value* argVal = callInstr->getOperand(i); - const Type* argType = argVal->getType(); - if (argType->isIntegral() && argType->isSigned()) { - unsigned argSize = target.getTargetData().getTypeSize(argType); - if (argSize <= 4) { - // create a temporary virtual reg. to hold the sign-extension - TmpInstruction* argExtend = new TmpInstruction(mcfi, argVal); - - // sign-extend argVal and put the result in the temporary reg. - target.getInstrInfo().CreateSignExtensionInstructions - (target, currentFunc, argVal, argExtend, - 8*argSize, mvec, mcfi); - - // replace argVal with argExtend in CallArgsDescriptor - argDesc->getArgInfo(i-1).replaceArgVal(argExtend); - } - } - } - } - - // Insert copy instructions to get all the arguments into - // all the places that they need to be. - // - for (unsigned i=1, N=callInstr->getNumOperands(); i < N; ++i) { - int argNo = i-1; - CallArgInfo& argInfo = argDesc->getArgInfo(argNo); - Value* argVal = argInfo.getArgVal(); // don't use callInstr arg here - const Type* argType = argVal->getType(); - unsigned regType = regInfo.getRegTypeForDataType(argType); - unsigned argSize = target.getTargetData().getTypeSize(argType); - int regNumForArg = TargetRegInfo::getInvalidRegNum(); - unsigned regClassIDOfArgReg; - - // Check for FP arguments to varargs functions. - // Any such argument in the first $K$ args must be passed in an - // integer register. If there is no prototype, it must also - // be passed as an FP register. - // K = #integer argument registers. - bool isFPArg = argVal->getType()->isFloatingPoint(); - if (isVarArgs && isFPArg) { - - if (noPrototype) { - // It is a function with no prototype: pass value - // as an FP value as well as a varargs value. The FP value - // may go in a register or on the stack. The copy instruction - // to the outgoing reg/stack is created by the normal argument - // handling code since this is the "normal" passing mode. - // - regNumForArg = regInfo.regNumForFPArg(regType, - false, false, argNo, - regClassIDOfArgReg); - if (regNumForArg == regInfo.getInvalidRegNum()) - argInfo.setUseStackSlot(); - else - argInfo.setUseFPArgReg(); - } - - // If this arg. is in the first $K$ regs, add special copy- - // float-to-int instructions to pass the value as an int. - // To check if it is in the first $K$, get the register - // number for the arg #i. These copy instructions are - // generated here because they are extra cases and not needed - // for the normal argument handling (some code reuse is - // possible though -- later). - // - int copyRegNum = regInfo.regNumForIntArg(false, false, argNo, - regClassIDOfArgReg); - if (copyRegNum != regInfo.getInvalidRegNum()) { - // Create a virtual register to represent copyReg. Mark - // this vreg as being an implicit operand of the call MI - const Type* loadTy = (argType == Type::FloatTy - ? Type::IntTy : Type::LongTy); - TmpInstruction* argVReg = new TmpInstruction(mcfi, loadTy, - argVal, NULL, - "argRegCopy"); - callMI->addImplicitRef(argVReg); - - // Get a temp stack location to use to copy - // float-to-int via the stack. - // - // FIXME: For now, we allocate permanent space because - // the stack frame manager does not allow locals to be - // allocated (e.g., for alloca) after a temp is - // allocated! - // - // int tmpOffset = MF.getInfo()->pushTempValue(argSize); - int tmpOffset = MF.getInfo()->allocateLocalVar(argVReg); - - // Generate the store from FP reg to stack - unsigned StoreOpcode = ChooseStoreInstruction(argType); - M = BuildMI(convertOpcodeFromRegToImm(StoreOpcode), 3) - .addReg(argVal).addMReg(regInfo.getFramePointer()) - .addSImm(tmpOffset); - mvec.push_back(M); - - // Generate the load from stack to int arg reg - unsigned LoadOpcode = ChooseLoadInstruction(loadTy); - M = BuildMI(convertOpcodeFromRegToImm(LoadOpcode), 3) - .addMReg(regInfo.getFramePointer()).addSImm(tmpOffset) - .addReg(argVReg, MachineOperand::Def); - - // Mark operand with register it should be assigned - // both for copy and for the callMI - M->SetRegForOperand(M->getNumOperands()-1, copyRegNum); - callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1, - copyRegNum); - mvec.push_back(M); - - // Add info about the argument to the CallArgsDescriptor - argInfo.setUseIntArgReg(); - argInfo.setArgCopy(copyRegNum); - } else { - // Cannot fit in first $K$ regs so pass arg on stack - argInfo.setUseStackSlot(); - } - } else if (isFPArg) { - // Get the outgoing arg reg to see if there is one. - regNumForArg = regInfo.regNumForFPArg(regType, false, false, - argNo, regClassIDOfArgReg); - if (regNumForArg == regInfo.getInvalidRegNum()) - argInfo.setUseStackSlot(); - else { - argInfo.setUseFPArgReg(); - regNumForArg =regInfo.getUnifiedRegNum(regClassIDOfArgReg, - regNumForArg); - } - } else { - // Get the outgoing arg reg to see if there is one. - regNumForArg = regInfo.regNumForIntArg(false,false, - argNo, regClassIDOfArgReg); - if (regNumForArg == regInfo.getInvalidRegNum()) - argInfo.setUseStackSlot(); - else { - argInfo.setUseIntArgReg(); - regNumForArg =regInfo.getUnifiedRegNum(regClassIDOfArgReg, - regNumForArg); - } - } - - // - // Now insert copy instructions to stack slot or arg. register - // - if (argInfo.usesStackSlot()) { - // Get the stack offset for this argument slot. - // FP args on stack are right justified so adjust offset! - // int arguments are also right justified but they are - // always loaded as a full double-word so the offset does - // not need to be adjusted. - int argOffset = frameInfo.getOutgoingArgOffset(MF, argNo); - if (argType->isFloatingPoint()) { - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); - assert(argSize <= slotSize && "Insufficient slot size!"); - argOffset += slotSize - argSize; - } - - // Now generate instruction to copy argument to stack - MachineOpCode storeOpCode = - (argType->isFloatingPoint() - ? ((argSize == 4)? V9::STFi : V9::STDFi) : V9::STXi); - - M = BuildMI(storeOpCode, 3).addReg(argVal) - .addMReg(regInfo.getStackPointer()).addSImm(argOffset); - mvec.push_back(M); - } - else if (regNumForArg != regInfo.getInvalidRegNum()) { - - // Create a virtual register to represent the arg reg. Mark - // this vreg as being an implicit operand of the call MI. - TmpInstruction* argVReg = - new TmpInstruction(mcfi, argVal, NULL, "argReg"); - - callMI->addImplicitRef(argVReg); - - // Generate the reg-to-reg copy into the outgoing arg reg. - // -- For FP values, create a FMOVS or FMOVD instruction - // -- For non-FP values, create an add-with-0 instruction - if (argType->isFloatingPoint()) - M=(BuildMI(argType==Type::FloatTy? V9::FMOVS :V9::FMOVD,2) - .addReg(argVal).addReg(argVReg, MachineOperand::Def)); - else - M = (BuildMI(ChooseAddInstructionByType(argType), 3) - .addReg(argVal).addSImm((int64_t) 0) - .addReg(argVReg, MachineOperand::Def)); - - // Mark the operand with the register it should be assigned - M->SetRegForOperand(M->getNumOperands()-1, regNumForArg); - callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1, - regNumForArg); - - mvec.push_back(M); - } - else - assert(argInfo.getArgCopy() != regInfo.getInvalidRegNum() && - "Arg. not in stack slot, primary or secondary register?"); - } - - // add call instruction and delay slot before copying return value - mvec.push_back(callMI); - mvec.push_back(BuildMI(V9::NOP, 0)); - - // Add the return value as an implicit ref. The call operands - // were added above. Also, add code to copy out the return value. - // This is always register-to-register for int or FP return values. - // - if (callInstr->getType() != Type::VoidTy) { - // Get the return value reg. - const Type* retType = callInstr->getType(); - - int regNum = (retType->isFloatingPoint() - ? (unsigned) SparcFloatRegClass::f0 - : (unsigned) SparcIntRegClass::o0); - unsigned regClassID = regInfo.getRegClassIDOfType(retType); - regNum = regInfo.getUnifiedRegNum(regClassID, regNum); - - // Create a virtual register to represent it and mark - // this vreg as being an implicit operand of the call MI - TmpInstruction* retVReg = - new TmpInstruction(mcfi, callInstr, NULL, "argReg"); - - callMI->addImplicitRef(retVReg, /*isDef*/ true); - - // Generate the reg-to-reg copy from the return value reg. - // -- For FP values, create a FMOVS or FMOVD instruction - // -- For non-FP values, create an add-with-0 instruction - if (retType->isFloatingPoint()) - M = (BuildMI(retType==Type::FloatTy? V9::FMOVS : V9::FMOVD, 2) - .addReg(retVReg).addReg(callInstr, MachineOperand::Def)); - else - M = (BuildMI(ChooseAddInstructionByType(retType), 3) - .addReg(retVReg).addSImm((int64_t) 0) - .addReg(callInstr, MachineOperand::Def)); - - // Mark the operand with the register it should be assigned - // Also mark the implicit ref of the call defining this operand - M->SetRegForOperand(0, regNum); - callMI->SetRegForImplicitRef(callMI->getNumImplicitRefs()-1,regNum); - - mvec.push_back(M); - } - - // For the CALL instruction, the ret. addr. reg. is also implicit - if (isa<Function>(callee)) - callMI->addImplicitRef(retAddrReg, /*isDef*/ true); - - MF.getInfo()->popAllTempValues(); // free temps used for this inst - } - - break; - } - - case 62: // reg: Shl(reg, reg) - { - Value* argVal1 = subtreeRoot->leftChild()->getValue(); - Value* argVal2 = subtreeRoot->rightChild()->getValue(); - Instruction* shlInstr = subtreeRoot->getInstruction(); - - const Type* opType = argVal1->getType(); - assert((opType->isInteger() || isa<PointerType>(opType)) && - "Shl unsupported for other types"); - unsigned opSize = target.getTargetData().getTypeSize(opType); - - CreateShiftInstructions(target, shlInstr->getParent()->getParent(), - (opSize > 4)? V9::SLLXr6:V9::SLLr5, - argVal1, argVal2, 0, shlInstr, mvec, - MachineCodeForInstruction::get(shlInstr)); - break; - } - - case 63: // reg: Shr(reg, reg) - { - const Type* opType = subtreeRoot->leftChild()->getValue()->getType(); - assert((opType->isInteger() || isa<PointerType>(opType)) && - "Shr unsupported for other types"); - unsigned opSize = target.getTargetData().getTypeSize(opType); - Add3OperandInstr(opType->isSigned() - ? (opSize > 4? V9::SRAXr6 : V9::SRAr5) - : (opSize > 4? V9::SRLXr6 : V9::SRLr5), - subtreeRoot, mvec); - break; - } - - case 64: // reg: Phi(reg,reg) - break; // don't forward the value - - case 65: // reg: VANext(reg): the va_next(va_list, type) instruction - { // Increment the va_list pointer register according to the type. - // All LLVM argument types are <= 64 bits, so use one doubleword. - Instruction* vaNextI = subtreeRoot->getInstruction(); - assert(target.getTargetData().getTypeSize(vaNextI->getType()) <= 8 && - "We assumed that all LLVM parameter types <= 8 bytes!"); - int argSize = target.getFrameInfo().getSizeOfEachArgOnStack(); - mvec.push_back(BuildMI(V9::ADDi, 3).addReg(vaNextI->getOperand(0)). - addSImm(argSize).addRegDef(vaNextI)); - break; - } - - case 66: // reg: VAArg (reg): the va_arg instruction - { // Load argument from stack using current va_list pointer value. - // Use 64-bit load for all non-FP args, and LDDF or double for FP. - Instruction* vaArgI = subtreeRoot->getInstruction(); - MachineOpCode loadOp = (vaArgI->getType()->isFloatingPoint() - ? (vaArgI->getType() == Type::FloatTy - ? V9::LDFi : V9::LDDFi) - : V9::LDXi); - mvec.push_back(BuildMI(loadOp, 3).addReg(vaArgI->getOperand(0)). - addSImm(0).addRegDef(vaArgI)); - break; - } - - case 71: // reg: VReg - case 72: // reg: Constant - break; // don't forward the value - - default: - assert(0 && "Unrecognized BURG rule"); - break; - } - } - - if (forwardOperandNum >= 0) { - // We did not generate a machine instruction but need to use operand. - // If user is in the same tree, replace Value in its machine operand. - // If not, insert a copy instruction which should get coalesced away - // by register allocation. - if (subtreeRoot->parent() != NULL) - ForwardOperand(subtreeRoot, subtreeRoot->parent(), forwardOperandNum); - else { - std::vector<MachineInstr*> minstrVec; - Instruction* instr = subtreeRoot->getInstruction(); - target.getInstrInfo(). - CreateCopyInstructionsByType(target, - instr->getParent()->getParent(), - instr->getOperand(forwardOperandNum), - instr, minstrVec, - MachineCodeForInstruction::get(instr)); - assert(minstrVec.size() > 0); - mvec.insert(mvec.end(), minstrVec.begin(), minstrVec.end()); - } - } - - if (maskUnsignedResult) { - // If result is unsigned and smaller than int reg size, - // we need to clear high bits of result value. - assert(forwardOperandNum < 0 && "Need mask but no instruction generated"); - Instruction* dest = subtreeRoot->getInstruction(); - if (dest->getType()->isUnsigned()) { - unsigned destSize=target.getTargetData().getTypeSize(dest->getType()); - if (destSize <= 4) { - // Mask high 64 - N bits, where N = 4*destSize. - - // Use a TmpInstruction to represent the - // intermediate result before masking. Since those instructions - // have already been generated, go back and substitute tmpI - // for dest in the result position of each one of them. - // - MachineCodeForInstruction& mcfi = MachineCodeForInstruction::get(dest); - TmpInstruction *tmpI = new TmpInstruction(mcfi, dest->getType(), - dest, NULL, "maskHi"); - Value* srlArgToUse = tmpI; - - unsigned numSubst = 0; - for (unsigned i=0, N=mvec.size(); i < N; ++i) { - - // Make sure we substitute all occurrences of dest in these instrs. - // Otherwise, we will have bogus code. - bool someArgsWereIgnored = false; - - // Make sure not to substitute an upwards-exposed use -- that would - // introduce a use of `tmpI' with no preceding def. Therefore, - // substitute a use or def-and-use operand only if a previous def - // operand has already been substituted (i.e., numSusbt > 0). - // - numSubst += mvec[i]->substituteValue(dest, tmpI, - /*defsOnly*/ numSubst == 0, - /*notDefsAndUses*/ numSubst > 0, - someArgsWereIgnored); - assert(!someArgsWereIgnored && - "Operand `dest' exists but not replaced: probably bogus!"); - } - assert(numSubst > 0 && "Operand `dest' not replaced: probably bogus!"); - - // Left shift 32-N if size (N) is less than 32 bits. - // Use another tmp. virtual register to represent this result. - if (destSize < 4) { - srlArgToUse = new TmpInstruction(mcfi, dest->getType(), - tmpI, NULL, "maskHi2"); - mvec.push_back(BuildMI(V9::SLLXi6, 3).addReg(tmpI) - .addZImm(8*(4-destSize)) - .addReg(srlArgToUse, MachineOperand::Def)); - } - - // Logical right shift 32-N to get zero extension in top 64-N bits. - mvec.push_back(BuildMI(V9::SRLi5, 3).addReg(srlArgToUse) - .addZImm(8*(4-destSize)) - .addReg(dest, MachineOperand::Def)); - - } else if (destSize < 8) { - assert(0 && "Unsupported type size: 32 < size < 64 bits"); - } - } - } -} - -} diff --git a/llvm/lib/Target/Sparc/SparcInstrSelectionSupport.h b/llvm/lib/Target/Sparc/SparcInstrSelectionSupport.h deleted file mode 100644 index b69c5c2b6e4..00000000000 --- a/llvm/lib/Target/Sparc/SparcInstrSelectionSupport.h +++ /dev/null @@ -1,227 +0,0 @@ -//===-- llvm/CodeGen/SparcInstrSelectionSupport.h ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// TODO: Need a description here. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARC_INSTR_SELECTION_SUPPORT_h -#define SPARC_INSTR_SELECTION_SUPPORT_h - -#include "llvm/DerivedTypes.h" -#include "SparcInternals.h" - -namespace llvm { - -// Choose load instruction opcode based on type of value -inline MachineOpCode -ChooseLoadInstruction(const Type *DestTy) -{ - switch (DestTy->getPrimitiveID()) { - case Type::BoolTyID: - case Type::UByteTyID: return V9::LDUBr; - case Type::SByteTyID: return V9::LDSBr; - case Type::UShortTyID: return V9::LDUHr; - case Type::ShortTyID: return V9::LDSHr; - case Type::UIntTyID: return V9::LDUWr; - case Type::IntTyID: return V9::LDSWr; - case Type::PointerTyID: - case Type::ULongTyID: - case Type::LongTyID: return V9::LDXr; - case Type::FloatTyID: return V9::LDFr; - case Type::DoubleTyID: return V9::LDDFr; - default: assert(0 && "Invalid type for Load instruction"); - } - - return 0; -} - -// Choose store instruction opcode based on type of value -inline MachineOpCode -ChooseStoreInstruction(const Type *DestTy) -{ - switch (DestTy->getPrimitiveID()) { - case Type::BoolTyID: - case Type::UByteTyID: - case Type::SByteTyID: return V9::STBr; - case Type::UShortTyID: - case Type::ShortTyID: return V9::STHr; - case Type::UIntTyID: - case Type::IntTyID: return V9::STWr; - case Type::PointerTyID: - case Type::ULongTyID: - case Type::LongTyID: return V9::STXr; - case Type::FloatTyID: return V9::STFr; - case Type::DoubleTyID: return V9::STDFr; - default: assert(0 && "Invalid type for Store instruction"); - } - - return 0; -} - - -inline MachineOpCode -ChooseAddInstructionByType(const Type* resultType) -{ - MachineOpCode opCode = V9::INVALID_OPCODE; - - if (resultType->isIntegral() || - isa<PointerType>(resultType) || - isa<FunctionType>(resultType) || - resultType == Type::LabelTy) - { - opCode = V9::ADDr; - } - else - switch(resultType->getPrimitiveID()) - { - case Type::FloatTyID: opCode = V9::FADDS; break; - case Type::DoubleTyID: opCode = V9::FADDD; break; - default: assert(0 && "Invalid type for ADD instruction"); break; - } - - return opCode; -} - - -// Because the Sparc instruction selector likes to re-write operands to -// instructions, making them change from a Value* (virtual register) to a -// Constant* (making an immediate field), we need to change the opcode from a -// register-based instruction to an immediate-based instruction, hence this -// mapping. -static unsigned -convertOpcodeFromRegToImm(unsigned Opcode) { - switch (Opcode) { - /* arithmetic */ - case V9::ADDr: return V9::ADDi; - case V9::ADDccr: return V9::ADDcci; - case V9::ADDCr: return V9::ADDCi; - case V9::ADDCccr: return V9::ADDCcci; - case V9::SUBr: return V9::SUBi; - case V9::SUBccr: return V9::SUBcci; - case V9::SUBCr: return V9::SUBCi; - case V9::SUBCccr: return V9::SUBCcci; - case V9::MULXr: return V9::MULXi; - case V9::SDIVXr: return V9::SDIVXi; - case V9::UDIVXr: return V9::UDIVXi; - - /* logical */ - case V9::ANDr: return V9::ANDi; - case V9::ANDccr: return V9::ANDcci; - case V9::ANDNr: return V9::ANDNi; - case V9::ANDNccr: return V9::ANDNcci; - case V9::ORr: return V9::ORi; - case V9::ORccr: return V9::ORcci; - case V9::ORNr: return V9::ORNi; - case V9::ORNccr: return V9::ORNcci; - case V9::XORr: return V9::XORi; - case V9::XORccr: return V9::XORcci; - case V9::XNORr: return V9::XNORi; - case V9::XNORccr: return V9::XNORcci; - - /* shift */ - case V9::SLLr5: return V9::SLLi5; - case V9::SRLr5: return V9::SRLi5; - case V9::SRAr5: return V9::SRAi5; - case V9::SLLXr6: return V9::SLLXi6; - case V9::SRLXr6: return V9::SRLXi6; - case V9::SRAXr6: return V9::SRAXi6; - - /* Conditional move on int comparison with zero */ - case V9::MOVRZr: return V9::MOVRZi; - case V9::MOVRLEZr: return V9::MOVRLEZi; - case V9::MOVRLZr: return V9::MOVRLZi; - case V9::MOVRNZr: return V9::MOVRNZi; - case V9::MOVRGZr: return V9::MOVRGZi; - case V9::MOVRGEZr: return V9::MOVRGEZi; - - - /* Conditional move on int condition code */ - case V9::MOVAr: return V9::MOVAi; - case V9::MOVNr: return V9::MOVNi; - case V9::MOVNEr: return V9::MOVNEi; - case V9::MOVEr: return V9::MOVEi; - case V9::MOVGr: return V9::MOVGi; - case V9::MOVLEr: return V9::MOVLEi; - case V9::MOVGEr: return V9::MOVGEi; - case V9::MOVLr: return V9::MOVLi; - case V9::MOVGUr: return V9::MOVGUi; - case V9::MOVLEUr: return V9::MOVLEUi; - case V9::MOVCCr: return V9::MOVCCi; - case V9::MOVCSr: return V9::MOVCSi; - case V9::MOVPOSr: return V9::MOVPOSi; - case V9::MOVNEGr: return V9::MOVNEGi; - case V9::MOVVCr: return V9::MOVVCi; - case V9::MOVVSr: return V9::MOVVSi; - - /* Conditional move of int reg on fp condition code */ - case V9::MOVFAr: return V9::MOVFAi; - case V9::MOVFNr: return V9::MOVFNi; - case V9::MOVFUr: return V9::MOVFUi; - case V9::MOVFGr: return V9::MOVFGi; - case V9::MOVFUGr: return V9::MOVFUGi; - case V9::MOVFLr: return V9::MOVFLi; - case V9::MOVFULr: return V9::MOVFULi; - case V9::MOVFLGr: return V9::MOVFLGi; - case V9::MOVFNEr: return V9::MOVFNEi; - case V9::MOVFEr: return V9::MOVFEi; - case V9::MOVFUEr: return V9::MOVFUEi; - case V9::MOVFGEr: return V9::MOVFGEi; - case V9::MOVFUGEr: return V9::MOVFUGEi; - case V9::MOVFLEr: return V9::MOVFLEi; - case V9::MOVFULEr: return V9::MOVFULEi; - case V9::MOVFOr: return V9::MOVFOi; - - /* load */ - case V9::LDSBr: return V9::LDSBi; - case V9::LDSHr: return V9::LDSHi; - case V9::LDSWr: return V9::LDSWi; - case V9::LDUBr: return V9::LDUBi; - case V9::LDUHr: return V9::LDUHi; - case V9::LDUWr: return V9::LDUWi; - case V9::LDXr: return V9::LDXi; - case V9::LDFr: return V9::LDFi; - case V9::LDDFr: return V9::LDDFi; - case V9::LDQFr: return V9::LDQFi; - case V9::LDFSRr: return V9::LDFSRi; - case V9::LDXFSRr: return V9::LDXFSRi; - - /* store */ - case V9::STBr: return V9::STBi; - case V9::STHr: return V9::STHi; - case V9::STWr: return V9::STWi; - case V9::STXr: return V9::STXi; - case V9::STFr: return V9::STFi; - case V9::STDFr: return V9::STDFi; - case V9::STFSRr: return V9::STFSRi; - case V9::STXFSRr: return V9::STXFSRi; - - /* jump & return */ - case V9::JMPLCALLr: return V9::JMPLCALLi; - case V9::JMPLRETr: return V9::JMPLRETi; - case V9::RETURNr: return V9::RETURNi; - - /* save and restore */ - case V9::SAVEr: return V9::SAVEi; - case V9::RESTOREr: return V9::RESTOREi; - - default: - // It's already in correct format - // Or, it's just not handled yet, but an assert() would break LLC -#if 0 - std::cerr << "Unhandled opcode in convertOpcodeFromRegToImm(): " << Opcode - << "\n"; -#endif - return Opcode; - } -} - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcInternals.h b/llvm/lib/Target/Sparc/SparcInternals.h deleted file mode 100644 index aaf39feb60a..00000000000 --- a/llvm/lib/Target/Sparc/SparcInternals.h +++ /dev/null @@ -1,134 +0,0 @@ -//===-- SparcInternals.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines stuff that is to be private to the Sparc backend, but is -// shared among different portions of the backend. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARC_INTERNALS_H -#define SPARC_INTERNALS_H - -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetSchedInfo.h" -#include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetCacheInfo.h" -#include "llvm/Target/TargetRegInfo.h" -#include "llvm/Type.h" -#include "SparcRegClassInfo.h" -#include "Config/sys/types.h" - -namespace llvm { - -class LiveRange; -class SparcTargetMachine; -class Pass; - -enum SparcInstrSchedClass { - SPARC_NONE, /* Instructions with no scheduling restrictions */ - SPARC_IEUN, /* Integer class that can use IEU0 or IEU1 */ - SPARC_IEU0, /* Integer class IEU0 */ - SPARC_IEU1, /* Integer class IEU1 */ - SPARC_FPM, /* FP Multiply or Divide instructions */ - SPARC_FPA, /* All other FP instructions */ - SPARC_CTI, /* Control-transfer instructions */ - SPARC_LD, /* Load instructions */ - SPARC_ST, /* Store instructions */ - SPARC_SINGLE, /* Instructions that must issue by themselves */ - - SPARC_INV, /* This should stay at the end for the next value */ - SPARC_NUM_SCHED_CLASSES = SPARC_INV -}; - - -//--------------------------------------------------------------------------- -// enum SparcMachineOpCode. -// const TargetInstrDescriptor SparcMachineInstrDesc[] -// -// Purpose: -// Description of UltraSparc machine instructions. -// -//--------------------------------------------------------------------------- - -namespace V9 { - enum SparcMachineOpCode { -#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \ - NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS) \ - ENUM, -#include "SparcInstr.def" - - // End-of-array marker - INVALID_OPCODE, - NUM_REAL_OPCODES = PHI, // number of valid opcodes - NUM_TOTAL_OPCODES = INVALID_OPCODE - }; -} - -// Array of machine instruction descriptions... -extern const TargetInstrDescriptor SparcMachineInstrDesc[]; - -//--------------------------------------------------------------------------- -// class SparcSchedInfo -// -// Purpose: -// Interface to instruction scheduling information for UltraSPARC. -// The parameter values above are based on UltraSPARC IIi. -//--------------------------------------------------------------------------- - -class SparcSchedInfo: public TargetSchedInfo { -public: - SparcSchedInfo(const TargetMachine &tgt); -protected: - virtual void initializeResources(); -}; - -//--------------------------------------------------------------------------- -// class SparcCacheInfo -// -// Purpose: -// Interface to cache parameters for the UltraSPARC. -// Just use defaults for now. -//--------------------------------------------------------------------------- - -struct SparcCacheInfo: public TargetCacheInfo { - SparcCacheInfo(const TargetMachine &T) : TargetCacheInfo(T) {} -}; - - -/// createStackSlotsPass - External interface to stack-slots pass that enters 2 -/// empty slots at the top of each function stack -/// -Pass *createStackSlotsPass(const TargetMachine &TM); - -/// Specializes LLVM code for a target machine. -/// -FunctionPass *createPreSelectionPass(const TargetMachine &TM); - -/// Peephole optimization pass operating on machine code -/// -FunctionPass *createPeepholeOptsPass(const TargetMachine &TM); - -/// Writes out assembly code for the module, one function at a time -/// -FunctionPass *createAsmPrinterPass(std::ostream &Out, const TargetMachine &TM); - -/// getPrologEpilogInsertionPass - Inserts prolog/epilog code. -/// -FunctionPass* createPrologEpilogInsertionPass(); - -/// getBytecodeAsmPrinterPass - Emits final LLVM bytecode to assembly file. -/// -Pass* createBytecodeAsmPrinterPass(std::ostream &Out); - -FunctionPass *createSparcMachineCodeDestructionPass(); - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcRegClassInfo.cpp b/llvm/lib/Target/Sparc/SparcRegClassInfo.cpp deleted file mode 100644 index b1387bfa9c0..00000000000 --- a/llvm/lib/Target/Sparc/SparcRegClassInfo.cpp +++ /dev/null @@ -1,397 +0,0 @@ -//===-- SparcRegClassInfo.cpp - Register class def'ns for Sparc -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the register classes used by the Sparc target description. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Type.h" -#include "SparcRegClassInfo.h" -#include "SparcInternals.h" -#include "SparcRegInfo.h" -#include "RegAlloc/RegAllocCommon.h" -#include "RegAlloc/IGNode.h" - -namespace llvm { - -//----------------------------------------------------------------------------- -// Int Register Class - method for coloring a node in the interference graph. -// -// Algorithm: -// Record the colors/suggested colors of all neighbors. -// -// If there is a suggested color, try to allocate it -// If there is no call interf, try to allocate volatile, then non volatile -// If there is call interf, try to allocate non-volatile. If that fails -// try to allocate a volatile and insert save across calls -// If both above fail, spill. -// -//----------------------------------------------------------------------------- -void SparcIntRegClass::colorIGNode(IGNode * Node, - const std::vector<bool> &IsColorUsedArr) const -{ - LiveRange *LR = Node->getParentLR(); - - if (DEBUG_RA) { - std::cerr << "\nColoring LR [CallInt=" << LR->isCallInterference() <<"]:"; - printSet(*LR); - } - - if (LR->hasSuggestedColor()) { - unsigned SugCol = LR->getSuggestedColor(); - if (!IsColorUsedArr[SugCol]) { - if (LR->isSuggestedColorUsable()) { - // if the suggested color is volatile, we should use it only if - // there are no call interferences. Otherwise, it will get spilled. - if (DEBUG_RA) - std::cerr << "\n -Coloring with sug color: " << SugCol; - - LR->setColor(LR->getSuggestedColor()); - return; - } else if(DEBUG_RA) { - std::cerr << "\n Couldn't alloc Sug col - LR volatile & calls interf"; - } - } else if (DEBUG_RA) { // can't allocate the suggested col - std::cerr << "\n Could NOT allocate the suggested color (already used) "; - printSet(*LR); std::cerr << "\n"; - } - } - - unsigned SearchStart; // start pos of color in pref-order - bool ColorFound= false; // have we found a color yet? - - //if this Node is between calls - if (! LR->isCallInterference()) { - // start with volatiles (we can allocate volatiles safely) - SearchStart = SparcIntRegClass::StartOfAllRegs; - } else { - // start with non volatiles (no non-volatiles) - SearchStart = SparcIntRegClass::StartOfNonVolatileRegs; - } - - unsigned c=0; // color - - // find first unused color - for (c=SearchStart; c < SparcIntRegClass::NumOfAvailRegs; c++) { - if (!IsColorUsedArr[c]) { - ColorFound = true; - break; - } - } - - if (ColorFound) { - LR->setColor(c); // first color found in preferred order - if (DEBUG_RA) std::cerr << "\n Colored after first search with col " << c; - } - - // if color is not found because of call interference - // try even finding a volatile color and insert save across calls - // - else if (LR->isCallInterference()) { - // start from 0 - try to find even a volatile this time - SearchStart = SparcIntRegClass::StartOfAllRegs; - - // find first unused volatile color - for(c=SearchStart; c < SparcIntRegClass::StartOfNonVolatileRegs; c++) { - if (! IsColorUsedArr[c]) { - ColorFound = true; - break; - } - } - - if (ColorFound) { - LR->setColor(c); - // get the live range corresponding to live var - // since LR span across calls, must save across calls - // - LR->markForSaveAcrossCalls(); - if (DEBUG_RA) - std::cerr << "\n Colored after SECOND search with col " << c; - } - } - - - // If we couldn't find a color regardless of call interference - i.e., we - // don't have either a volatile or non-volatile color left - // - if (!ColorFound) - LR->markForSpill(); // no color found - must spill -} - -//----------------------------------------------------------------------------- -// Int CC Register Class - method for coloring a node in the interference graph. -// -// Algorithm: -// -// If (node has any interferences) -// /* all interference operations can use only one register! */ -// mark the LR for spilling -// else { -// if (the LR is a 64-bit comparison) use %xcc -// else /*32-bit or smaller*/ use %icc -// } -// -// Note: The third name (%ccr) is essentially an assembly mnemonic and -// depends solely on the opcode, so the name can be chosen in EmitAssembly. -//----------------------------------------------------------------------------- -void SparcIntCCRegClass::colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const -{ - if (Node->getNumOfNeighbors() > 0) - Node->getParentLR()->markForSpill(); - - // Mark the appropriate register in any case (even if it needs to be spilled) - // because there is only one possible register, but more importantly, the - // spill algorithm cannot find it. In particular, we have to choose - // whether to use %xcc or %icc based on type of value compared - // - const LiveRange* ccLR = Node->getParentLR(); - const Type* setCCType = (* ccLR->begin())->getType(); // any Value in LR - assert(setCCType->isIntegral() || isa<PointerType>(setCCType)); - int ccReg = ((isa<PointerType>(setCCType) || setCCType == Type::LongTy) - ? xcc : icc); - -#ifndef NDEBUG - // Let's just make sure values of two different types have not been - // coalesced into this LR. - for (ValueSet::const_iterator I=ccLR->begin(), E=ccLR->end(); I!=E; ++I) { - const Type* ccType = (*I)->getType(); - assert((ccReg == xcc && (isa<PointerType>(ccType) - || ccType == Type::LongTy)) || - (ccReg == icc && ccType->isIntegral() && ccType != Type::LongTy) - && "Comparisons needing different intCC regs coalesced in LR!"); - } -#endif - - Node->setColor(ccReg); // only one int cc reg is available -} - - -void SparcFloatCCRegClass::colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const { - for(unsigned c = 0; c != 4; ++c) - if (!IsColorUsedArr[c]) { // find unused color - Node->setColor(c); - return; - } - - Node->getParentLR()->markForSpill(); -} - - - -//----------------------------------------------------------------------------- -// Float Register Class - method for coloring a node in the interference graph. -// -// Algorithm: -// -// If the LR is a double try to allocate f32 - f63 -// If the above fails or LR is single precision -// If the LR does not interfere with a call -// start allocating from f0 -// Else start allocating from f6 -// If a color is still not found because LR interferes with a call -// Search in f0 - f6. If found mark for spill across calls. -// If a color is still not fond, mark for spilling -// -//---------------------------------------------------------------------------- -void SparcFloatRegClass::colorIGNode(IGNode * Node, - const std::vector<bool> &IsColorUsedArr) const -{ - LiveRange *LR = Node->getParentLR(); - -#ifndef NDEBUG - // Check that the correct colors have been are marked for fp-doubles. - // - // FIXME: This is old code that is no longer needed. Temporarily converting - // it into a big assertion just to check that the replacement logic - // (invoking SparcFloatRegClass::markColorsUsed() directly from - // RegClass::colorIGNode) works correctly. - // - // In fact, this entire function should be identical to - // SparcIntRegClass::colorIGNode(), and perhaps can be - // made into a general case in CodeGen/RegAlloc/RegClass.cpp. - // - unsigned NumNeighbors = Node->getNumOfNeighbors(); // total # of neighbors - for(unsigned n=0; n < NumNeighbors; n++) { // for each neigh - IGNode *NeighIGNode = Node->getAdjIGNode(n); - LiveRange *NeighLR = NeighIGNode->getParentLR(); - - if (NeighLR->hasColor()) { - assert(IsColorUsedArr[ NeighLR->getColor() ]); - if (NeighLR->getType() == Type::DoubleTy) - assert(IsColorUsedArr[ NeighLR->getColor()+1 ]); - - } else if (NeighLR->hasSuggestedColor() && - NeighLR-> isSuggestedColorUsable() ) { - - // if the neighbour can use the suggested color - assert(IsColorUsedArr[ NeighLR->getSuggestedColor() ]); - if (NeighLR->getType() == Type::DoubleTy) - assert(IsColorUsedArr[ NeighLR->getSuggestedColor()+1 ]); - } - } -#endif - - // **NOTE: We don't check for call interferences in allocating suggested - // color in this class since ALL registers are volatile. If this fact - // changes, we should change the following part - //- see SparcIntRegClass::colorIGNode() - // - if( LR->hasSuggestedColor() ) { - if( ! IsColorUsedArr[ LR->getSuggestedColor() ] ) { - LR->setColor( LR->getSuggestedColor() ); - return; - } else if (DEBUG_RA) { // can't allocate the suggested col - std::cerr << " Could NOT allocate the suggested color for LR "; - printSet(*LR); std::cerr << "\n"; - } - } - - - int ColorFound = -1; // have we found a color yet? - bool isCallInterf = LR->isCallInterference(); - - // if value is a double - search the double only region (f32 - f63) - // i.e. we try to allocate f32 - f63 first for doubles since singles - // cannot go there. By doing that, we provide more space for singles - // in f0 - f31 - // - if (LR->getType() == Type::DoubleTy) - ColorFound = findFloatColor( LR, 32, 64, IsColorUsedArr ); - - if (ColorFound >= 0) { // if we could find a color - LR->setColor(ColorFound); - return; - } else { - - // if we didn't find a color because the LR was single precision or - // all f32-f63 range is filled, we try to allocate a register from - // the f0 - f31 region - - unsigned SearchStart; // start pos of color in pref-order - - //if this Node is between calls (i.e., no call interferences ) - if (! isCallInterf) { - // start with volatiles (we can allocate volatiles safely) - SearchStart = SparcFloatRegClass::StartOfAllRegs; - } else { - // start with non volatiles (no non-volatiles) - SearchStart = SparcFloatRegClass::StartOfNonVolatileRegs; - } - - ColorFound = findFloatColor(LR, SearchStart, 32, IsColorUsedArr); - } - - if (ColorFound >= 0) { // if we could find a color - LR->setColor(ColorFound); - return; - } else if (isCallInterf) { - // We are here because there is a call interference and no non-volatile - // color could be found. - // Now try to allocate even a volatile color - ColorFound = findFloatColor(LR, SparcFloatRegClass::StartOfAllRegs, - SparcFloatRegClass::StartOfNonVolatileRegs, - IsColorUsedArr); - } - - if (ColorFound >= 0) { - LR->setColor(ColorFound); // first color found in preferred order - LR->markForSaveAcrossCalls(); - } else { - // we are here because no color could be found - LR->markForSpill(); // no color found - must spill - } -} - -//----------------------------------------------------------------------------- -// This method marks the registers used for a given register number. -// This marks a single register for Float regs, but the R,R+1 pair -// for double-precision registers. -//----------------------------------------------------------------------------- - -void SparcFloatRegClass::markColorsUsed(unsigned RegInClass, - int UserRegType, - int RegTypeWanted, - std::vector<bool> &IsColorUsedArr) const -{ - if (UserRegType == SparcRegInfo::FPDoubleRegType || - RegTypeWanted == SparcRegInfo::FPDoubleRegType) { - // This register is used as or is needed as a double-precision reg. - // We need to mark the [even,odd] pair corresponding to this reg. - // Get the even numbered register corresponding to this reg. - unsigned EvenRegInClass = RegInClass & ~1u; - assert(EvenRegInClass+1 < NumOfAllRegs && - EvenRegInClass+1 < IsColorUsedArr.size()); - IsColorUsedArr[EvenRegInClass] = true; - IsColorUsedArr[EvenRegInClass+1] = true; - } - else { - assert(RegInClass < NumOfAllRegs && RegInClass < IsColorUsedArr.size()); - assert(UserRegType == RegTypeWanted - && "Something other than FP single/double types share a reg class?"); - IsColorUsedArr[RegInClass] = true; - } -} - -// This method finds unused registers of the specified register type, -// using the given "used" flag array IsColorUsedArr. It checks a single -// entry in the array directly for float regs, and checks the pair [R,R+1] -// for double-precision registers -// It returns -1 if no unused color is found. -// -int SparcFloatRegClass::findUnusedColor(int RegTypeWanted, - const std::vector<bool> &IsColorUsedArr) const -{ - if (RegTypeWanted == SparcRegInfo::FPDoubleRegType) { - unsigned NC = 2 * this->getNumOfAvailRegs(); - assert(IsColorUsedArr.size() == NC && "Invalid colors-used array"); - for (unsigned c = 0; c < NC; c+=2) - if (!IsColorUsedArr[c]) { - assert(!IsColorUsedArr[c+1] && "Incorrect used regs for FP double!"); - return c; - } - return -1; - } - else - return TargetRegClassInfo::findUnusedColor(RegTypeWanted, IsColorUsedArr); -} - -//----------------------------------------------------------------------------- -// Helper method for coloring a node of Float Reg class. -// Finds the first available color in the range [Start,End] depending on the -// type of the Node (i.e., float/double) -//----------------------------------------------------------------------------- - -int SparcFloatRegClass::findFloatColor(const LiveRange *LR, - unsigned Start, - unsigned End, - const std::vector<bool> &IsColorUsedArr) const -{ - if (LR->getType() == Type::DoubleTy) { - // find first unused color for a double - assert(Start % 2 == 0 && "Odd register number could be used for double!"); - for (unsigned c=Start; c < End ; c+= 2) - if (!IsColorUsedArr[c]) { - assert(!IsColorUsedArr[c+1] && - "Incorrect marking of used regs for Sparc FP double!"); - return c; - } - } else { - // find first unused color for a single - for (unsigned c = Start; c < End; c++) - if (!IsColorUsedArr[c]) - return c; - } - - return -1; - -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/SparcRegClassInfo.h b/llvm/lib/Target/Sparc/SparcRegClassInfo.h deleted file mode 100644 index cc492e77c72..00000000000 --- a/llvm/lib/Target/Sparc/SparcRegClassInfo.h +++ /dev/null @@ -1,224 +0,0 @@ -//===-- SparcRegClassInfo.h - Register class def'ns for Sparc ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the register classes used by the Sparc target description. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARC_REG_CLASS_INFO_H -#define SPARC_REG_CLASS_INFO_H - -#include "llvm/Target/TargetRegInfo.h" - -namespace llvm { - -//----------------------------------------------------------------------------- -// Integer Register Class -//----------------------------------------------------------------------------- - -struct SparcIntRegClass : public TargetRegClassInfo { - SparcIntRegClass(unsigned ID) - : TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) { } - - void colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const; - - inline bool isRegVolatile(int Reg) const { - return (Reg < (int)StartOfNonVolatileRegs); - } - - inline bool modifiedByCall(int Reg) const { - return Reg==(int)ModifiedByCall; - } - - enum { // colors possible for a LR (in preferred order) - // --- following colors are volatile across function calls - // %g0 can't be used for coloring - always 0 - o0, o1, o2, o3, o4, o5, o7, // %o0-%o5, - - // %o6 is sp, - // all %0's can get modified by a call - - // --- following colors are NON-volatile across function calls - l0, l1, l2, l3, l4, l5, l6, l7, // %l0-%l7 - i0, i1, i2, i3, i4, i5, // %i0-%i5: i's need not be preserved - - // %i6 is the fp - so not allocated - // %i7 is the ret address by convention - can be used for others - - // max # of colors reg coloring can allocate (NumOfAvailRegs) - - // --- following colors are not available for allocation within this phase - // --- but can appear for pre-colored ranges - - i6, i7, g0, g1, g2, g3, g4, g5, g6, g7, o6, - - NumOfAllRegs, // Must be first AFTER registers... - - //*** NOTE: If we decide to use some %g regs, they are volatile - // (see sparc64ABI) - // Move the %g regs from the end of the enumeration to just above the - // enumeration of %o0 (change StartOfAllRegs below) - // change isRegVloatile method below - // Also change IntRegNames above. - - // max # of colors reg coloring can allocate - NumOfAvailRegs = i6, - - StartOfNonVolatileRegs = l0, - StartOfAllRegs = o0, - - ModifiedByCall = o7, - }; - - const char * const getRegName(unsigned reg) const; -}; - - - - -//----------------------------------------------------------------------------- -// Float Register Class -//----------------------------------------------------------------------------- - -class SparcFloatRegClass : public TargetRegClassInfo { - int findFloatColor(const LiveRange *LR, unsigned Start, - unsigned End, - const std::vector<bool> &IsColorUsedArr) const; -public: - SparcFloatRegClass(unsigned ID) - : TargetRegClassInfo(ID, NumOfAvailRegs, NumOfAllRegs) {} - - // This method marks the registers used for a given register number. - // This marks a single register for Float regs, but the R,R+1 pair - // for double-precision registers. - // - virtual void markColorsUsed(unsigned RegInClass, - int UserRegType, - int RegTypeWanted, - std::vector<bool> &IsColorUsedArr) const; - - // This method finds unused registers of the specified register type, - // using the given "used" flag array IsColorUsedArr. It checks a single - // entry in the array directly for float regs, and checks the pair [R,R+1] - // for double-precision registers - // It returns -1 if no unused color is found. - // - virtual int findUnusedColor(int RegTypeWanted, - const std::vector<bool> &IsColorUsedArr) const; - - void colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const; - - // according to Sparc 64 ABI, all %fp regs are volatile - inline bool isRegVolatile(int Reg) const { return true; } - - enum { - f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, - f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, - f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, - f30, f31, f32, f33, f34, f35, f36, f37, f38, f39, - f40, f41, f42, f43, f44, f45, f46, f47, f48, f49, - f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, - f60, f61, f62, f63, - - // there are 64 regs alltogether but only 32 regs can be allocated at - // a time. - // - NumOfAvailRegs = 32, - NumOfAllRegs = 64, - - StartOfNonVolatileRegs = f32, - StartOfAllRegs = f0, - }; - - const char * const getRegName(unsigned reg) const; -}; - - - - -//----------------------------------------------------------------------------- -// Int CC Register Class -// Only one integer cc register is available. However, this register is -// referred to as %xcc or %icc when instructions like subcc are executed but -// referred to as %ccr (i.e., %xcc . %icc") when this register is moved -// into an integer register using RD or WR instrcutions. So, three ids are -// allocated for the three names. -//----------------------------------------------------------------------------- - -struct SparcIntCCRegClass : public TargetRegClassInfo { - SparcIntCCRegClass(unsigned ID) - : TargetRegClassInfo(ID, 1, 3) { } - - void colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const; - - // according to Sparc 64 ABI, %ccr is volatile - // - inline bool isRegVolatile(int Reg) const { return true; } - - enum { - xcc, icc, ccr // only one is available - see the note above - }; - - const char * const getRegName(unsigned reg) const; -}; - - -//----------------------------------------------------------------------------- -// Float CC Register Class -// Only 4 Float CC registers are available for allocation. -//----------------------------------------------------------------------------- - -struct SparcFloatCCRegClass : public TargetRegClassInfo { - SparcFloatCCRegClass(unsigned ID) - : TargetRegClassInfo(ID, 4, 5) { } - - void colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const; - - // according to Sparc 64 ABI, all %fp CC regs are volatile - // - inline bool isRegVolatile(int Reg) const { return true; } - - enum { - fcc0, fcc1, fcc2, fcc3, fsr // fsr is not used in allocation - }; // but has a name in getRegName() - - const char * const getRegName(unsigned reg) const; -}; - -//----------------------------------------------------------------------------- -// Sparc special register class. These registers are not used for allocation -// but are used as arguments of some instructions. -//----------------------------------------------------------------------------- - -struct SparcSpecialRegClass : public TargetRegClassInfo { - SparcSpecialRegClass(unsigned ID) - : TargetRegClassInfo(ID, 0, 1) { } - - void colorIGNode(IGNode *Node, - const std::vector<bool> &IsColorUsedArr) const { - assert(0 && "SparcSpecialRegClass should never be used for allocation"); - } - - // all currently included special regs are volatile - inline bool isRegVolatile(int Reg) const { return true; } - - enum { - fsr // floating point state register - }; - - const char * const getRegName(unsigned reg) const; -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcRegInfo.cpp b/llvm/lib/Target/Sparc/SparcRegInfo.cpp deleted file mode 100644 index 33690f8aa49..00000000000 --- a/llvm/lib/Target/Sparc/SparcRegInfo.cpp +++ /dev/null @@ -1,978 +0,0 @@ -//===-- SparcRegInfo.cpp - Sparc Target Register Information --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains implementation of Sparc specific helper methods -// used for register allocation. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/InstrSelection.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineCodeForInstruction.h" -#include "llvm/CodeGen/MachineInstrAnnot.h" -#include "RegAlloc/LiveRangeInfo.h" -#include "RegAlloc/LiveRange.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/iTerminators.h" -#include "llvm/iOther.h" -#include "SparcInternals.h" -#include "SparcRegClassInfo.h" -#include "SparcRegInfo.h" -#include "SparcTargetMachine.h" - -namespace llvm { - -enum { - BadRegClass = ~0 -}; - -SparcRegInfo::SparcRegInfo(const SparcTargetMachine &tgt) - : TargetRegInfo(tgt), NumOfIntArgRegs(6), NumOfFloatArgRegs(32) -{ - MachineRegClassArr.push_back(new SparcIntRegClass(IntRegClassID)); - MachineRegClassArr.push_back(new SparcFloatRegClass(FloatRegClassID)); - MachineRegClassArr.push_back(new SparcIntCCRegClass(IntCCRegClassID)); - MachineRegClassArr.push_back(new SparcFloatCCRegClass(FloatCCRegClassID)); - MachineRegClassArr.push_back(new SparcSpecialRegClass(SpecialRegClassID)); - - assert(SparcFloatRegClass::StartOfNonVolatileRegs == 32 && - "32 Float regs are used for float arg passing"); -} - - -// getZeroRegNum - returns the register that contains always zero. -// this is the unified register number -// -unsigned SparcRegInfo::getZeroRegNum() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g0); -} - -// getCallAddressReg - returns the reg used for pushing the address when a -// method is called. This can be used for other purposes between calls -// -unsigned SparcRegInfo::getCallAddressReg() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::o7); -} - -// Returns the register containing the return address. -// It should be made sure that this register contains the return -// value when a return instruction is reached. -// -unsigned SparcRegInfo::getReturnAddressReg() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::i7); -} - -// Register get name implementations... - -// Int register names in same order as enum in class SparcIntRegClass -static const char * const IntRegNames[] = { - "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - "i0", "i1", "i2", "i3", "i4", "i5", - "i6", "i7", - "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - "o6" -}; - -const char * const SparcIntRegClass::getRegName(unsigned reg) const { - assert(reg < NumOfAllRegs); - return IntRegNames[reg]; -} - -static const char * const FloatRegNames[] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", - "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", - "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", - "f30", "f31", "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39", - "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47", "f48", "f49", - "f50", "f51", "f52", "f53", "f54", "f55", "f56", "f57", "f58", "f59", - "f60", "f61", "f62", "f63" -}; - -const char * const SparcFloatRegClass::getRegName(unsigned reg) const { - assert (reg < NumOfAllRegs); - return FloatRegNames[reg]; -} - - -static const char * const IntCCRegNames[] = { - "xcc", "icc", "ccr" -}; - -const char * const SparcIntCCRegClass::getRegName(unsigned reg) const { - assert(reg < 3); - return IntCCRegNames[reg]; -} - -static const char * const FloatCCRegNames[] = { - "fcc0", "fcc1", "fcc2", "fcc3" -}; - -const char * const SparcFloatCCRegClass::getRegName(unsigned reg) const { - assert (reg < 5); - return FloatCCRegNames[reg]; -} - -static const char * const SpecialRegNames[] = { - "fsr" -}; - -const char * const SparcSpecialRegClass::getRegName(unsigned reg) const { - assert (reg < 1); - return SpecialRegNames[reg]; -} - -// Get unified reg number for frame pointer -unsigned SparcRegInfo::getFramePointer() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::i6); -} - -// Get unified reg number for stack pointer -unsigned SparcRegInfo::getStackPointer() const { - return getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::o6); -} - - -//--------------------------------------------------------------------------- -// Finds whether a call is an indirect call -//--------------------------------------------------------------------------- - -inline bool -isVarArgsFunction(const Type *funcType) { - return cast<FunctionType>(cast<PointerType>(funcType) - ->getElementType())->isVarArg(); -} - -inline bool -isVarArgsCall(const MachineInstr *CallMI) { - Value* callee = CallMI->getOperand(0).getVRegValue(); - // const Type* funcType = isa<Function>(callee)? callee->getType() - // : cast<PointerType>(callee->getType())->getElementType(); - const Type* funcType = callee->getType(); - return isVarArgsFunction(funcType); -} - - -// Get the register number for the specified argument #argNo, -// -// Return value: -// getInvalidRegNum(), if there is no int register available for the arg. -// regNum, otherwise (this is NOT the unified reg. num). -// regClassId is set to the register class ID. -// -int -SparcRegInfo::regNumForIntArg(bool inCallee, bool isVarArgsCall, - unsigned argNo, unsigned& regClassId) const -{ - regClassId = IntRegClassID; - if (argNo >= NumOfIntArgRegs) - return getInvalidRegNum(); - else - return argNo + (inCallee? SparcIntRegClass::i0 : SparcIntRegClass::o0); -} - -// Get the register number for the specified FP argument #argNo, -// Use INT regs for FP args if this is a varargs call. -// -// Return value: -// getInvalidRegNum(), if there is no int register available for the arg. -// regNum, otherwise (this is NOT the unified reg. num). -// regClassId is set to the register class ID. -// -int -SparcRegInfo::regNumForFPArg(unsigned regType, - bool inCallee, bool isVarArgsCall, - unsigned argNo, unsigned& regClassId) const -{ - if (isVarArgsCall) - return regNumForIntArg(inCallee, isVarArgsCall, argNo, regClassId); - else - { - regClassId = FloatRegClassID; - if (regType == FPSingleRegType) - return (argNo*2+1 >= NumOfFloatArgRegs)? - getInvalidRegNum() : SparcFloatRegClass::f0 + (argNo * 2 + 1); - else if (regType == FPDoubleRegType) - return (argNo*2 >= NumOfFloatArgRegs)? - getInvalidRegNum() : SparcFloatRegClass::f0 + (argNo * 2); - else - assert(0 && "Illegal FP register type"); - return 0; - } -} - - -//--------------------------------------------------------------------------- -// Finds the return address of a call sparc specific call instruction -//--------------------------------------------------------------------------- - -// The following 4 methods are used to find the RegType (SparcInternals.h) -// of a LiveRange, a Value, and for a given register unified reg number. -// -int SparcRegInfo::getRegTypeForClassAndType(unsigned regClassID, - const Type* type) const -{ - switch (regClassID) { - case IntRegClassID: return IntRegType; - case FloatRegClassID: - if (type == Type::FloatTy) return FPSingleRegType; - else if (type == Type::DoubleTy) return FPDoubleRegType; - assert(0 && "Unknown type in FloatRegClass"); return 0; - case IntCCRegClassID: return IntCCRegType; - case FloatCCRegClassID: return FloatCCRegType; - case SpecialRegClassID: return SpecialRegType; - default: assert( 0 && "Unknown reg class ID"); return 0; - } -} - -int SparcRegInfo::getRegTypeForDataType(const Type* type) const -{ - return getRegTypeForClassAndType(getRegClassIDOfType(type), type); -} - -int SparcRegInfo::getRegTypeForLR(const LiveRange *LR) const -{ - return getRegTypeForClassAndType(LR->getRegClassID(), LR->getType()); -} - -int SparcRegInfo::getRegType(int unifiedRegNum) const -{ - if (unifiedRegNum < 32) - return IntRegType; - else if (unifiedRegNum < (32 + 32)) - return FPSingleRegType; - else if (unifiedRegNum < (64 + 32)) - return FPDoubleRegType; - else if (unifiedRegNum < (64+32+4)) - return FloatCCRegType; - else if (unifiedRegNum < (64+32+4+2)) - return IntCCRegType; - else - assert(0 && "Invalid unified register number in getRegType"); - return 0; -} - - -// To find the register class used for a specified Type -// -unsigned SparcRegInfo::getRegClassIDOfType(const Type *type, - bool isCCReg) const { - Type::PrimitiveID ty = type->getPrimitiveID(); - unsigned res; - - // FIXME: Comparing types like this isn't very safe... - if ((ty && ty <= Type::LongTyID) || (ty == Type::LabelTyID) || - (ty == Type::FunctionTyID) || (ty == Type::PointerTyID) ) - res = IntRegClassID; // sparc int reg (ty=0: void) - else if (ty <= Type::DoubleTyID) - res = FloatRegClassID; // sparc float reg class - else { - //std::cerr << "TypeID: " << ty << "\n"; - assert(0 && "Cannot resolve register class for type"); - return 0; - } - - if (isCCReg) - return res + 2; // corresponding condition code register - else - return res; -} - -unsigned SparcRegInfo::getRegClassIDOfRegType(int regType) const { - switch(regType) { - case IntRegType: return IntRegClassID; - case FPSingleRegType: - case FPDoubleRegType: return FloatRegClassID; - case IntCCRegType: return IntCCRegClassID; - case FloatCCRegType: return FloatCCRegClassID; - default: - assert(0 && "Invalid register type in getRegClassIDOfRegType"); - return 0; - } -} - -//--------------------------------------------------------------------------- -// Suggests a register for the ret address in the RET machine instruction. -// We always suggest %i7 by convention. -//--------------------------------------------------------------------------- -void SparcRegInfo::suggestReg4RetAddr(MachineInstr *RetMI, - LiveRangeInfo& LRI) const { - - assert(target.getInstrInfo().isReturn(RetMI->getOpcode())); - - // return address is always mapped to i7 so set it immediately - RetMI->SetRegForOperand(0, getUnifiedRegNum(IntRegClassID, - SparcIntRegClass::i7)); - - // Possible Optimization: - // Instead of setting the color, we can suggest one. In that case, - // we have to test later whether it received the suggested color. - // In that case, a LR has to be created at the start of method. - // It has to be done as follows (remove the setRegVal above): - - // MachineOperand & MO = RetMI->getOperand(0); - // const Value *RetAddrVal = MO.getVRegValue(); - // assert( RetAddrVal && "LR for ret address must be created at start"); - // LiveRange * RetAddrLR = LRI.getLiveRangeForValue( RetAddrVal); - // RetAddrLR->setSuggestedColor(getUnifiedRegNum( IntRegClassID, - // SparcIntRegOrdr::i7) ); -} - - -//--------------------------------------------------------------------------- -// Suggests a register for the ret address in the JMPL/CALL machine instr. -// Sparc ABI dictates that %o7 be used for this purpose. -//--------------------------------------------------------------------------- -void -SparcRegInfo::suggestReg4CallAddr(MachineInstr * CallMI, - LiveRangeInfo& LRI) const -{ - CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI); - const Value *RetAddrVal = argDesc->getReturnAddrReg(); - assert(RetAddrVal && "INTERNAL ERROR: Return address value is required"); - - // A LR must already exist for the return address. - LiveRange *RetAddrLR = LRI.getLiveRangeForValue(RetAddrVal); - assert(RetAddrLR && "INTERNAL ERROR: No LR for return address of call!"); - - unsigned RegClassID = RetAddrLR->getRegClassID(); - RetAddrLR->setColor(getUnifiedRegNum(IntRegClassID, SparcIntRegClass::o7)); -} - - - -//--------------------------------------------------------------------------- -// This method will suggest colors to incoming args to a method. -// According to the Sparc ABI, the first 6 incoming args are in -// %i0 - %i5 (if they are integer) OR in %f0 - %f31 (if they are float). -// If the arg is passed on stack due to the lack of regs, NOTHING will be -// done - it will be colored (or spilled) as a normal live range. -//--------------------------------------------------------------------------- -void SparcRegInfo::suggestRegs4MethodArgs(const Function *Meth, - LiveRangeInfo& LRI) const -{ - // Check if this is a varArgs function. needed for choosing regs. - bool isVarArgs = isVarArgsFunction(Meth->getType()); - - // Count the arguments, *ignoring* whether they are int or FP args. - // Use this common arg numbering to pick the right int or fp register. - unsigned argNo=0; - for(Function::const_aiterator I = Meth->abegin(), E = Meth->aend(); - I != E; ++I, ++argNo) { - LiveRange *LR = LRI.getLiveRangeForValue(I); - assert(LR && "No live range found for method arg"); - - unsigned regType = getRegTypeForLR(LR); - unsigned regClassIDOfArgReg = BadRegClass; // for chosen reg (unused) - - int regNum = (regType == IntRegType) - ? regNumForIntArg(/*inCallee*/ true, isVarArgs, argNo, regClassIDOfArgReg) - : regNumForFPArg(regType, /*inCallee*/ true, isVarArgs, argNo, - regClassIDOfArgReg); - - if (regNum != getInvalidRegNum()) - LR->setSuggestedColor(regNum); - } -} - - -//--------------------------------------------------------------------------- -// This method is called after graph coloring to move incoming args to -// the correct hardware registers if they did not receive the correct -// (suggested) color through graph coloring. -//--------------------------------------------------------------------------- -void SparcRegInfo::colorMethodArgs(const Function *Meth, - LiveRangeInfo &LRI, - std::vector<MachineInstr*>& InstrnsBefore, - std::vector<MachineInstr*>& InstrnsAfter) const { - - // check if this is a varArgs function. needed for choosing regs. - bool isVarArgs = isVarArgsFunction(Meth->getType()); - MachineInstr *AdMI; - - // for each argument - // for each argument. count INT and FP arguments separately. - unsigned argNo=0, intArgNo=0, fpArgNo=0; - for(Function::const_aiterator I = Meth->abegin(), E = Meth->aend(); - I != E; ++I, ++argNo) { - // get the LR of arg - LiveRange *LR = LRI.getLiveRangeForValue(I); - assert( LR && "No live range found for method arg"); - - unsigned regType = getRegTypeForLR(LR); - unsigned RegClassID = LR->getRegClassID(); - - // Find whether this argument is coming in a register (if not, on stack) - // Also find the correct register the argument must use (UniArgReg) - // - bool isArgInReg = false; - unsigned UniArgReg = getInvalidRegNum(); // reg that LR MUST be colored with - unsigned regClassIDOfArgReg = BadRegClass; // reg class of chosen reg - - int regNum = (regType == IntRegType) - ? regNumForIntArg(/*inCallee*/ true, isVarArgs, - argNo, regClassIDOfArgReg) - : regNumForFPArg(regType, /*inCallee*/ true, isVarArgs, - argNo, regClassIDOfArgReg); - - if(regNum != getInvalidRegNum()) { - isArgInReg = true; - UniArgReg = getUnifiedRegNum( regClassIDOfArgReg, regNum); - } - - if( ! LR->isMarkedForSpill() ) { // if this arg received a register - - unsigned UniLRReg = getUnifiedRegNum( RegClassID, LR->getColor() ); - - // if LR received the correct color, nothing to do - // - if( UniLRReg == UniArgReg ) - continue; - - // We are here because the LR did not receive the suggested - // but LR received another register. - // Now we have to copy the %i reg (or stack pos of arg) - // to the register the LR was colored with. - - // if the arg is coming in UniArgReg register, it MUST go into - // the UniLRReg register - // - if( isArgInReg ) { - if( regClassIDOfArgReg != RegClassID ) { - assert(0 && "This could should work but it is not tested yet"); - - // It is a variable argument call: the float reg must go in a %o reg. - // We have to move an int reg to a float reg via memory. - // - assert(isVarArgs && - RegClassID == FloatRegClassID && - regClassIDOfArgReg == IntRegClassID && - "This should only be an Int register for an FP argument"); - - int TmpOff = MachineFunction::get(Meth).getInfo()->pushTempValue( - getSpilledRegSize(regType)); - cpReg2MemMI(InstrnsBefore, - UniArgReg, getFramePointer(), TmpOff, IntRegType); - - cpMem2RegMI(InstrnsBefore, - getFramePointer(), TmpOff, UniLRReg, regType); - } - else { - cpReg2RegMI(InstrnsBefore, UniArgReg, UniLRReg, regType); - } - } - else { - - // Now the arg is coming on stack. Since the LR received a register, - // we just have to load the arg on stack into that register - // - const TargetFrameInfo& frameInfo = target.getFrameInfo(); - int offsetFromFP = - frameInfo.getIncomingArgOffset(MachineFunction::get(Meth), - argNo); - - // float arguments on stack are right justified so adjust the offset! - // int arguments are also right justified but they are always loaded as - // a full double-word so the offset does not need to be adjusted. - if (regType == FPSingleRegType) { - unsigned argSize = target.getTargetData().getTypeSize(LR->getType()); - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); - assert(argSize <= slotSize && "Insufficient slot size!"); - offsetFromFP += slotSize - argSize; - } - - cpMem2RegMI(InstrnsBefore, - getFramePointer(), offsetFromFP, UniLRReg, regType); - } - - } // if LR received a color - - else { - - // Now, the LR did not receive a color. But it has a stack offset for - // spilling. - // So, if the arg is coming in UniArgReg register, we can just move - // that on to the stack pos of LR - - if( isArgInReg ) { - - if( regClassIDOfArgReg != RegClassID ) { - assert(0 && - "FP arguments to a varargs function should be explicitly " - "copied to/from int registers by instruction selection!"); - - // It must be a float arg for a variable argument call, which - // must come in a %o reg. Move the int reg to the stack. - // - assert(isVarArgs && regClassIDOfArgReg == IntRegClassID && - "This should only be an Int register for an FP argument"); - - cpReg2MemMI(InstrnsBefore, UniArgReg, - getFramePointer(), LR->getSpillOffFromFP(), IntRegType); - } - else { - cpReg2MemMI(InstrnsBefore, UniArgReg, - getFramePointer(), LR->getSpillOffFromFP(), regType); - } - } - - else { - - // Now the arg is coming on stack. Since the LR did NOT - // received a register as well, it is allocated a stack position. We - // can simply change the stack position of the LR. We can do this, - // since this method is called before any other method that makes - // uses of the stack pos of the LR (e.g., updateMachineInstr) - // - const TargetFrameInfo& frameInfo = target.getFrameInfo(); - int offsetFromFP = - frameInfo.getIncomingArgOffset(MachineFunction::get(Meth), - argNo); - - // FP arguments on stack are right justified so adjust offset! - // int arguments are also right justified but they are always loaded as - // a full double-word so the offset does not need to be adjusted. - if (regType == FPSingleRegType) { - unsigned argSize = target.getTargetData().getTypeSize(LR->getType()); - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); - assert(argSize <= slotSize && "Insufficient slot size!"); - offsetFromFP += slotSize - argSize; - } - - LR->modifySpillOffFromFP( offsetFromFP ); - } - - } - - } // for each incoming argument - -} - - - -//--------------------------------------------------------------------------- -// This method is called before graph coloring to suggest colors to the -// outgoing call args and the return value of the call. -//--------------------------------------------------------------------------- -void SparcRegInfo::suggestRegs4CallArgs(MachineInstr *CallMI, - LiveRangeInfo& LRI) const { - assert ( (target.getInstrInfo()).isCall(CallMI->getOpcode()) ); - - CallArgsDescriptor* argDesc = CallArgsDescriptor::get(CallMI); - - suggestReg4CallAddr(CallMI, LRI); - - // First color the return value of the call instruction, if any. - // The return value will be in %o0 if the value is an integer type, - // or in %f0 if the value is a float type. - // - if (const Value *RetVal = argDesc->getReturnValue()) { - LiveRange *RetValLR = LRI.getLiveRangeForValue(RetVal); - assert(RetValLR && "No LR for return Value of call!"); - - unsigned RegClassID = RetValLR->getRegClassID(); - - // now suggest a register depending on the register class of ret arg - if( RegClassID == IntRegClassID ) - RetValLR->setSuggestedColor(SparcIntRegClass::o0); - else if (RegClassID == FloatRegClassID ) - RetValLR->setSuggestedColor(SparcFloatRegClass::f0 ); - else assert( 0 && "Unknown reg class for return value of call\n"); - } - - // Now suggest colors for arguments (operands) of the call instruction. - // Colors are suggested only if the arg number is smaller than the - // the number of registers allocated for argument passing. - // Now, go thru call args - implicit operands of the call MI - - unsigned NumOfCallArgs = argDesc->getNumArgs(); - - for(unsigned argNo=0, i=0, intArgNo=0, fpArgNo=0; - i < NumOfCallArgs; ++i, ++argNo) { - - const Value *CallArg = argDesc->getArgInfo(i).getArgVal(); - - // get the LR of call operand (parameter) - LiveRange *const LR = LRI.getLiveRangeForValue(CallArg); - if (!LR) - continue; // no live ranges for constants and labels - - unsigned regType = getRegTypeForLR(LR); - unsigned regClassIDOfArgReg = BadRegClass; // chosen reg class (unused) - - // Choose a register for this arg depending on whether it is - // an INT or FP value. Here we ignore whether or not it is a - // varargs calls, because FP arguments will be explicitly copied - // to an integer Value and handled under (argCopy != NULL) below. - int regNum = (regType == IntRegType) - ? regNumForIntArg(/*inCallee*/ false, /*isVarArgs*/ false, - argNo, regClassIDOfArgReg) - : regNumForFPArg(regType, /*inCallee*/ false, /*isVarArgs*/ false, - argNo, regClassIDOfArgReg); - - // If a register could be allocated, use it. - // If not, do NOTHING as this will be colored as a normal value. - if(regNum != getInvalidRegNum()) - LR->setSuggestedColor(regNum); - } // for all call arguments -} - - -//--------------------------------------------------------------------------- -// this method is called for an LLVM return instruction to identify which -// values will be returned from this method and to suggest colors. -//--------------------------------------------------------------------------- -void SparcRegInfo::suggestReg4RetValue(MachineInstr *RetMI, - LiveRangeInfo& LRI) const { - - assert( (target.getInstrInfo()).isReturn( RetMI->getOpcode() ) ); - - suggestReg4RetAddr(RetMI, LRI); - - // To find the return value (if any), we can get the LLVM return instr. - // from the return address register, which is the first operand - Value* tmpI = RetMI->getOperand(0).getVRegValue(); - ReturnInst* retI=cast<ReturnInst>(cast<TmpInstruction>(tmpI)->getOperand(0)); - if (const Value *RetVal = retI->getReturnValue()) - if (LiveRange *const LR = LRI.getLiveRangeForValue(RetVal)) - LR->setSuggestedColor(LR->getRegClassID() == IntRegClassID - ? (unsigned) SparcIntRegClass::i0 - : (unsigned) SparcFloatRegClass::f0); -} - -//--------------------------------------------------------------------------- -// Check if a specified register type needs a scratch register to be -// copied to/from memory. If it does, the reg. type that must be used -// for scratch registers is returned in scratchRegType. -// -// Only the int CC register needs such a scratch register. -// The FP CC registers can (and must) be copied directly to/from memory. -//--------------------------------------------------------------------------- - -bool -SparcRegInfo::regTypeNeedsScratchReg(int RegType, - int& scratchRegType) const -{ - if (RegType == IntCCRegType) - { - scratchRegType = IntRegType; - return true; - } - return false; -} - -//--------------------------------------------------------------------------- -// Copy from a register to register. Register number must be the unified -// register number. -//--------------------------------------------------------------------------- - -void -SparcRegInfo::cpReg2RegMI(std::vector<MachineInstr*>& mvec, - unsigned SrcReg, - unsigned DestReg, - int RegType) const { - assert( ((int)SrcReg != getInvalidRegNum()) && - ((int)DestReg != getInvalidRegNum()) && - "Invalid Register"); - - MachineInstr * MI = NULL; - - switch( RegType ) { - - case IntCCRegType: - if (getRegType(DestReg) == IntRegType) { - // copy intCC reg to int reg - MI = (BuildMI(V9::RDCCR, 2) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr)) - .addMReg(DestReg,MachineOperand::Def)); - } else { - // copy int reg to intCC reg - assert(getRegType(SrcReg) == IntRegType - && "Can only copy CC reg to/from integer reg"); - MI = (BuildMI(V9::WRCCRr, 3) - .addMReg(SrcReg) - .addMReg(SparcIntRegClass::g0) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr), - MachineOperand::Def)); - } - break; - - case FloatCCRegType: - assert(0 && "Cannot copy FPCC register to any other register"); - break; - - case IntRegType: - MI = BuildMI(V9::ADDr, 3).addMReg(SrcReg).addMReg(getZeroRegNum()) - .addMReg(DestReg, MachineOperand::Def); - break; - - case FPSingleRegType: - MI = BuildMI(V9::FMOVS, 2).addMReg(SrcReg) - .addMReg(DestReg, MachineOperand::Def); - break; - - case FPDoubleRegType: - MI = BuildMI(V9::FMOVD, 2).addMReg(SrcReg) - .addMReg(DestReg, MachineOperand::Def); - break; - - default: - assert(0 && "Unknown RegType"); - break; - } - - if (MI) - mvec.push_back(MI); -} - -//--------------------------------------------------------------------------- -// Copy from a register to memory (i.e., Store). Register number must -// be the unified register number -//--------------------------------------------------------------------------- - - -void -SparcRegInfo::cpReg2MemMI(std::vector<MachineInstr*>& mvec, - unsigned SrcReg, - unsigned PtrReg, - int Offset, int RegType, - int scratchReg) const { - MachineInstr * MI = NULL; - int OffReg = -1; - - // If the Offset will not fit in the signed-immediate field, find an - // unused register to hold the offset value. This takes advantage of - // the fact that all the opcodes used below have the same size immed. field. - // Use the register allocator, PRA, to find an unused reg. at this MI. - // - if (RegType != IntCCRegType) // does not use offset below - if (! target.getInstrInfo().constantFitsInImmedField(V9::LDXi, Offset)) { -#ifdef CAN_FIND_FREE_REGISTER_TRANSPARENTLY - RegClass* RC = PRA.getRegClassByID(this->getRegClassIDOfRegType(RegType)); - OffReg = PRA.getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef); -#else - // Default to using register g4 for holding large offsets - OffReg = getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g4); -#endif - assert(OffReg >= 0 && "FIXME: cpReg2MemMI cannot find an unused reg."); - mvec.push_back(BuildMI(V9::SETSW, 2).addZImm(Offset).addReg(OffReg)); - } - - switch (RegType) { - case IntRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::STXi, Offset)) - MI = BuildMI(V9::STXi,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset); - else - MI = BuildMI(V9::STXr,3).addMReg(SrcReg).addMReg(PtrReg).addMReg(OffReg); - break; - - case FPSingleRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::STFi, Offset)) - MI = BuildMI(V9::STFi, 3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset); - else - MI = BuildMI(V9::STFr, 3).addMReg(SrcReg).addMReg(PtrReg).addMReg(OffReg); - break; - - case FPDoubleRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::STDFi, Offset)) - MI = BuildMI(V9::STDFi,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(Offset); - else - MI = BuildMI(V9::STDFr,3).addMReg(SrcReg).addMReg(PtrReg).addSImm(OffReg); - break; - - case IntCCRegType: - assert(scratchReg >= 0 && "Need scratch reg to store %ccr to memory"); - assert(getRegType(scratchReg) ==IntRegType && "Invalid scratch reg"); - MI = (BuildMI(V9::RDCCR, 2) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr)) - .addMReg(scratchReg, MachineOperand::Def)); - mvec.push_back(MI); - - cpReg2MemMI(mvec, scratchReg, PtrReg, Offset, IntRegType); - return; - - case FloatCCRegType: { - unsigned fsrReg = getUnifiedRegNum(SparcRegInfo::SpecialRegClassID, - SparcSpecialRegClass::fsr); - if (target.getInstrInfo().constantFitsInImmedField(V9::STXFSRi, Offset)) - MI=BuildMI(V9::STXFSRi,3).addMReg(fsrReg).addMReg(PtrReg).addSImm(Offset); - else - MI=BuildMI(V9::STXFSRr,3).addMReg(fsrReg).addMReg(PtrReg).addMReg(OffReg); - break; - } - default: - assert(0 && "Unknown RegType in cpReg2MemMI"); - } - mvec.push_back(MI); -} - - -//--------------------------------------------------------------------------- -// Copy from memory to a reg (i.e., Load) Register number must be the unified -// register number -//--------------------------------------------------------------------------- - - -void -SparcRegInfo::cpMem2RegMI(std::vector<MachineInstr*>& mvec, - unsigned PtrReg, - int Offset, - unsigned DestReg, - int RegType, - int scratchReg) const { - MachineInstr * MI = NULL; - int OffReg = -1; - - // If the Offset will not fit in the signed-immediate field, find an - // unused register to hold the offset value. This takes advantage of - // the fact that all the opcodes used below have the same size immed. field. - // Use the register allocator, PRA, to find an unused reg. at this MI. - // - if (RegType != IntCCRegType) // does not use offset below - if (! target.getInstrInfo().constantFitsInImmedField(V9::LDXi, Offset)) { -#ifdef CAN_FIND_FREE_REGISTER_TRANSPARENTLY - RegClass* RC = PRA.getRegClassByID(this->getRegClassIDOfRegType(RegType)); - OffReg = PRA.getUnusedUniRegAtMI(RC, RegType, MInst, LVSetBef); -#else - // Default to using register g4 for holding large offsets - OffReg = getUnifiedRegNum(SparcRegInfo::IntRegClassID, - SparcIntRegClass::g4); -#endif - assert(OffReg >= 0 && "FIXME: cpReg2MemMI cannot find an unused reg."); - mvec.push_back(BuildMI(V9::SETSW, 2).addZImm(Offset).addReg(OffReg)); - } - - switch (RegType) { - case IntRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::LDXi, Offset)) - MI = BuildMI(V9::LDXi, 3).addMReg(PtrReg).addSImm(Offset) - .addMReg(DestReg, MachineOperand::Def); - else - MI = BuildMI(V9::LDXr, 3).addMReg(PtrReg).addMReg(OffReg) - .addMReg(DestReg, MachineOperand::Def); - break; - - case FPSingleRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::LDFi, Offset)) - MI = BuildMI(V9::LDFi, 3).addMReg(PtrReg).addSImm(Offset) - .addMReg(DestReg, MachineOperand::Def); - else - MI = BuildMI(V9::LDFr, 3).addMReg(PtrReg).addMReg(OffReg) - .addMReg(DestReg, MachineOperand::Def); - break; - - case FPDoubleRegType: - if (target.getInstrInfo().constantFitsInImmedField(V9::LDDFi, Offset)) - MI= BuildMI(V9::LDDFi, 3).addMReg(PtrReg).addSImm(Offset) - .addMReg(DestReg, MachineOperand::Def); - else - MI= BuildMI(V9::LDDFr, 3).addMReg(PtrReg).addMReg(OffReg) - .addMReg(DestReg, MachineOperand::Def); - break; - - case IntCCRegType: - assert(scratchReg >= 0 && "Need scratch reg to load %ccr from memory"); - assert(getRegType(scratchReg) ==IntRegType && "Invalid scratch reg"); - cpMem2RegMI(mvec, PtrReg, Offset, scratchReg, IntRegType); - MI = (BuildMI(V9::WRCCRr, 3) - .addMReg(scratchReg) - .addMReg(SparcIntRegClass::g0) - .addMReg(getUnifiedRegNum(SparcRegInfo::IntCCRegClassID, - SparcIntCCRegClass::ccr), MachineOperand::Def)); - break; - - case FloatCCRegType: { - unsigned fsrRegNum = getUnifiedRegNum(SparcRegInfo::SpecialRegClassID, - SparcSpecialRegClass::fsr); - if (target.getInstrInfo().constantFitsInImmedField(V9::LDXFSRi, Offset)) - MI = BuildMI(V9::LDXFSRi, 3).addMReg(PtrReg).addSImm(Offset) - .addMReg(fsrRegNum, MachineOperand::UseAndDef); - else - MI = BuildMI(V9::LDXFSRr, 3).addMReg(PtrReg).addMReg(OffReg) - .addMReg(fsrRegNum, MachineOperand::UseAndDef); - break; - } - default: - assert(0 && "Unknown RegType in cpMem2RegMI"); - } - mvec.push_back(MI); -} - - -//--------------------------------------------------------------------------- -// Generate a copy instruction to copy a value to another. Temporarily -// used by PhiElimination code. -//--------------------------------------------------------------------------- - - -void -SparcRegInfo::cpValue2Value(Value *Src, Value *Dest, - std::vector<MachineInstr*>& mvec) const { - int RegType = getRegTypeForDataType(Src->getType()); - MachineInstr * MI = NULL; - - switch( RegType ) { - case IntRegType: - MI = BuildMI(V9::ADDr, 3).addReg(Src).addMReg(getZeroRegNum()) - .addRegDef(Dest); - break; - case FPSingleRegType: - MI = BuildMI(V9::FMOVS, 2).addReg(Src).addRegDef(Dest); - break; - case FPDoubleRegType: - MI = BuildMI(V9::FMOVD, 2).addReg(Src).addRegDef(Dest); - break; - default: - assert(0 && "Unknow RegType in CpValu2Value"); - } - - mvec.push_back(MI); -} - - - -//--------------------------------------------------------------------------- -// Print the register assigned to a LR -//--------------------------------------------------------------------------- - -void SparcRegInfo::printReg(const LiveRange *LR) const { - unsigned RegClassID = LR->getRegClassID(); - std::cerr << " Node "; - - if (!LR->hasColor()) { - std::cerr << " - could not find a color\n"; - return; - } - - // if a color is found - - std::cerr << " colored with color "<< LR->getColor(); - - unsigned uRegName = getUnifiedRegNum(RegClassID, LR->getColor()); - - std::cerr << "["; - std::cerr<< getUnifiedRegName(uRegName); - if (RegClassID == FloatRegClassID && LR->getType() == Type::DoubleTy) - std::cerr << "+" << getUnifiedRegName(uRegName+1); - std::cerr << "]\n"; -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/SparcV9.td b/llvm/lib/Target/Sparc/SparcV9.td deleted file mode 100644 index 4cb00102e2b..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9.td +++ /dev/null @@ -1,786 +0,0 @@ -//===- SparcV9.td - Target Description for Sparc V9 Target ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// TODO: Need a description here. -// -//===----------------------------------------------------------------------===// - -include "../Target.td" - -include "SparcV9_Reg.td" - -//===----------------------------------------------------------------------===// -// Instructions -//===----------------------------------------------------------------------===// - -class InstV9 : Instruction { // Sparc instruction baseline - field bits<32> Inst; - - let Namespace = "V9"; - - bits<2> op; - let Inst{31-30} = op; // Top two bits are the 'op' field - - // Bit attributes specific to Sparc instructions - bit isPasi = 0; // Does this instruction affect an alternate addr space? - bit isDeprecated = 0; // Is this instruction deprecated? - bit isPrivileged = 0; // Is this a privileged instruction? -} - -include "SparcV9_F2.td" -include "SparcV9_F3.td" -include "SparcV9_F4.td" - -//===----------------------------------------------------------------------===// -// Instruction list... -// - -// Section A.2: Add - p137 -def ADDr : F3_1<2, 0b000000, "add">; // add rs1, rs2, rd -def ADDi : F3_2<2, 0b000000, "add">; // add rs1, imm, rd -def ADDccr : F3_1<2, 0b010000, "addcc">; // addcc rs1, rs2, rd -def ADDcci : F3_2<2, 0b010000, "addcc">; // addcc rs1, imm, rd -def ADDCr : F3_1<2, 0b001000, "addC">; // addC rs1, rs2, rd -def ADDCi : F3_2<2, 0b001000, "addC">; // addC rs1, imm, rd -def ADDCccr : F3_1<2, 0b011000, "addCcc">; // addCcc rs1, rs2, rd -def ADDCcci : F3_2<2, 0b011000, "addCcc">; // addCcc rs1, imm, rd - -// Section A.3: Branch on Integer Register with Prediction - p138 -let op2 = 0b011 in { - def BRZ : F2_4<0b001, "brz">; // Branch on rs1 == 0 - def BRLEZ : F2_4<0b010, "brlez">; // Branch on rs1 <= 0 - def BRLZ : F2_4<0b011, "brlz">; // Branch on rs1 < 0 - def BRNZ : F2_4<0b101, "brnz">; // Branch on rs1 != 0 - def BRGZ : F2_4<0b110, "brgz">; // Branch on rs1 > 0 - def BRGEZ : F2_4<0b111, "brgez">; // Branch on rs1 >= 0 -} - -// Section A.4: Branch on Floating-Point Condition Codes (FBfcc) p140 -// The following deprecated instructions don't seem to play nice on Sparc -/* -let isDeprecated = 1 in { - let op2 = 0b110 in { - def FBA : F2_2<0b1000, "fba">; // Branch always - def FBN : F2_2<0b0000, "fbn">; // Branch never - def FBU : F2_2<0b0111, "fbu">; // Branch on unordered - def FBG : F2_2<0b0110, "fbg">; // Branch > - def FBUG : F2_2<0b0101, "fbug">; // Branch on unordered or > - def FBL : F2_2<0b0100, "fbl">; // Branch < - def FBUL : F2_2<0b0011, "fbul">; // Branch on unordered or < - def FBLG : F2_2<0b0010, "fblg">; // Branch < or > - def FBNE : F2_2<0b0001, "fbne">; // Branch != - def FBE : F2_2<0b1001, "fbe">; // Branch == - def FBUE : F2_2<0b1010, "fbue">; // Branch on unordered or == - def FBGE : F2_2<0b1011, "fbge">; // Branch > or == - def FBUGE : F2_2<0b1100, "fbuge">; // Branch unord or > or == - def FBLE : F2_2<0b1101, "fble">; // Branch < or == - def FBULE : F2_2<0b1110, "fbule">; // Branch unord or < or == - def FBO : F2_2<0b1111, "fbo">; // Branch on ordered - } -} -*/ - -// We now make these same opcodes represent the FBPfcc instructions -let op2 = 0b101 in { - def FBA : F2_3<0b1000, "fba">; // Branch always - def FBN : F2_3<0b0000, "fbn">; // Branch never - def FBU : F2_3<0b0111, "fbu">; // Branch on unordered - def FBG : F2_3<0b0110, "fbg">; // Branch > - def FBUG : F2_3<0b0101, "fbug">; // Branch on unordered or > - def FBL : F2_3<0b0100, "fbl">; // Branch < - def FBUL : F2_3<0b0011, "fbul">; // Branch on unordered or < - def FBLG : F2_3<0b0010, "fblg">; // Branch < or > - def FBNE : F2_3<0b0001, "fbne">; // Branch != - def FBE : F2_3<0b1001, "fbe">; // Branch == - def FBUE : F2_3<0b1010, "fbue">; // Branch on unordered or == - def FBGE : F2_3<0b1011, "fbge">; // Branch > or == - def FBUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == - def FBLE : F2_3<0b1101, "fble">; // Branch < or == - def FBULE : F2_3<0b1110, "fbule">; // Branch unord or < or == - def FBO : F2_3<0b1111, "fbo">; // Branch on ordered -} - -// Section A.5: Branch on FP condition codes with prediction - p143 -// Not used in the Sparc backend (directly) -/* -let op2 = 0b101 in { - def FBPA : F2_3<0b1000, "fba">; // Branch always - def FBPN : F2_3<0b0000, "fbn">; // Branch never - def FBPU : F2_3<0b0111, "fbu">; // Branch on unordered - def FBPG : F2_3<0b0110, "fbg">; // Branch > - def FBPUG : F2_3<0b0101, "fbug">; // Branch on unordered or > - def FBPL : F2_3<0b0100, "fbl">; // Branch < - def FBPUL : F2_3<0b0011, "fbul">; // Branch on unordered or < - def FBPLG : F2_3<0b0010, "fblg">; // Branch < or > - def FBPNE : F2_3<0b0001, "fbne">; // Branch != - def FBPE : F2_3<0b1001, "fbe">; // Branch == - def FBPUE : F2_3<0b1010, "fbue">; // Branch on unordered or == - def FBPGE : F2_3<0b1011, "fbge">; // Branch > or == - def FBPUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == - def FBPLE : F2_3<0b1101, "fble">; // Branch < or == - def FBPULE : F2_3<0b1110, "fbule">; // Branch unord or < or == - def FBPO : F2_3<0b1111, "fbo">; // Branch on ordered -} -*/ - -// Section A.6: Branch on Integer condition codes (Bicc) - p146 -/* -let isDeprecated = 1 in { - let op2 = 0b010 in { - def BA : F2_2<0b1000, "ba">; // Branch always - def BN : F2_2<0b0000, "bn">; // Branch never - def BNE : F2_2<0b1001, "bne">; // Branch != - def BE : F2_2<0b0001, "be">; // Branch == - def BG : F2_2<0b1010, "bg">; // Branch > - def BLE : F2_2<0b0010, "ble">; // Branch <= - def BGE : F2_2<0b1011, "bge">; // Branch >= - def BL : F2_2<0b0011, "bl">; // Branch < - def BGU : F2_2<0b1100, "bgu">; // Branch unsigned > - def BLEU : F2_2<0b0100, "bleu">; // Branch unsigned <= - def BCC : F2_2<0b1101, "bcc">; // Branch unsigned >= - def BCS : F2_2<0b0101, "bcs">; // Branch unsigned <= - def BPOS : F2_2<0b1110, "bpos">; // Branch on positive - def BNEG : F2_2<0b0110, "bneg">; // Branch on negative - def BVC : F2_2<0b1111, "bvc">; // Branch on overflow clear - def BVS : F2_2<0b0111, "bvs">; // Branch on overflow set - } -} -*/ - -// Using the format of A.7 instructions... -let op2 = 0b001 in { - let cc = 0 in { // BA and BN don't read condition codes - def BA : F2_3<0b1000, "ba">; // Branch always - def BN : F2_3<0b0000, "bn">; // Branch never - } - def BNE : F2_3<0b1001, "bne">; // Branch != - def BE : F2_3<0b0001, "be">; // Branch == - def BG : F2_3<0b1010, "bg">; // Branch > - def BLE : F2_3<0b0010, "ble">; // Branch <= - def BGE : F2_3<0b1011, "bge">; // Branch >= - def BL : F2_3<0b0011, "bl">; // Branch < - def BGU : F2_3<0b1100, "bgu">; // Branch unsigned > - def BLEU : F2_3<0b0100, "bleu">; // Branch unsigned <= - def BCC : F2_3<0b1101, "bcc">; // Branch unsigned >= - def BCS : F2_3<0b0101, "bcs">; // Branch unsigned <= - def BPOS : F2_3<0b1110, "bpos">; // Branch on positive - def BNEG : F2_3<0b0110, "bneg">; // Branch on negative - def BVC : F2_3<0b1111, "bvc">; // Branch on overflow clear - def BVS : F2_3<0b0111, "bvs">; // Branch on overflow set -} - -// Section A.7: Branch on integer condition codes with prediction - p148 -// Not used in the Sparc backend -/* -let op2 = 0b001 in { - def BPA : F2_3<0b1000, "bpa">; // Branch always - def BPN : F2_3<0b0000, "bpn">; // Branch never - def BPNE : F2_3<0b1001, "bpne">; // Branch != - def BPE : F2_3<0b0001, "bpe">; // Branch == - def BPG : F2_3<0b1010, "bpg">; // Branch > - def BPLE : F2_3<0b0010, "bple">; // Branch <= - def BPGE : F2_3<0b1011, "bpge">; // Branch >= - def BPL : F2_3<0b0011, "bpl">; // Branch < - def BPGU : F2_3<0b1100, "bpgu">; // Branch unsigned > - def BPLEU : F2_3<0b0100, "bpleu">; // Branch unsigned <= - def BPCC : F2_3<0b1101, "bpcc">; // Branch unsigned >= - def BPCS : F2_3<0b0101, "bpcs">; // Branch unsigned <= - def BPPOS : F2_3<0b1110, "bppos">; // Branch on positive - def BPNEG : F2_3<0b0110, "bpneg">; // Branch on negative - def BPVC : F2_3<0b1111, "bpvc">; // Branch on overflow clear - def BPVS : F2_3<0b0111, "bpvs">; // Branch on overflow set -} -*/ - -// Section A.8: CALL - p151, the only Format #1 instruction -def CALL : InstV9 { - bits<30> disp; - let op = 1; - let Inst{29-0} = disp; - let Name = "call"; - let isCall = 1; -} - -// Section A.9: Compare and Swap - p176 -// CASA/CASXA: are for alternate address spaces! Ignore them - - -// Section A.10: Divide (64-bit / 32-bit) - p178 -// Not used in the Sparc backend -/* -let isDeprecated = 1 in { - def UDIVr : F3_1<2, 0b001110, "udiv">; // udiv r, r, r - def UDIVi : F3_2<2, 0b001110, "udiv">; // udiv r, r, i - def SDIVr : F3_1<2, 0b001111, "sdiv">; // sdiv r, r, r - def SDIVi : F3_2<2, 0b001111, "sdiv">; // sdiv r, r, i - def UDIVCCr : F3_1<2, 0b011110, "udivcc">; // udivcc r, r, r - def UDIVCCi : F3_2<2, 0b011110, "udivcc">; // udivcc r, r, i - def SDIVCCr : F3_1<2, 0b011111, "sdivcc">; // sdivcc r, r, r - def SDIVCCi : F3_2<2, 0b011111, "sdivcc">; // sdivcc r, r, i -} -*/ - -// Section A.11: DONE and RETRY - p181 -// Not used in the Sparc backend -/* -let isPrivileged = 1 in { - def DONE : F3_18<0, "done">; // done - def RETRY : F3_18<1, "retry">; // retry -} -*/ - -// Section A.12: Floating-Point Add and Subtract - p156 -def FADDS : F3_16<2, 0b110100, 0x41, "fadds">; // fadds frs1, frs2, frd -def FADDD : F3_16<2, 0b110100, 0x42, "faddd">; // faddd frs1, frs2, frd -def FADDQ : F3_16<2, 0b110100, 0x43, "faddq">; // faddq frs1, frs2, frd -def FSUBS : F3_16<2, 0b110100, 0x45, "fsubs">; // fsubs frs1, frs2, frd -def FSUBD : F3_16<2, 0b110100, 0x46, "fsubd">; // fsubd frs1, frs2, frd -def FSUBQ : F3_16<2, 0b110100, 0x47, "fsubq">; // fsubq frs1, frs2, frd - -// Section A.13: Floating-point compare - p159 -def FCMPS : F3_15<2, 0b110101, 0b001010001, "fcmps">; // fcmps %fcc, r1, r2 -def FCMPD : F3_15<2, 0b110101, 0b001010010, "fcmpd">; // fcmpd %fcc, r1, r2 -def FCMPQ : F3_15<2, 0b110101, 0b001010011, "fcmpq">; // fcmpq %fcc, r1, r2 -// Currently unused in the Sparc backend -/* -def FCMPES : F3_15<2, 0b110101, 0b001010101, "fcmpes">; // fcmpes %fcc, r1, r2 -def FCMPED : F3_15<2, 0b110101, 0b001010110, "fcmped">; // fcmped %fcc, r1, r2 -def FCMPEQ : F3_15<2, 0b110101, 0b001010111, "fcmpeq">; // fcmpeq %fcc, r1, r2 -*/ - -// Section A.14: Convert floating-point to integer - p161 -def FSTOX : F3_14<2, 0b110100, 0b010000001, "fstox">; // fstox rs2, rd -def FDTOX : F3_14<2, 0b110100, 0b010000010, "fstox">; // fstox rs2, rd -def FQTOX : F3_14<2, 0b110100, 0b010000011, "fstox">; // fstox rs2, rd -def FSTOI : F3_14<2, 0b110100, 0b011010001, "fstoi">; // fstoi rs2, rd -def FDTOI : F3_14<2, 0b110100, 0b011010010, "fdtoi">; // fdtoi rs2, rd -def FQTOI : F3_14<2, 0b110100, 0b011010011, "fqtoi">; // fqtoi rs2, rd - -// Section A.15: Convert between floating-point formats - p162 -def FSTOD : F3_14<2, 0b110100, 0b011001001, "fstod">; // fstod rs2, rd -def FSTOQ : F3_14<2, 0b110100, 0b011001101, "fstoq">; // fstoq rs2, rd -def FDTOS : F3_14<2, 0b110100, 0b011000110, "fstos">; // fstos rs2, rd -def FDTOQ : F3_14<2, 0b110100, 0b011001110, "fdtoq">; // fdtoq rs2, rd -def FQTOS : F3_14<2, 0b110100, 0b011000111, "fqtos">; // fqtos rs2, rd -def FQTOD : F3_14<2, 0b110100, 0b011001011, "fqtod">; // fqtod rs2, rd - -// Section A.16: Convert integer to floating-point - p163 -def FXTOS : F3_14<2, 0b110100, 0b010000100, "fxtos">; // fxtos rs2, rd -def FXTOD : F3_14<2, 0b110100, 0b010001000, "fxtod">; // fxtod rs2, rd -def FXTOQ : F3_14<2, 0b110100, 0b010001100, "fxtoq">; // fxtoq rs2, rd -def FITOS : F3_14<2, 0b110100, 0b011000100, "fitos">; // fitos rs2, rd -def FITOD : F3_14<2, 0b110100, 0b011001000, "fitod">; // fitod rs2, rd -def FITOQ : F3_14<2, 0b110100, 0b011001100, "fitoq">; // fitoq rs2, rd - -// Section A.17: Floating-Point Move - p164 -def FMOVS : F3_14<2, 0b110100, 0b000000001, "fmovs">; // fmovs r, r -def FMOVD : F3_14<2, 0b110100, 0b000000010, "fmovs">; // fmovd r, r -//def FMOVQ : F3_14<2, 0b110100, 0b000000011, "fmovs">; // fmovq r, r -def FNEGS : F3_14<2, 0b110100, 0b000000101, "fnegs">; // fnegs r, r -def FNEGD : F3_14<2, 0b110100, 0b000000110, "fnegs">; // fnegs r, r -//def FNEGQ : F3_14<2, 0b110100, 0b000000111, "fnegs">; // fnegs r, r -def FABSS : F3_14<2, 0b110100, 0b000001001, "fabss">; // fabss r, r -def FABSD : F3_14<2, 0b110100, 0b000001010, "fabss">; // fabss r, r -//def FABSQ : F3_14<2, 0b110100, 0b000001011, "fabss">; // fabss r, r - -// Section A.18: Floating-Point Multiply and Divide - p165 -def FMULS : F3_16<2, 0b110100, 0b001001001, "fmuls">; // fmuls r, r, r -def FMULD : F3_16<2, 0b110100, 0b001001010, "fmuld">; // fmuld r, r, r -def FMULQ : F3_16<2, 0b110100, 0b001001011, "fmulq">; // fmulq r, r, r -def FSMULD : F3_16<2, 0b110100, 0b001101001, "fsmuld">; // fsmuls r, r, r -def FDMULQ : F3_16<2, 0b110100, 0b001101110, "fdmulq">; // fdmuls r, r, r -def FDIVS : F3_16<2, 0b110100, 0b001001101, "fdivs">; // fdivs r, r, r -def FDIVD : F3_16<2, 0b110100, 0b001001110, "fdivs">; // fdivd r, r, r -def FDIVQ : F3_16<2, 0b110100, 0b001001111, "fdivs">; // fdivq r, r, r - -// Section A.19: Floating-Point Square Root - p166 -def FSQRTS : F3_14<2, 0b110100, 0b000101001, "fsqrts">; // fsqrts r, r -def FSQRTD : F3_14<2, 0b110100, 0b000101010, "fsqrts">; // fsqrts r, r -def FSQRTQ : F3_14<2, 0b110100, 0b000101011, "fsqrts">; // fsqrts r, r - -// A.20: Flush Instruction Memory - p167 -// Not currently used - -// A.21: Flush Register Windows - p169 -// Not currently used - -// A.22: Illegal instruction Trap - p170 -// Not currently used - -// A.23: Implementation-Dependent Instructions - p171 -// Not currently used - -// Section A.24: Jump and Link - p172 -// Mimicking the Sparc's instr def... -def JMPLCALLr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd -def JMPLCALLi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd -def JMPLRETr : F3_1<2, 0b111000, "jmpl">; // jmpl [rs1+rs2], rd -def JMPLRETi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd - -// Section A.25: Load Floating-Point - p173 -def LDFr : F3_1<3, 0b100000, "ld">; // ld [rs1+rs2], rd -def LDFi : F3_2<3, 0b100000, "ld">; // ld [rs1+imm], rd -def LDDFr : F3_1<3, 0b100011, "ldd">; // ldd [rs1+rs2], rd -def LDDFi : F3_2<3, 0b100011, "ldd">; // ldd [rs1+imm], rd -def LDQFr : F3_1<3, 0b100010, "ldq">; // ldq [rs1+rs2], rd -def LDQFi : F3_2<3, 0b100010, "ldq">; // ldq [rs1+imm], rd -let isDeprecated = 1 in { - let rd = 0 in { - def LDFSRr : F3_1<3, 0b100001, "ld">; // ld [rs1+rs2], rd - def LDFSRi : F3_2<3, 0b100001, "ld">; // ld [rs1+imm], rd - } -} -let rd = 1 in { - def LDXFSRr : F3_1<3, 0b100001, "ldx">; // ldx [rs1+rs2], rd - def LDXFSRi : F3_2<3, 0b100001, "ldx">; // ldx [rs1+imm], rd -} - -// Section A.27: Load Integer - p178 -def LDSBr : F3_1<3, 0b001001, "ldsb">; // ldsb [rs1+rs2], rd -def LDSBi : F3_2<3, 0b001001, "ldsb">; // ldsb [rs1+imm], rd -def LDSHr : F3_1<3, 0b001010, "ldsh">; // ldsh [rs1+rs2], rd -def LDSHi : F3_2<3, 0b001010, "ldsh">; // ldsh [rs1+imm], rd -def LDSWr : F3_1<3, 0b001000, "ldsw">; // ldsh [rs1+rs2], rd -def LDSWi : F3_2<3, 0b001000, "ldsw">; // ldsh [rs1+imm], rd -def LDUBr : F3_1<3, 0b000001, "ldub">; // ldub [rs1+rs2], rd -def LDUBi : F3_2<3, 0b000001, "ldub">; // ldub [rs1+imm], rd -def LDUHr : F3_1<3, 0b000010, "lduh">; // lduh [rs1+rs2], rd -def LDUHi : F3_2<3, 0b000010, "lduh">; // lduh [rs1+imm], rd -// synonym: LD -def LDUWr : F3_1<3, 0b000000, "lduw">; // lduw [rs1+rs2], rd -def LDUWi : F3_2<3, 0b000000, "lduw">; // lduw [rs1+imm], rd -def LDXr : F3_1<3, 0b001011, "ldx">; // ldx [rs1+rs2], rd -def LDXi : F3_2<3, 0b001011, "ldx">; // ldx [rs1+imm], rd -/* -let isDeprecated = 1 in { - def LDDr : F3_1<3, 0b000011, "ldd">; // ldd [rs1+rs2], rd - def LDDi : F3_2<3, 0b000011, "ldd">; // ldd [rs1+imm], rd -} -*/ - -// Section A.31: Logical operations -def ANDr : F3_1<2, 0b000001, "and">; // and rs1, rs2, rd -def ANDi : F3_2<2, 0b000001, "and">; // and rs1, imm, rd -def ANDccr : F3_1<2, 0b010001, "andcc">; // andcc rs1, rs2, rd -def ANDcci : F3_2<2, 0b010001, "andcc">; // andcc rs1, imm, rd -def ANDNr : F3_1<2, 0b000101, "andn">; // andn rs1, rs2, rd -def ANDNi : F3_2<2, 0b000101, "andn">; // andn rs1, imm, rd -def ANDNccr : F3_1<2, 0b010101, "andncc">; // andncc rs1, rs2, rd -def ANDNcci : F3_2<2, 0b010101, "andncc">; // andncc rs1, imm, rd - -def ORr : F3_1<2, 0b000010, "or">; // or rs1, rs2, rd -def ORi : F3_2<2, 0b000010, "or">; // or rs1, imm, rd -def ORccr : F3_1<2, 0b010010, "orcc">; // orcc rs1, rs2, rd -def ORcci : F3_2<2, 0b010010, "orcc">; // orcc rs1, imm, rd -def ORNr : F3_1<2, 0b000110, "orn">; // orn rs1, rs2, rd -def ORNi : F3_2<2, 0b000110, "orn">; // orn rs1, imm, rd -def ORNccr : F3_1<2, 0b010110, "orncc">; // orncc rs1, rs2, rd -def ORNcci : F3_2<2, 0b010110, "orncc">; // orncc rs1, imm, rd - -def XORr : F3_1<2, 0b000011, "xor">; // xor rs1, rs2, rd -def XORi : F3_2<2, 0b000011, "xor">; // xor rs1, imm, rd -def XORccr : F3_1<2, 0b010011, "xorcc">; // xorcc rs1, rs2, rd -def XORcci : F3_2<2, 0b010011, "xorcc">; // xorcc rs1, imm, rd -def XNORr : F3_1<2, 0b000111, "xnor">; // xnor rs1, rs2, rd -def XNORi : F3_2<2, 0b000111, "xnor">; // xnor rs1, imm, rd -def XNORccr : F3_1<2, 0b010111, "xnorcc">; // xnorcc rs1, rs2, rd -def XNORcci : F3_2<2, 0b010111, "xnorcc">; // xnorcc rs1, imm, rd - -// Section A.32: Memory Barrier - p186 -// Not currently used in the Sparc backend - -// Section A.33: Move Floating-Point Register on Condition (FMOVcc) -// ======================= Single Floating Point ====================== -// For integer condition codes -def FMOVSA : F4_7<2, 0b110101, 0b1000, 0b000001, "fmovsa">; // fmovsa cc, r, r -def FMOVSN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsn">; // fmovsn cc, r, r -def FMOVSNE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsne">; // fmovsne cc, r, r -def FMOVSE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovse">; // fmovse cc, r, r -def FMOVSG : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsg">; // fmovsg cc, r, r -def FMOVSLE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsle">; // fmovsle cc, r, r -def FMOVSGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc, r, r -def FMOVSL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsl">; // fmovsl cc, r, r -def FMOVSGU : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsgu">; // fmovsgu cc, r, r -def FMOVSLEU : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsleu">; // fmovsleu cc, r, r -def FMOVSCC : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovscc">; // fmovscc cc, r, r -def FMOVSCS : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovscs">; // fmovscs cc, r, r -def FMOVSPOS : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovspos">; // fmovspos cc, r, r -def FMOVSNEG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsneg">; // fmovsneg cc, r, r -def FMOVSVC : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsvc">; // fmovsvc cc, r, r -def FMOVSVS : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsvs">; // fmovsvs cc, r, r - -// For floating-point condition codes -def FMOVSFA : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfa">; // fmovsfa cc,r,r -def FMOVSFN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsfn">; // fmovsfa cc,r,r -def FMOVSFU : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsfu">; // fmovsfu cc,r,r -def FMOVSFG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsfg">; // fmovsfg cc,r,r -def FMOVSFUG : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovsfug">; // fmovsfug cc,r,r -def FMOVSFL : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfl">; // fmovsfl cc,r,r -def FMOVSFUL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsful">; // fmovsful cc,r,r -def FMOVSFLG : F4_7<2, 0b110101, 0b0010, 0b000001, "fmovsflg">; // fmovsflg cc,r,r -def FMOVSFNE : F4_7<2, 0b110101, 0b0001, 0b000001, "fmovsfne">; // fmovsfne cc,r,r -def FMOVSFE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsfe">; // fmovsfe cc,r,r -def FMOVSFUE : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsfue">; // fmovsfue cc,r,r -def FMOVSFGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc,r,r -def FMOVSFUGE : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsfuge">;// fmovsfuge cc,r,r -def FMOVSFLE : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovsfle">; // fmovsfle cc,r,r -def FMOVSFULE : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovsfule">;// fmovsfule cc,r,r -def FMOVSFO : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsfo">; // fmovsfo cc,r,r - -// ======================= Double Floating Point ====================== -// For integer condition codes -def FMOVDA : F4_7<2, 0b110101, 0b1000, 0b000010, "fmovda">; // fmovda cc, r, r -def FMOVDN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdn">; // fmovdn cc, r, r -def FMOVDNE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdne">; // fmovdne cc, r, r -def FMOVDE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovde">; // fmovde cc, r, r -def FMOVDG : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdg">; // fmovdg cc, r, r -def FMOVDLE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdle">; // fmovdle cc, r, r -def FMOVDGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc, r, r -def FMOVDL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdl">; // fmovdl cc, r, r -def FMOVDGU : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdgu">; // fmovdgu cc, r, r -def FMOVDLEU : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdleu">; // fmovdleu cc, r, r -def FMOVDCC : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdcc">; // fmovdcc cc, r, r -def FMOVDCS : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdcs">; // fmovdcs cc, r, r -def FMOVDPOS : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdpos">; // fmovdpos cc, r, r -def FMOVDNEG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdneg">; // fmovdneg cc, r, r -def FMOVDVC : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdvc">; // fmovdvc cc, r, r -def FMOVDVS : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdvs">; // fmovdvs cc, r, r - -// For floating-point condition codes -def FMOVDFA : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfa">; // fmovdfa cc,r,r -def FMOVDFN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdfn">; // fmovdfa cc,r,r -def FMOVDFU : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdfu">; // fmovdfu cc,r,r -def FMOVDFG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdfg">; // fmovdfg cc,r,r -def FMOVDFUG : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdfug">; // fmovdfug cc,r,r -def FMOVDFL : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfl">; // fmovdfl cc,r,r -def FMOVDFUL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdful">; // fmovdful cc,r,r -def FMOVDFLG : F4_7<2, 0b110101, 0b0010, 0b000010, "fmovdflg">; // fmovdflg cc,r,r -def FMOVDFNE : F4_7<2, 0b110101, 0b0001, 0b000010, "fmovdfne">; // fmovdfne cc,r,r -def FMOVDFE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdfe">; // fmovdfe cc,r,r -def FMOVDFUE : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdfue">; // fmovdfue cc,r,r -def FMOVDFGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc,r,r -def FMOVDFUGE : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdfuge">;// fmovdfuge cc,r,r -def FMOVDFLE : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdfle">; // fmovdfle cc,r,r -def FMOVDFULE : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdfule">;// fmovdfule cc,r,r -def FMOVDFO : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdfo">; // fmovdfo cc,r,r - -// ======================= Quad Floating Point ====================== -// For integer condition codes -def FMOVQA : F4_7<2, 0b110101, 0b1000, 0b000011, "fmovqa">; // fmovqa cc, r, r -def FMOVQN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqn">; // fmovqn cc, r, r -def FMOVQNE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqne">; // fmovqne cc, r, r -def FMOVQE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqe">; // fmovqe cc, r, r -def FMOVQG : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqg">; // fmovqg cc, r, r -def FMOVQLE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqle">; // fmovqle cc, r, r -def FMOVQGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc, r, r -def FMOVQL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovql">; // fmovql cc, r, r -def FMOVQGU : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqgu">; // fmovqgu cc, r, r -def FMOVQLEU : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqleu">; // fmovqleu cc, r, r -def FMOVQCC : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqcc">; // fmovqcc cc, r, r -def FMOVQCS : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqcs">; // fmovqcs cc, r, r -def FMOVQPOS : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqpos">; // fmovqpos cc, r, r -def FMOVQNEG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqneg">; // fmovqneg cc, r, r -def FMOVQVC : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqvc">; // fmovqvc cc, r, r -def FMOVQVS : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqvs">; // fmovqvs cc, r, r - -// For floating-point condition codes -def FMOVQFA : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfa">; // fmovqfa cc,r,r -def FMOVQFN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqfn">; // fmovqfa cc,r,r -def FMOVQFU : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqfu">; // fmovqfu cc,r,r -def FMOVQFG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqfg">; // fmovqfg cc,r,r -def FMOVQFUG : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqfug">; // fmovqfug cc,r,r -def FMOVQFL : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfl">; // fmovqfl cc,r,r -def FMOVQFUL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovqful">; // fmovqful cc,r,r -def FMOVQFLG : F4_7<2, 0b110101, 0b0010, 0b000011, "fmovqflg">; // fmovqflg cc,r,r -def FMOVQFNE : F4_7<2, 0b110101, 0b0001, 0b000011, "fmovqfne">; // fmovqfne cc,r,r -def FMOVQFE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqfe">; // fmovqfe cc,r,r -def FMOVQFUE : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqfue">; // fmovqfue cc,r,r -def FMOVQFGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc,r,r -def FMOVQFUGE : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqfuge">;// fmovqfuge cc,r,r -def FMOVQFLE : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqfle">; // fmovqfle cc,r,r -def FMOVQFULE : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqfule">;// fmovqfule cc,r,r -def FMOVQFO : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqfo">; // fmovqfo cc,r,r - -// Section A.34: Move FP Register on Integer Register condition (FMOVr) - p192 -def FMOVRSZ : F4_6<2, 0b110101, 0b001, 0b00101, "fmovrsz">; //fmovsrz r,r,rd -def FMOVRSLEZ : F4_6<2, 0b110101, 0b010, 0b00101, "fmovrslez">;//fmovsrz r,r,rd -def FMOVRSLZ : F4_6<2, 0b110101, 0b011, 0b00101, "fmovrslz">; //fmovsrz r,r,rd -def FMOVRSNZ : F4_6<2, 0b110101, 0b101, 0b00101, "fmovrsne">; //fmovsrz r,r,rd -def FMOVRSGZ : F4_6<2, 0b110101, 0b110, 0b00101, "fmovrsgz">; //fmovsrz r,r,rd -def FMOVRSGEZ : F4_6<2, 0b110101, 0b111, 0b00101, "fmovrsgez">;//fmovsrz r,r,rd - -def FMOVRDZ : F4_6<2, 0b110101, 0b001, 0b00110, "fmovrdz">; //fmovsrz r,r,rd -def FMOVRDLEZ : F4_6<2, 0b110101, 0b010, 0b00110, "fmovrdlez">;//fmovsrz r,r,rd -def FMOVRDLZ : F4_6<2, 0b110101, 0b011, 0b00110, "fmovrdlz">; //fmovsrz r,r,rd -def FMOVRDNZ : F4_6<2, 0b110101, 0b101, 0b00110, "fmovrdne">; //fmovsrz r,r,rd -def FMOVRDGZ : F4_6<2, 0b110101, 0b110, 0b00110, "fmovrdgz">; //fmovsrz r,r,rd -def FMOVRDGEZ : F4_6<2, 0b110101, 0b111, 0b00110, "fmovrdgez">;//fmovsrz r,r,rd - -def FMOVRQZ : F4_6<2, 0b110101, 0b001, 0b00111, "fmovrqz">; //fmovsrz r,r,rd -def FMOVRQLEZ : F4_6<2, 0b110101, 0b010, 0b00111, "fmovrqlez">;//fmovsrz r,r,rd -def FMOVRQLZ : F4_6<2, 0b110101, 0b011, 0b00111, "fmovrqlz">; //fmovsrz r,r,rd -def FMOVRQNZ : F4_6<2, 0b110101, 0b101, 0b00111, "fmovrqne">; //fmovsrz r,r,rd -def FMOVRQGZ : F4_6<2, 0b110101, 0b110, 0b00111, "fmovrqgz">; //fmovsrz r,r,rd -def FMOVRQGEZ : F4_6<2, 0b110101, 0b111, 0b00111, "fmovrqgez">;//fmovsrz r,r,rd - - -// Section A.35: Move Integer Register on Condition (MOVcc) - p194 -// For integer condition codes -def MOVAr : F4_3<2, 0b101100, 0b1000, "mova">; // mova i/xcc, rs2, rd -def MOVAi : F4_4<2, 0b101100, 0b1000, "mova">; // mova i/xcc, imm, rd -def MOVNr : F4_3<2, 0b101100, 0b0000, "movn">; // movn i/xcc, rs2, rd -def MOVNi : F4_4<2, 0b101100, 0b0000, "movn">; // movn i/xcc, imm, rd -def MOVNEr : F4_3<2, 0b101100, 0b1001, "movne">; // movne i/xcc, rs2, rd -def MOVNEi : F4_4<2, 0b101100, 0b1001, "movne">; // movne i/xcc, imm, rd -def MOVEr : F4_3<2, 0b101100, 0b0001, "move">; // move i/xcc, rs2, rd -def MOVEi : F4_4<2, 0b101100, 0b0001, "move">; // move i/xcc, imm, rd -def MOVGr : F4_3<2, 0b101100, 0b1010, "movg">; // movg i/xcc, rs2, rd -def MOVGi : F4_4<2, 0b101100, 0b1010, "movg">; // movg i/xcc, imm, rd -def MOVLEr : F4_3<2, 0b101100, 0b0010, "movle">; // movle i/xcc, rs2, rd -def MOVLEi : F4_4<2, 0b101100, 0b0010, "movle">; // movle i/xcc, imm, rd -def MOVGEr : F4_3<2, 0b101100, 0b1011, "movge">; // movge i/xcc, rs2, rd -def MOVGEi : F4_4<2, 0b101100, 0b1011, "movge">; // movge i/xcc, imm, rd -def MOVLr : F4_3<2, 0b101100, 0b0011, "movl">; // movl i/xcc, rs2, rd -def MOVLi : F4_4<2, 0b101100, 0b0011, "movl">; // movl i/xcc, imm, rd -def MOVGUr : F4_3<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, rs2, rd -def MOVGUi : F4_4<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, imm, rd -def MOVLEUr : F4_3<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, rs2, rd -def MOVLEUi : F4_4<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, imm, rd -def MOVCCr : F4_3<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, rs2, rd -def MOVCCi : F4_4<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, imm, rd -def MOVCSr : F4_3<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, rs2, rd -def MOVCSi : F4_4<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, imm, rd -def MOVPOSr : F4_3<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, rs2, rd -def MOVPOSi : F4_4<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, imm, rd -def MOVNEGr : F4_3<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, rs2, rd -def MOVNEGi : F4_4<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, imm, rd -def MOVVCr : F4_3<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, rs2, rd -def MOVVCi : F4_4<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, imm, rd -def MOVVSr : F4_3<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, rs2, rd -def MOVVSi : F4_4<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, imm, rd - -// For floating-point condition codes -def MOVFAr : F4_3<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, rs2, rd -def MOVFAi : F4_4<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, imm, rd -def MOVFNr : F4_3<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, rs2, rd -def MOVFNi : F4_4<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, imm, rd -def MOVFUr : F4_3<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, rs2, rd -def MOVFUi : F4_4<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, imm, rd -def MOVFGr : F4_3<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, rs2, rd -def MOVFGi : F4_4<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, imm, rd -def MOVFUGr : F4_3<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, rs2, rd -def MOVFUGi : F4_4<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, imm, rd -def MOVFLr : F4_3<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, rs2, rd -def MOVFLi : F4_4<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, imm, rd -def MOVFULr : F4_3<2, 0b101100, 0b0011, "movful">; // movful i/xcc, rs2, rd -def MOVFULi : F4_4<2, 0b101100, 0b0011, "movful">; // movful i/xcc, imm, rd -def MOVFLGr : F4_3<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, rs2, rd -def MOVFLGi : F4_4<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, imm, rd -def MOVFNEr : F4_3<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, rs2, rd -def MOVFNEi : F4_4<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, imm, rd -def MOVFEr : F4_3<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, rs2, rd -def MOVFEi : F4_4<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, imm, rd -def MOVFUEr : F4_3<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, rs2, rd -def MOVFUEi : F4_4<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, imm, rd -def MOVFGEr : F4_3<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, rs2, rd -def MOVFGEi : F4_4<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, imm, rd -def MOVFUGEr : F4_3<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, rs2, rd -def MOVFUGEi : F4_4<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, imm, rd -def MOVFLEr : F4_3<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, rs2, rd -def MOVFLEi : F4_4<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, imm, rd -def MOVFULEr : F4_3<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, rs2, rd -def MOVFULEi : F4_4<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, imm, rd -def MOVFOr : F4_3<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, rs2, rd -def MOVFOi : F4_4<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, imm, rd - -// Section A.36: Move Integer Register on Register Condition (MOVR) - p198 -def MOVRZr : F3_5<2, 0b101111, 0b001, "movrz">; // movrz rs1, rs2, rd -def MOVRZi : F3_6<2, 0b101111, 0b001, "movrz">; // movrz rs1, imm, rd -def MOVRLEZr : F3_5<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, rs2, rd -def MOVRLEZi : F3_6<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, imm, rd -def MOVRLZr : F3_5<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, rs2, rd -def MOVRLZi : F3_6<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, imm, rd -def MOVRNZr : F3_5<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, rs2, rd -def MOVRNZi : F3_6<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, imm, rd -def MOVRGZr : F3_5<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, rs2, rd -def MOVRGZi : F3_6<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, imm, rd -def MOVRGEZr : F3_5<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, rs2, rd -def MOVRGEZi : F3_6<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, imm, rd - -// Section A.37: Multiply and Divide (64-bit) - p199 -def MULXr : F3_1<2, 0b001001, "mulx">; // mulx r, r, r -def MULXi : F3_2<2, 0b001001, "mulx">; // mulx r, i, r -def SDIVXr : F3_1<2, 0b101101, "sdivx">; // sdivx r, r, r -def SDIVXi : F3_2<2, 0b101101, "sdivx">; // sdivx r, i, r -def UDIVXr : F3_1<2, 0b001101, "udivx">; // udivx r, r, r -def UDIVXi : F3_2<2, 0b001101, "udivx">; // udivx r, i, r - -// Section A.38: Multiply (32-bit) - p200 -// Not used in the Sparc backend -/* -let Inst{13} = 0 in { - def UMULr : F3_1<2, 0b001010, "umul">; // umul r, r, r - def SMULr : F3_1<2, 0b001011, "smul">; // smul r, r, r - def UMULCCr : F3_1<2, 0b011010, "umulcc">; // mulcc r, r, r - def SMULCCr : F3_1<2, 0b011011, "smulcc">; // smulcc r, r, r -} -let Inst{13} = 1 in { - def UMULi : F3_1<2, 0b001010, "umul">; // umul r, i, r - def SMULi : F3_1<2, 0b001011, "smul">; // smul r, i, r - def UMULCCi : F3_1<2, 0b011010, "umulcc">; // umulcc r, i, r - def SMULCCi : F3_1<2, 0b011011, "smulcc">; // smulcc r, i, r -} -*/ - -// Section A.39: Multiply Step - p202 -// Not currently used in the Sparc backend - -// Section A.40: No operation - p204 -// NOP is really a pseudo-instruction (special case of SETHI) -let op2 = 0b100 in { - let rd = 0 in { - let imm = 0 in { - def NOP : F2_1<"nop">; // nop - } - } -} - -// Section A.41: Population Count - p205 -// Not currently used in the Sparc backend - -// Section A.42: Prefetch Data - p206 -// Not currently used in the Sparc backend - -// Section A.43: Read Privileged Register - p211 -// Not currently used in the Sparc backend - -// Section A.44: Read State Register -// The only instr from this section currently used is RDCCR -let rs1 = 2 in { - def RDCCR : F3_17<2, 0b101000, "rd">; // rd %ccr, r -} - -// Section A.45: RETURN - p216 -let isReturn = 1 in { - def RETURNr : F3_3<2, 0b111001, "return">; // return - def RETURNi : F3_4<2, 0b111001, "return">; // return -} - -// Section A.46: SAVE and RESTORE - p217 -def SAVEr : F3_1<2, 0b111100, "save">; // save r, r, r -def SAVEi : F3_2<2, 0b111100, "save">; // save r, i, r -def RESTOREr : F3_1<2, 0b111101, "restore">; // restore r, r, r -def RESTOREi : F3_2<2, 0b111101, "restore">; // restore r, i, r - -// Section A.47: SAVED and RESTORED - p219 -// Not currently used in Sparc backend - -// Section A.48: SETHI - p220 -let op2 = 0b100 in { - def SETHI : F2_1<"sethi">; // sethi -} - -// Section A.49: Shift - p221 -// Not currently used in the Sparc backend -/* - uses 5 least significant bits of rs2 -let x = 0 in { - def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r - def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r - def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r - def SLLXr5 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r - def SRLXr5 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r - def SRAXr5 : F3_11<2, 0b100111, "srax">; // srax r, r, r -} -*/ - -// uses 6 least significant bits of rs2 -let x = 0 in { - def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r - def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r - def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r -} -let x = 1 in { - def SLLXr6 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r - def SRLXr6 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r - def SRAXr6 : F3_11<2, 0b100111, "srax">; // srax r, r, r -} - -def SLLi5 : F3_12<2, 0b100101, "sll">; // sll r, shcnt32, r -def SRLi5 : F3_12<2, 0b100110, "srl">; // srl r, shcnt32, r -def SRAi5 : F3_12<2, 0b100111, "sra">; // sra r, shcnt32, r -def SLLXi6 : F3_13<2, 0b100101, "sllx">; // sllx r, shcnt64, r -def SRLXi6 : F3_13<2, 0b100110, "srlx">; // srlx r, shcnt64, r -def SRAXi6 : F3_13<2, 0b100111, "srax">; // srax r, shcnt64, r - -// Section A.50: Sofware-Initiated Reset - p223 -// Not currently used in the Sparc backend - -// Section A.51: Store Barrier - p224 -// Not currently used in the Sparc backend - -// Section A.52: Store Floating-point - p225 -// Store instructions all want their rd register first -def STFr : F3_1rd<3, 0b100100, "st">; // st r, [r+r] -def STFi : F3_2rd<3, 0b100100, "st">; // st r, [r+i] -def STDFr : F3_1rd<3, 0b100111, "std">; // std r, [r+r] -def STDFi : F3_2rd<3, 0b100111, "std">; // std r, [r+i] - -// Not currently used in the Sparc backend -/* -def STQFr : F3_1rd<3, 0b100110, "stq">; // stq r, [r+r] -def STQFi : F3_2rd<3, 0b100110, "stq">; // stq r, [r+i] -*/ - -// FIXME: An encoding needs to be chosen here, because STFSRx expect rd=0, -// while STXFSRx expect rd=1, but assembly syntax dictates %fsr as first arg. -// These are being disabled because they aren't used in the Sparc backend. -/* -let isDeprecated = 1 in { - def STFSRr : F3_1<3, 0b100101, "st">; // st %fsr, [r+r] - def STFSRi : F3_2<3, 0b100101, "st">; // st %fsr, [r+i] -} -*/ -def STXFSRr : F3_1<3, 0b100101, "stx">; // stx %fsr, [r+r] -def STXFSRi : F3_2<3, 0b100101, "stx">; // stx %fsr, [r+i] - -// Section A.53: Store Floating-Point into Alternate Space - p227 -// Not currently used in the Sparc backend - -// Section A.54: Store Integer - p229 -// Store instructions all want their rd register first -def STBr : F3_1rd<3, 0b000101, "stb">; // stb r, [r+r] -def STBi : F3_2rd<3, 0b000101, "stb">; // stb r, [r+i] -def STHr : F3_1rd<3, 0b000110, "sth">; // sth r, [r+r] -def STHi : F3_2rd<3, 0b000110, "sth">; // sth r, [r+i] -def STWr : F3_1rd<3, 0b000100, "stw">; // stw r, [r+r] -def STWi : F3_2rd<3, 0b000100, "stw">; // stw r, [r+i] -def STXr : F3_1rd<3, 0b001110, "stx">; // stx r, [r+r] -def STXi : F3_2rd<3, 0b001110, "stx">; // stx r, [r+i] - -// Section A.55: Store Integer into Alternate Space - p231 -// Not currently used in the Sparc backend - -// Section A.56: Subtract - p233 -def SUBr : F3_1<2, 0b000100, "sub">; // sub r, r, r -def SUBi : F3_2<2, 0b000100, "sub">; // sub r, i, r -def SUBccr : F3_1<2, 0b010100, "subcc">; // subcc r, r, r -def SUBcci : F3_2<2, 0b010100, "subcc">; // subcc r, i, r -def SUBCr : F3_1<2, 0b001100, "subc">; // subc r, r, r -def SUBCi : F3_2<2, 0b001100, "subc">; // subc r, i, r -def SUBCccr : F3_1<2, 0b011100, "subccc">; // subccc r, r, r -def SUBCcci : F3_2<2, 0b011100, "subccc">; // subccc r, i, r - -// FIXME: More...? - -// Section A.63: Write State Register - p244 -let rd = 2 in { - def WRCCRr : F3_1<2, 0b110000, "wr">; // wr r, r, %y/ccr/etc - def WRCCRi : F3_2<2, 0b110000, "wr">; // wr r, i, %y/ccr/etc -} diff --git a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp deleted file mode 100644 index f2368d654b5..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp +++ /dev/null @@ -1,823 +0,0 @@ -//===-- SparcV9CodeEmitter.cpp --------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// SPARC-specific backend for emitting machine code to memory. -// -// This module also contains the code for lazily resolving the targets -// of call instructions, including the callback used to redirect calls -// to functions for which the code has not yet been generated into the -// JIT compiler. -// -// This file #includes SparcV9CodeEmitter.inc, which contains the code -// for getBinaryCodeForInstr(), a method that converts a MachineInstr -// into the corresponding binary machine code word. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/PassManager.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineConstantPool.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetData.h" -#include "Support/Debug.h" -#include "Support/hash_set" -#include "Support/Statistic.h" -#include "SparcInternals.h" -#include "SparcTargetMachine.h" -#include "SparcRegInfo.h" -#include "SparcV9CodeEmitter.h" -#include "Config/alloca.h" - -namespace llvm { - -namespace { - Statistic<> OverwrittenCalls("call-ovwr", "Number of over-written calls"); - Statistic<> UnmodifiedCalls("call-skip", "Number of unmodified calls"); - Statistic<> CallbackCalls("callback", "Number CompilationCallback() calls"); -} - -bool SparcTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, - MachineCodeEmitter &MCE) { - MachineCodeEmitter *M = &MCE; - DEBUG(M = MachineCodeEmitter::createFilePrinterEmitter(MCE)); - PM.add(new SparcV9CodeEmitter(*this, *M)); - PM.add(createSparcMachineCodeDestructionPass()); //Free stuff no longer needed - return false; -} - -namespace { - class JITResolver { - SparcV9CodeEmitter &SparcV9; - MachineCodeEmitter &MCE; - - /// LazyCodeGenMap - Keep track of call sites for functions that are to be - /// lazily resolved. - /// - std::map<uint64_t, Function*> LazyCodeGenMap; - - /// LazyResolverMap - Keep track of the lazy resolver created for a - /// particular function so that we can reuse them if necessary. - /// - std::map<Function*, uint64_t> LazyResolverMap; - - public: - enum CallType { ShortCall, FarCall }; - - private: - /// We need to keep track of whether we used a simple call or a far call - /// (many instructions) in sequence. This means we need to keep track of - /// what type of stub we generate. - static std::map<uint64_t, CallType> LazyCallFlavor; - - public: - JITResolver(SparcV9CodeEmitter &V9, - MachineCodeEmitter &mce) : SparcV9(V9), MCE(mce) {} - uint64_t getLazyResolver(Function *F); - uint64_t addFunctionReference(uint64_t Address, Function *F); - void deleteFunctionReference(uint64_t Address); - void addCallFlavor(uint64_t Address, CallType Flavor) { - LazyCallFlavor[Address] = Flavor; - } - - // Utility functions for accessing data from static callback - uint64_t getCurrentPCValue() { - return MCE.getCurrentPCValue(); - } - unsigned getBinaryCodeForInstr(MachineInstr &MI) { - return SparcV9.getBinaryCodeForInstr(MI); - } - - inline void insertFarJumpAtAddr(int64_t Value, uint64_t Addr); - void insertJumpAtAddr(int64_t Value, uint64_t &Addr); - - private: - uint64_t emitStubForFunction(Function *F); - static void SaveRegisters(uint64_t DoubleFP[], uint64_t CC[], - uint64_t Globals[]); - static void RestoreRegisters(uint64_t DoubleFP[], uint64_t CC[], - uint64_t Globals[]); - static void CompilationCallback(); - uint64_t resolveFunctionReference(uint64_t RetAddr); - - }; - - JITResolver *TheJITResolver; - std::map<uint64_t, JITResolver::CallType> JITResolver::LazyCallFlavor; -} - -/// addFunctionReference - This method is called when we need to emit the -/// address of a function that has not yet been emitted, so we don't know the -/// address. Instead, we emit a call to the CompilationCallback method, and -/// keep track of where we are. -/// -uint64_t JITResolver::addFunctionReference(uint64_t Address, Function *F) { - LazyCodeGenMap[Address] = F; - return (intptr_t)&JITResolver::CompilationCallback; -} - -/// deleteFunctionReference - If we are emitting a far call, we already added a -/// reference to the function, but it is now incorrect, since the address to the -/// JIT resolver is too far away to be a simple call instruction. This is used -/// to remove the address from the map. -/// -void JITResolver::deleteFunctionReference(uint64_t Address) { - std::map<uint64_t, Function*>::iterator I = LazyCodeGenMap.find(Address); - assert(I != LazyCodeGenMap.end() && "Not in map!"); - LazyCodeGenMap.erase(I); -} - -uint64_t JITResolver::resolveFunctionReference(uint64_t RetAddr) { - std::map<uint64_t, Function*>::iterator I = LazyCodeGenMap.find(RetAddr); - assert(I != LazyCodeGenMap.end() && "Not in map!"); - Function *F = I->second; - LazyCodeGenMap.erase(I); - return MCE.forceCompilationOf(F); -} - -uint64_t JITResolver::getLazyResolver(Function *F) { - std::map<Function*, uint64_t>::iterator I = LazyResolverMap.lower_bound(F); - if (I != LazyResolverMap.end() && I->first == F) return I->second; - - uint64_t Stub = emitStubForFunction(F); - LazyResolverMap.insert(I, std::make_pair(F, Stub)); - return Stub; -} - -void JITResolver::insertJumpAtAddr(int64_t JumpTarget, uint64_t &Addr) { - DEBUG(std::cerr << "Emitting a jump to 0x" << std::hex << JumpTarget << "\n"); - - // If the target function is close enough to fit into the 19bit disp of - // BA, we should use this version, as it's much cheaper to generate. - int64_t BranchTarget = (JumpTarget-Addr) >> 2; - if (BranchTarget >= (1 << 19) || BranchTarget <= -(1 << 19)) { - TheJITResolver->insertFarJumpAtAddr(JumpTarget, Addr); - } else { - // ba <target> - MachineInstr *I = BuildMI(V9::BA, 1).addSImm(BranchTarget); - *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*I); - Addr += 4; - delete I; - - // nop - I = BuildMI(V9::NOP, 0); - *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*I); - delete I; - } -} - -void JITResolver::insertFarJumpAtAddr(int64_t Target, uint64_t Addr) { - static const unsigned - o6 = SparcIntRegClass::o6, g0 = SparcIntRegClass::g0, - g1 = SparcIntRegClass::g1, g5 = SparcIntRegClass::g5; - - MachineInstr* BinaryCode[] = { - // - // Get address to branch into %g1, using %g5 as a temporary - // - // sethi %uhi(Target), %g5 ;; get upper 22 bits of Target into %g5 - BuildMI(V9::SETHI, 2).addSImm(Target >> 42).addReg(g5), - // or %g5, %ulo(Target), %g5 ;; get 10 lower bits of upper word into %g5 - BuildMI(V9::ORi, 3).addReg(g5).addSImm((Target >> 32) & 0x03ff).addReg(g5), - // sllx %g5, 32, %g5 ;; shift those 10 bits to the upper word - BuildMI(V9::SLLXi6, 3).addReg(g5).addSImm(32).addReg(g5), - // sethi %hi(Target), %g1 ;; extract bits 10-31 into the dest reg - BuildMI(V9::SETHI, 2).addSImm((Target >> 10) & 0x03fffff).addReg(g1), - // or %g5, %g1, %g1 ;; get upper word (in %g5) into %g1 - BuildMI(V9::ORr, 3).addReg(g5).addReg(g1).addReg(g1), - // or %g1, %lo(Target), %g1 ;; get lowest 10 bits of Target into %g1 - BuildMI(V9::ORi, 3).addReg(g1).addSImm(Target & 0x03ff).addReg(g1), - // jmpl %g1, %g0, %g0 ;; indirect branch on %g1 - BuildMI(V9::JMPLRETr, 3).addReg(g1).addReg(g0).addReg(g0), - // nop ;; delay slot - BuildMI(V9::NOP, 0) - }; - - for (unsigned i=0, e=sizeof(BinaryCode)/sizeof(BinaryCode[0]); i!=e; ++i) { - *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*BinaryCode[i]); - delete BinaryCode[i]; - Addr += 4; - } -} - -void JITResolver::SaveRegisters(uint64_t DoubleFP[], uint64_t CC[], - uint64_t Globals[]) { -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - - __asm__ __volatile__ (// Save condition-code registers - "stx %%fsr, %0;\n\t" - "rd %%fprs, %1;\n\t" - "rd %%ccr, %2;\n\t" - : "=m"(CC[0]), "=r"(CC[1]), "=r"(CC[2])); - - __asm__ __volatile__ (// Save globals g1 and g5 - "stx %%g1, %0;\n\t" - "stx %%g5, %0;\n\t" - : "=m"(Globals[0]), "=m"(Globals[1])); - - // GCC says: `asm' only allows up to thirty parameters! - __asm__ __volatile__ (// Save Single/Double FP registers, part 1 - "std %%f0, %0;\n\t" "std %%f2, %1;\n\t" - "std %%f4, %2;\n\t" "std %%f6, %3;\n\t" - "std %%f8, %4;\n\t" "std %%f10, %5;\n\t" - "std %%f12, %6;\n\t" "std %%f14, %7;\n\t" - "std %%f16, %8;\n\t" "std %%f18, %9;\n\t" - "std %%f20, %10;\n\t" "std %%f22, %11;\n\t" - "std %%f24, %12;\n\t" "std %%f26, %13;\n\t" - "std %%f28, %14;\n\t" "std %%f30, %15;\n\t" - : "=m"(DoubleFP[ 0]), "=m"(DoubleFP[ 1]), - "=m"(DoubleFP[ 2]), "=m"(DoubleFP[ 3]), - "=m"(DoubleFP[ 4]), "=m"(DoubleFP[ 5]), - "=m"(DoubleFP[ 6]), "=m"(DoubleFP[ 7]), - "=m"(DoubleFP[ 8]), "=m"(DoubleFP[ 9]), - "=m"(DoubleFP[10]), "=m"(DoubleFP[11]), - "=m"(DoubleFP[12]), "=m"(DoubleFP[13]), - "=m"(DoubleFP[14]), "=m"(DoubleFP[15])); - - __asm__ __volatile__ (// Save Double FP registers, part 2 - "std %%f32, %0;\n\t" "std %%f34, %1;\n\t" - "std %%f36, %2;\n\t" "std %%f38, %3;\n\t" - "std %%f40, %4;\n\t" "std %%f42, %5;\n\t" - "std %%f44, %6;\n\t" "std %%f46, %7;\n\t" - "std %%f48, %8;\n\t" "std %%f50, %9;\n\t" - "std %%f52, %10;\n\t" "std %%f54, %11;\n\t" - "std %%f56, %12;\n\t" "std %%f58, %13;\n\t" - "std %%f60, %14;\n\t" "std %%f62, %15;\n\t" - : "=m"(DoubleFP[16]), "=m"(DoubleFP[17]), - "=m"(DoubleFP[18]), "=m"(DoubleFP[19]), - "=m"(DoubleFP[20]), "=m"(DoubleFP[21]), - "=m"(DoubleFP[22]), "=m"(DoubleFP[23]), - "=m"(DoubleFP[24]), "=m"(DoubleFP[25]), - "=m"(DoubleFP[26]), "=m"(DoubleFP[27]), - "=m"(DoubleFP[28]), "=m"(DoubleFP[29]), - "=m"(DoubleFP[30]), "=m"(DoubleFP[31])); -#endif -} - - -void JITResolver::RestoreRegisters(uint64_t DoubleFP[], uint64_t CC[], - uint64_t Globals[]) -{ -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - - __asm__ __volatile__ (// Restore condition-code registers - "ldx %0, %%fsr;\n\t" - "wr %1, 0, %%fprs;\n\t" - "wr %2, 0, %%ccr;\n\t" - :: "m"(CC[0]), "r"(CC[1]), "r"(CC[2])); - - __asm__ __volatile__ (// Restore globals g1 and g5 - "ldx %0, %%g1;\n\t" - "ldx %0, %%g5;\n\t" - :: "m"(Globals[0]), "m"(Globals[1])); - - // GCC says: `asm' only allows up to thirty parameters! - __asm__ __volatile__ (// Restore Single/Double FP registers, part 1 - "ldd %0, %%f0;\n\t" "ldd %1, %%f2;\n\t" - "ldd %2, %%f4;\n\t" "ldd %3, %%f6;\n\t" - "ldd %4, %%f8;\n\t" "ldd %5, %%f10;\n\t" - "ldd %6, %%f12;\n\t" "ldd %7, %%f14;\n\t" - "ldd %8, %%f16;\n\t" "ldd %9, %%f18;\n\t" - "ldd %10, %%f20;\n\t" "ldd %11, %%f22;\n\t" - "ldd %12, %%f24;\n\t" "ldd %13, %%f26;\n\t" - "ldd %14, %%f28;\n\t" "ldd %15, %%f30;\n\t" - :: "m"(DoubleFP[0]), "m"(DoubleFP[1]), - "m"(DoubleFP[2]), "m"(DoubleFP[3]), - "m"(DoubleFP[4]), "m"(DoubleFP[5]), - "m"(DoubleFP[6]), "m"(DoubleFP[7]), - "m"(DoubleFP[8]), "m"(DoubleFP[9]), - "m"(DoubleFP[10]), "m"(DoubleFP[11]), - "m"(DoubleFP[12]), "m"(DoubleFP[13]), - "m"(DoubleFP[14]), "m"(DoubleFP[15])); - - __asm__ __volatile__ (// Restore Double FP registers, part 2 - "ldd %0, %%f32;\n\t" "ldd %1, %%f34;\n\t" - "ldd %2, %%f36;\n\t" "ldd %3, %%f38;\n\t" - "ldd %4, %%f40;\n\t" "ldd %5, %%f42;\n\t" - "ldd %6, %%f44;\n\t" "ldd %7, %%f46;\n\t" - "ldd %8, %%f48;\n\t" "ldd %9, %%f50;\n\t" - "ldd %10, %%f52;\n\t" "ldd %11, %%f54;\n\t" - "ldd %12, %%f56;\n\t" "ldd %13, %%f58;\n\t" - "ldd %14, %%f60;\n\t" "ldd %15, %%f62;\n\t" - :: "m"(DoubleFP[16]), "m"(DoubleFP[17]), - "m"(DoubleFP[18]), "m"(DoubleFP[19]), - "m"(DoubleFP[20]), "m"(DoubleFP[21]), - "m"(DoubleFP[22]), "m"(DoubleFP[23]), - "m"(DoubleFP[24]), "m"(DoubleFP[25]), - "m"(DoubleFP[26]), "m"(DoubleFP[27]), - "m"(DoubleFP[28]), "m"(DoubleFP[29]), - "m"(DoubleFP[30]), "m"(DoubleFP[31])); -#endif -} - -void JITResolver::CompilationCallback() { - // Local space to save the registers - uint64_t DoubleFP[32]; - uint64_t CC[3]; - uint64_t Globals[2]; - - SaveRegisters(DoubleFP, CC, Globals); - ++CallbackCalls; - - uint64_t CameFrom = (uint64_t)(intptr_t)__builtin_return_address(0); - uint64_t CameFrom1 = (uint64_t)(intptr_t)__builtin_return_address(1); - int64_t Target = (int64_t)TheJITResolver->resolveFunctionReference(CameFrom); - DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << CameFrom << "\n"); - register int64_t returnAddr = 0; -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - __asm__ __volatile__ ("add %%i7, %%g0, %0" : "=r" (returnAddr) : ); - DEBUG(std::cerr << "Read i7 (return addr) = " - << std::hex << returnAddr << ", value: " - << std::hex << *(unsigned*)returnAddr << "\n"); -#endif - - // If we can rewrite the ORIGINAL caller, we eliminate the whole need for a - // trampoline function stub!! - unsigned OrigCallInst = *((unsigned*)(intptr_t)CameFrom1); - int64_t OrigTarget = (Target-CameFrom1) >> 2; - if ((OrigCallInst & (1 << 30)) && - (OrigTarget <= (1 << 30) && OrigTarget >= -(1 << 30))) - { - // The original call instruction was CALL <immed>, which means we can - // overwrite it directly, since the offset will fit into 30 bits - MachineInstr *C = BuildMI(V9::CALL, 1).addSImm(OrigTarget); - *((unsigned*)(intptr_t)CameFrom1)=TheJITResolver->getBinaryCodeForInstr(*C); - delete C; - ++OverwrittenCalls; - } else { - ++UnmodifiedCalls; - } - - // Rewrite the call target so that we don't fault every time we execute it. - // - - static const unsigned o6 = SparcIntRegClass::o6; - - // Subtract enough to overwrite up to the 'save' instruction - // This depends on whether we made a short call (1 instruction) or the - // farCall (7 instructions) - uint64_t Offset = (LazyCallFlavor[CameFrom] == ShortCall) ? 4 : 28; - uint64_t CodeBegin = CameFrom - Offset; - - // FIXME FIXME FIXME FIXME: __builtin_frame_address doesn't work if frame - // pointer elimination has been performed. Having a variable sized alloca - // disables frame pointer elimination currently, even if it's dead. This is - // a gross hack. - alloca(42+Offset); - // FIXME FIXME FIXME FIXME - - // Make sure that what we're about to overwrite is indeed "save" - MachineInstr *SV =BuildMI(V9::SAVEi, 3).addReg(o6).addSImm(-192).addReg(o6); - unsigned SaveInst = TheJITResolver->getBinaryCodeForInstr(*SV); - delete SV; - unsigned CodeInMem = *(unsigned*)(intptr_t)CodeBegin; - if (CodeInMem != SaveInst) { - std::cerr << "About to overwrite smthg not a save instr!"; - abort(); - } - // Overwrite it - TheJITResolver->insertJumpAtAddr(Target, CodeBegin); - - // Flush the I-Cache: FLUSH clears out a doubleword at a given address - // Self-modifying code MUST clear out the I-Cache to be portable -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - for (int i = -Offset, e = 32-((int64_t)Offset); i < e; i += 8) - __asm__ __volatile__ ("flush %%i7 + %0" : : "r" (i)); -#endif - - // Change the return address to re-execute the restore, then the jump. - DEBUG(std::cerr << "Callback returning to: 0x" - << std::hex << (CameFrom-Offset-12) << "\n"); -#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) - __asm__ __volatile__ ("sub %%i7, %0, %%i7" : : "r" (Offset+12)); -#endif - - RestoreRegisters(DoubleFP, CC, Globals); -} - -/// emitStubForFunction - This method is used by the JIT when it needs to emit -/// the address of a function for a function whose code has not yet been -/// generated. In order to do this, it generates a stub which jumps to the lazy -/// function compiler, which will eventually get fixed to call the function -/// directly. -/// -uint64_t JITResolver::emitStubForFunction(Function *F) { - MCE.startFunctionStub(*F, 44); - - DEBUG(std::cerr << "Emitting stub at addr: 0x" - << std::hex << MCE.getCurrentPCValue() << "\n"); - - unsigned o6 = SparcIntRegClass::o6, g0 = SparcIntRegClass::g0; - - // restore %g0, 0, %g0 - MachineInstr *R = BuildMI(V9::RESTOREi, 3).addMReg(g0).addSImm(0) - .addMReg(g0, MachineOperand::Def); - SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*R)); - delete R; - - // save %sp, -192, %sp - MachineInstr *SV = BuildMI(V9::SAVEi, 3).addReg(o6).addSImm(-192).addReg(o6); - SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*SV)); - delete SV; - - int64_t CurrPC = MCE.getCurrentPCValue(); - int64_t Addr = (int64_t)addFunctionReference(CurrPC, F); - int64_t CallTarget = (Addr-CurrPC) >> 2; - if (CallTarget >= (1 << 29) || CallTarget <= -(1 << 29)) { - // Since this is a far call, the actual address of the call is shifted - // by the number of instructions it takes to calculate the exact address - deleteFunctionReference(CurrPC); - SparcV9.emitFarCall(Addr, F); - } else { - // call CallTarget ;; invoke the callback - MachineInstr *Call = BuildMI(V9::CALL, 1).addSImm(CallTarget); - SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*Call)); - delete Call; - - // nop ;; call delay slot - MachineInstr *Nop = BuildMI(V9::NOP, 0); - SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*Nop)); - delete Nop; - - addCallFlavor(CurrPC, ShortCall); - } - - SparcV9.emitWord(0xDEADBEEF); // marker so that we know it's really a stub - return (intptr_t)MCE.finishFunctionStub(*F)+4; /* 1 instr past the restore */ -} - -SparcV9CodeEmitter::SparcV9CodeEmitter(TargetMachine &tm, - MachineCodeEmitter &M): TM(tm), MCE(M) -{ - TheJITResolver = new JITResolver(*this, M); -} - -SparcV9CodeEmitter::~SparcV9CodeEmitter() { - delete TheJITResolver; -} - -void SparcV9CodeEmitter::emitWord(unsigned Val) { - // Output the constant in big endian byte order... - unsigned byteVal; - for (int i = 3; i >= 0; --i) { - byteVal = Val >> 8*i; - MCE.emitByte(byteVal & 255); - } -} - -unsigned -SparcV9CodeEmitter::getRealRegNum(unsigned fakeReg, - MachineInstr &MI) { - const TargetRegInfo &RI = TM.getRegInfo(); - unsigned regClass, regType = RI.getRegType(fakeReg); - // At least map fakeReg into its class - fakeReg = RI.getClassRegNum(fakeReg, regClass); - - switch (regClass) { - case SparcRegInfo::IntRegClassID: { - // Sparc manual, p31 - static const unsigned IntRegMap[] = { - // "o0", "o1", "o2", "o3", "o4", "o5", "o7", - 8, 9, 10, 11, 12, 13, 15, - // "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", - 16, 17, 18, 19, 20, 21, 22, 23, - // "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", - 24, 25, 26, 27, 28, 29, 30, 31, - // "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", - 0, 1, 2, 3, 4, 5, 6, 7, - // "o6" - 14 - }; - - return IntRegMap[fakeReg]; - break; - } - case SparcRegInfo::FloatRegClassID: { - DEBUG(std::cerr << "FP reg: " << fakeReg << "\n"); - if (regType == SparcRegInfo::FPSingleRegType) { - // only numbered 0-31, hence can already fit into 5 bits (and 6) - DEBUG(std::cerr << "FP single reg, returning: " << fakeReg << "\n"); - } else if (regType == SparcRegInfo::FPDoubleRegType) { - // FIXME: This assumes that we only have 5-bit register fields! - // From Sparc Manual, page 40. - // The bit layout becomes: b[4], b[3], b[2], b[1], b[5] - fakeReg |= (fakeReg >> 5) & 1; - fakeReg &= 0x1f; - DEBUG(std::cerr << "FP double reg, returning: " << fakeReg << "\n"); - } - return fakeReg; - } - case SparcRegInfo::IntCCRegClassID: { - /* xcc, icc, ccr */ - static const unsigned IntCCReg[] = { 6, 4, 2 }; - - assert(fakeReg < sizeof(IntCCReg)/sizeof(IntCCReg[0]) - && "CC register out of bounds for IntCCReg map"); - DEBUG(std::cerr << "IntCC reg: " << IntCCReg[fakeReg] << "\n"); - return IntCCReg[fakeReg]; - } - case SparcRegInfo::FloatCCRegClassID: { - /* These are laid out %fcc0 - %fcc3 => 0 - 3, so are correct */ - DEBUG(std::cerr << "FP CC reg: " << fakeReg << "\n"); - return fakeReg; - } - default: - assert(0 && "Invalid unified register number in getRegType"); - return fakeReg; - } -} - - -// WARNING: if the call used the delay slot to do meaningful work, that's not -// being accounted for, and the behavior will be incorrect!! -inline void SparcV9CodeEmitter::emitFarCall(uint64_t Target, Function *F) { - static const unsigned o6 = SparcIntRegClass::o6, - o7 = SparcIntRegClass::o7, g0 = SparcIntRegClass::g0, - g1 = SparcIntRegClass::g1, g5 = SparcIntRegClass::g5; - - MachineInstr* BinaryCode[] = { - // - // Get address to branch into %g1, using %g5 as a temporary - // - // sethi %uhi(Target), %g5 ;; get upper 22 bits of Target into %g5 - BuildMI(V9::SETHI, 2).addSImm(Target >> 42).addReg(g5), - // or %g5, %ulo(Target), %g5 ;; get 10 lower bits of upper word into %1 - BuildMI(V9::ORi, 3).addReg(g5).addSImm((Target >> 32) & 0x03ff).addReg(g5), - // sllx %g5, 32, %g5 ;; shift those 10 bits to the upper word - BuildMI(V9::SLLXi6, 3).addReg(g5).addSImm(32).addReg(g5), - // sethi %hi(Target), %g1 ;; extract bits 10-31 into the dest reg - BuildMI(V9::SETHI, 2).addSImm((Target >> 10) & 0x03fffff).addReg(g1), - // or %g5, %g1, %g1 ;; get upper word (in %g5) into %g1 - BuildMI(V9::ORr, 3).addReg(g5).addReg(g1).addReg(g1), - // or %g1, %lo(Target), %g1 ;; get lowest 10 bits of Target into %g1 - BuildMI(V9::ORi, 3).addReg(g1).addSImm(Target & 0x03ff).addReg(g1), - // jmpl %g1, %g0, %o7 ;; indirect call on %g1 - BuildMI(V9::JMPLRETr, 3).addReg(g1).addReg(g0).addReg(o7), - // nop ;; delay slot - BuildMI(V9::NOP, 0) - }; - - for (unsigned i=0, e=sizeof(BinaryCode)/sizeof(BinaryCode[0]); i!=e; ++i) { - // This is where we save the return address in the LazyResolverMap!! - if (i == 6 && F != 0) { // Do this right before the JMPL - uint64_t CurrPC = MCE.getCurrentPCValue(); - TheJITResolver->addFunctionReference(CurrPC, F); - // Remember that this is a far call, to subtract appropriate offset later - TheJITResolver->addCallFlavor(CurrPC, JITResolver::FarCall); - } - - emitWord(getBinaryCodeForInstr(*BinaryCode[i])); - delete BinaryCode[i]; - } -} - -void SparcJITInfo::replaceMachineCodeForFunction (void *Old, void *New) { - assert (TheJITResolver && - "Can only call replaceMachineCodeForFunction from within JIT"); - uint64_t Target = (uint64_t)(intptr_t)New; - uint64_t CodeBegin = (uint64_t)(intptr_t)Old; - TheJITResolver->insertJumpAtAddr(Target, CodeBegin); -} - -int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI, - MachineOperand &MO) { - int64_t rv = 0; // Return value; defaults to 0 for unhandled cases - // or things that get fixed up later by the JIT. - if (MO.isPCRelativeDisp()) { - DEBUG(std::cerr << "PCRelativeDisp: "); - Value *V = MO.getVRegValue(); - if (BasicBlock *BB = dyn_cast<BasicBlock>(V)) { - DEBUG(std::cerr << "Saving reference to BB (VReg)\n"); - unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue(); - BBRefs.push_back(std::make_pair(BB, std::make_pair(CurrPC, &MI))); - } else if (const Constant *C = dyn_cast<Constant>(V)) { - if (const ConstantInt *CI = dyn_cast<ConstantInt>(C)) { - rv = CI->getRawValue() - MCE.getCurrentPCValue(); - } else { - std::cerr << "Cannot have non-integral const in instruction: " - << *C; - abort(); - } - } else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) { - // same as MO.isGlobalAddress() - DEBUG(std::cerr << "GlobalValue: "); - // external function calls, etc.? - if (Function *F = dyn_cast<Function>(GV)) { - DEBUG(std::cerr << "Function: "); - // NOTE: This results in stubs being generated even for - // external, native functions, which is not optimal. See PR103. - rv = (int64_t)MCE.getGlobalValueAddress(F); - if (rv == 0) { - DEBUG(std::cerr << "not yet generated\n"); - // Function has not yet been code generated! - TheJITResolver->addFunctionReference(MCE.getCurrentPCValue(), F); - // Delayed resolution... - rv = TheJITResolver->getLazyResolver(F); - } else { - DEBUG(std::cerr << "already generated: 0x" << std::hex << rv << "\n"); - } - } else { - rv = (int64_t)MCE.getGlobalValueAddress(GV); - DEBUG(std::cerr << "Global addr: 0x" << std::hex << rv << "\n"); - } - // The real target of the call is Addr = PC + (rv * 4) - // So undo that: give the instruction (Addr - PC) / 4 - if (MI.getOpcode() == V9::CALL) { - int64_t CurrPC = MCE.getCurrentPCValue(); - DEBUG(std::cerr << "rv addr: 0x" << std::hex << rv << "\n" - << "curr PC: 0x" << std::hex << CurrPC << "\n"); - int64_t CallInstTarget = (rv - CurrPC) >> 2; - if (CallInstTarget >= (1<<29) || CallInstTarget <= -(1<<29)) { - DEBUG(std::cerr << "Making far call!\n"); - // address is out of bounds for the 30-bit call, - // make an indirect jump-and-link - emitFarCall(rv); - // this invalidates the instruction so that the call with an incorrect - // address will not be emitted - rv = 0; - } else { - // The call fits into 30 bits, so just return the corrected address - rv = CallInstTarget; - } - DEBUG(std::cerr << "returning addr: 0x" << rv << "\n"); - } - } else { - std::cerr << "ERROR: PC relative disp unhandled:" << MO << "\n"; - abort(); - } - } else if (MO.isRegister() || MO.getType() == MachineOperand::MO_CCRegister) - { - // This is necessary because the Sparc backend doesn't actually lay out - // registers in the real fashion -- it skips those that it chooses not to - // allocate, i.e. those that are the FP, SP, etc. - unsigned fakeReg = MO.getReg(); - unsigned realRegByClass = getRealRegNum(fakeReg, MI); - DEBUG(std::cerr << MO << ": Reg[" << std::dec << fakeReg << "] => " - << realRegByClass << " (LLC: " - << TM.getRegInfo().getUnifiedRegName(fakeReg) << ")\n"); - rv = realRegByClass; - } else if (MO.isImmediate()) { - rv = MO.getImmedValue(); - DEBUG(std::cerr << "immed: " << rv << "\n"); - } else if (MO.isGlobalAddress()) { - DEBUG(std::cerr << "GlobalAddress: not PC-relative\n"); - rv = (int64_t) - (intptr_t)getGlobalAddress(cast<GlobalValue>(MO.getVRegValue()), - MI, MO.isPCRelative()); - } else if (MO.isMachineBasicBlock()) { - // Duplicate code of the above case for VirtualRegister, BasicBlock... - // It should really hit this case, but Sparc backend uses VRegs instead - DEBUG(std::cerr << "Saving reference to MBB\n"); - const BasicBlock *BB = MO.getMachineBasicBlock()->getBasicBlock(); - unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue(); - BBRefs.push_back(std::make_pair(BB, std::make_pair(CurrPC, &MI))); - } else if (MO.isExternalSymbol()) { - // Sparc backend doesn't generate this (yet...) - std::cerr << "ERROR: External symbol unhandled: " << MO << "\n"; - abort(); - } else if (MO.isFrameIndex()) { - // Sparc backend doesn't generate this (yet...) - int FrameIndex = MO.getFrameIndex(); - std::cerr << "ERROR: Frame index unhandled.\n"; - abort(); - } else if (MO.isConstantPoolIndex()) { - unsigned Index = MO.getConstantPoolIndex(); - rv = MCE.getConstantPoolEntryAddress(Index); - } else { - std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n"; - abort(); - } - - // Finally, deal with the various bitfield-extracting functions that - // are used in SPARC assembly. (Some of these make no sense in combination - // with some of the above; we'll trust that the instruction selector - // will not produce nonsense, and not check for valid combinations here.) - if (MO.isLoBits32()) { // %lo(val) == %lo() in Sparc ABI doc - return rv & 0x03ff; - } else if (MO.isHiBits32()) { // %lm(val) == %hi() in Sparc ABI doc - return (rv >> 10) & 0x03fffff; - } else if (MO.isLoBits64()) { // %hm(val) == %ulo() in Sparc ABI doc - return (rv >> 32) & 0x03ff; - } else if (MO.isHiBits64()) { // %hh(val) == %uhi() in Sparc ABI doc - return rv >> 42; - } else { // (unadorned) val - return rv; - } -} - -unsigned SparcV9CodeEmitter::getValueBit(int64_t Val, unsigned bit) { - Val >>= bit; - return (Val & 1); -} - -bool SparcV9CodeEmitter::runOnMachineFunction(MachineFunction &MF) { - MCE.startFunction(MF); - DEBUG(std::cerr << "Starting function " << MF.getFunction()->getName() - << ", address: " << "0x" << std::hex - << (long)MCE.getCurrentPCValue() << "\n"); - - MCE.emitConstantPool(MF.getConstantPool()); - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - emitBasicBlock(*I); - MCE.finishFunction(MF); - - DEBUG(std::cerr << "Finishing fn " << MF.getFunction()->getName() << "\n"); - - // Resolve branches to BasicBlocks for the entire function - for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { - long Location = BBLocations[BBRefs[i].first]; - unsigned *Ref = BBRefs[i].second.first; - MachineInstr *MI = BBRefs[i].second.second; - DEBUG(std::cerr << "Fixup @ " << std::hex << Ref << " to 0x" << Location - << " in instr: " << std::dec << *MI); - for (unsigned ii = 0, ee = MI->getNumOperands(); ii != ee; ++ii) { - MachineOperand &op = MI->getOperand(ii); - if (op.isPCRelativeDisp()) { - // the instruction's branch target is made such that it branches to - // PC + (branchTarget * 4), so undo that arithmetic here: - // Location is the target of the branch - // Ref is the location of the instruction, and hence the PC - int64_t branchTarget = (Location - (long)Ref) >> 2; - // Save the flags. - bool loBits32=false, hiBits32=false, loBits64=false, hiBits64=false; - if (op.isLoBits32()) { loBits32=true; } - if (op.isHiBits32()) { hiBits32=true; } - if (op.isLoBits64()) { loBits64=true; } - if (op.isHiBits64()) { hiBits64=true; } - MI->SetMachineOperandConst(ii, MachineOperand::MO_SignExtendedImmed, - branchTarget); - if (loBits32) { MI->setOperandLo32(ii); } - else if (hiBits32) { MI->setOperandHi32(ii); } - else if (loBits64) { MI->setOperandLo64(ii); } - else if (hiBits64) { MI->setOperandHi64(ii); } - DEBUG(std::cerr << "Rewrote BB ref: "); - unsigned fixedInstr = SparcV9CodeEmitter::getBinaryCodeForInstr(*MI); - *Ref = fixedInstr; - break; - } - } - } - BBRefs.clear(); - BBLocations.clear(); - - return false; -} - -void SparcV9CodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { - currBB = MBB.getBasicBlock(); - BBLocations[currBB] = MCE.getCurrentPCValue(); - for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){ - unsigned binCode = getBinaryCodeForInstr(*I); - if (binCode == (1 << 30)) { - // this is an invalid call: the addr is out of bounds. that means a code - // sequence has already been emitted, and this is a no-op - DEBUG(std::cerr << "Call supressed: already emitted far call.\n"); - } else { - emitWord(binCode); - } - } -} - -void* SparcV9CodeEmitter::getGlobalAddress(GlobalValue *V, MachineInstr &MI, - bool isPCRelative) -{ - if (isPCRelative) { // must be a call, this is a major hack! - // Try looking up the function to see if it is already compiled! - if (void *Addr = (void*)(intptr_t)MCE.getGlobalValueAddress(V)) { - intptr_t CurByte = MCE.getCurrentPCValue(); - // The real target of the call is Addr = PC + (target * 4) - // CurByte is the PC, Addr we just received - return (void*) (((long)Addr - (long)CurByte) >> 2); - } else { - if (Function *F = dyn_cast<Function>(V)) { - // Function has not yet been code generated! - TheJITResolver->addFunctionReference(MCE.getCurrentPCValue(), - cast<Function>(V)); - // Delayed resolution... - return - (void*)(intptr_t)TheJITResolver->getLazyResolver(cast<Function>(V)); - } else { - std::cerr << "Unhandled global: " << *V << "\n"; - abort(); - } - } - } else { - return (void*)(intptr_t)MCE.getGlobalValueAddress(V); - } -} - -#include "SparcV9CodeEmitter.inc" - -} // End llvm namespace - diff --git a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h deleted file mode 100644 index d21345ec041..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h +++ /dev/null @@ -1,88 +0,0 @@ -//===-- SparcV9CodeEmitter.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// TODO: Need a description here. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCV9CODEEMITTER_H -#define SPARCV9CODEEMITTER_H - -#include "llvm/BasicBlock.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Target/TargetMachine.h" - -namespace llvm { - -class GlobalValue; -class MachineInstr; -class MachineOperand; - -class SparcV9CodeEmitter : public MachineFunctionPass { - TargetMachine &TM; - MachineCodeEmitter &MCE; - const BasicBlock *currBB; - - // Tracks which instruction references which BasicBlock - std::vector<std::pair<const BasicBlock*, - std::pair<unsigned*,MachineInstr*> > > BBRefs; - // Tracks where each BasicBlock starts - std::map<const BasicBlock*, long> BBLocations; - -public: - SparcV9CodeEmitter(TargetMachine &T, MachineCodeEmitter &M); - ~SparcV9CodeEmitter(); - - /// runOnMachineFunction - emits the given machine function to memory. - /// - bool runOnMachineFunction(MachineFunction &F); - - /// emitWord - writes out the given 32-bit value to memory at the current PC. - /// - void emitWord(unsigned Val); - - /// getBinaryCodeForInstr - This function, generated by the - /// CodeEmitterGenerator using TableGen, produces the binary encoding for - /// machine instructions. - /// - unsigned getBinaryCodeForInstr(MachineInstr &MI); - - /// emitFarCall - produces a code sequence to make a call to a destination - /// that does not fit in the 30 bits that a call instruction allows. - /// If the function F is non-null, this also saves the return address in - /// the LazyResolver map of the JITResolver. - void emitFarCall(uint64_t Addr, Function *F = 0); - -private: - /// getMachineOpValue - - /// - int64_t getMachineOpValue(MachineInstr &MI, MachineOperand &MO); - - /// emitBasicBlock - - /// - void emitBasicBlock(MachineBasicBlock &MBB); - - /// getValueBit - - /// - unsigned getValueBit(int64_t Val, unsigned bit); - - /// getGlobalAddress - - /// - void* getGlobalAddress(GlobalValue *V, MachineInstr &MI, - bool isPCRelative); - /// emitFarCall - - /// - unsigned getRealRegNum(unsigned fakeReg, MachineInstr &MI); - -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9FrameInfo.cpp b/llvm/lib/Target/Sparc/SparcV9FrameInfo.cpp deleted file mode 100644 index d283e942bb4..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9FrameInfo.cpp +++ /dev/null @@ -1,65 +0,0 @@ -//===-- Sparc.cpp - General implementation file for the Sparc Target ------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interface to stack frame layout info for the UltraSPARC. Starting offsets -// for each area of the stack frame are aligned at a multiple of -// getStackFrameSizeAlignment(). -// -//===----------------------------------------------------------------------===// - -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/Target/TargetFrameInfo.h" -#include "SparcFrameInfo.h" - -using namespace llvm; - -int -SparcFrameInfo::getFirstAutomaticVarOffset(MachineFunction&, bool& pos) const { - pos = false; // static stack area grows downwards - return StaticAreaOffsetFromFP; -} - -int -SparcFrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const -{ - // ensure no more auto vars are added - mcInfo.getInfo()->freezeAutomaticVarsArea(); - - pos = false; // static stack area grows downwards - unsigned autoVarsSize = mcInfo.getInfo()->getAutomaticVarsSize(); - return StaticAreaOffsetFromFP - autoVarsSize; -} - -int SparcFrameInfo::getTmpAreaOffset(MachineFunction& mcInfo, bool& pos) const { - MachineFunctionInfo *MFI = mcInfo.getInfo(); - MFI->freezeAutomaticVarsArea(); // ensure no more auto vars are added - MFI->freezeSpillsArea(); // ensure no more spill slots are added - - pos = false; // static stack area grows downwards - unsigned autoVarsSize = MFI->getAutomaticVarsSize(); - unsigned spillAreaSize = MFI->getRegSpillsSize(); - int offset = autoVarsSize + spillAreaSize; - return StaticAreaOffsetFromFP - offset; -} - -int -SparcFrameInfo::getDynamicAreaOffset(MachineFunction& mcInfo, bool& pos) const { - // Dynamic stack area grows downwards starting at top of opt-args area. - // The opt-args, required-args, and register-save areas are empty except - // during calls and traps, so they are shifted downwards on each - // dynamic-size alloca. - pos = false; - unsigned optArgsSize = mcInfo.getInfo()->getMaxOptionalArgsSize(); - if (int extra = optArgsSize % getStackFrameSizeAlignment()) - optArgsSize += (getStackFrameSizeAlignment() - extra); - int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP; - assert((offset - OFFSET) % getStackFrameSizeAlignment() == 0); - return offset; -} diff --git a/llvm/lib/Target/Sparc/SparcV9FrameInfo.h b/llvm/lib/Target/Sparc/SparcV9FrameInfo.h deleted file mode 100644 index 903859675ce..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9FrameInfo.h +++ /dev/null @@ -1,174 +0,0 @@ -//===-- SparcFrameInfo.h - Define TargetFrameInfo for Sparc -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interface to stack frame layout info for the UltraSPARC. -// Starting offsets for each area of the stack frame are aligned at -// a multiple of getStackFrameSizeAlignment(). -// -//---------------------------------------------------------------------------- - -#ifndef SPARC_FRAMEINFO_H -#define SPARC_FRAMEINFO_H - -#include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegInfo.h" - -namespace llvm { - -class SparcFrameInfo: public TargetFrameInfo { - const TargetMachine ⌖ -public: - SparcFrameInfo(const TargetMachine &TM) - : TargetFrameInfo(StackGrowsDown, StackFrameSizeAlignment, 0), target(TM) {} - -public: - // These methods provide constant parameters of the frame layout. - // - int getStackFrameSizeAlignment() const { return StackFrameSizeAlignment;} - int getMinStackFrameSize() const { return MinStackFrameSize; } - int getNumFixedOutgoingArgs() const { return NumFixedOutgoingArgs; } - int getSizeOfEachArgOnStack() const { return SizeOfEachArgOnStack; } - bool argsOnStackHaveFixedSize() const { return true; } - - // This method adjusts a stack offset to meet alignment rules of target. - // The fixed OFFSET (0x7ff) must be subtracted and the result aligned. - virtual int adjustAlignment(int unalignedOffset, bool growUp, - unsigned int align) const { - return unalignedOffset + (growUp? +1:-1)*((unalignedOffset-OFFSET) % align); - } - - // These methods compute offsets using the frame contents for a - // particular function. The frame contents are obtained from the - // MachineCodeInfoForMethod object for the given function. - // - int getFirstIncomingArgOffset(MachineFunction& mcInfo, bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstIncomingArgOffsetFromFP; - } - int getFirstOutgoingArgOffset(MachineFunction& mcInfo, bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstOutgoingArgOffsetFromSP; - } - int getFirstOptionalOutgoingArgOffset(MachineFunction& mcInfo, - bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstOptionalOutgoingArgOffsetFromSP; - } - - int getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const; - int getRegSpillAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - int getTmpAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - int getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - - // - // These methods specify the base register used for each stack area - // (generally FP or SP) - // - virtual int getIncomingArgBaseRegNum() const { - return (int) target.getRegInfo().getFramePointer(); - } - virtual int getOutgoingArgBaseRegNum() const { - return (int) target.getRegInfo().getStackPointer(); - } - virtual int getOptionalOutgoingArgBaseRegNum() const { - return (int) target.getRegInfo().getStackPointer(); - } - virtual int getAutomaticVarBaseRegNum() const { - return (int) target.getRegInfo().getFramePointer(); - } - virtual int getRegSpillAreaBaseRegNum() const { - return (int) target.getRegInfo().getFramePointer(); - } - virtual int getDynamicAreaBaseRegNum() const { - return (int) target.getRegInfo().getStackPointer(); - } - - virtual int getIncomingArgOffset(MachineFunction& mcInfo, - unsigned argNum) const { - assert(argsOnStackHaveFixedSize()); - - unsigned relativeOffset = argNum * getSizeOfEachArgOnStack(); - bool growUp; // do args grow up or down - int firstArg = getFirstIncomingArgOffset(mcInfo, growUp); - return growUp ? firstArg + relativeOffset : firstArg - relativeOffset; - } - - virtual int getOutgoingArgOffset(MachineFunction& mcInfo, - unsigned argNum) const { - assert(argsOnStackHaveFixedSize()); - //assert(((int) argNum - this->getNumFixedOutgoingArgs()) - // <= (int) mcInfo.getInfo()->getMaxOptionalNumArgs()); - - unsigned relativeOffset = argNum * getSizeOfEachArgOnStack(); - bool growUp; // do args grow up or down - int firstArg = getFirstOutgoingArgOffset(mcInfo, growUp); - return growUp ? firstArg + relativeOffset : firstArg - relativeOffset; - } - -private: - /*---------------------------------------------------------------------- - This diagram shows the stack frame layout used by llc on Sparc V9. - Note that only the location of automatic variables, spill area, - temporary storage, and dynamically allocated stack area are chosen - by us. The rest conform to the Sparc V9 ABI. - All stack addresses are offset by OFFSET = 0x7ff (2047). - - Alignment assumptions and other invariants: - (1) %sp+OFFSET and %fp+OFFSET are always aligned on 16-byte boundary - (2) Variables in automatic, spill, temporary, or dynamic regions - are aligned according to their size as in all memory accesses. - (3) Everything below the dynamically allocated stack area is only used - during a call to another function, so it is never needed when - the current function is active. This is why space can be allocated - dynamically by incrementing %sp any time within the function. - - STACK FRAME LAYOUT: - - ... - %fp+OFFSET+176 Optional extra incoming arguments# 1..N - %fp+OFFSET+168 Incoming argument #6 - ... ... - %fp+OFFSET+128 Incoming argument #1 - ... ... - ---%fp+OFFSET-0--------Bottom of caller's stack frame-------------------- - %fp+OFFSET-8 Automatic variables <-- ****TOP OF STACK FRAME**** - Spill area - Temporary storage - ... - - %sp+OFFSET+176+8N Bottom of dynamically allocated stack area - %sp+OFFSET+168+8N Optional extra outgoing argument# N - ... ... - %sp+OFFSET+176 Optional extra outgoing argument# 1 - %sp+OFFSET+168 Outgoing argument #6 - ... ... - %sp+OFFSET+128 Outgoing argument #1 - %sp+OFFSET+120 Save area for %i7 - ... ... - %sp+OFFSET+0 Save area for %l0 <-- ****BOTTOM OF STACK FRAME**** - - *----------------------------------------------------------------------*/ - - // All stack addresses must be offset by 0x7ff (2047) on Sparc V9. - static const int OFFSET = (int) 0x7ff; - static const int StackFrameSizeAlignment = 16; - static const int MinStackFrameSize = 176; - static const int NumFixedOutgoingArgs = 6; - static const int SizeOfEachArgOnStack = 8; - static const int FirstIncomingArgOffsetFromFP = 128 + OFFSET; - static const int FirstOptionalIncomingArgOffsetFromFP = 176 + OFFSET; - static const int StaticAreaOffsetFromFP = 0 + OFFSET; - static const int FirstOutgoingArgOffsetFromSP = 128 + OFFSET; - static const int FirstOptionalOutgoingArgOffsetFromSP = 176 + OFFSET; -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9InstrInfo.h b/llvm/lib/Target/Sparc/SparcV9InstrInfo.h deleted file mode 100644 index 0be2544c607..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9InstrInfo.h +++ /dev/null @@ -1,201 +0,0 @@ -//===-- SparcInstrInfo.h - Define TargetInstrInfo for Sparc -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class contains 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 TargetInstrInfo. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARC_INSTRINFO_H -#define SPARC_INSTRINFO_H - -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "SparcInternals.h" - -namespace llvm { - -struct SparcInstrInfo : public TargetInstrInfo { - SparcInstrInfo(); - - // All immediate constants are in position 1 except the - // store instructions and SETxx. - // - virtual int getImmedConstantPos(MachineOpCode opCode) const { - bool ignore; - if (this->maxImmedConstant(opCode, ignore) != 0) { - // 1st store opcode - assert(! this->isStore((MachineOpCode) V9::STBr - 1)); - // last store opcode - assert(! this->isStore((MachineOpCode) V9::STXFSRi + 1)); - - if (opCode == V9::SETSW || opCode == V9::SETUW || - opCode == V9::SETX || opCode == V9::SETHI) - return 0; - if (opCode >= V9::STBr && opCode <= V9::STXFSRi) - return 2; - return 1; - } - else - return -1; - } - - /// createNOPinstr - returns the target's implementation of NOP, which is - /// usually a pseudo-instruction, implemented by a degenerate version of - /// another instruction, e.g. X86: xchg ax, ax; SparcV9: sethi 0, g0 - /// - MachineInstr* createNOPinstr() const { - return BuildMI(V9::SETHI, 2).addZImm(0).addReg(SparcIntRegClass::g0); - } - - /// isNOPinstr - not having a special NOP opcode, we need to know if a given - /// instruction is interpreted as an `official' NOP instr, i.e., there may be - /// more than one way to `do nothing' but only one canonical way to slack off. - /// - bool isNOPinstr(const MachineInstr &MI) const { - // Make sure the instruction is EXACTLY `sethi g0, 0' - if (MI.getOpcode() == V9::SETHI && MI.getNumOperands() == 2) { - const MachineOperand &op0 = MI.getOperand(0), &op1 = MI.getOperand(1); - if (op0.isImmediate() && op0.getImmedValue() == 0 && - op1.getType() == MachineOperand::MO_MachineRegister && - op1.getMachineRegNum() == SparcIntRegClass::g0) - { - return true; - } - } - return false; - } - - virtual bool hasResultInterlock(MachineOpCode opCode) const - { - // All UltraSPARC instructions have interlocks (note that delay slots - // are not considered here). - // However, instructions that use the result of an FCMP produce a - // 9-cycle stall if they are issued less than 3 cycles after the FCMP. - // Force the compiler to insert a software interlock (i.e., gap of - // 2 other groups, including NOPs if necessary). - return (opCode == V9::FCMPS || opCode == V9::FCMPD || opCode == V9::FCMPQ); - } - - //------------------------------------------------------------------------- - // Queries about representation of LLVM quantities (e.g., constants) - //------------------------------------------------------------------------- - - virtual bool ConstantMayNotFitInImmedField(const Constant* CV, - const Instruction* I) const; - - //------------------------------------------------------------------------- - // Code generation support for creating individual machine instructions - //------------------------------------------------------------------------- - - // Get certain common op codes for the current target. This and all the - // Create* methods below should be moved to a machine code generation class - // - virtual MachineOpCode getNOPOpCode() const { return V9::NOP; } - - // Get the value of an integral constant in the form that must - // be put into the machine register. The specified constant is interpreted - // as (i.e., converted if necessary to) the specified destination type. The - // result is always returned as an uint64_t, since the representation of - // int64_t and uint64_t are identical. The argument can be any known const. - // - // isValidConstant is set to true if a valid constant was found. - // - virtual uint64_t ConvertConstantToIntType(const TargetMachine &target, - const Value *V, - const Type *destType, - bool &isValidConstant) const; - - // 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 `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateCodeToLoadConst(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; - - // 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 `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateCodeToCopyIntToFloat(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; - - // Similarly, create an instruction sequence to copy an FP value - // `val' to an integer value `dest' by copying to memory and back. - // The generated instructions are returned in `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateCodeToCopyFloatToInt(const TargetMachine& target, - Function* F, - Value* val, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; - - // Create instruction(s) to copy src to dest, for arbitrary types - // The generated instructions are returned in `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateCopyInstructionsByType(const TargetMachine& target, - Function* F, - Value* src, - Instruction* dest, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; - - // Create instruction sequence to produce a sign-extended register value - // from an arbitrary sized value (sized in bits, not bytes). - // The generated instructions are appended to `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateSignExtensionInstructions(const TargetMachine& target, - Function* F, - Value* srcVal, - Value* destVal, - unsigned int numLowBits, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; - - // Create instruction sequence to produce a zero-extended register value - // from an arbitrary sized value (sized in bits, not bytes). - // The generated instructions are appended to `mvec'. - // Any temp. registers (TmpInstruction) created are recorded in mcfi. - // Any stack space required is allocated via mcff. - // - virtual void CreateZeroExtensionInstructions(const TargetMachine& target, - Function* F, - Value* srcVal, - Value* destVal, - unsigned int numLowBits, - std::vector<MachineInstr*>& mvec, - MachineCodeForInstruction& mcfi) const; -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9JITInfo.h b/llvm/lib/Target/Sparc/SparcV9JITInfo.h deleted file mode 100644 index b667c5599e4..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9JITInfo.h +++ /dev/null @@ -1,48 +0,0 @@ -//===- SparcJITInfo.h - Sparc implementation of the JIT interface -*-C++-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the Sparc implementation of the TargetJITInfo class. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCJITINFO_H -#define SPARCJITINFO_H - -#include "llvm/Target/TargetJITInfo.h" - -namespace llvm { - class TargetMachine; - - class SparcJITInfo : public TargetJITInfo { - TargetMachine &TM; - public: - SparcJITInfo(TargetMachine &tm) : TM(tm) {} - - /// addPassesToJITCompile - Add passes to the specified pass manager to - /// implement a fast dynamic compiler for this target. Return true if this - /// is not supported for this target. - /// - virtual void addPassesToJITCompile(FunctionPassManager &PM); - - /// replaceMachineCodeForFunction - Make it so that calling the function - /// whose machine code is at OLD turns into a call to NEW, perhaps by - /// overwriting OLD with a branch to NEW. This is used for self-modifying - /// code. - /// - virtual void replaceMachineCodeForFunction (void *Old, void *New); - - /// getJITStubForFunction - Create or return a stub for the specified - /// function. This stub acts just like the specified function, except that - /// it allows the "address" of the function to be taken without having to - /// generate code for it. - //virtual void *getJITStubForFunction(Function *F, MachineCodeEmitter &MCE); - }; -} - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9RegInfo.h b/llvm/lib/Target/Sparc/SparcV9RegInfo.h deleted file mode 100644 index 3dd9e683e03..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9RegInfo.h +++ /dev/null @@ -1,193 +0,0 @@ -//===-- SparcRegInfo.h - Define TargetRegInfo for Sparc ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class implements the virtual class TargetRegInfo for Sparc. -// -//---------------------------------------------------------------------------- - -#ifndef SPARC_REGINFO_H -#define SPARC_REGINFO_H - -#include "llvm/Target/TargetRegInfo.h" - -namespace llvm { - -class SparcTargetMachine; - -class SparcRegInfo : public TargetRegInfo { - -private: - - // Number of registers used for passing int args (usually 6: %o0 - %o5) - // - unsigned const NumOfIntArgRegs; - - // Number of registers used for passing float args (usually 32: %f0 - %f31) - // - unsigned const NumOfFloatArgRegs; - - // The following methods are used to color special live ranges (e.g. - // function args and return values etc.) with specific hardware registers - // as required. See SparcRegInfo.cpp for the implementation. - // - void suggestReg4RetAddr(MachineInstr *RetMI, - LiveRangeInfo &LRI) const; - - void suggestReg4CallAddr(MachineInstr *CallMI, LiveRangeInfo &LRI) const; - - // Helper used by the all the getRegType() functions. - int getRegTypeForClassAndType(unsigned regClassID, const Type* type) const; - -public: - // Type of registers available in Sparc. There can be several reg types - // in the same class. For instace, the float reg class has Single/Double - // types - // - enum RegTypes { - IntRegType, - FPSingleRegType, - FPDoubleRegType, - IntCCRegType, - FloatCCRegType, - SpecialRegType - }; - - // The actual register classes in the Sparc - // - // **** WARNING: If this enum order is changed, also modify - // getRegisterClassOfValue method below since it assumes this particular - // order for efficiency. - // - enum RegClassIDs { - IntRegClassID, // Integer - FloatRegClassID, // Float (both single/double) - IntCCRegClassID, // Int Condition Code - FloatCCRegClassID, // Float Condition code - SpecialRegClassID // Special (unallocated) registers - }; - - SparcRegInfo(const SparcTargetMachine &tgt); - - // To find the register class used for a specified Type - // - unsigned getRegClassIDOfType(const Type *type, - bool isCCReg = false) const; - - // To find the register class to which a specified register belongs - // - unsigned getRegClassIDOfRegType(int regType) const; - - // getZeroRegNum - returns the register that contains always zero this is the - // unified register number - // - virtual unsigned getZeroRegNum() const; - - // getCallAddressReg - returns the reg used for pushing the address when a - // function is called. This can be used for other purposes between calls - // - unsigned getCallAddressReg() const; - - // Returns the register containing the return address. - // It should be made sure that this register contains the return - // value when a return instruction is reached. - // - unsigned getReturnAddressReg() const; - - // Number of registers used for passing int args (usually 6: %o0 - %o5) - // and float args (usually 32: %f0 - %f31) - // - unsigned const getNumOfIntArgRegs() const { return NumOfIntArgRegs; } - unsigned const getNumOfFloatArgRegs() const { return NumOfFloatArgRegs; } - - // Compute which register can be used for an argument, if any - // - int regNumForIntArg(bool inCallee, bool isVarArgsCall, - unsigned argNo, unsigned& regClassId) const; - - int regNumForFPArg(unsigned RegType, bool inCallee, bool isVarArgsCall, - unsigned argNo, unsigned& regClassId) const; - - // The following methods are used to color special live ranges (e.g. - // function args and return values etc.) with specific hardware registers - // as required. See SparcRegInfo.cpp for the implementation for Sparc. - // - void suggestRegs4MethodArgs(const Function *Meth, - LiveRangeInfo& LRI) const; - - void suggestRegs4CallArgs(MachineInstr *CallMI, - LiveRangeInfo& LRI) const; - - void suggestReg4RetValue(MachineInstr *RetMI, - LiveRangeInfo& LRI) const; - - void colorMethodArgs(const Function *Meth, LiveRangeInfo& LRI, - std::vector<MachineInstr*>& InstrnsBefore, - std::vector<MachineInstr*>& InstrnsAfter) const; - - // method used for printing a register for debugging purposes - // - void printReg(const LiveRange *LR) const; - - // returns the # of bytes of stack space allocated for each register - // type. For Sparc, currently we allocate 8 bytes on stack for all - // register types. We can optimize this later if necessary to save stack - // space (However, should make sure that stack alignment is correct) - // - inline int getSpilledRegSize(int RegType) const { - return 8; - } - - // To obtain the return value and the indirect call address (if any) - // contained in a CALL machine instruction - // - const Value * getCallInstRetVal(const MachineInstr *CallMI) const; - const Value * getCallInstIndirectAddrVal(const MachineInstr *CallMI) const; - - // The following methods are used to generate "copy" machine instructions - // for an architecture. - // - // The function regTypeNeedsScratchReg() can be used to check whether a - // scratch register is needed to copy a register of type `regType' to - // or from memory. If so, such a scratch register can be provided by - // the caller (e.g., if it knows which regsiters are free); otherwise - // an arbitrary one will be chosen and spilled by the copy instructions. - // - bool regTypeNeedsScratchReg(int RegType, - int& scratchRegClassId) const; - - void cpReg2RegMI(std::vector<MachineInstr*>& mvec, - unsigned SrcReg, unsigned DestReg, - int RegType) const; - - void cpReg2MemMI(std::vector<MachineInstr*>& mvec, - unsigned SrcReg, unsigned DestPtrReg, - int Offset, int RegType, int scratchReg = -1) const; - - void cpMem2RegMI(std::vector<MachineInstr*>& mvec, - unsigned SrcPtrReg, int Offset, unsigned DestReg, - int RegType, int scratchReg = -1) const; - - void cpValue2Value(Value *Src, Value *Dest, - std::vector<MachineInstr*>& mvec) const; - - // Get the register type for a register identified different ways. - // Note that getRegTypeForLR(LR) != getRegTypeForDataType(LR->getType())! - // The reg class of a LR depends both on the Value types in it and whether - // they are CC registers or not (for example). - int getRegTypeForDataType(const Type* type) const; - int getRegTypeForLR(const LiveRange *LR) const; - int getRegType(int unifiedRegNum) const; - - virtual unsigned getFramePointer() const; - virtual unsigned getStackPointer() const; -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9TargetMachine.h b/llvm/lib/Target/Sparc/SparcV9TargetMachine.h deleted file mode 100644 index be50174de72..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9TargetMachine.h +++ /dev/null @@ -1,52 +0,0 @@ -//===-- SparcTargetMachine.h - Define TargetMachine for Sparc ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the top-level UltraSPARC target machine. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARC_TARGETMACHINE_H -#define SPARC_TARGETMACHINE_H - -#include "llvm/Target/TargetFrameInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "SparcInstrInfo.h" -#include "SparcInternals.h" -#include "SparcRegInfo.h" -#include "SparcFrameInfo.h" -#include "SparcJITInfo.h" - -namespace llvm { - class PassManager; - -class SparcTargetMachine : public TargetMachine { - SparcInstrInfo instrInfo; - SparcSchedInfo schedInfo; - SparcRegInfo regInfo; - SparcFrameInfo frameInfo; - SparcCacheInfo cacheInfo; - SparcJITInfo jitInfo; -public: - SparcTargetMachine(IntrinsicLowering *IL); - - virtual const TargetInstrInfo &getInstrInfo() const { return instrInfo; } - virtual const TargetSchedInfo &getSchedInfo() const { return schedInfo; } - virtual const TargetRegInfo &getRegInfo() const { return regInfo; } - virtual const TargetFrameInfo &getFrameInfo() const { return frameInfo; } - virtual const TargetCacheInfo &getCacheInfo() const { return cacheInfo; } - virtual TargetJITInfo *getJITInfo() { return &jitInfo; } - - virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); - virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, - MachineCodeEmitter &MCE); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/lib/Target/Sparc/SparcV9_F2.td b/llvm/lib/Target/Sparc/SparcV9_F2.td deleted file mode 100644 index cfaf5d87a95..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9_F2.td +++ /dev/null @@ -1,71 +0,0 @@ -//===- SparcV9_F2.td - Format 2 instructions: Sparc V9 Target -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Format #2 classes -// -class F2 : InstV9 { // Format 2 instructions - bits<3> op2; - let op = 0; // Op = 0 - let Inst{24-22} = op2; -} - -// Format 2.1 instructions -class F2_1<string name> : F2 { - bits<22> imm; - bits<5> rd; - - let Name = name; - let Inst{29-25} = rd; - let Inst{21-0} = imm; -} - -class F2_br : F2 { // Format 2 Branch instruction - let isBranch = 1; // All instances are branch instructions -} - -class F2_2<bits<4> cond, string name> : F2_br { // Format 2.2 instructions - bits<22> disp; - bit annul = 0; // currently unused by Sparc backend - - let Name = name; - let Inst{29} = annul; - let Inst{28-25} = cond; - let Inst{21-0} = disp; -} - -class F2_3<bits<4> cond, string name> : F2_br { // Format 2.3 instructions - bits<2> cc; - bits<19> disp; - bit predict = 1; - bit annul = 0; // currently unused by Sparc backend - - let Name = name; - let Inst{29} = annul; - let Inst{28-25} = cond; - let Inst{21-20} = cc; - let Inst{19} = predict; - let Inst{18-0} = disp; -} - -class F2_4<bits<3> rcond, string name> : F2_br { // Format 2.4 instructions - bits<5> rs1; - bits<16> disp; - bit predict = 1; - bit annul = 0; // currently unused by Sparc backend - - let Name = name; - let Inst{29} = annul; - let Inst{28} = 0; - let Inst{27-25} = rcond; - let Inst{21-20} = disp{15-14}; - let Inst{19} = predict; - let Inst{18-14} = rs1; - let Inst{13-0 } = disp{13-0}; -} diff --git a/llvm/lib/Target/Sparc/SparcV9_F3.td b/llvm/lib/Target/Sparc/SparcV9_F3.td deleted file mode 100644 index 718b0dea064..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9_F3.td +++ /dev/null @@ -1,267 +0,0 @@ -//===- SparcV9_F3.td - Format 3 Instructions: Sparc V9 Target -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Format #3 classes -// - -// F3 - Common superclass of all F3 instructions. All instructions have an op3 -// field. -class F3 : InstV9 { - bits<6> op3; - let op{1} = 1; // Op = 2 or 3 - let Inst{24-19} = op3; -} - -// F3_rs1 - Common class of instructions that have an rs1 field -class F3_rs1 : F3 { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields -class F3_rs1rs2 : F3_rs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F3_rs1rs2 - Common class of instructions that only have rs1 and rs2 fields -class F3_rs1rs2rd : F3_rs1rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs1simm13 - Common class of instructions that only have rs1 and simm13 -class F3_rs1simm13 : F3_rs1 { - bits<13> simm13; - let Inst{12-0} = simm13; -} - -class F3_rs1simm13rd : F3_rs1simm13 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs1rd - Common class of instructions that have an rs1 and rd fields -class F3_rs1rd : F3_rs1 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rs2 - Common class of instructions that don't use an rs1 -class F3_rs2 : F3 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F3_rs2rd - Common class of instructions that use rs2 and rd, but not rs1 -class F3_rs2rd : F3_rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rd - Common class of instructions that have an rd field -class F3_rd : F3 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F3_rdrs1 - Common class of instructions that have rd and rs1 fields -class F3_rdrs1 : F3_rd { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F3_rdrs1simm13 - Common class of instructions that have rd, rs1, and simm13 -class F3_rdrs1simm13 : F3_rdrs1 { - bits<13> simm13; - let Inst{12-0} = simm13; -} - -// F3_rdrs1rs2 - Common class of instructions that have rd, rs1, and rs2 fields -class F3_rdrs1rs2 : F3_rdrs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - - -// Specific F3 classes... -// - -class F3_1<bits<2> opVal, bits<6> op3val, string name> : F3_rs1rs2rd { - let op = opVal; - let op3 = op3val; - let Name = name; - let Inst{13} = 0; // i field = 0 - let Inst{12-5} = 0; // don't care -} - -// The store instructions seem to like to see rd first, then rs1 and rs2 -class F3_1rd<bits<2> opVal, bits<6> op3val, string name> : F3_rdrs1rs2 { - let op = opVal; - let op3 = op3val; - let Name = name; - let Inst{13} = 0; // i field = 0 - let Inst{12-5} = 0; // don't care -} - -class F3_2<bits<2> opVal, bits<6> op3val, string name> : F3_rs1simm13rd { - let op = opVal; - let op3 = op3val; - let Name = name; - let Inst{13} = 1; // i field = 1 -} - -// The store instructions seem to like to see rd first, then rs1 and imm -class F3_2rd<bits<2> opVal, bits<6> op3val, string name> : F3_rdrs1simm13 { - let op = opVal; - let op3 = op3val; - let Name = name; - let Inst{13} = 1; // i field = 1 -} - -class F3_3<bits<2> opVal, bits<6> op3val, string name> : F3_rs1rs2 { - let op = opVal; - let op3 = op3val; - let Name = name; - let Inst{29-25} = 0; // don't care - let Inst{13} = 0; // i field = 0 - let Inst{12-5} = 0; // don't care -} - -class F3_4<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1simm13 { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{29-25} = 0; // don't care - let Inst{13} = 1; // i field = 1 - let Inst{12-0} = simm13; -} - -class F3_5<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal, - string name> : F3_rs1rs2rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13} = 0; // i field = 0 - let Inst{12-10} = rcondVal; // rcond field - let Inst{9-5} = 0; // don't care -} - -class F3_6<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal, - string name> : F3_rs1 { - bits<10> simm10; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{29-25} = rd; - let Inst{13} = 1; // i field = 1 - let Inst{12-10} = rcondVal; // rcond field - let Inst{9-0} = simm10; -} - -//FIXME: classes 7-10 not defined!! - -class F3_11<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1rs2rd { - bit x; - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13} = 0; // i field = 0 - let Inst{12} = x; - let Inst{11-5} = 0; // don't care -} - -class F3_12<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1 { - bits<5> shcnt; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{29-25} = rd; - let Inst{13} = 1; // i field = 1 - let Inst{12} = 0; // x field = 0 - let Inst{11-5} = 0; // don't care - let Inst{4-0} = shcnt; -} - -class F3_13<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1 { - bits<6> shcnt; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{29-25} = rd; - let Inst{13} = 1; // i field = 1 - let Inst{12} = 1; // x field = 1 - let Inst{11-6} = 0; // don't care - let Inst{5-0} = shcnt; -} - -class F3_14<bits<2> opVal, bits<6> op3Val, - bits<9> opfVal, string name> : F3_rs2rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{18-14} = 0; // don't care - let Inst{13-5} = opfVal; -} - -class F3_15<bits<2> opVal, bits<6> op3Val, - bits<9> opfVal, string name> : F3 { - bits<2> cc; - bits<5> rs1; - bits<5> rs2; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{29-27} = 0; // defined to be zero - let Inst{26-25} = cc; - let Inst{18-14} = rs1; - let Inst{13-5} = opfVal; - let Inst{4-0} = rs2; -} - -class F3_16<bits<2> opVal, bits<6> op3Val, - bits<9> opfval, string name> : F3_rs1rs2rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13-5} = opfval; -} - -class F3_17<bits<2> opVal, bits<6> op3Val, string name> : F3_rs1rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13-0} = 0; // don't care -} - -class F3_18<bits<5> fcn, string name> : F3 { - let op = 2; - let op3 = 0b111110; - let Name = name; - let Inst{29-25} = fcn; - let Inst{18-0 } = 0; // don't care; -} - -class F3_19<bits<2> opVal, bits<6> op3Val, string name> : F3_rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{18-0} = 0; // don't care -} - -// FIXME: class F3_20 -// FIXME: class F3_21 diff --git a/llvm/lib/Target/Sparc/SparcV9_F4.td b/llvm/lib/Target/Sparc/SparcV9_F4.td deleted file mode 100644 index 19e52e108a2..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9_F4.td +++ /dev/null @@ -1,141 +0,0 @@ -//===- SparcV9_F4.td - Format 4 instructions: Sparc V9 Target -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//----------------------- F4 classes ----------------------------------------- - -// F4 - Common superclass of all F4 instructions. All instructions have an op3 -// field. -class F4 : InstV9 { - bits<6> op3; - let Inst{24-19} = op3; -} - -// F4_rs1 - Common class of instructions that use an rs1 field -class F4_rs1 : F4 { - bits<5> rs1; - let Inst{18-14} = rs1; -} - -// F4_rs1rs2 - Common class of instructions that have rs1 and rs2 fields -class F4_rs1rs2 : F4_rs1 { - bits<5> rs2; - let Inst{4-0} = rs2; -} - -// F4_rs1rs2rd - Common class of instructions that have 3 register operands -class F4_rs1rs2rd : F4_rs1rs2 { - bits<5> rd; - let Inst{29-25} = rd; -} - -// F4_rs1rs2rd - Common class of instructions that have 2 reg and 1 imm operand -class F4_rs1simm11rd : F4_rs1 { - bits<11> simm11; - bits<5> rd; - - let Inst{10-0} = simm11; - let Inst{29-25} = rd; -} - -// F4_cc - Common class of instructions that have a cond field -class F4_cond : F4 { - bits<4> cond; - let Inst{17-14} = cond; -} - -// F4_cc - Common class of instructions that have cc register as first operand -class F4_condcc : F4_cond { - bits<3> cc; - let Inst{18} = cc{2}; - let Inst{12} = cc{1}; - let Inst{11} = cc{0}; -} - -// Actual F4 instruction classes -// -class F4_1<bits<2> opVal, bits<6> op3Val, string name> : F4_rs1rs2rd { - bits<2> cc; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13} = 0; // i bit - let Inst{12-11} = cc; - let Inst{10-5} = 0; // don't care -} - -class F4_2<bits<2> opVal, bits<6> op3Val, string name> : F4_rs1simm11rd { - bits<2> cc; - - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13} = 1; // i bit - let Inst{12-11} = cc; -} - -class F4_3<bits<2> opVal, bits<6> op3Val, bits<4> condVal, - string name> : F4_condcc { - bits<5> rs2; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let cond = condVal; - let Name = name; - let Inst{29-25} = rd; - let Inst{13} = 0; // i bit - let Inst{10-5} = 0; // don't care - let Inst{4-0} = rs2; -} - -class F4_4<bits<2> opVal, bits<6> op3Val, bits<4> condVal, - string name> : F4_condcc { - bits<11> simm11; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let cond = condVal; - let Name = name; - let Inst{29-25} = rd; - let Inst{13} = 1; // i bit - let Inst{10-0} = simm11; -} - -// FIXME: class F4_5 - -class F4_6<bits<2> opVal, bits<6> op3Val, bits<3> rcondVal, - bits<5> opf_lowVal, string name> : F4_rs1rs2rd { - let op = opVal; - let op3 = op3Val; - let Name = name; - let Inst{13} = 0; - let Inst{12-10} = rcondVal; - let Inst{9-5} = opf_lowVal; -} - -class F4_7<bits<2> opVal, bits<6> op3Val, bits<4> condVal, - bits<6> opf_lowVal, string name> : F4_cond { - bits<3> cc; - bits<5> rs2; - bits<5> rd; - - let op = opVal; - let op3 = op3Val; - let cond = condVal; - let Name = name; - let Inst{29-25} = rd; - let Inst{18} = 0; - let Inst{13-11} = cc; - let Inst{10-5} = opf_lowVal; - let Inst{4-0} = rs2; -} - -// FIXME: F4 classes 8-9 diff --git a/llvm/lib/Target/Sparc/SparcV9_Reg.td b/llvm/lib/Target/Sparc/SparcV9_Reg.td deleted file mode 100644 index 6d5ad1d55a0..00000000000 --- a/llvm/lib/Target/Sparc/SparcV9_Reg.td +++ /dev/null @@ -1,41 +0,0 @@ -//===- SparcV9_Reg.td - Sparc V9 Register definitions ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// Declarations that describe the Sparc register file -//===----------------------------------------------------------------------===// - -// Ri - One of the 32 64 bit integer registers -class Ri<bits<5> num> : Register { - field bits<5> Num = num; // Numbers are identified with a 5 bit ID -} - -let Namespace = "SparcV9" in { - def G0 : Ri< 0>; def G1 : Ri< 1>; def G2 : Ri< 2>; def G3 : Ri< 3>; - def G4 : Ri< 4>; def G5 : Ri< 5>; def G6 : Ri< 6>; def G7 : Ri< 7>; - def O0 : Ri< 8>; def O1 : Ri< 9>; def O2 : Ri<10>; def O3 : Ri<11>; - def O4 : Ri<12>; def O5 : Ri<13>; def O6 : Ri<14>; def O7 : Ri<15>; - def L0 : Ri<16>; def L1 : Ri<17>; def L2 : Ri<18>; def L3 : Ri<19>; - def L4 : Ri<20>; def L5 : Ri<21>; def L6 : Ri<22>; def L7 : Ri<23>; - def I0 : Ri<24>; def I1 : Ri<25>; def I2 : Ri<26>; def I3 : Ri<27>; - def I4 : Ri<28>; def I5 : Ri<29>; def I6 : Ri<30>; def I7 : Ri<31>; - // Floating-point registers? - // ... -} - - -// For fun, specify a register class. -// -// FIXME: the register order should be defined in terms of the preferred -// allocation order... -// -def IntRegs : RegisterClass<i64, 8, [G0, G1, G2, G3, G4, G5, G6, G7, - O0, O1, O2, O3, O4, O5, O6, O7, - L0, L1, L2, L3, L4, L5, L6, L7, - I0, I1, I2, I3, I4, I5, I6, I7]>; diff --git a/llvm/lib/Target/Sparc/StackSlots.cpp b/llvm/lib/Target/Sparc/StackSlots.cpp deleted file mode 100644 index 5fd0ba19271..00000000000 --- a/llvm/lib/Target/Sparc/StackSlots.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===- StackSlots.cpp - Specialize LLVM code for target machine ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass adds 2 empty slots at the top of function stack. These two slots -// are later used during code reoptimization for spilling the register values -// when rewriting branches. -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" -#include "llvm/Constant.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/CodeGen/MachineFunctionInfo.h" -#include "llvm/CodeGen/MachineFunctionPass.h" - -namespace llvm { - -namespace { - class StackSlots : public MachineFunctionPass { - const TargetMachine &Target; - public: - StackSlots(const TargetMachine &T) : Target(T) {} - - const char *getPassName() const { - return "Stack Slot Insertion for profiling code"; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - } - - bool runOnMachineFunction(MachineFunction &MF) { - const Type *PtrInt = PointerType::get(Type::IntTy); - unsigned Size = Target.getTargetData().getTypeSize(PtrInt); - - Value *V = Constant::getNullValue(Type::IntTy); - MF.getInfo()->allocateLocalVar(V, 2*Size); - return true; - } - }; -} - -Pass *createStackSlotsPass(const TargetMachine &Target) { - return new StackSlots(Target); -} - -} // End llvm namespace diff --git a/llvm/lib/Target/Sparc/UltraSparcSchedInfo.cpp b/llvm/lib/Target/Sparc/UltraSparcSchedInfo.cpp deleted file mode 100644 index 016587458ba..00000000000 --- a/llvm/lib/Target/Sparc/UltraSparcSchedInfo.cpp +++ /dev/null @@ -1,773 +0,0 @@ -//===-- UltraSparcSchedInfo.cpp -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Describe the scheduling characteristics of the UltraSparc -// -//===----------------------------------------------------------------------===// - -#include "SparcInternals.h" - -using namespace llvm; - -/*--------------------------------------------------------------------------- -Scheduling guidelines for SPARC IIi: - -I-Cache alignment rules (pg 326) --- Align a branch target instruction so that it's entire group is within - the same cache line (may be 1-4 instructions). -** Don't let a branch that is predicted taken be the last instruction - on an I-cache line: delay slot will need an entire line to be fetched --- Make a FP instruction or a branch be the 4th instruction in a group. - For branches, there are tradeoffs in reordering to make this happen - (see pg. 327). -** Don't put a branch in a group that crosses a 32-byte boundary! - An artificial branch is inserted after every 32 bytes, and having - another branch will force the group to be broken into 2 groups. - -iTLB rules: --- Don't let a loop span two memory pages, if possible - -Branch prediction performance: --- Don't make the branch in a delay slot the target of a branch --- Try not to have 2 predicted branches within a group of 4 instructions - (because each such group has a single branch target field). --- Try to align branches in slots 0, 2, 4 or 6 of a cache line (to avoid - the wrong prediction bits being used in some cases). - -D-Cache timing constraints: --- Signed int loads of less than 64 bits have 3 cycle latency, not 2 --- All other loads that hit in D-Cache have 2 cycle latency --- All loads are returned IN ORDER, so a D-Cache miss will delay a later hit --- Mis-aligned loads or stores cause a trap. In particular, replace - mis-aligned FP double precision l/s with 2 single-precision l/s. --- Simulations of integer codes show increase in avg. group size of - 33% when code (including esp. non-faulting loads) is moved across - one branch, and 50% across 2 branches. - -E-Cache timing constraints: --- Scheduling for E-cache (D-Cache misses) is effective (due to load buffering) - -Store buffer timing constraints: --- Stores can be executed in same cycle as instruction producing the value --- Stores are buffered and have lower priority for E-cache until - highwater mark is reached in the store buffer (5 stores) - -Pipeline constraints: --- Shifts can only use IEU0. --- CC setting instructions can only use IEU1. --- Several other instructions must only use IEU1: - EDGE(?), ARRAY(?), CALL, JMPL, BPr, PST, and FCMP. --- Two instructions cannot store to the same register file in a single cycle - (single write port per file). - -Issue and grouping constraints: --- FP and branch instructions must use slot 4. --- Shift instructions cannot be grouped with other IEU0-specific instructions. --- CC setting instructions cannot be grouped with other IEU1-specific instrs. --- Several instructions must be issued in a single-instruction group: - MOVcc or MOVr, MULs/x and DIVs/x, SAVE/RESTORE, many others --- A CALL or JMPL breaks a group, ie, is not combined with subsequent instrs. --- --- - -Branch delay slot scheduling rules: --- A CTI couple (two back-to-back CTI instructions in the dynamic stream) - has a 9-instruction penalty: the entire pipeline is flushed when the - second instruction reaches stage 9 (W-Writeback). --- Avoid putting multicycle instructions, and instructions that may cause - load misses, in the delay slot of an annulling branch. --- Avoid putting WR, SAVE..., RESTORE and RETURN instructions in the - delay slot of an annulling branch. - - *--------------------------------------------------------------------------- */ - -//--------------------------------------------------------------------------- -// List of CPUResources for UltraSPARC IIi. -//--------------------------------------------------------------------------- - -static const CPUResource AllIssueSlots( "All Instr Slots", 4); -static const CPUResource IntIssueSlots( "Int Instr Slots", 3); -static const CPUResource First3IssueSlots("Instr Slots 0-3", 3); -static const CPUResource LSIssueSlots( "Load-Store Instr Slot", 1); -static const CPUResource CTIIssueSlots( "Ctrl Transfer Instr Slot", 1); -static const CPUResource FPAIssueSlots( "FP Instr Slot 1", 1); -static const CPUResource FPMIssueSlots( "FP Instr Slot 2", 1); - -// IEUN instructions can use either Alu and should use IAluN. -// IEU0 instructions must use Alu 1 and should use both IAluN and IAlu0. -// IEU1 instructions must use Alu 2 and should use both IAluN and IAlu1. -static const CPUResource IAluN("Int ALU 1or2", 2); -static const CPUResource IAlu0("Int ALU 1", 1); -static const CPUResource IAlu1("Int ALU 2", 1); - -static const CPUResource LSAluC1("Load/Store Unit Addr Cycle", 1); -static const CPUResource LSAluC2("Load/Store Unit Issue Cycle", 1); -static const CPUResource LdReturn("Load Return Unit", 1); - -static const CPUResource FPMAluC1("FP Mul/Div Alu Cycle 1", 1); -static const CPUResource FPMAluC2("FP Mul/Div Alu Cycle 2", 1); -static const CPUResource FPMAluC3("FP Mul/Div Alu Cycle 3", 1); - -static const CPUResource FPAAluC1("FP Other Alu Cycle 1", 1); -static const CPUResource FPAAluC2("FP Other Alu Cycle 2", 1); -static const CPUResource FPAAluC3("FP Other Alu Cycle 3", 1); - -static const CPUResource IRegReadPorts("Int Reg ReadPorts", INT_MAX); // CHECK -static const CPUResource IRegWritePorts("Int Reg WritePorts", 2); // CHECK -static const CPUResource FPRegReadPorts("FP Reg Read Ports", INT_MAX);// CHECK -static const CPUResource FPRegWritePorts("FP Reg Write Ports", 1); // CHECK - -static const CPUResource CTIDelayCycle( "CTI delay cycle", 1); -static const CPUResource FCMPDelayCycle("FCMP delay cycle", 1); - - - -//--------------------------------------------------------------------------- -// const InstrClassRUsage SparcRUsageDesc[] -// -// Purpose: -// Resource usage information for instruction in each scheduling class. -// The InstrRUsage Objects for individual classes are specified first. -// Note that fetch and decode are decoupled from the execution pipelines -// via an instr buffer, so they are not included in the cycles below. -//--------------------------------------------------------------------------- - -static const InstrClassRUsage NoneClassRUsage = { - SPARC_NONE, - /*totCycles*/ 7, - - /* maxIssueNum */ 4, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 0, - /* V[] */ { - /*Cycle G */ - /*Ccle E */ - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage IEUNClassRUsage = { - SPARC_IEUN, - /*totCycles*/ 7, - - /* maxIssueNum */ 3, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage IEU0ClassRUsage = { - SPARC_IEU0, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - { IAlu0.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage IEU1ClassRUsage = { - SPARC_IEU1, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { IntIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAluN.rid, 1, 1 }, - { IAlu1.rid, 1, 1 }, - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage FPMClassRUsage = { - SPARC_FPM, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 7, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { FPMIssueSlots.rid, 0, 1 }, - /*Cycle E */ { FPRegReadPorts.rid, 1, 1 }, - /*Cycle C */ { FPMAluC1.rid, 2, 1 }, - /*Cycle N1*/ { FPMAluC2.rid, 3, 1 }, - /*Cycle N1*/ { FPMAluC3.rid, 4, 1 }, - /*Cycle N1*/ - /*Cycle W */ { FPRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage FPAClassRUsage = { - SPARC_FPA, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 7, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { FPAIssueSlots.rid, 0, 1 }, - /*Cycle E */ { FPRegReadPorts.rid, 1, 1 }, - /*Cycle C */ { FPAAluC1.rid, 2, 1 }, - /*Cycle N1*/ { FPAAluC2.rid, 3, 1 }, - /*Cycle N1*/ { FPAAluC3.rid, 4, 1 }, - /*Cycle N1*/ - /*Cycle W */ { FPRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage LDClassRUsage = { - SPARC_LD, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2, }, - - /*numEntries*/ 6, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { First3IssueSlots.rid, 0, 1 }, - { LSIssueSlots.rid, 0, 1 }, - /*Cycle E */ { LSAluC1.rid, 1, 1 }, - /*Cycle C */ { LSAluC2.rid, 2, 1 }, - { LdReturn.rid, 2, 1 }, - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ { IRegWritePorts.rid, 6, 1 } - } -}; - -static const InstrClassRUsage STClassRUsage = { - SPARC_ST, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 3, - /* feasibleSlots[] */ { 0, 1, 2 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { First3IssueSlots.rid, 0, 1 }, - { LSIssueSlots.rid, 0, 1 }, - /*Cycle E */ { LSAluC1.rid, 1, 1 }, - /*Cycle C */ { LSAluC2.rid, 2, 1 } - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage CTIClassRUsage = { - SPARC_CTI, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ false, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 4, - /* feasibleSlots[] */ { 0, 1, 2, 3 }, - - /*numEntries*/ 4, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { CTIIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAlu0.rid, 1, 1 }, - /*Cycles E-C */ { CTIDelayCycle.rid, 1, 2 } - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - -static const InstrClassRUsage SingleClassRUsage = { - SPARC_SINGLE, - /*totCycles*/ 7, - - /* maxIssueNum */ 1, - /* isSingleIssue */ true, - /* breaksGroup */ false, - /* numBubbles */ 0, - - /*numSlots*/ 1, - /* feasibleSlots[] */ { 0 }, - - /*numEntries*/ 5, - /* V[] */ { - /*Cycle G */ { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - { AllIssueSlots.rid, 0, 1 }, - /*Cycle E */ { IAlu0.rid, 1, 1 } - /*Cycle C */ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle N1*/ - /*Cycle W */ - } -}; - - -static const InstrClassRUsage SparcRUsageDesc[] = { - NoneClassRUsage, - IEUNClassRUsage, - IEU0ClassRUsage, - IEU1ClassRUsage, - FPMClassRUsage, - FPAClassRUsage, - CTIClassRUsage, - LDClassRUsage, - STClassRUsage, - SingleClassRUsage -}; - - - -//--------------------------------------------------------------------------- -// const InstrIssueDelta SparcInstrIssueDeltas[] -// -// Purpose: -// Changes to issue restrictions information in InstrClassRUsage for -// instructions that differ from other instructions in their class. -//--------------------------------------------------------------------------- - -static const InstrIssueDelta SparcInstrIssueDeltas[] = { - - // opCode, isSingleIssue, breaksGroup, numBubbles - - // Special cases for single-issue only - // Other single issue cases are below. -//{ V9::LDDA, true, true, 0 }, -//{ V9::STDA, true, true, 0 }, -//{ V9::LDDF, true, true, 0 }, -//{ V9::LDDFA, true, true, 0 }, - { V9::ADDCr, true, true, 0 }, - { V9::ADDCi, true, true, 0 }, - { V9::ADDCccr, true, true, 0 }, - { V9::ADDCcci, true, true, 0 }, - { V9::SUBCr, true, true, 0 }, - { V9::SUBCi, true, true, 0 }, - { V9::SUBCccr, true, true, 0 }, - { V9::SUBCcci, true, true, 0 }, -//{ V9::LDSTUB, true, true, 0 }, -//{ V9::SWAP, true, true, 0 }, -//{ V9::SWAPA, true, true, 0 }, -//{ V9::CAS, true, true, 0 }, -//{ V9::CASA, true, true, 0 }, -//{ V9::CASX, true, true, 0 }, -//{ V9::CASXA, true, true, 0 }, -//{ V9::LDFSR, true, true, 0 }, -//{ V9::LDFSRA, true, true, 0 }, -//{ V9::LDXFSR, true, true, 0 }, -//{ V9::LDXFSRA, true, true, 0 }, -//{ V9::STFSR, true, true, 0 }, -//{ V9::STFSRA, true, true, 0 }, -//{ V9::STXFSR, true, true, 0 }, -//{ V9::STXFSRA, true, true, 0 }, -//{ V9::SAVED, true, true, 0 }, -//{ V9::RESTORED, true, true, 0 }, -//{ V9::FLUSH, true, true, 9 }, -//{ V9::FLUSHW, true, true, 9 }, -//{ V9::ALIGNADDR, true, true, 0 }, - { V9::RETURNr, true, true, 0 }, - { V9::RETURNi, true, true, 0 }, -//{ V9::DONE, true, true, 0 }, -//{ V9::RETRY, true, true, 0 }, -//{ V9::TCC, true, true, 0 }, -//{ V9::SHUTDOWN, true, true, 0 }, - - // Special cases for breaking group *before* - // CURRENTLY NOT SUPPORTED! - { V9::CALL, false, false, 0 }, - { V9::JMPLCALLr, false, false, 0 }, - { V9::JMPLCALLi, false, false, 0 }, - { V9::JMPLRETr, false, false, 0 }, - { V9::JMPLRETi, false, false, 0 }, - - // Special cases for breaking the group *after* - { V9::MULXr, true, true, (4+34)/2 }, - { V9::MULXi, true, true, (4+34)/2 }, - { V9::FDIVS, false, true, 0 }, - { V9::FDIVD, false, true, 0 }, - { V9::FDIVQ, false, true, 0 }, - { V9::FSQRTS, false, true, 0 }, - { V9::FSQRTD, false, true, 0 }, - { V9::FSQRTQ, false, true, 0 }, -//{ V9::FCMP{LE,GT,NE,EQ}, false, true, 0 }, - - // Instructions that introduce bubbles -//{ V9::MULScc, true, true, 2 }, -//{ V9::SMULcc, true, true, (4+18)/2 }, -//{ V9::UMULcc, true, true, (4+19)/2 }, - { V9::SDIVXr, true, true, 68 }, - { V9::SDIVXi, true, true, 68 }, - { V9::UDIVXr, true, true, 68 }, - { V9::UDIVXi, true, true, 68 }, -//{ V9::SDIVcc, true, true, 36 }, -//{ V9::UDIVcc, true, true, 37 }, - { V9::WRCCRr, true, true, 4 }, - { V9::WRCCRi, true, true, 4 }, -//{ V9::WRPR, true, true, 4 }, -//{ V9::RDCCR, true, true, 0 }, // no bubbles after, but see below -//{ V9::RDPR, true, true, 0 }, -}; - - - - -//--------------------------------------------------------------------------- -// const InstrRUsageDelta SparcInstrUsageDeltas[] -// -// Purpose: -// Changes to resource usage information in InstrClassRUsage for -// instructions that differ from other instructions in their class. -//--------------------------------------------------------------------------- - -static const InstrRUsageDelta SparcInstrUsageDeltas[] = { - - // MachineOpCode, Resource, Start cycle, Num cycles - - // - // JMPL counts as a load/store instruction for issue! - // - { V9::JMPLCALLr, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLCALLi, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLRETr, LSIssueSlots.rid, 0, 1 }, - { V9::JMPLRETi, LSIssueSlots.rid, 0, 1 }, - - // - // Many instructions cannot issue for the next 2 cycles after an FCMP - // We model that with a fake resource FCMPDelayCycle. - // - { V9::FCMPS, FCMPDelayCycle.rid, 1, 3 }, - { V9::FCMPD, FCMPDelayCycle.rid, 1, 3 }, - { V9::FCMPQ, FCMPDelayCycle.rid, 1, 3 }, - - { V9::MULXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::MULXi, FCMPDelayCycle.rid, 1, 1 }, - { V9::SDIVXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::SDIVXi, FCMPDelayCycle.rid, 1, 1 }, - { V9::UDIVXr, FCMPDelayCycle.rid, 1, 1 }, - { V9::UDIVXi, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::SMULcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::UMULcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::SDIVcc, FCMPDelayCycle.rid, 1, 1 }, -//{ V9::UDIVcc, FCMPDelayCycle.rid, 1, 1 }, - { V9::STDFr, FCMPDelayCycle.rid, 1, 1 }, - { V9::STDFi, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSLEZ,FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSLZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSNZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSGZ, FCMPDelayCycle.rid, 1, 1 }, - { V9::FMOVRSGEZ,FCMPDelayCycle.rid, 1, 1 }, - - // - // Some instructions are stalled in the GROUP stage if a CTI is in - // the E or C stage. We model that with a fake resource CTIDelayCycle. - // - { V9::LDDFr, CTIDelayCycle.rid, 1, 1 }, - { V9::LDDFi, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDSTUB, CTIDelayCycle.rid, 1, 1 }, -//{ V9::LDDSTUBA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::SWAP, CTIDelayCycle.rid, 1, 1 }, -//{ V9::SWAPA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CAS, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASA, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASX, CTIDelayCycle.rid, 1, 1 }, -//{ V9::CASXA, CTIDelayCycle.rid, 1, 1 }, - - // - // Signed int loads of less than dword size return data in cycle N1 (not C) - // and put all loads in consecutive cycles into delayed load return mode. - // - { V9::LDSBr, LdReturn.rid, 2, -1 }, - { V9::LDSBr, LdReturn.rid, 3, 1 }, - { V9::LDSBi, LdReturn.rid, 2, -1 }, - { V9::LDSBi, LdReturn.rid, 3, 1 }, - - { V9::LDSHr, LdReturn.rid, 2, -1 }, - { V9::LDSHr, LdReturn.rid, 3, 1 }, - { V9::LDSHi, LdReturn.rid, 2, -1 }, - { V9::LDSHi, LdReturn.rid, 3, 1 }, - - { V9::LDSWr, LdReturn.rid, 2, -1 }, - { V9::LDSWr, LdReturn.rid, 3, 1 }, - { V9::LDSWi, LdReturn.rid, 2, -1 }, - { V9::LDSWi, LdReturn.rid, 3, 1 }, - - // - // RDPR from certain registers and RD from any register are not dispatchable - // until four clocks after they reach the head of the instr. buffer. - // Together with their single-issue requirement, this means all four issue - // slots are effectively blocked for those cycles, plus the issue cycle. - // This does not increase the latency of the instruction itself. - // - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - { V9::RDCCR, AllIssueSlots.rid, 0, 5 }, - -#undef EXPLICIT_BUBBLES_NEEDED -#ifdef EXPLICIT_BUBBLES_NEEDED - // - // MULScc inserts one bubble. - // This means it breaks the current group (captured in UltraSparcSchedInfo) - // *and occupies all issue slots for the next cycle - // -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, -//{ V9::MULScc, AllIssueSlots.rid, 2, 2-1 }, - - // - // SMULcc inserts between 4 and 18 bubbles, depending on #leading 0s in rs1. - // We just model this with a simple average. - // -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, -//{ V9::SMULcc, AllIssueSlots.rid, 2, ((4+18)/2)-1 }, - - // SMULcc inserts between 4 and 19 bubbles, depending on #leading 0s in rs1. -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, -//{ V9::UMULcc, AllIssueSlots.rid, 2, ((4+19)/2)-1 }, - - // - // MULX inserts between 4 and 34 bubbles, depending on #leading 0s in rs1. - // - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - { V9::MULX, AllIssueSlots.rid, 2, ((4+34)/2)-1 }, - - // - // SDIVcc inserts 36 bubbles. - // -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, -//{ V9::SDIVcc, AllIssueSlots.rid, 2, 36-1 }, - - // UDIVcc inserts 37 bubbles. -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, -//{ V9::UDIVcc, AllIssueSlots.rid, 2, 37-1 }, - - // - // SDIVX inserts 68 bubbles. - // - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::SDIVX, AllIssueSlots.rid, 2, 68-1 }, - - // - // UDIVX inserts 68 bubbles. - // - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - { V9::UDIVX, AllIssueSlots.rid, 2, 68-1 }, - - // - // WR inserts 4 bubbles. - // -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WR, AllIssueSlots.rid, 2, 68-1 }, - - // - // WRPR inserts 4 bubbles. - // -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, -//{ V9::WRPR, AllIssueSlots.rid, 2, 68-1 }, - - // - // DONE inserts 9 bubbles. - // -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::DONE, AllIssueSlots.rid, 2, 9-1 }, - - // - // RETRY inserts 9 bubbles. - // -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, -//{ V9::RETRY, AllIssueSlots.rid, 2, 9-1 }, - -#endif /*EXPLICIT_BUBBLES_NEEDED */ -}; - -// Additional delays to be captured in code: -// 1. RDPR from several state registers (page 349) -// 2. RD from *any* register (page 349) -// 3. Writes to TICK, PSTATE, TL registers and FLUSH{W} instr (page 349) -// 4. Integer store can be in same group as instr producing value to store. -// 5. BICC and BPICC can be in the same group as instr producing CC (pg 350) -// 6. FMOVr cannot be in the same or next group as an IEU instr (pg 351). -// 7. The second instr. of a CTI group inserts 9 bubbles (pg 351) -// 8. WR{PR}, SVAE, SAVED, RESTORE, RESTORED, RETURN, RETRY, and DONE that -// follow an annulling branch cannot be issued in the same group or in -// the 3 groups following the branch. -// 9. A predicted annulled load does not stall dependent instructions. -// Other annulled delay slot instructions *do* stall dependents, so -// nothing special needs to be done for them during scheduling. -//10. Do not put a load use that may be annulled in the same group as the -// branch. The group will stall until the load returns. -//11. Single-prec. FP loads lock 2 registers, for dependency checking. -// -// -// Additional delays we cannot or will not capture: -// 1. If DCTI is last word of cache line, it is delayed until next line can be -// fetched. Also, other DCTI alignment-related delays (pg 352) -// 2. Load-after-store is delayed by 7 extra cycles if load hits in D-Cache. -// Also, several other store-load and load-store conflicts (pg 358) -// 3. MEMBAR, LD{X}FSR, LDD{A} and a bunch of other load stalls (pg 358) -// 4. There can be at most 8 outstanding buffered store instructions -// (including some others like MEMBAR, LDSTUB, CAS{AX}, and FLUSH) - - - -//--------------------------------------------------------------------------- -// class SparcSchedInfo -// -// Purpose: -// Scheduling information for the UltraSPARC. -// Primarily just initializes machine-dependent parameters in -// class TargetSchedInfo. -//--------------------------------------------------------------------------- - -/*ctor*/ -SparcSchedInfo::SparcSchedInfo(const TargetMachine& tgt) - : TargetSchedInfo(tgt, - (unsigned int) SPARC_NUM_SCHED_CLASSES, - SparcRUsageDesc, - SparcInstrUsageDeltas, - SparcInstrIssueDeltas, - sizeof(SparcInstrUsageDeltas)/sizeof(InstrRUsageDelta), - sizeof(SparcInstrIssueDeltas)/sizeof(InstrIssueDelta)) -{ - maxNumIssueTotal = 4; - longestIssueConflict = 0; // computed from issuesGaps[] - - branchMispredictPenalty = 4; // 4 for SPARC IIi - branchTargetUnknownPenalty = 2; // 2 for SPARC IIi - l1DCacheMissPenalty = 8; // 7 or 9 for SPARC IIi - l1ICacheMissPenalty = 8; // ? for SPARC IIi - - inOrderLoads = true; // true for SPARC IIi - inOrderIssue = true; // true for SPARC IIi - inOrderExec = false; // false for most architectures - inOrderRetire= true; // true for most architectures - - // must be called after above parameters are initialized. - initializeResources(); -} - -void -SparcSchedInfo::initializeResources() -{ - // Compute TargetSchedInfo::instrRUsages and TargetSchedInfo::issueGaps - TargetSchedInfo::initializeResources(); - - // Machine-dependent fixups go here. None for now. -} |