diff options
author | Chris Lattner <sabre@nondot.org> | 2001-09-14 03:47:57 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2001-09-14 03:47:57 +0000 |
commit | 20b1ea0c987e506f022787a2f2b80fa038df2661 (patch) | |
tree | 62661dada392b5c901232808670a63e8ed5ca39a | |
parent | 1fddfd18abde2578a487bb247110acfd2226d62b (diff) |
Move files.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@561 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Target/SparcV9/Makefile | 14 | ||||
-rw-r--r-- | lib/Target/SparcV9/SparcV9InstrSelection.cpp | 2016 | ||||
-rw-r--r-- | lib/Target/SparcV9/SparcV9RegInfo.cpp | 301 | ||||
-rw-r--r-- | lib/Target/SparcV9/SparcV9TargetMachine.cpp | 123 |
4 files changed, 2454 insertions, 0 deletions
diff --git a/lib/Target/SparcV9/Makefile b/lib/Target/SparcV9/Makefile new file mode 100644 index 0000000000..2daca1f772 --- /dev/null +++ b/lib/Target/SparcV9/Makefile @@ -0,0 +1,14 @@ +LEVEL = ../../../.. + +DIRS = + +LIBRARYNAME = sparc + +## List source files in link order +Source = \ + Sparc.o \ + Sparc.burm.o \ + SparcInstrSelection.o + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/SparcV9/SparcV9InstrSelection.cpp b/lib/Target/SparcV9/SparcV9InstrSelection.cpp new file mode 100644 index 0000000000..c73264c221 --- /dev/null +++ b/lib/Target/SparcV9/SparcV9InstrSelection.cpp @@ -0,0 +1,2016 @@ +//*************************************************************************** +// File: +// SparcInstrSelection.cpp +// +// Purpose: +// +// History: +// 7/02/01 - Vikram Adve - Created +//**************************************************************************/ + +#include "SparcInternals.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/InstrForest.h" +#include "llvm/CodeGen/InstrSelection.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/DerivedTypes.h" +#include "llvm/iTerminators.h" +#include "llvm/iMemory.h" +#include "llvm/iOther.h" +#include "llvm/BasicBlock.h" +#include "llvm/Method.h" +#include "llvm/ConstPoolVals.h" + + +//******************** Internal Data Declarations ************************/ + +// to be used later +struct BranchPattern { + bool flipCondition; // should the sense of the test be reversed + BasicBlock* targetBB; // which basic block to branch to + MachineInstr* extraBranch; // if neither branch is fall-through, then this + // BA must be inserted after the cond'l one +}; + +//************************* Forward Declarations ***************************/ + + +static MachineOpCode ChooseBprInstruction (const InstructionNode* instrNode); + +static MachineOpCode ChooseBccInstruction (const InstructionNode* instrNode, + bool& isFPBranch); + +static MachineOpCode ChooseBpccInstruction (const InstructionNode* instrNode, + const BinaryOperator* setCCInst); + +static MachineOpCode ChooseBFpccInstruction (const InstructionNode* instrNode, + const BinaryOperator* setCCInst); + +static MachineOpCode ChooseMovFpccInstruction(const InstructionNode*); + +static MachineOpCode ChooseMovpccAfterSub (const InstructionNode* instrNode, + bool& mustClearReg, + int& valueToMove); + +static MachineOpCode ChooseConvertToFloatInstr(const InstructionNode*, + const Type* opType); + +static MachineOpCode ChooseConvertToIntInstr(const InstructionNode* instrNode, + const Type* opType); + +static MachineOpCode ChooseAddInstruction (const InstructionNode* instrNode); + +static MachineOpCode ChooseSubInstruction (const InstructionNode* instrNode); + +static MachineOpCode ChooseFcmpInstruction (const InstructionNode* instrNode); + +static MachineOpCode ChooseMulInstruction (const InstructionNode* instrNode, + bool checkCasts); + +static MachineOpCode ChooseDivInstruction (const InstructionNode* instrNode); + +static MachineOpCode ChooseLoadInstruction (const Type* resultType); + +static MachineOpCode ChooseStoreInstruction (const Type* valueType); + +static void SetOperandsForMemInstr(MachineInstr* minstr, + const InstructionNode* vmInstrNode, + const TargetMachine& target); + +static void SetMemOperands_Internal (MachineInstr* minstr, + const InstructionNode* vmInstrNode, + Value* ptrVal, + Value* arrayOffsetVal, + const vector<ConstPoolVal*>& idxVec, + const TargetMachine& target); + +static unsigned FixConstantOperands(const InstructionNode* vmInstrNode, + MachineInstr** mvec, + unsigned numInstr, + TargetMachine& target); + +static MachineInstr* MakeLoadConstInstr(Instruction* vmInstr, + Value* val, + TmpInstruction*& tmpReg, + MachineInstr*& getMinstr2); + +static void ForwardOperand (InstructionNode* treeNode, + InstructionNode* parent, + int operandNum); + + +//************************ Internal Functions ******************************/ + +// 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: +// GetConstantValueAsSignedInt: any of the above, but the value +// must fit into a int64_t. +// +// isValidConstant is set to true if a valid constant was found. +// + +static int64_t GetConstantValueAsSignedInt(const Value *V, + bool &isValidConstant) { + if (!V->isConstant()) { isValidConstant = false; return 0; } + isValidConstant = true; + + if (V->getType() == Type::BoolTy) + return ((ConstPoolBool*)V)->getValue(); + if (V->getType()->isIntegral()) { + 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; + } + + isValidConstant = false; + return 0; +} + + + +//------------------------------------------------------------------------ +// 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 112: // stmt: boolconst + case 113: // stmt: bool + case 121: + case 122: + case 123: + case 124: + case 125: + case 126: + case 127: + case 128: + case 129: + case 130: + case 131: + case 132: + case 153: + case 155: return true; break; + + default: return false; break; + } +} + + +static inline MachineOpCode +ChooseBprInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode; + + Instruction* setCCInstr = + ((InstructionNode*) instrNode->leftChild())->getInstruction(); + + switch(setCCInstr->getOpcode()) + { + case Instruction::SetEQ: opCode = BRZ; break; + case Instruction::SetNE: opCode = BRNZ; break; + case Instruction::SetLE: opCode = BRLEZ; break; + case Instruction::SetGE: opCode = BRGEZ; break; + case Instruction::SetLT: opCode = BRLZ; break; + case Instruction::SetGT: opCode = BRGZ; break; + default: + assert(0 && "Unrecognized VM instruction!"); + opCode = INVALID_OPCODE; + break; + } + + return opCode; +} + + +static inline MachineOpCode +ChooseBccInstruction(const InstructionNode* instrNode, + bool& isFPBranch) +{ + InstructionNode* setCCNode = (InstructionNode*) instrNode->leftChild(); + BinaryOperator* setCCInstr = (BinaryOperator*) setCCNode->getInstruction(); + const Type* setCCType = setCCInstr->getOperand(0)->getType(); + + isFPBranch = (setCCType == Type::FloatTy || setCCType == Type::DoubleTy); + + if (isFPBranch) + return ChooseBFpccInstruction(instrNode, setCCInstr); + else + return ChooseBpccInstruction(instrNode, setCCInstr); +} + + +static inline MachineOpCode +ChooseBpccInstruction(const InstructionNode* instrNode, + const BinaryOperator* setCCInstr) +{ + MachineOpCode opCode = INVALID_OPCODE; + + bool isSigned = setCCInstr->getOperand(0)->getType()->isSigned(); + + if (isSigned) + { + switch(setCCInstr->getOpcode()) + { + case Instruction::SetEQ: opCode = BE; break; + case Instruction::SetNE: opCode = BNE; break; + case Instruction::SetLE: opCode = BLE; break; + case Instruction::SetGE: opCode = BGE; break; + case Instruction::SetLT: opCode = BL; break; + case Instruction::SetGT: opCode = BG; break; + default: + assert(0 && "Unrecognized VM instruction!"); + break; + } + } + else + { + switch(setCCInstr->getOpcode()) + { + case Instruction::SetEQ: opCode = BE; break; + case Instruction::SetNE: opCode = BNE; break; + case Instruction::SetLE: opCode = BLEU; break; + case Instruction::SetGE: opCode = BCC; break; + case Instruction::SetLT: opCode = BCS; break; + case Instruction::SetGT: opCode = BGU; break; + default: + assert(0 && "Unrecognized VM instruction!"); + break; + } + } + + return opCode; +} + +static inline MachineOpCode +ChooseBFpccInstruction(const InstructionNode* instrNode, + const BinaryOperator* setCCInstr) +{ + MachineOpCode opCode = INVALID_OPCODE; + + switch(setCCInstr->getOpcode()) + { + case Instruction::SetEQ: opCode = FBE; break; + case Instruction::SetNE: opCode = FBNE; break; + case Instruction::SetLE: opCode = FBLE; break; + case Instruction::SetGE: opCode = FBGE; break; + case Instruction::SetLT: opCode = FBL; break; + case Instruction::SetGT: opCode = FBG; break; + default: + assert(0 && "Unrecognized VM instruction!"); + break; + } + + return opCode; +} + + +static inline MachineOpCode +ChooseMovFpccInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode = INVALID_OPCODE; + + switch(instrNode->getInstruction()->getOpcode()) + { + case Instruction::SetEQ: opCode = MOVFE; break; + case Instruction::SetNE: opCode = MOVFNE; break; + case Instruction::SetLE: opCode = MOVFLE; break; + case Instruction::SetGE: opCode = MOVFGE; break; + case Instruction::SetLT: opCode = MOVFL; break; + case Instruction::SetGT: opCode = MOVFG; break; + default: + assert(0 && "Unrecognized VM instruction!"); + break; + } + + return opCode; +} + + +// Assumes that SUBcc v1, v2 -> v3 has been executed. +// In most cases, we want to clear v3 and then follow it by instruction +// MOVcc 1 -> v3. +// Set mustClearReg=false if v3 need not be cleared before conditional move. +// Set valueToMove=0 if we want to conditionally move 0 instead of 1 +// (i.e., we want to test inverse of a condition) +// +// +static MachineOpCode +ChooseMovpccAfterSub(const InstructionNode* instrNode, + bool& mustClearReg, + int& valueToMove) +{ + MachineOpCode opCode = INVALID_OPCODE; + mustClearReg = true; + valueToMove = 1; + + switch(instrNode->getInstruction()->getOpcode()) + { + case Instruction::SetEQ: opCode = MOVNE; mustClearReg = false; + valueToMove = 0; break; + case Instruction::SetLE: opCode = MOVLE; break; + case Instruction::SetGE: opCode = MOVGE; break; + case Instruction::SetLT: opCode = MOVL; break; + case Instruction::SetGT: opCode = MOVG; break; + + case Instruction::SetNE: assert(0 && "No move required!"); + + default: + assert(0 && "Unrecognized VM instruction!"); + break; + } + + return opCode; +} + + +static inline MachineOpCode +ChooseConvertToFloatInstr(const InstructionNode* instrNode, + const Type* opType) +{ + MachineOpCode opCode = INVALID_OPCODE; + + switch(instrNode->getOpLabel()) + { + case ToFloatTy: + if (opType == Type::SByteTy || opType == Type::ShortTy || opType == Type::IntTy) + opCode = FITOS; + else if (opType == Type::LongTy) + opCode = FXTOS; + else if (opType == Type::DoubleTy) + opCode = FDTOS; + else if (opType == Type::FloatTy) + ; + else + assert(0 && "Cannot convert this type to FLOAT on SPARC"); + break; + + case ToDoubleTy: + if (opType == Type::SByteTy || opType == Type::ShortTy || opType == Type::IntTy) + opCode = FITOD; + else if (opType == Type::LongTy) + opCode = FXTOD; + else if (opType == Type::FloatTy) + opCode = FSTOD; + else if (opType == Type::DoubleTy) + ; + else + assert(0 && "Cannot convert this type to DOUBLE on SPARC"); + break; + + default: + break; + } + + return opCode; +} + +static inline MachineOpCode +ChooseConvertToIntInstr(const InstructionNode* instrNode, + const Type* opType) +{ + MachineOpCode opCode = INVALID_OPCODE;; + + int instrType = (int) instrNode->getOpLabel(); + + if (instrType == ToSByteTy || instrType == ToShortTy || instrType == ToIntTy) + { + switch (opType->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FSTOI; break; + case Type::DoubleTyID: opCode = FDTOI; break; + default: + assert(0 && "Non-numeric non-bool type cannot be converted to Int"); + break; + } + } + else if (instrType == ToLongTy) + { + switch (opType->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FSTOX; break; + case Type::DoubleTyID: opCode = FDTOX; break; + default: + assert(0 && "Non-numeric non-bool type cannot be converted to Long"); + break; + } + } + else + assert(0 && "Should not get here, Mo!"); + + return opCode; +} + + +static inline MachineOpCode +ChooseAddInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode = INVALID_OPCODE; + + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType->isIntegral() || + resultType->isPointerType() || + resultType->isMethodType() || + resultType->isLabelType()) + { + opCode = ADD; + } + else + { + Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue(); + switch(operand->getType()->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FADDS; break; + case Type::DoubleTyID: opCode = FADDD; break; + default: assert(0 && "Invalid type for ADD instruction"); break; + } + } + + return opCode; +} + + +static inline MachineInstr* +CreateMovFloatInstruction(const InstructionNode* instrNode, + const Type* resultType) +{ + MachineInstr* minstr = new MachineInstr((resultType == Type::FloatTy) + ? FMOVS : FMOVD); + minstr->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + minstr->SetMachineOperand(1, MachineOperand::MO_VirtualRegister, + instrNode->getValue()); + return minstr; +} + +static inline MachineInstr* +CreateAddConstInstruction(const InstructionNode* instrNode) +{ + MachineInstr* minstr = NULL; + + Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); + assert(constOp->isConstant()); + + // 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. + // + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType == Type::FloatTy || resultType == Type::DoubleTy) { + double dval = ((ConstPoolFP*) constOp)->getValue(); + if (dval == 0.0) + minstr = CreateMovFloatInstruction(instrNode, resultType); + } + + return minstr; +} + + +static inline MachineOpCode +ChooseSubInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode = INVALID_OPCODE; + + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType->isIntegral() || + resultType->isPointerType()) + { + opCode = SUB; + } + else + { + Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue(); + switch(operand->getType()->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FSUBS; break; + case Type::DoubleTyID: opCode = 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(constOp->isConstant()); + + // 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. + // + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType == Type::FloatTy || + resultType == Type::DoubleTy) + { + double dval = ((ConstPoolFP*) constOp)->getValue(); + if (dval == 0.0) + minstr = CreateMovFloatInstruction(instrNode, resultType); + } + + return minstr; +} + + +static inline MachineOpCode +ChooseFcmpInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode = INVALID_OPCODE; + + Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue(); + switch(operand->getType()->getPrimitiveID()) { + case Type::FloatTyID: opCode = FCMPS; break; + case Type::DoubleTyID: opCode = 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 +ChooseMulInstruction(const InstructionNode* instrNode, + bool checkCasts) +{ + MachineOpCode opCode = INVALID_OPCODE; + + if (checkCasts && BothFloatToDouble(instrNode)) + { + return opCode = FSMULD; + } + // else fall through and use the regular multiply instructions + + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType->isIntegral()) + { + opCode = MULX; + } + else + { + switch(instrNode->leftChild()->getValue()->getType()->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FMULS; break; + case Type::DoubleTyID: opCode = FMULD; break; + default: assert(0 && "Invalid type for MUL instruction"); break; + } + } + + return opCode; +} + + +static inline MachineInstr* +CreateIntNegInstruction(Value* vreg) +{ + MachineInstr* minstr = new MachineInstr(SUB); + minstr->SetMachineOperand(0, /*regNum %g0*/(unsigned int) 0); + minstr->SetMachineOperand(1, MachineOperand::MO_VirtualRegister, vreg); + minstr->SetMachineOperand(2, MachineOperand::MO_VirtualRegister, vreg); + return minstr; +} + + +static inline MachineInstr* +CreateMulConstInstruction(const InstructionNode* instrNode, + MachineInstr*& getMinstr2) +{ + MachineInstr* minstr = NULL; + getMinstr2 = NULL; + bool needNeg = false; + + Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); + assert(constOp->isConstant()); + + // 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 = instrNode->getInstruction()->getType(); + + if (resultType->isIntegral()) + { + unsigned pow; + bool isValidConst; + int64_t C = GetConstantValueAsSignedInt(constOp, isValidConst); + if (isValidConst) + { + bool needNeg = false; + if (C < 0) + { + needNeg = true; + C = -C; + } + + if (C == 0 || C == 1) + { + minstr = new MachineInstr(ADD); + + if (C == 0) + minstr->SetMachineOperand(0, /*regNum %g0*/ (unsigned int) 0); + else + minstr->SetMachineOperand(0,MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + minstr->SetMachineOperand(1, /*regNum %g0*/ (unsigned int) 0); + } + else if (IsPowerOf2(C, pow)) + { + minstr = new MachineInstr((resultType == Type::LongTy) + ? SLLX : SLL); + minstr->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + minstr->SetMachineOperand(1, MachineOperand::MO_UnextendedImmed, + pow); + } + + if (minstr && needNeg) + { // insert <reg = SUB 0, reg> after the instr to flip the sign + getMinstr2 = CreateIntNegInstruction(instrNode->getValue()); + } + } + } + else + { + if (resultType == Type::FloatTy || + resultType == Type::DoubleTy) + { + bool isValidConst; + double dval = ((ConstPoolFP*) constOp)->getValue(); + + if (isValidConst) + { + if (dval == 0) + { + minstr = new MachineInstr((resultType == Type::FloatTy) + ? FITOS : FITOD); + minstr->SetMachineOperand(0, /*regNum %g0*/(unsigned int) 0); + } + else if (fabs(dval) == 1) + { + bool needNeg = (dval < 0); + + MachineOpCode opCode = needNeg + ? (resultType == Type::FloatTy? FNEGS : FNEGD) + : (resultType == Type::FloatTy? FMOVS : FMOVD); + + minstr = new MachineInstr(opCode); + minstr->SetMachineOperand(0, + MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + } + } + } + } + + if (minstr != NULL) + minstr->SetMachineOperand(2, MachineOperand::MO_VirtualRegister, + instrNode->getValue()); + + return minstr; +} + + +static inline MachineOpCode +ChooseDivInstruction(const InstructionNode* instrNode) +{ + MachineOpCode opCode = INVALID_OPCODE; + + const Type* resultType = instrNode->getInstruction()->getType(); + + if (resultType->isIntegral()) + { + opCode = resultType->isSigned()? SDIVX : UDIVX; + } + else + { + Value* operand = ((InstrTreeNode*) instrNode->leftChild())->getValue(); + switch(operand->getType()->getPrimitiveID()) + { + case Type::FloatTyID: opCode = FDIVS; break; + case Type::DoubleTyID: opCode = FDIVD; break; + default: assert(0 && "Invalid type for DIV instruction"); break; + } + } + + return opCode; +} + + +static inline MachineInstr* +CreateDivConstInstruction(const InstructionNode* instrNode, + MachineInstr*& getMinstr2) +{ + MachineInstr* minstr = NULL; + getMinstr2 = NULL; + + Value* constOp = ((InstrTreeNode*) instrNode->rightChild())->getValue(); + assert(constOp->isConstant()); + + // 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->isIntegral()) + { + unsigned pow; + bool isValidConst; + int64_t C = GetConstantValueAsSignedInt(constOp, isValidConst); + if (isValidConst) + { + bool needNeg = false; + if (C < 0) + { + needNeg = true; + C = -C; + } + + if (C == 1) + { + minstr = new MachineInstr(ADD); + minstr->SetMachineOperand(0,MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + minstr->SetMachineOperand(1, /*regNum %g0*/ (unsigned int) 0); + } + else if (IsPowerOf2(C, pow)) + { + MachineOpCode opCode= ((resultType->isSigned()) + ? (resultType==Type::LongTy)? SRAX : SRA + : (resultType==Type::LongTy)? SRLX : SRL); + minstr = new MachineInstr(opCode); + minstr->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + minstr->SetMachineOperand(1, MachineOperand::MO_UnextendedImmed, + pow); + } + + if (minstr && needNeg) + { // insert <reg = SUB 0, reg> after the instr to flip the sign + getMinstr2 = CreateIntNegInstruction(instrNode->getValue()); + } + } + } + else + { + if (resultType == Type::FloatTy || + resultType == Type::DoubleTy) + { + bool isValidConst; + double dval = ((ConstPoolFP*) constOp)->getValue(); + + if (isValidConst && fabs(dval) == 1) + { + bool needNeg = (dval < 0); + + MachineOpCode opCode = needNeg + ? (resultType == Type::FloatTy? FNEGS : FNEGD) + : (resultType == Type::FloatTy? FMOVS : FMOVD); + + minstr = new MachineInstr(opCode); + minstr->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, + instrNode->leftChild()->getValue()); + } + } + } + + if (minstr != NULL) + minstr->SetMachineOperand(2, MachineOperand::MO_VirtualRegister, + instrNode->getValue()); + + return minstr; +} + + +static inline MachineOpCode +ChooseLoadInstruction(const Type* resultType) +{ + MachineOpCode opCode = INVALID_OPCODE; + + switch (resultType->getPrimitiveID()) + { + case Type::BoolTyID: opCode = LDUB; break; + case Type::UByteTyID: opCode = LDUB; break; + case Type::SByteTyID: opCode = LDSB; break; + case Type::UShortTyID: opCode = LDUH; break; + case Type::ShortTyID: opCode = LDSH; break; + case Type::UIntTyID: opCode = LDUW; break; + case Type::IntTyID: opCode = LDSW; break; + case Type::ULongTyID: + case Type::LongTyID: opCode = LDX; break; + case Type::FloatTyID: opCode = LD; break; + case Type::DoubleTyID: opCode = LDD; break; + default: assert(0 && "Invalid type for Load instruction"); break; + } + + return opCode; +} + + +static inline MachineOpCode +ChooseStoreInstruction(const Type* valueType) +{ + MachineOpCode opCode = INVALID_OPCODE; + + switch (valueType->getPrimitiveID()) + { + case Type::BoolTyID: + case Type::UByteTyID: + case Type::SByteTyID: opCode = STB; break; + case Type::UShortTyID: + case Type::ShortTyID: opCode = STH; break; + case Type::UIntTyID: + case Type::IntTyID: opCode = STW; break; + case Type::ULongTyID: + case Type::LongTyID: opCode = STX; break; + case Type::FloatTyID: opCode = ST; break; + case Type::DoubleTyID: opCode = STD; break; + default: assert(0 && "Invalid type for Store instruction"); break; + } + + return opCode; +} + + +//------------------------------------------------------------------------ +// 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(MachineInstr* minstr, + const InstructionNode* vmInstrNode, + const TargetMachine& target) +{ + MemAccessInst* memInst = (MemAccessInst*) vmInstrNode->getInstruction(); + + // Variables to hold the index vector, ptr value, and offset value. + // The major work here is to extract these for all 3 instruction types + // and then call the common function SetMemOperands_Internal(). + // + const vector<ConstPoolVal*>* idxVec = & memInst->getIndexVec(); + vector<ConstPoolVal*>* newIdxVec = NULL; + Value* ptrVal; + Value* arrayOffsetVal = NULL; + + // Test if a GetElemPtr instruction is being folded into this mem instrn. + // If so, it will be in the left child for Load and GetElemPtr, + // and in the right child for Store instructions. + // + InstrTreeNode* ptrChild = (vmInstrNode->getOpLabel() == Instruction::Store + ? vmInstrNode->rightChild() + : vmInstrNode->leftChild()); + + if (ptrChild->getOpLabel() == Instruction::GetElementPtr || + ptrChild->getOpLabel() == GetElemPtrIdx) + { + // There is a GetElemPtr instruction and there may be a chain of + // more than one. Use the pointer value of the last one in the chain. + // Fold the index vectors from the entire chain and from the mem + // instruction into one single index vector. + // Finally, we never fold for an array instruction so make that NULL. + + newIdxVec = new vector<ConstPoolVal*>; + ptrVal = FoldGetElemChain((InstructionNode*) ptrChild, *newIdxVec); + + newIdxVec->insert(newIdxVec->end(), idxVec->begin(), idxVec->end()); + idxVec = newIdxVec; + + assert(! ((PointerType*)ptrVal->getType())->getValueType()->isArrayType() + && "GetElemPtr cannot be folded into array refs in selection"); + } + else + { + // There is no GetElemPtr instruction. + // Use the pointer value and the index vector from the Mem instruction. + // If it is an array reference, get the array offset value. + // + ptrVal = memInst->getPtrOperand(); + + const Type* opType = + ((const PointerType*) ptrVal->getType())->getValueType(); + if (opType->isArrayType()) + { + assert((memInst->getNumOperands() + == (unsigned) 1 + memInst->getFirstOffsetIdx()) + && "Array refs must be lowered before Instruction Selection"); + + arrayOffsetVal = memInst->getOperand(memInst->getFirstOffsetIdx()); + } + } + + SetMemOperands_Internal(minstr, vmInstrNode, ptrVal, arrayOffsetVal, + *idxVec, target); + + if (newIdxVec != NULL) + delete newIdxVec; +} + + +static void +SetMemOperands_Internal(MachineInstr* minstr, + const InstructionNode* vmInstrNode, + Value* ptrVal, + Value* arrayOffsetVal, + const vector<ConstPoolVal*>& idxVec, + const TargetMachine& target) +{ + MemAccessInst* memInst = (MemAccessInst*) vmInstrNode->getInstruction(); + + // Initialize so we default to storing the offset in a register. + int64_t smallConstOffset; + Value* valueForRegOffset = NULL; + MachineOperand::MachineOperandType offsetOpType =MachineOperand::MO_VirtualRegister; + + // Check if there is an index vector and if so, if it translates to + // a small enough constant to fit in the immediate-offset field. + // + if (idxVec.size() > 0) + { + bool isConstantOffset = false; + unsigned offset; + + const PointerType* ptrType = (PointerType*) ptrVal->getType(); + + if (ptrType->getValueType()->isStructType()) + { + // the offset is always constant for structs + isConstantOffset = true; + + // Compute the offset value using the index vector + offset = target.DataLayout.getIndexedOffset(ptrType, idxVec); + } + else + { + // It must be an array ref. Check if the offset is a constant, + // and that the indexing has been lowered to a single offset. + // + assert(ptrType->getValueType()->isArrayType()); + assert(arrayOffsetVal != NULL + && "Expect to be given Value* for array offsets"); + + if (ConstPoolVal *CPV = arrayOffsetVal->castConstant()) + { + isConstantOffset = true; // always constant for structs + assert(arrayOffsetVal->getType()->isIntegral()); + offset = (CPV->getType()->isSigned() + ? ((ConstPoolSInt*)CPV)->getValue() + : (int64_t) ((ConstPoolUInt*)CPV)->getValue()); + } + else + { + valueForRegOffset = arrayOffsetVal; + } + } + + if (isConstantOffset) + { + // create a virtual register for the constant + valueForRegOffset = ConstPoolSInt::get(Type::IntTy, offset); + } + } + else + { + offsetOpType = MachineOperand::MO_SignExtendedImmed; + smallConstOffset = 0; + } + + // Operand 0 is value for STORE, ptr for LOAD or GET_ELEMENT_PTR + // It is the left child in the instruction tree in all cases. + Value* leftVal = vmInstrNode->leftChild()->getValue(); + minstr->SetMachineOperand(0, MachineOperand::MO_VirtualRegister, leftVal); + + // Operand 1 is ptr for STORE, offset for LOAD or GET_ELEMENT_PTR + // Operand 3 is offset for STORE, result reg for LOAD or GET_ELEMENT_PTR + // + unsigned offsetOpNum = (memInst->getOpcode() == Instruction::Store)? 2 : 1; + if (offsetOpType == MachineOperand::MO_VirtualRegister) + { + assert(valueForRegOffset != NULL); + minstr->SetMachineOperand(offsetOpNum, offsetOpType, valueForRegOff |