//===-- 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 "SparcInternals.h"
#include "SparcInstrSelectionSupport.h"
+#include "SparcInternals.h"
#include "SparcRegClassInfo.h"
-#include "llvm/CodeGen/InstrSelectionSupport.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineInstrAnnot.h"
+#include "llvm/Constants.h"
+#include "llvm/ConstantHandling.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/MachineCodeForInstruction.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/iTerminators.h"
-#include "llvm/iMemory.h"
-#include "llvm/iOther.h"
-#include "llvm/Function.h"
-#include "llvm/Constants.h"
-#include "llvm/ConstantHandling.h"
-#include "llvm/Intrinsics.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineInstrAnnot.h"
#include "Support/MathExtras.h"
-#include <math.h>
#include <algorithm>
+#include <cmath>
static inline void Add3OperandInstr(unsigned Opcode, InstructionNode* Node,
std::vector<MachineInstr*>& mvec) {
}
-
-//---------------------------------------------------------------------------
-// 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.
-//---------------------------------------------------------------------------
-
-
//---------------------------------------------------------------------------
// Function: FoldGetElemChain
//
Value* ptrVal = gepI->getPointerOperand();
InstrTreeNode* ptrChild = gepNode->leftChild();
- // Extract the index vector of the GEP instructin.
+ // 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();
{
switch (iid) {
case LLVMIntrinsic::va_start: {
- // Get the address of the first vararg value on stack and copy it to
- // the argument of va_start(va_list* ap).
+ // 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 firstVarArgOff = numFixedArgs * argSize + target.getFrameInfo().
getFirstIncomingArgOffset(MachineFunction::get(func), ignore);
mvec.push_back(BuildMI(V9::ADDi, 3).addMReg(fpReg).addSImm(firstVarArgOff).
- addReg(callInstr.getOperand(1)));
+ addRegDef(&callInstr));
return true;
}
return true; // no-op on Sparc
case LLVMIntrinsic::va_copy:
- // Simple copy of current va_list (arg2) to new va_list (arg1)
+ // 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(2)).
- addReg(callInstr.getOperand(1)));
+ addReg(callInstr.getOperand(1)).
+ addRegDef(&callInstr));
+ return true;
+
+ case LLVMIntrinsic::sigsetjmp:
+ case LLVMIntrinsic::setjmp: {
+ // act as if we return 0
+ unsigned g0 = target.getRegInfo().getZeroRegNum();
+ mvec.push_back(BuildMI(V9::ORr,3).addMReg(g0).addMReg(g0)
+ .addReg(&callInstr, MOTy::Def));
+ return true;
+ }
+
+ case LLVMIntrinsic::siglongjmp:
+ case LLVMIntrinsic::longjmp: {
+ // call abort()
+ Module* M = callInstr.getParent()->getParent()->getParent();
+ const FunctionType *voidvoidFuncTy =
+ FunctionType::get(Type::VoidTy, std::vector<const Type*>(), false);
+ Function *F = M->getOrInsertFunction("abort", voidvoidFuncTy);
+ assert(F && "Unable to get or create `abort' function declaration");
+
+ // Create hidden virtual register for return address with type void*
+ TmpInstruction* retAddrReg =
+ new TmpInstruction(MachineCodeForInstruction::get(&callInstr),
+ PointerType::get(Type::VoidTy), &callInstr);
+
+ // 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, false, false);
+
+ MachineInstr* callMI = BuildMI(V9::CALL, 1).addPCDisp(F);
+ callMI->addImplicitRef(retAddrReg, /*isDef*/ true);
+
+ mvec.push_back(callMI);
+ mvec.push_back(BuildMI(V9::NOP, 0));
return true;
+ }
default:
return false;
// 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)
+ 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.
mvec.push_back(BuildMI(V9::ANDNr, 3).addReg(lhs).addReg(notArg)
.addReg(dest, MOTy::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, MOTy::UseAndDef));
- }
+ 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, MOTy::UseAndDef));
+ }
break;
}
mvec.push_back(BuildMI(V9::ORNr, 3).addReg(lhs).addReg(notArg)
.addReg(dest, MOTy::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, MOTy::UseAndDef));
- }
+ 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, MOTy::UseAndDef));
+ }
break;
}
mvec.push_back(BuildMI(V9::XNORr, 3).addReg(lhs).addReg(notArg)
.addReg(dest, MOTy::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, MOTy::UseAndDef));
- }
+ 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, MOTy::UseAndDef));
+ }
break;
}
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,
+ 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));
+ && 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, MOTy::UseAndDef));
+ // 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, MOTy::UseAndDef));
- break;
- }
+ break;
}
+ }
// ELSE FALL THROUGH
}
case 64: // reg: Phi(reg,reg)
break; // don't forward the value
- case 65: // reg: VaArg(reg)
- {
- // Use value initialized by va_start as pointer to args on the stack.
- // Load argument via current pointer value, then increment pointer.
+ 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();
- mvec.push_back(BuildMI(V9::LDXi, 3).addReg(vaArgI->getOperand(0)).
+ 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));
- mvec.push_back(BuildMI(V9::ADDi, 3).addReg(vaArgI->getOperand(0)).
- addSImm(argSize).addRegDef(vaArgI->getOperand(0)));
break;
}
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 registe to represent this result.
+ // Use another tmp. virtual register to represent this result.
if (destSize < 4) {
srlArgToUse = new TmpInstruction(mcfi, dest->getType(),
tmpI, NULL, "maskHi2");