From: Vikram S. Adve Date: Wed, 17 Oct 2001 23:57:50 +0000 (+0000) Subject: 1. Add a bottom-up pass on BURG trees that is used to fix constant operands. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=6d35326cd549163a9af189dddca45c92f6014242;p=oota-llvm.git 1. Add a bottom-up pass on BURG trees that is used to fix constant operands. Needs to be bottom up because constant values may be forward-substituted to their uses (i.e., into the parent in the BURG tree). 2. Move most of the constant-fixup code into machine-indepedent file InstrSelectionSupport.cpp. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@859 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/InstrSelection/InstrSelection.cpp b/lib/CodeGen/InstrSelection/InstrSelection.cpp index d52088c0eb6..df9098f2191 100644 --- a/lib/CodeGen/InstrSelection/InstrSelection.cpp +++ b/lib/CodeGen/InstrSelection/InstrSelection.cpp @@ -15,6 +15,7 @@ #include "llvm/CodeGen/InstrSelection.h" +#include "llvm/CodeGen/InstrSelectionSupport.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Instruction.h" @@ -22,7 +23,7 @@ #include "llvm/Method.h" static bool SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, - TargetMachine &Target); + TargetMachine &target); enum SelectDebugLevel_t { @@ -48,7 +49,7 @@ cl::Enum SelectDebugLevel("dselect", cl::NoFlags, //--------------------------------------------------------------------------- bool -SelectInstructionsForMethod(Method* method, TargetMachine &Target) +SelectInstructionsForMethod(Method* method, TargetMachine &target) { bool failed = false; @@ -86,7 +87,7 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) } // Then recursively walk the tree to select instructions - if (SelectInstructionsForTree(basicNode, /*goalnt*/1, Target)) + if (SelectInstructionsForTree(basicNode, /*goalnt*/1, target)) { failed = true; break; @@ -120,6 +121,35 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) //*********************** Private Functions *****************************/ +//--------------------------------------------------------------------------- +// 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 +PostprocessMachineCodeForTree(InstructionNode* instrNode, + int ruleForNode, + short* nts, + TargetMachine &target) +{ + // 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(); + MachineCodeForVMInstr& mvec = vmInstr->getMachineInstrVec(); + for (int i = (int) mvec.size()-1; i >= 0; i--) + { + vector loadConstVec = + FixConstantOperandsForInstr(vmInstr, mvec[i], target); + + if (loadConstVec.size() > 0) + mvec.insert(mvec.begin()+i, loadConstVec.begin(), loadConstVec.end()); + } +} + //--------------------------------------------------------------------------- // Function SelectInstructionsForTree // @@ -138,7 +168,7 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) bool SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, - TargetMachine &Target) + TargetMachine &target) { // Use a static vector to avoid allocating a new one per VM instruction static MachineInstr* minstrVec[MAX_INSTR_PER_VMINSTR]; @@ -158,7 +188,6 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, // 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. @@ -168,7 +197,7 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, InstructionNode* instrNode = (InstructionNode*)treeRoot; assert(instrNode->getNodeType() == InstrTreeNode::NTInstructionNode); - unsigned N = GetInstructionsByRule(instrNode, ruleForNode, nts, Target, + unsigned N = GetInstructionsByRule(instrNode, ruleForNode, nts, target, minstrVec); assert(N <= MAX_INSTR_PER_VMINSTR); for (unsigned i=0; i < N; i++) @@ -206,12 +235,21 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, if (nodeType == InstrTreeNode::NTVRegListNode || nodeType == InstrTreeNode::NTInstructionNode) { - if (SelectInstructionsForTree(kids[i], nts[i], Target)) + if (SelectInstructionsForTree(kids[i], nts[i], target)) return true; // failure } } } + // Finally, do any postprocessing on this node after its children + // have been translated + // + if (treeRoot->opLabel != VRegListOp) + { + InstructionNode* instrNode = (InstructionNode*)treeRoot; + PostprocessMachineCodeForTree(instrNode, ruleForNode, nts, target); + } + return false; // success } diff --git a/lib/CodeGen/InstrSelection/InstrSelectionSupport.cpp b/lib/CodeGen/InstrSelection/InstrSelectionSupport.cpp index 685463c49fe..7fe91643a2f 100644 --- a/lib/CodeGen/InstrSelection/InstrSelectionSupport.cpp +++ b/lib/CodeGen/InstrSelection/InstrSelectionSupport.cpp @@ -24,84 +24,77 @@ //*************************** Local Functions ******************************/ -inline int64_t -GetSignedIntConstantValue(Value* val, bool& isValidConstant) + +static TmpInstruction* +InsertCodeToLoadConstant(Value* opValue, + Instruction* vmInstr, + vector& loadConstVec, + TargetMachine& target) { - int64_t intValue = 0; - isValidConstant = false; + vector tempVec; - if (val->getValueType() == Value::ConstantVal) - { - switch(val->getType()->getPrimitiveID()) - { - case Type::BoolTyID: - intValue = ((ConstPoolBool*) val)->getValue()? 1 : 0; - isValidConstant = true; - break; - case Type::SByteTyID: - case Type::ShortTyID: - case Type::IntTyID: - case Type::LongTyID: - intValue = ((ConstPoolSInt*) val)->getValue(); - isValidConstant = true; - break; - default: - break; - } - } + // Create a tmp virtual register to hold the constant. + TmpInstruction* tmpReg = + new TmpInstruction(TMP_INSTRUCTION_OPCODE, opValue, NULL); + vmInstr->getMachineInstrVec().addTempValue(tmpReg); - return intValue; -} - -inline uint64_t -GetUnsignedIntConstantValue(Value* val, bool& isValidConstant) -{ - uint64_t intValue = 0; - isValidConstant = false; + target.getInstrInfo().CreateCodeToLoadConst(opValue, tmpReg, + loadConstVec, tempVec); - if (val->getValueType() == Value::ConstantVal) - { - switch(val->getType()->getPrimitiveID()) - { - case Type::BoolTyID: - intValue = ((ConstPoolBool*) val)->getValue()? 1 : 0; - isValidConstant = true; - break; - case Type::UByteTyID: - case Type::UShortTyID: - case Type::UIntTyID: - case Type::ULongTyID: - intValue = ((ConstPoolUInt*) val)->getValue(); - isValidConstant = true; - break; - default: - break; - } - } + // Register the new tmp values created for this m/c instruction sequence + for (unsigned i=0; i < tempVec.size(); i++) + vmInstr->getMachineInstrVec().addTempValue(tempVec[i]); + + // 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 intValue; + return tmpReg; } -inline int64_t -GetConstantValueAsSignedInt(Value* val, bool& isValidConstant) +//--------------------------------------------------------------------------- +// Function GetConstantValueAsSignedInt +// +// Convenience function to get the value of an integer constant, for an +// appropriate integer or non-integer type that can be held in an integer. +// The type of the argument must be the following: +// Signed or unsigned integer +// Boolean +// Pointer +// +// isValidConstant is set to true if a valid constant was found. +//--------------------------------------------------------------------------- + +int64_t +GetConstantValueAsSignedInt(const Value *V, + bool &isValidConstant) { - int64_t intValue = 0; - - if (val->getType()->isSigned()) + if (!isa(V)) { - intValue = GetSignedIntConstantValue(val, isValidConstant); + isValidConstant = false; + return 0; } - else // non-numeric types will fall here + + isValidConstant = true; + + if (V->getType() == Type::BoolTy) + return (int64_t) ((ConstPoolBool*)V)->getValue(); + + if (V->getType()->isIntegral()) { - uint64_t uintValue = GetUnsignedIntConstantValue(val, isValidConstant); - if (isValidConstant && uintValue < INT64_MAX) // safe to use signed - intValue = (int64_t) uintValue; - else - isValidConstant = false; + if (V->getType()->isSigned()) + return ((ConstPoolSInt*)V)->getValue(); + + assert(V->getType()->isUnsigned()); + uint64_t Val = ((ConstPoolUInt*)V)->getValue(); + if (Val < INT64_MAX) // then safe to cast to signed + return (int64_t)Val; } - - return intValue; + + isValidConstant = false; + return 0; } @@ -183,81 +176,6 @@ Set2OperandsFromInstr(MachineInstr* minstr, /*op2Position*/ -1, resultPosition); } -#undef REVERT_TO_EXPLICIT_CONSTANT_CHECKS -#ifdef REVERT_TO_EXPLICIT_CONSTANT_CHECKS -unsigned -Set3OperandsFromInstrJUNK(MachineInstr* minstr, - InstructionNode* vmInstrNode, - const TargetMachine& target, - bool canDiscardResult, - int op1Position, - int op2Position, - int resultPosition) -{ - assert(op1Position >= 0); - assert(resultPosition >= 0); - - unsigned returnFlags = 0x0; - - // Check if operand 1 is 0. If so, try to use a hardwired 0 register. - Value* op1Value = vmInstrNode->leftChild()->getValue(); - bool isValidConstant; - int64_t intValue = GetConstantValueAsSignedInt(op1Value, isValidConstant); - if (isValidConstant && intValue == 0 && target.zeroRegNum >= 0) - minstr->SetMachineOperand(op1Position, /*regNum*/ target.zeroRegNum); - else - { - if (isa(op1Value)) - { - // value is constant and must be loaded from constant pool - returnFlags = returnFlags | (1 << op1Position); - } - minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister, - op1Value); - } - - // Check if operand 2 (if any) fits in the immed. field of the instruction, - // or if it is 0 and can use a dedicated machine register - if (op2Position >= 0) - { - Value* op2Value = vmInstrNode->rightChild()->getValue(); - int64_t immedValue; - unsigned int machineRegNum; - - MachineOperand::MachineOperandType - op2type = ChooseRegOrImmed(op2Value, minstr->getOpCode(), target, - /*canUseImmed*/ true, - machineRegNum, immedValue); - - if (op2type == MachineOperand::MO_MachineRegister) - minstr->SetMachineOperand(op2Position, machineRegNum); - else if (op2type == MachineOperand::MO_VirtualRegister) - { - if (isa(op2Value)) - { - // value is constant and must be loaded from constant pool - returnFlags = returnFlags | (1 << op2Position); - } - minstr->SetMachineOperand(op2Position, op2type, op2Value); - } - else - { - assert(op2type != MO_CCRegister); - minstr->SetMachineOperand(op2Position, op2type, immedValue); - } - } - - // If operand 3 (result) can be discarded, use a dead register if one exists - if (canDiscardResult && target.zeroRegNum >= 0) - minstr->SetMachineOperand(resultPosition, target.zeroRegNum); - else - minstr->SetMachineOperand(resultPosition, - MachineOperand::MO_VirtualRegister, vmInstrNode->getValue()); - - return returnFlags; -} -#endif - void Set3OperandsFromInstr(MachineInstr* minstr, @@ -355,3 +273,132 @@ ChooseRegOrImmed(Value* val, return opType; } + +//--------------------------------------------------------------------------- +// 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'. +//--------------------------------------------------------------------------- + +vector +FixConstantOperandsForInstr(Instruction* vmInstr, + MachineInstr* minstr, + TargetMachine& target) +{ + vector loadConstVec; + + const MachineInstrDescriptor& instrDesc = + target.getInstrInfo().getDescriptor(minstr->getOpCode()); + + for (unsigned op=0; op < minstr->getNumOperands(); op++) + { + const MachineOperand& mop = minstr->getOperand(op); + + // skip the result position (for efficiency below) and any other + // positions already marked as not a virtual register + if (instrDesc.resultPos == (int) op || + mop.getOperandType() != MachineOperand::MO_VirtualRegister || + mop.getVRegValue() == NULL) + { + continue; + } + + Value* opValue = mop.getVRegValue(); + bool constantThatMustBeLoaded = false; + + if (isa(opValue)) + { + unsigned int machineRegNum; + int64_t immedValue; + MachineOperand::MachineOperandType opType = + ChooseRegOrImmed(opValue, minstr->getOpCode(), target, + /*canUseImmed*/ (op == 1), + machineRegNum, immedValue); + + if (opType == MachineOperand::MO_MachineRegister) + minstr->SetMachineOperand(op, machineRegNum); + else if (opType == MachineOperand::MO_VirtualRegister) + constantThatMustBeLoaded = true; // load is generated below + else + minstr->SetMachineOperand(op, opType, immedValue); + } + + if (constantThatMustBeLoaded || isa(opValue)) + { // opValue is a constant that must be explicitly loaded into a reg. + TmpInstruction* tmpReg = InsertCodeToLoadConstant(opValue, vmInstr, + loadConstVec, target); + minstr->SetMachineOperand(op, MachineOperand::MO_VirtualRegister, + tmpReg); + } + } + + // + // Also, check for implicit operands used (not those defined) by the + // machine instruction. 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. + // + for (unsigned i=0, N=minstr->getNumImplicitRefs(); i < N; ++i) + if (isa(minstr->getImplicitRef(i)) || + isa(minstr->getImplicitRef(i))) + { + TmpInstruction* tmpReg = + InsertCodeToLoadConstant(minstr->getImplicitRef(i), vmInstr, + loadConstVec, target); + minstr->setImplicitRef(i, tmpReg); + } + + return loadConstVec; +} + + +#undef SAVE_TO_MOVE_BACK_TO_SPARCISSCPP +#ifdef SAVE_TO_MOVE_BACK_TO_SPARCISSCPP +unsigned +FixConstantOperands(const InstructionNode* vmInstrNode, + TargetMachine& target) +{ + Instruction* vmInstr = vmInstrNode->getInstruction(); + MachineCodeForVMInstr& mvec = vmInstr->getMachineInstrVec(); + + for (unsigned i=0; i < mvec.size(); i++) + { + vector loadConstVec = + FixConstantOperandsForInstr(mvec[i], target); + } + + // + // Finally, inserted the generated instructions in the vector + // to be returned. + // + unsigned numNew = loadConstVec.size(); + if (numNew > 0) + { + // Insert the new instructions *before* the old ones by moving + // the old ones over `numNew' positions (last-to-first, of course!). + // We do check *after* returning that we did not exceed the vector mvec. + for (int i=numInstr-1; i >= 0; i--) + mvec[i+numNew] = mvec[i]; + + for (unsigned i=0; i < numNew; i++) + mvec[i] = loadConstVec[i]; + } + + return (numInstr + numNew); +} +#endif SAVE_TO_MOVE_BACK_TO_SPARCISSCPP + + diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index 8cbf55e840f..76fd4e7c835 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -98,9 +98,10 @@ operator<< (ostream& os, const MachineInstr& minstr) const Value* val = *vo; os << val << (vo.isDef()? "(def), " : ", "); } - os << endl; #endif + os << endl; + return os; } @@ -170,7 +171,7 @@ PrintMachineInstructions(const Method *const method) MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec(); for (unsigned i=0; i < mvec.size(); i++) - cout << "\t" << *mvec[i] << endl; + cout << "\t" << *mvec[i]; } cout << endl << "End method \"" << method->getName() << "\"" << endl << endl; diff --git a/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp b/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp index d52088c0eb6..df9098f2191 100644 --- a/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp +++ b/lib/Target/SparcV9/InstrSelection/InstrSelection.cpp @@ -15,6 +15,7 @@ #include "llvm/CodeGen/InstrSelection.h" +#include "llvm/CodeGen/InstrSelectionSupport.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Instruction.h" @@ -22,7 +23,7 @@ #include "llvm/Method.h" static bool SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, - TargetMachine &Target); + TargetMachine &target); enum SelectDebugLevel_t { @@ -48,7 +49,7 @@ cl::Enum SelectDebugLevel("dselect", cl::NoFlags, //--------------------------------------------------------------------------- bool -SelectInstructionsForMethod(Method* method, TargetMachine &Target) +SelectInstructionsForMethod(Method* method, TargetMachine &target) { bool failed = false; @@ -86,7 +87,7 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) } // Then recursively walk the tree to select instructions - if (SelectInstructionsForTree(basicNode, /*goalnt*/1, Target)) + if (SelectInstructionsForTree(basicNode, /*goalnt*/1, target)) { failed = true; break; @@ -120,6 +121,35 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) //*********************** Private Functions *****************************/ +//--------------------------------------------------------------------------- +// 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 +PostprocessMachineCodeForTree(InstructionNode* instrNode, + int ruleForNode, + short* nts, + TargetMachine &target) +{ + // 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(); + MachineCodeForVMInstr& mvec = vmInstr->getMachineInstrVec(); + for (int i = (int) mvec.size()-1; i >= 0; i--) + { + vector loadConstVec = + FixConstantOperandsForInstr(vmInstr, mvec[i], target); + + if (loadConstVec.size() > 0) + mvec.insert(mvec.begin()+i, loadConstVec.begin(), loadConstVec.end()); + } +} + //--------------------------------------------------------------------------- // Function SelectInstructionsForTree // @@ -138,7 +168,7 @@ SelectInstructionsForMethod(Method* method, TargetMachine &Target) bool SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, - TargetMachine &Target) + TargetMachine &target) { // Use a static vector to avoid allocating a new one per VM instruction static MachineInstr* minstrVec[MAX_INSTR_PER_VMINSTR]; @@ -158,7 +188,6 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, // 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. @@ -168,7 +197,7 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, InstructionNode* instrNode = (InstructionNode*)treeRoot; assert(instrNode->getNodeType() == InstrTreeNode::NTInstructionNode); - unsigned N = GetInstructionsByRule(instrNode, ruleForNode, nts, Target, + unsigned N = GetInstructionsByRule(instrNode, ruleForNode, nts, target, minstrVec); assert(N <= MAX_INSTR_PER_VMINSTR); for (unsigned i=0; i < N; i++) @@ -206,12 +235,21 @@ SelectInstructionsForTree(InstrTreeNode* treeRoot, int goalnt, if (nodeType == InstrTreeNode::NTVRegListNode || nodeType == InstrTreeNode::NTInstructionNode) { - if (SelectInstructionsForTree(kids[i], nts[i], Target)) + if (SelectInstructionsForTree(kids[i], nts[i], target)) return true; // failure } } } + // Finally, do any postprocessing on this node after its children + // have been translated + // + if (treeRoot->opLabel != VRegListOp) + { + InstructionNode* instrNode = (InstructionNode*)treeRoot; + PostprocessMachineCodeForTree(instrNode, ruleForNode, nts, target); + } + return false; // success } diff --git a/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp b/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp index 685463c49fe..7fe91643a2f 100644 --- a/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp +++ b/lib/Target/SparcV9/InstrSelection/InstrSelectionSupport.cpp @@ -24,84 +24,77 @@ //*************************** Local Functions ******************************/ -inline int64_t -GetSignedIntConstantValue(Value* val, bool& isValidConstant) + +static TmpInstruction* +InsertCodeToLoadConstant(Value* opValue, + Instruction* vmInstr, + vector& loadConstVec, + TargetMachine& target) { - int64_t intValue = 0; - isValidConstant = false; + vector tempVec; - if (val->getValueType() == Value::ConstantVal) - { - switch(val->getType()->getPrimitiveID()) - { - case Type::BoolTyID: - intValue = ((ConstPoolBool*) val)->getValue()? 1 : 0; - isValidConstant = true; - break; - case Type::SByteTyID: - case Type::ShortTyID: - case Type::IntTyID: - case Type::LongTyID: - intValue = ((ConstPoolSInt*) val)->getValue(); - isValidConstant = true; - break; - default: - break; - } - } + // Create a tmp virtual register to hold the constant. + TmpInstruction* tmpReg = + new TmpInstruction(TMP_INSTRUCTION_OPCODE, opValue, NULL); + vmInstr->getMachineInstrVec().addTempValue(tmpReg); - return intValue; -} - -inline uint64_t -GetUnsignedIntConstantValue(Value* val, bool& isValidConstant) -{ - uint64_t intValue = 0; - isValidConstant = false; + target.getInstrInfo().CreateCodeToLoadConst(opValue, tmpReg, + loadConstVec, tempVec); - if (val->getValueType() == Value::ConstantVal) - { - switch(val->getType()->getPrimitiveID()) - { - case Type::BoolTyID: - intValue = ((ConstPoolBool*) val)->getValue()? 1 : 0; - isValidConstant = true; - break; - case Type::UByteTyID: - case Type::UShortTyID: - case Type::UIntTyID: - case Type::ULongTyID: - intValue = ((ConstPoolUInt*) val)->getValue(); - isValidConstant = true; - break; - default: - break; - } - } + // Register the new tmp values created for this m/c instruction sequence + for (unsigned i=0; i < tempVec.size(); i++) + vmInstr->getMachineInstrVec().addTempValue(tempVec[i]); + + // 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 intValue; + return tmpReg; } -inline int64_t -GetConstantValueAsSignedInt(Value* val, bool& isValidConstant) +//--------------------------------------------------------------------------- +// Function GetConstantValueAsSignedInt +// +// Convenience function to get the value of an integer constant, for an +// appropriate integer or non-integer type that can be held in an integer. +// The type of the argument must be the following: +// Signed or unsigned integer +// Boolean +// Pointer +// +// isValidConstant is set to true if a valid constant was found. +//--------------------------------------------------------------------------- + +int64_t +GetConstantValueAsSignedInt(const Value *V, + bool &isValidConstant) { - int64_t intValue = 0; - - if (val->getType()->isSigned()) + if (!isa(V)) { - intValue = GetSignedIntConstantValue(val, isValidConstant); + isValidConstant = false; + return 0; } - else // non-numeric types will fall here + + isValidConstant = true; + + if (V->getType() == Type::BoolTy) + return (int64_t) ((ConstPoolBool*)V)->getValue(); + + if (V->getType()->isIntegral()) { - uint64_t uintValue = GetUnsignedIntConstantValue(val, isValidConstant); - if (isValidConstant && uintValue < INT64_MAX) // safe to use signed - intValue = (int64_t) uintValue; - else - isValidConstant = false; + if (V->getType()->isSigned()) + return ((ConstPoolSInt*)V)->getValue(); + + assert(V->getType()->isUnsigned()); + uint64_t Val = ((ConstPoolUInt*)V)->getValue(); + if (Val < INT64_MAX) // then safe to cast to signed + return (int64_t)Val; } - - return intValue; + + isValidConstant = false; + return 0; } @@ -183,81 +176,6 @@ Set2OperandsFromInstr(MachineInstr* minstr, /*op2Position*/ -1, resultPosition); } -#undef REVERT_TO_EXPLICIT_CONSTANT_CHECKS -#ifdef REVERT_TO_EXPLICIT_CONSTANT_CHECKS -unsigned -Set3OperandsFromInstrJUNK(MachineInstr* minstr, - InstructionNode* vmInstrNode, - const TargetMachine& target, - bool canDiscardResult, - int op1Position, - int op2Position, - int resultPosition) -{ - assert(op1Position >= 0); - assert(resultPosition >= 0); - - unsigned returnFlags = 0x0; - - // Check if operand 1 is 0. If so, try to use a hardwired 0 register. - Value* op1Value = vmInstrNode->leftChild()->getValue(); - bool isValidConstant; - int64_t intValue = GetConstantValueAsSignedInt(op1Value, isValidConstant); - if (isValidConstant && intValue == 0 && target.zeroRegNum >= 0) - minstr->SetMachineOperand(op1Position, /*regNum*/ target.zeroRegNum); - else - { - if (isa(op1Value)) - { - // value is constant and must be loaded from constant pool - returnFlags = returnFlags | (1 << op1Position); - } - minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister, - op1Value); - } - - // Check if operand 2 (if any) fits in the immed. field of the instruction, - // or if it is 0 and can use a dedicated machine register - if (op2Position >= 0) - { - Value* op2Value = vmInstrNode->rightChild()->getValue(); - int64_t immedValue; - unsigned int machineRegNum; - - MachineOperand::MachineOperandType - op2type = ChooseRegOrImmed(op2Value, minstr->getOpCode(), target, - /*canUseImmed*/ true, - machineRegNum, immedValue); - - if (op2type == MachineOperand::MO_MachineRegister) - minstr->SetMachineOperand(op2Position, machineRegNum); - else if (op2type == MachineOperand::MO_VirtualRegister) - { - if (isa(op2Value)) - { - // value is constant and must be loaded from constant pool - returnFlags = returnFlags | (1 << op2Position); - } - minstr->SetMachineOperand(op2Position, op2type, op2Value); - } - else - { - assert(op2type != MO_CCRegister); - minstr->SetMachineOperand(op2Position, op2type, immedValue); - } - } - - // If operand 3 (result) can be discarded, use a dead register if one exists - if (canDiscardResult && target.zeroRegNum >= 0) - minstr->SetMachineOperand(resultPosition, target.zeroRegNum); - else - minstr->SetMachineOperand(resultPosition, - MachineOperand::MO_VirtualRegister, vmInstrNode->getValue()); - - return returnFlags; -} -#endif - void Set3OperandsFromInstr(MachineInstr* minstr, @@ -355,3 +273,132 @@ ChooseRegOrImmed(Value* val, return opType; } + +//--------------------------------------------------------------------------- +// 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'. +//--------------------------------------------------------------------------- + +vector +FixConstantOperandsForInstr(Instruction* vmInstr, + MachineInstr* minstr, + TargetMachine& target) +{ + vector loadConstVec; + + const MachineInstrDescriptor& instrDesc = + target.getInstrInfo().getDescriptor(minstr->getOpCode()); + + for (unsigned op=0; op < minstr->getNumOperands(); op++) + { + const MachineOperand& mop = minstr->getOperand(op); + + // skip the result position (for efficiency below) and any other + // positions already marked as not a virtual register + if (instrDesc.resultPos == (int) op || + mop.getOperandType() != MachineOperand::MO_VirtualRegister || + mop.getVRegValue() == NULL) + { + continue; + } + + Value* opValue = mop.getVRegValue(); + bool constantThatMustBeLoaded = false; + + if (isa(opValue)) + { + unsigned int machineRegNum; + int64_t immedValue; + MachineOperand::MachineOperandType opType = + ChooseRegOrImmed(opValue, minstr->getOpCode(), target, + /*canUseImmed*/ (op == 1), + machineRegNum, immedValue); + + if (opType == MachineOperand::MO_MachineRegister) + minstr->SetMachineOperand(op, machineRegNum); + else if (opType == MachineOperand::MO_VirtualRegister) + constantThatMustBeLoaded = true; // load is generated below + else + minstr->SetMachineOperand(op, opType, immedValue); + } + + if (constantThatMustBeLoaded || isa(opValue)) + { // opValue is a constant that must be explicitly loaded into a reg. + TmpInstruction* tmpReg = InsertCodeToLoadConstant(opValue, vmInstr, + loadConstVec, target); + minstr->SetMachineOperand(op, MachineOperand::MO_VirtualRegister, + tmpReg); + } + } + + // + // Also, check for implicit operands used (not those defined) by the + // machine instruction. 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. + // + for (unsigned i=0, N=minstr->getNumImplicitRefs(); i < N; ++i) + if (isa(minstr->getImplicitRef(i)) || + isa(minstr->getImplicitRef(i))) + { + TmpInstruction* tmpReg = + InsertCodeToLoadConstant(minstr->getImplicitRef(i), vmInstr, + loadConstVec, target); + minstr->setImplicitRef(i, tmpReg); + } + + return loadConstVec; +} + + +#undef SAVE_TO_MOVE_BACK_TO_SPARCISSCPP +#ifdef SAVE_TO_MOVE_BACK_TO_SPARCISSCPP +unsigned +FixConstantOperands(const InstructionNode* vmInstrNode, + TargetMachine& target) +{ + Instruction* vmInstr = vmInstrNode->getInstruction(); + MachineCodeForVMInstr& mvec = vmInstr->getMachineInstrVec(); + + for (unsigned i=0; i < mvec.size(); i++) + { + vector loadConstVec = + FixConstantOperandsForInstr(mvec[i], target); + } + + // + // Finally, inserted the generated instructions in the vector + // to be returned. + // + unsigned numNew = loadConstVec.size(); + if (numNew > 0) + { + // Insert the new instructions *before* the old ones by moving + // the old ones over `numNew' positions (last-to-first, of course!). + // We do check *after* returning that we did not exceed the vector mvec. + for (int i=numInstr-1; i >= 0; i--) + mvec[i+numNew] = mvec[i]; + + for (unsigned i=0; i < numNew; i++) + mvec[i] = loadConstVec[i]; + } + + return (numInstr + numNew); +} +#endif SAVE_TO_MOVE_BACK_TO_SPARCISSCPP + +