2009-05-03 20:57:15 +08:00
|
|
|
//===-- MSP430ISelLowering.cpp - MSP430 DAG Lowering Implementation ------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the MSP430TargetLowering class.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "msp430-lower"
|
|
|
|
|
|
|
|
#include "MSP430ISelLowering.h"
|
|
|
|
#include "MSP430.h"
|
2009-12-07 10:28:10 +08:00
|
|
|
#include "MSP430MachineFunctionInfo.h"
|
2009-05-03 20:57:15 +08:00
|
|
|
#include "MSP430Subtarget.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "MSP430TargetMachine.h"
|
2009-05-03 20:57:15 +08:00
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
2010-02-16 06:37:53 +08:00
|
|
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
2009-05-03 20:57:15 +08:00
|
|
|
#include "llvm/CodeGen/ValueTypes.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/CallingConv.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalAlias.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
|
|
#include "llvm/IR/Intrinsics.h"
|
2009-12-07 10:27:08 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2009-05-03 20:57:15 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2009-07-09 03:04:27 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-08-23 15:05:07 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2009-05-03 20:57:15 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2009-12-07 10:27:08 +08:00
|
|
|
typedef enum {
|
|
|
|
NoHWMult,
|
|
|
|
HWMultIntr,
|
|
|
|
HWMultNoIntr
|
|
|
|
} HWMultUseMode;
|
|
|
|
|
|
|
|
static cl::opt<HWMultUseMode>
|
2013-10-19 07:38:13 +08:00
|
|
|
HWMultMode("msp430-hwmult-mode", cl::Hidden,
|
2009-12-07 10:27:08 +08:00
|
|
|
cl::desc("Hardware multiplier use mode"),
|
|
|
|
cl::init(HWMultNoIntr),
|
|
|
|
cl::values(
|
|
|
|
clEnumValN(NoHWMult, "no",
|
|
|
|
"Do not use hardware multiplier"),
|
|
|
|
clEnumValN(HWMultIntr, "interrupts",
|
|
|
|
"Assume hardware multiplier can be used inside interrupts"),
|
|
|
|
clEnumValN(HWMultNoIntr, "use",
|
|
|
|
"Assume hardware multiplier cannot be used inside interrupts"),
|
|
|
|
clEnumValEnd));
|
|
|
|
|
2009-05-03 20:57:15 +08:00
|
|
|
MSP430TargetLowering::MSP430TargetLowering(MSP430TargetMachine &tm) :
|
2009-07-28 11:13:23 +08:00
|
|
|
TargetLowering(tm, new TargetLoweringObjectFileELF()),
|
2012-06-07 02:25:08 +08:00
|
|
|
Subtarget(*tm.getSubtargetImpl()) {
|
2009-05-03 20:57:15 +08:00
|
|
|
|
2012-10-09 00:38:25 +08:00
|
|
|
TD = getDataLayout();
|
2009-12-07 10:28:10 +08:00
|
|
|
|
2009-05-03 20:57:15 +08:00
|
|
|
// Set up the register classes.
|
2012-04-20 15:30:17 +08:00
|
|
|
addRegisterClass(MVT::i8, &MSP430::GR8RegClass);
|
|
|
|
addRegisterClass(MVT::i16, &MSP430::GR16RegClass);
|
2009-05-03 20:57:15 +08:00
|
|
|
|
|
|
|
// Compute derived properties from the register classes
|
|
|
|
computeRegisterProperties();
|
2009-05-03 20:59:50 +08:00
|
|
|
|
2009-05-03 21:03:14 +08:00
|
|
|
// Provide all sorts of operation actions
|
|
|
|
|
|
|
|
// Division is expensive
|
|
|
|
setIntDivIsCheap(false);
|
|
|
|
|
2009-05-03 21:11:35 +08:00
|
|
|
setStackPointerRegisterToSaveRestore(MSP430::SPW);
|
|
|
|
setBooleanContents(ZeroOrOneBooleanContent);
|
2011-09-07 03:07:46 +08:00
|
|
|
setBooleanVectorContents(ZeroOrOneBooleanContent); // FIXME: Is this correct?
|
2009-05-03 21:11:35 +08:00
|
|
|
|
2009-11-08 01:15:25 +08:00
|
|
|
// We have post-incremented loads / stores.
|
2009-11-08 01:15:06 +08:00
|
|
|
setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal);
|
|
|
|
setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal);
|
|
|
|
|
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
|
|
|
|
setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i16, Expand);
|
2009-05-03 21:06:03 +08:00
|
|
|
|
2009-05-03 21:06:26 +08:00
|
|
|
// We don't have any truncstores
|
2009-08-12 04:47:22 +08:00
|
|
|
setTruncStoreAction(MVT::i16, MVT::i8, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::SRA, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SHL, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SRL, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SRA, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::SHL, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::SRL, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::ROTL, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::ROTR, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::ROTL, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::ROTR, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom);
|
2010-05-01 20:04:32 +08:00
|
|
|
setOperationAction(ISD::BlockAddress, MVT::i16, Custom);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
|
2009-12-12 07:01:29 +08:00
|
|
|
setOperationAction(ISD::SETCC, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::i16, Custom);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::SELECT, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SELECT, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND, MVT::i16, Custom);
|
2009-08-26 01:00:23 +08:00
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
|
|
|
|
setOperationAction(ISD::CTTZ, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::CTTZ, MVT::i16, Expand);
|
2011-12-13 09:56:10 +08:00
|
|
|
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i16, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::CTLZ, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::CTLZ, MVT::i16, Expand);
|
2011-12-13 09:56:10 +08:00
|
|
|
setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i16, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::CTPOP, MVT::i16, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::SHL_PARTS, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SRL_PARTS, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SRA_PARTS, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
2009-07-17 15:28:06 +08:00
|
|
|
|
2009-05-03 21:14:25 +08:00
|
|
|
// FIXME: Implement efficiently multiplication by a constant
|
2009-11-08 01:14:39 +08:00
|
|
|
setOperationAction(ISD::MUL, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::MULHS, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::MULHU, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::MUL, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::MULHS, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::MULHU, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
|
|
|
|
|
2009-11-08 01:14:39 +08:00
|
|
|
setOperationAction(ISD::UDIV, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::UDIVREM, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::UREM, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SDIV, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SDIVREM, MVT::i8, Expand);
|
|
|
|
setOperationAction(ISD::SREM, MVT::i8, Expand);
|
2009-08-12 04:47:22 +08:00
|
|
|
setOperationAction(ISD::UDIV, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::UDIVREM, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::UREM, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SDIV, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SDIVREM, MVT::i16, Expand);
|
|
|
|
setOperationAction(ISD::SREM, MVT::i16, Expand);
|
2009-12-07 10:27:08 +08:00
|
|
|
|
2012-11-22 01:28:27 +08:00
|
|
|
// varargs support
|
|
|
|
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
2013-07-02 03:44:44 +08:00
|
|
|
setOperationAction(ISD::JumpTable, MVT::i16, Custom);
|
2012-11-22 01:28:27 +08:00
|
|
|
|
2009-12-07 10:27:08 +08:00
|
|
|
// Libcalls names.
|
|
|
|
if (HWMultMode == HWMultIntr) {
|
|
|
|
setLibcallName(RTLIB::MUL_I8, "__mulqi3hw");
|
|
|
|
setLibcallName(RTLIB::MUL_I16, "__mulhi3hw");
|
|
|
|
} else if (HWMultMode == HWMultNoIntr) {
|
|
|
|
setLibcallName(RTLIB::MUL_I8, "__mulqi3hw_noint");
|
|
|
|
setLibcallName(RTLIB::MUL_I16, "__mulhi3hw_noint");
|
|
|
|
}
|
2011-05-07 04:34:06 +08:00
|
|
|
|
|
|
|
setMinFunctionAlignment(1);
|
|
|
|
setPrefFunctionAlignment(2);
|
2009-05-03 20:57:15 +08:00
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerOperation(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2009-05-03 20:57:15 +08:00
|
|
|
switch (Op.getOpcode()) {
|
2009-05-03 21:13:17 +08:00
|
|
|
case ISD::SHL: // FALLTHROUGH
|
2009-05-03 21:16:17 +08:00
|
|
|
case ISD::SRL:
|
2009-05-03 21:07:31 +08:00
|
|
|
case ISD::SRA: return LowerShifts(Op, DAG);
|
2009-05-03 21:08:33 +08:00
|
|
|
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
2010-05-01 20:04:32 +08:00
|
|
|
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
|
2009-05-03 21:14:46 +08:00
|
|
|
case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG);
|
2009-12-12 07:01:29 +08:00
|
|
|
case ISD::SETCC: return LowerSETCC(Op, DAG);
|
2009-05-03 21:19:09 +08:00
|
|
|
case ISD::BR_CC: return LowerBR_CC(Op, DAG);
|
|
|
|
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG);
|
2009-05-03 21:17:49 +08:00
|
|
|
case ISD::SIGN_EXTEND: return LowerSIGN_EXTEND(Op, DAG);
|
2009-12-07 10:28:10 +08:00
|
|
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
|
|
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
2012-11-22 01:28:27 +08:00
|
|
|
case ISD::VASTART: return LowerVASTART(Op, DAG);
|
2013-07-02 03:44:44 +08:00
|
|
|
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
|
2009-05-03 20:57:15 +08:00
|
|
|
default:
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable("unimplemented operand");
|
2009-05-03 20:57:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-26 21:44:29 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// MSP430 Inline Assembly Support
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// getConstraintType - Given a constraint letter, return the type of
|
|
|
|
/// constraint it is for this target.
|
|
|
|
TargetLowering::ConstraintType
|
|
|
|
MSP430TargetLowering::getConstraintType(const std::string &Constraint) const {
|
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
case 'r':
|
|
|
|
return C_RegisterClass;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TargetLowering::getConstraintType(Constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<unsigned, const TargetRegisterClass*>
|
|
|
|
MSP430TargetLowering::
|
|
|
|
getRegForInlineAsmConstraint(const std::string &Constraint,
|
2013-06-23 02:37:38 +08:00
|
|
|
MVT VT) const {
|
2009-08-26 21:44:29 +08:00
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
// GCC Constraint Letters
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
default: break;
|
|
|
|
case 'r': // GENERAL_REGS
|
|
|
|
if (VT == MVT::i8)
|
2012-04-20 15:30:17 +08:00
|
|
|
return std::make_pair(0U, &MSP430::GR8RegClass);
|
2009-08-26 21:44:29 +08:00
|
|
|
|
2012-04-20 15:30:17 +08:00
|
|
|
return std::make_pair(0U, &MSP430::GR16RegClass);
|
2009-08-26 21:44:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
|
|
|
}
|
|
|
|
|
2009-05-03 20:59:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Calling Convention Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-05-03 20:57:15 +08:00
|
|
|
#include "MSP430GenCallingConv.inc"
|
2009-05-03 20:59:33 +08:00
|
|
|
|
2013-10-15 16:19:39 +08:00
|
|
|
/// For each argument in a function store the number of pieces it is composed
|
|
|
|
/// of.
|
|
|
|
template<typename ArgT>
|
|
|
|
static void ParseFunctionArgs(const SmallVectorImpl<ArgT> &Args,
|
|
|
|
SmallVectorImpl<unsigned> &Out) {
|
|
|
|
unsigned CurrentArgIndex = ~0U;
|
|
|
|
for (unsigned i = 0, e = Args.size(); i != e; i++) {
|
|
|
|
if (CurrentArgIndex == Args[i].OrigArgIndex) {
|
|
|
|
Out.back()++;
|
|
|
|
} else {
|
|
|
|
Out.push_back(1);
|
|
|
|
CurrentArgIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AnalyzeVarArgs(CCState &State,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs) {
|
|
|
|
State.AnalyzeCallOperands(Outs, CC_MSP430_AssignStack);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AnalyzeVarArgs(CCState &State,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins) {
|
|
|
|
State.AnalyzeFormalArguments(Ins, CC_MSP430_AssignStack);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Analyze incoming and outgoing function arguments. We need custom C++ code
|
|
|
|
/// to handle special constraints in the ABI like reversing the order of the
|
|
|
|
/// pieces of splitted arguments. In addition, all pieces of a certain argument
|
|
|
|
/// have to be passed either using registers or the stack but never mixing both.
|
|
|
|
template<typename ArgT>
|
|
|
|
static void AnalyzeArguments(CCState &State,
|
|
|
|
SmallVectorImpl<CCValAssign> &ArgLocs,
|
|
|
|
const SmallVectorImpl<ArgT> &Args) {
|
|
|
|
static const uint16_t RegList[] = {
|
|
|
|
MSP430::R15W, MSP430::R14W, MSP430::R13W, MSP430::R12W
|
|
|
|
};
|
|
|
|
static const unsigned NbRegs = array_lengthof(RegList);
|
|
|
|
|
|
|
|
if (State.isVarArg()) {
|
|
|
|
AnalyzeVarArgs(State, Args);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<unsigned, 4> ArgsParts;
|
|
|
|
ParseFunctionArgs(Args, ArgsParts);
|
|
|
|
|
|
|
|
unsigned RegsLeft = NbRegs;
|
|
|
|
bool UseStack = false;
|
|
|
|
unsigned ValNo = 0;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = ArgsParts.size(); i != e; i++) {
|
|
|
|
MVT ArgVT = Args[ValNo].VT;
|
|
|
|
ISD::ArgFlagsTy ArgFlags = Args[ValNo].Flags;
|
|
|
|
MVT LocVT = ArgVT;
|
|
|
|
CCValAssign::LocInfo LocInfo = CCValAssign::Full;
|
|
|
|
|
|
|
|
// Promote i8 to i16
|
|
|
|
if (LocVT == MVT::i8) {
|
|
|
|
LocVT = MVT::i16;
|
|
|
|
if (ArgFlags.isSExt())
|
|
|
|
LocInfo = CCValAssign::SExt;
|
|
|
|
else if (ArgFlags.isZExt())
|
|
|
|
LocInfo = CCValAssign::ZExt;
|
|
|
|
else
|
|
|
|
LocInfo = CCValAssign::AExt;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle byval arguments
|
|
|
|
if (ArgFlags.isByVal()) {
|
|
|
|
State.HandleByVal(ValNo++, ArgVT, LocVT, LocInfo, 2, 2, ArgFlags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Parts = ArgsParts[i];
|
|
|
|
|
|
|
|
if (!UseStack && Parts <= RegsLeft) {
|
|
|
|
unsigned FirstVal = ValNo;
|
|
|
|
for (unsigned j = 0; j < Parts; j++) {
|
|
|
|
unsigned Reg = State.AllocateReg(RegList, NbRegs);
|
|
|
|
State.addLoc(CCValAssign::getReg(ValNo++, ArgVT, Reg, LocVT, LocInfo));
|
|
|
|
RegsLeft--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reverse the order of the pieces to agree with the "big endian" format
|
|
|
|
// required in the calling convention ABI.
|
|
|
|
SmallVectorImpl<CCValAssign>::iterator B = ArgLocs.begin() + FirstVal;
|
|
|
|
std::reverse(B, B + Parts);
|
|
|
|
} else {
|
|
|
|
UseStack = true;
|
|
|
|
for (unsigned j = 0; j < Parts; j++)
|
|
|
|
CC_MSP430_AssignStack(ValNo++, ArgVT, LocVT, LocInfo, ArgFlags, State);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AnalyzeRetResult(CCState &State,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins) {
|
|
|
|
State.AnalyzeCallResult(Ins, RetCC_MSP430);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AnalyzeRetResult(CCState &State,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs) {
|
|
|
|
State.AnalyzeReturn(Outs, RetCC_MSP430);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ArgT>
|
|
|
|
static void AnalyzeReturnValues(CCState &State,
|
|
|
|
SmallVectorImpl<CCValAssign> &RVLocs,
|
|
|
|
const SmallVectorImpl<ArgT> &Args) {
|
|
|
|
AnalyzeRetResult(State, Args);
|
|
|
|
|
|
|
|
// Reverse splitted return values to get the "big endian" format required
|
|
|
|
// to agree with the calling convention ABI.
|
|
|
|
std::reverse(RVLocs.begin(), RVLocs.end());
|
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
|
|
|
MSP430TargetLowering::LowerFormalArguments(SDValue Chain,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
bool isVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg>
|
|
|
|
&Ins,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals)
|
|
|
|
const {
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
|
|
|
|
switch (CallConv) {
|
2009-05-03 20:59:33 +08:00
|
|
|
default:
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable("Unsupported calling convention");
|
2009-05-03 20:59:33 +08:00
|
|
|
case CallingConv::C:
|
|
|
|
case CallingConv::Fast:
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return LowerCCCArguments(Chain, CallConv, isVarArg, Ins, dl, DAG, InVals);
|
2009-12-07 10:27:53 +08:00
|
|
|
case CallingConv::MSP430_INTR:
|
2012-01-21 05:51:11 +08:00
|
|
|
if (Ins.empty())
|
|
|
|
return Chain;
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("ISRs cannot have arguments");
|
2009-05-03 20:59:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
2012-05-26 00:35:28 +08:00
|
|
|
MSP430TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2012-05-26 00:35:28 +08:00
|
|
|
SelectionDAG &DAG = CLI.DAG;
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc &dl = CLI.DL;
|
2013-07-14 12:42:23 +08:00
|
|
|
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
|
|
|
|
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
|
|
|
|
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
|
2012-05-26 00:35:28 +08:00
|
|
|
SDValue Chain = CLI.Chain;
|
|
|
|
SDValue Callee = CLI.Callee;
|
|
|
|
bool &isTailCall = CLI.IsTailCall;
|
|
|
|
CallingConv::ID CallConv = CLI.CallConv;
|
|
|
|
bool isVarArg = CLI.IsVarArg;
|
|
|
|
|
2010-01-27 08:07:07 +08:00
|
|
|
// MSP430 target does not yet support tail call optimization.
|
|
|
|
isTailCall = false;
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
|
|
|
|
switch (CallConv) {
|
2009-05-03 21:07:31 +08:00
|
|
|
default:
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable("Unsupported calling convention");
|
2009-05-03 21:07:31 +08:00
|
|
|
case CallingConv::Fast:
|
|
|
|
case CallingConv::C:
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return LowerCCCCallTo(Chain, Callee, CallConv, isVarArg, isTailCall,
|
2010-07-07 23:54:55 +08:00
|
|
|
Outs, OutVals, Ins, dl, DAG, InVals);
|
2009-12-07 10:27:53 +08:00
|
|
|
case CallingConv::MSP430_INTR:
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("ISRs cannot be called directly");
|
2009-05-03 21:07:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 20:59:33 +08:00
|
|
|
/// LowerCCCArguments - transform physical registers into virtual registers and
|
|
|
|
/// generate load operations for arguments places on the stack.
|
|
|
|
// FIXME: struct return stuff
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
|
|
|
MSP430TargetLowering::LowerCCCArguments(SDValue Chain,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
bool isVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg>
|
|
|
|
&Ins,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals)
|
|
|
|
const {
|
2009-05-03 20:59:33 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
2012-11-22 01:28:27 +08:00
|
|
|
MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>();
|
2009-05-03 20:59:33 +08:00
|
|
|
|
|
|
|
// Assign locations to all of the incoming arguments.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
2011-06-09 07:55:35 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 08:11:40 +08:00
|
|
|
getTargetMachine(), ArgLocs, *DAG.getContext());
|
2013-10-15 16:19:39 +08:00
|
|
|
AnalyzeArguments(CCInfo, ArgLocs, Ins);
|
2009-05-03 20:59:33 +08:00
|
|
|
|
2012-11-22 01:28:27 +08:00
|
|
|
// Create frame index for the start of the first vararg value
|
|
|
|
if (isVarArg) {
|
|
|
|
unsigned Offset = CCInfo.getNextStackOffset();
|
|
|
|
FuncInfo->setVarArgsFrameIndex(MFI->CreateFixedObject(1, Offset, true));
|
|
|
|
}
|
2009-05-03 20:59:33 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
// Arguments passed in registers
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT RegVT = VA.getLocVT();
|
2009-08-12 04:47:22 +08:00
|
|
|
switch (RegVT.getSimpleVT().SimpleTy) {
|
2011-02-26 05:41:48 +08:00
|
|
|
default:
|
2009-07-09 03:04:27 +08:00
|
|
|
{
|
2009-07-09 04:53:28 +08:00
|
|
|
#ifndef NDEBUG
|
2009-08-23 15:05:07 +08:00
|
|
|
errs() << "LowerFormalArguments Unhandled argument type: "
|
2009-08-12 04:47:22 +08:00
|
|
|
<< RegVT.getSimpleVT().SimpleTy << "\n";
|
2009-07-09 04:53:28 +08:00
|
|
|
#endif
|
2009-07-15 00:55:14 +08:00
|
|
|
llvm_unreachable(0);
|
2009-07-09 03:04:27 +08:00
|
|
|
}
|
2009-08-12 04:47:22 +08:00
|
|
|
case MVT::i16:
|
2012-04-20 15:30:17 +08:00
|
|
|
unsigned VReg = RegInfo.createVirtualRegister(&MSP430::GR16RegClass);
|
2009-05-03 20:59:33 +08:00
|
|
|
RegInfo.addLiveIn(VA.getLocReg(), VReg);
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
|
2009-05-03 20:59:33 +08:00
|
|
|
|
|
|
|
// If this is an 8-bit value, it is really passed promoted to 16
|
|
|
|
// bits. Insert an assert[sz]ext to capture this, then truncate to the
|
|
|
|
// right size.
|
|
|
|
if (VA.getLocInfo() == CCValAssign::SExt)
|
|
|
|
ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
else if (VA.getLocInfo() == CCValAssign::ZExt)
|
|
|
|
ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
|
|
|
|
if (VA.getLocInfo() != CCValAssign::Full)
|
|
|
|
ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
InVals.push_back(ArgValue);
|
2009-05-03 20:59:33 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Sanity check
|
|
|
|
assert(VA.isMemLoc());
|
2012-11-22 01:23:03 +08:00
|
|
|
|
|
|
|
SDValue InVal;
|
|
|
|
ISD::ArgFlagsTy Flags = Ins[i].Flags;
|
|
|
|
|
|
|
|
if (Flags.isByVal()) {
|
|
|
|
int FI = MFI->CreateFixedObject(Flags.getByValSize(),
|
|
|
|
VA.getLocMemOffset(), true);
|
|
|
|
InVal = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
} else {
|
|
|
|
// Load the argument to a virtual register
|
|
|
|
unsigned ObjSize = VA.getLocVT().getSizeInBits()/8;
|
|
|
|
if (ObjSize > 2) {
|
|
|
|
errs() << "LowerFormalArguments Unhandled argument type: "
|
|
|
|
<< EVT(VA.getLocVT()).getEVTString()
|
|
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
// Create the frame index object for this incoming parameter...
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
|
|
|
|
|
|
|
|
// Create the SelectionDAG nodes corresponding to a load
|
|
|
|
//from this parameter
|
|
|
|
SDValue FIN = DAG.getFrameIndex(FI, MVT::i16);
|
|
|
|
InVal = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
|
|
|
|
MachinePointerInfo::getFixedStack(FI),
|
|
|
|
false, false, false, 0);
|
2009-05-03 20:59:33 +08:00
|
|
|
}
|
2012-11-22 01:23:03 +08:00
|
|
|
|
|
|
|
InVals.push_back(InVal);
|
2009-05-03 20:59:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return Chain;
|
2009-05-03 20:59:33 +08:00
|
|
|
}
|
2009-05-03 20:59:50 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
|
|
|
MSP430TargetLowering::LowerReturn(SDValue Chain,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
2010-07-07 23:54:55 +08:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl, SelectionDAG &DAG) const {
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
|
2009-05-03 20:59:50 +08:00
|
|
|
// CCValAssign - represent the assignment of the return value to a location
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
|
2009-12-07 10:27:53 +08:00
|
|
|
// ISRs cannot return any value.
|
2012-01-21 05:51:11 +08:00
|
|
|
if (CallConv == CallingConv::MSP430_INTR && !Outs.empty())
|
2010-04-08 06:58:41 +08:00
|
|
|
report_fatal_error("ISRs cannot return any value");
|
2009-12-07 10:27:53 +08:00
|
|
|
|
2009-05-03 20:59:50 +08:00
|
|
|
// CCState - Info about the registers and stack slot.
|
2011-06-09 07:55:35 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 08:11:40 +08:00
|
|
|
getTargetMachine(), RVLocs, *DAG.getContext());
|
2009-05-03 20:59:50 +08:00
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
// Analize return values.
|
2013-10-15 16:19:39 +08:00
|
|
|
AnalyzeReturnValues(CCInfo, RVLocs, Outs);
|
2009-05-03 20:59:50 +08:00
|
|
|
|
|
|
|
SDValue Flag;
|
2013-02-06 02:12:06 +08:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
2009-05-03 20:59:50 +08:00
|
|
|
|
|
|
|
// Copy the result values into the output registers.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
CCValAssign &VA = RVLocs[i];
|
|
|
|
assert(VA.isRegLoc() && "Can only return in registers!");
|
|
|
|
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(),
|
2010-07-07 23:54:55 +08:00
|
|
|
OutVals[i], Flag);
|
2009-05-03 20:59:50 +08:00
|
|
|
|
2009-05-03 21:00:11 +08:00
|
|
|
// Guarantee that all emitted copies are stuck together,
|
|
|
|
// avoiding something bad.
|
2009-05-03 20:59:50 +08:00
|
|
|
Flag = Chain.getValue(1);
|
2013-02-06 02:12:06 +08:00
|
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
2009-05-03 20:59:50 +08:00
|
|
|
}
|
|
|
|
|
2009-12-07 10:27:53 +08:00
|
|
|
unsigned Opc = (CallConv == CallingConv::MSP430_INTR ?
|
|
|
|
MSP430ISD::RETI_FLAG : MSP430ISD::RET_FLAG);
|
|
|
|
|
2013-02-06 02:12:06 +08:00
|
|
|
RetOps[0] = Chain; // Update chain.
|
|
|
|
|
|
|
|
// Add the flag if we have it.
|
2009-05-03 20:59:50 +08:00
|
|
|
if (Flag.getNode())
|
2013-02-06 02:12:06 +08:00
|
|
|
RetOps.push_back(Flag);
|
2009-05-03 20:59:50 +08:00
|
|
|
|
2013-02-06 02:12:06 +08:00
|
|
|
return DAG.getNode(Opc, dl, MVT::Other, &RetOps[0], RetOps.size());
|
2009-05-03 20:59:50 +08:00
|
|
|
}
|
|
|
|
|
2009-05-03 21:07:31 +08:00
|
|
|
/// LowerCCCCallTo - functions arguments are copied from virtual regs to
|
|
|
|
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
|
2013-07-15 22:25:26 +08:00
|
|
|
// TODO: sret.
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
SDValue
|
|
|
|
MSP430TargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
bool isTailCall,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg>
|
|
|
|
&Outs,
|
2010-07-07 23:54:55 +08:00
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl, SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2009-05-03 21:07:31 +08:00
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
2011-06-09 07:55:35 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 08:11:40 +08:00
|
|
|
getTargetMachine(), ArgLocs, *DAG.getContext());
|
2013-10-15 16:19:39 +08:00
|
|
|
AnalyzeArguments(CCInfo, ArgLocs, Outs);
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
// Get a count of how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = CCInfo.getNextStackOffset();
|
|
|
|
|
|
|
|
Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes,
|
2013-05-30 06:03:55 +08:00
|
|
|
getPointerTy(), true),
|
|
|
|
dl);
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass;
|
|
|
|
SmallVector<SDValue, 12> MemOpChains;
|
|
|
|
SDValue StackPtr;
|
|
|
|
|
|
|
|
// Walk the register/memloc assignments, inserting copies/loads.
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
|
2010-07-07 23:54:55 +08:00
|
|
|
SDValue Arg = OutVals[i];
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
// Promote the value if needed.
|
|
|
|
switch (VA.getLocInfo()) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Unknown loc info!");
|
2009-05-03 21:07:31 +08:00
|
|
|
case CCValAssign::Full: break;
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arguments that can be passed on register must be kept at RegsToPass
|
|
|
|
// vector
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
|
|
|
} else {
|
|
|
|
assert(VA.isMemLoc());
|
|
|
|
|
|
|
|
if (StackPtr.getNode() == 0)
|
|
|
|
StackPtr = DAG.getCopyFromReg(Chain, dl, MSP430::SPW, getPointerTy());
|
|
|
|
|
|
|
|
SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(),
|
|
|
|
StackPtr,
|
|
|
|
DAG.getIntPtrConstant(VA.getLocMemOffset()));
|
|
|
|
|
2012-11-22 01:23:03 +08:00
|
|
|
SDValue MemOp;
|
|
|
|
ISD::ArgFlagsTy Flags = Outs[i].Flags;
|
|
|
|
|
|
|
|
if (Flags.isByVal()) {
|
|
|
|
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i16);
|
|
|
|
MemOp = DAG.getMemcpy(Chain, dl, PtrOff, Arg, SizeNode,
|
|
|
|
Flags.getByValAlign(),
|
|
|
|
/*isVolatile*/false,
|
|
|
|
/*AlwaysInline=*/true,
|
|
|
|
MachinePointerInfo(),
|
|
|
|
MachinePointerInfo());
|
|
|
|
} else {
|
|
|
|
MemOp = DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo(),
|
|
|
|
false, false, 0);
|
|
|
|
}
|
2009-05-03 21:07:31 +08:00
|
|
|
|
2012-11-22 01:23:03 +08:00
|
|
|
MemOpChains.push_back(MemOp);
|
2009-05-03 21:07:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform all store nodes into one single node because all store nodes are
|
|
|
|
// independent of each other.
|
|
|
|
if (!MemOpChains.empty())
|
2009-08-12 04:47:22 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
2009-05-03 21:07:31 +08:00
|
|
|
&MemOpChains[0], MemOpChains.size());
|
|
|
|
|
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token chain and
|
|
|
|
// flag operands which copy the outgoing args into registers. The InFlag in
|
2011-04-15 13:18:47 +08:00
|
|
|
// necessary since all emitted instructions must be stuck together.
|
2009-05-03 21:07:31 +08:00
|
|
|
SDValue InFlag;
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second, InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
|
|
|
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
2010-07-07 06:08:15 +08:00
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i16);
|
2009-05-03 21:07:31 +08:00
|
|
|
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
2009-08-12 04:47:22 +08:00
|
|
|
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i16);
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
// Returns a chain & a flag for retval copy to use.
|
2010-12-21 10:38:05 +08:00
|
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
2009-05-03 21:07:31 +08:00
|
|
|
SmallVector<SDValue, 8> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
|
|
|
|
|
|
|
// Add argument registers to the end of the list so that they are
|
|
|
|
// known live into the call.
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
|
|
|
|
if (InFlag.getNode())
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
|
|
|
|
Chain = DAG.getNode(MSP430ISD::CALL, dl, NodeTys, &Ops[0], Ops.size());
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
// Create the CALLSEQ_END node.
|
|
|
|
Chain = DAG.getCALLSEQ_END(Chain,
|
|
|
|
DAG.getConstant(NumBytes, getPointerTy(), true),
|
|
|
|
DAG.getConstant(0, getPointerTy(), true),
|
2013-05-30 06:03:55 +08:00
|
|
|
InFlag, dl);
|
2009-05-03 21:07:31 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
// Handle result values, copying them out of physregs into vregs that we
|
|
|
|
// return.
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl,
|
|
|
|
DAG, InVals);
|
2009-05-03 21:07:31 +08:00
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
/// LowerCallResult - Lower the result values of a call into the
|
|
|
|
/// appropriate copies out of appropriate physical registers.
|
|
|
|
///
|
|
|
|
SDValue
|
2009-05-03 21:07:31 +08:00
|
|
|
MSP430TargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag,
|
2009-09-02 16:44:58 +08:00
|
|
|
CallingConv::ID CallConv, bool isVarArg,
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl, SelectionDAG &DAG,
|
2010-04-17 23:26:15 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
// Assign locations to each value returned by this call.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
2011-06-09 07:55:35 +08:00
|
|
|
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(),
|
2012-07-19 08:11:40 +08:00
|
|
|
getTargetMachine(), RVLocs, *DAG.getContext());
|
2009-05-03 21:07:31 +08:00
|
|
|
|
2013-10-15 16:19:39 +08:00
|
|
|
AnalyzeReturnValues(CCInfo, RVLocs, Ins);
|
2009-05-03 21:07:31 +08:00
|
|
|
|
|
|
|
// Copy all of the result registers out of their specified physreg.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
|
|
|
|
RVLocs[i].getValVT(), InFlag).getValue(1);
|
|
|
|
InFlag = Chain.getValue(2);
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
InVals.push_back(Chain.getValue(0));
|
2009-05-03 21:07:31 +08:00
|
|
|
}
|
|
|
|
|
Major calling convention code refactoring.
Instead of awkwardly encoding calling-convention information with ISD::CALL,
ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
provides three virtual functions for targets to override:
LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
lowering done on the special nodes. They provide the same information, but
in a more immediately usable format.
This also reworks much of the target-independent tail call logic. The
decision of whether or not to perform a tail call is now cleanly split
between target-independent portions, and the target dependent portion
in IsEligibleForTailCallOptimization.
This also synchronizes all in-tree targets, to help enable future
refactoring and feature work.
llvm-svn: 78142
2009-08-05 09:29:28 +08:00
|
|
|
return Chain;
|
2009-05-03 21:07:31 +08:00
|
|
|
}
|
|
|
|
|
2009-05-03 21:03:33 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerShifts(SDValue Op,
|
2010-04-17 23:26:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
2009-05-03 21:13:17 +08:00
|
|
|
unsigned Opc = Op.getOpcode();
|
2009-05-03 21:03:33 +08:00
|
|
|
SDNode* N = Op.getNode();
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT VT = Op.getValueType();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(N);
|
2009-05-03 21:03:33 +08:00
|
|
|
|
2009-12-13 02:55:37 +08:00
|
|
|
// Expand non-constant shifts to loops:
|
2009-05-03 21:03:33 +08:00
|
|
|
if (!isa<ConstantSDNode>(N->getOperand(1)))
|
2009-12-13 02:55:37 +08:00
|
|
|
switch (Opc) {
|
2012-02-07 10:50:20 +08:00
|
|
|
default: llvm_unreachable("Invalid shift opcode!");
|
2009-12-13 02:55:37 +08:00
|
|
|
case ISD::SHL:
|
|
|
|
return DAG.getNode(MSP430ISD::SHL, dl,
|
|
|
|
VT, N->getOperand(0), N->getOperand(1));
|
|
|
|
case ISD::SRA:
|
|
|
|
return DAG.getNode(MSP430ISD::SRA, dl,
|
|
|
|
VT, N->getOperand(0), N->getOperand(1));
|
|
|
|
case ISD::SRL:
|
|
|
|
return DAG.getNode(MSP430ISD::SRL, dl,
|
|
|
|
VT, N->getOperand(0), N->getOperand(1));
|
|
|
|
}
|
2009-05-03 21:03:33 +08:00
|
|
|
|
|
|
|
uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
|
|
|
|
|
|
|
|
// Expand the stuff into sequence of shifts.
|
|
|
|
// FIXME: for some shift amounts this might be done better!
|
|
|
|
// E.g.: foo >> (8 + N) => sxt(swpb(foo)) >> N
|
|
|
|
SDValue Victim = N->getOperand(0);
|
2009-05-03 21:16:17 +08:00
|
|
|
|
|
|
|
if (Opc == ISD::SRL && ShiftAmount) {
|
|
|
|
// Emit a special goodness here:
|
|
|
|
// srl A, 1 => clrc; rrc A
|
2009-05-03 21:16:37 +08:00
|
|
|
Victim = DAG.getNode(MSP430ISD::RRC, dl, VT, Victim);
|
2009-05-03 21:16:17 +08:00
|
|
|
ShiftAmount -= 1;
|
|
|
|
}
|
|
|
|
|
2009-05-03 21:03:33 +08:00
|
|
|
while (ShiftAmount--)
|
2009-05-17 18:15:22 +08:00
|
|
|
Victim = DAG.getNode((Opc == ISD::SHL ? MSP430ISD::RLA : MSP430ISD::RRA),
|
2009-05-03 21:13:17 +08:00
|
|
|
dl, VT, Victim);
|
2009-05-03 21:03:33 +08:00
|
|
|
|
|
|
|
return Victim;
|
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerGlobalAddress(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2009-05-03 21:08:33 +08:00
|
|
|
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
|
|
|
int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
|
|
|
|
|
|
|
|
// Create the TargetGlobalAddress node, folding in the constant offset.
|
2013-05-25 10:42:55 +08:00
|
|
|
SDValue Result = DAG.getTargetGlobalAddress(GV, SDLoc(Op),
|
2010-07-07 06:08:15 +08:00
|
|
|
getPointerTy(), Offset);
|
2013-05-25 10:42:55 +08:00
|
|
|
return DAG.getNode(MSP430ISD::Wrapper, SDLoc(Op),
|
2009-05-03 21:08:33 +08:00
|
|
|
getPointerTy(), Result);
|
|
|
|
}
|
|
|
|
|
2009-05-03 21:14:46 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op,
|
2010-04-17 23:26:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2009-05-03 21:14:46 +08:00
|
|
|
const char *Sym = cast<ExternalSymbolSDNode>(Op)->getSymbol();
|
|
|
|
SDValue Result = DAG.getTargetExternalSymbol(Sym, getPointerTy());
|
|
|
|
|
2012-02-23 01:25:00 +08:00
|
|
|
return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);
|
2009-05-03 21:14:46 +08:00
|
|
|
}
|
|
|
|
|
2010-05-01 20:04:32 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerBlockAddress(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2010-05-01 20:04:32 +08:00
|
|
|
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
|
2012-09-13 05:43:09 +08:00
|
|
|
SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy());
|
2010-05-01 20:04:32 +08:00
|
|
|
|
2012-02-23 01:25:00 +08:00
|
|
|
return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);
|
2010-05-01 20:04:32 +08:00
|
|
|
}
|
|
|
|
|
2009-10-22 03:16:49 +08:00
|
|
|
static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC,
|
2009-05-03 21:19:09 +08:00
|
|
|
ISD::CondCode CC,
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl, SelectionDAG &DAG) {
|
2009-05-03 21:12:06 +08:00
|
|
|
// FIXME: Handle bittests someday
|
|
|
|
assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet");
|
|
|
|
|
|
|
|
// FIXME: Handle jump negative someday
|
2009-10-22 03:16:49 +08:00
|
|
|
MSP430CC::CondCodes TCC = MSP430CC::COND_INVALID;
|
2009-05-03 21:12:06 +08:00
|
|
|
switch (CC) {
|
2009-07-15 00:55:14 +08:00
|
|
|
default: llvm_unreachable("Invalid integer condition!");
|
2009-05-03 21:12:06 +08:00
|
|
|
case ISD::SETEQ:
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_E; // aka COND_Z
|
2010-01-15 09:29:49 +08:00
|
|
|
// Minor optimization: if LHS is a constant, swap operands, then the
|
2009-11-22 09:14:08 +08:00
|
|
|
// constant can be folded into comparison.
|
2010-01-15 09:29:49 +08:00
|
|
|
if (LHS.getOpcode() == ISD::Constant)
|
2009-11-22 09:14:08 +08:00
|
|
|
std::swap(LHS, RHS);
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
case ISD::SETNE:
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_NE; // aka COND_NZ
|
2010-01-15 09:29:49 +08:00
|
|
|
// Minor optimization: if LHS is a constant, swap operands, then the
|
2009-11-22 09:14:08 +08:00
|
|
|
// constant can be folded into comparison.
|
2010-01-15 09:29:49 +08:00
|
|
|
if (LHS.getOpcode() == ISD::Constant)
|
2009-11-22 09:14:08 +08:00
|
|
|
std::swap(LHS, RHS);
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
case ISD::SETULE:
|
|
|
|
std::swap(LHS, RHS); // FALLTHROUGH
|
|
|
|
case ISD::SETUGE:
|
2010-01-16 05:18:02 +08:00
|
|
|
// Turn lhs u>= rhs with lhs constant into rhs u< lhs+1, this allows us to
|
|
|
|
// fold constant into instruction.
|
|
|
|
if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
|
|
|
|
LHS = RHS;
|
|
|
|
RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0));
|
|
|
|
TCC = MSP430CC::COND_LO;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_HS; // aka COND_C
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
case ISD::SETUGT:
|
|
|
|
std::swap(LHS, RHS); // FALLTHROUGH
|
|
|
|
case ISD::SETULT:
|
2010-01-16 05:18:02 +08:00
|
|
|
// Turn lhs u< rhs with lhs constant into rhs u>= lhs+1, this allows us to
|
|
|
|
// fold constant into instruction.
|
|
|
|
if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
|
|
|
|
LHS = RHS;
|
|
|
|
RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0));
|
|
|
|
TCC = MSP430CC::COND_HS;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_LO; // aka COND_NC
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
case ISD::SETLE:
|
|
|
|
std::swap(LHS, RHS); // FALLTHROUGH
|
|
|
|
case ISD::SETGE:
|
2010-01-16 05:18:02 +08:00
|
|
|
// Turn lhs >= rhs with lhs constant into rhs < lhs+1, this allows us to
|
|
|
|
// fold constant into instruction.
|
|
|
|
if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
|
|
|
|
LHS = RHS;
|
|
|
|
RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0));
|
|
|
|
TCC = MSP430CC::COND_L;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_GE;
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
case ISD::SETGT:
|
|
|
|
std::swap(LHS, RHS); // FALLTHROUGH
|
|
|
|
case ISD::SETLT:
|
2010-01-16 05:18:02 +08:00
|
|
|
// Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
|
|
|
|
// fold constant into instruction.
|
|
|
|
if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) {
|
|
|
|
LHS = RHS;
|
|
|
|
RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0));
|
|
|
|
TCC = MSP430CC::COND_GE;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-22 03:16:49 +08:00
|
|
|
TCC = MSP430CC::COND_L;
|
2009-05-03 21:12:06 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-10-22 03:16:49 +08:00
|
|
|
TargetCC = DAG.getConstant(TCC, MVT::i8);
|
2010-12-21 10:38:05 +08:00
|
|
|
return DAG.getNode(MSP430ISD::CMP, dl, MVT::Glue, LHS, RHS);
|
2009-05-03 21:12:06 +08:00
|
|
|
}
|
|
|
|
|
2009-05-03 21:19:09 +08:00
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
2009-05-03 21:12:06 +08:00
|
|
|
SDValue Chain = Op.getOperand(0);
|
2009-05-03 21:19:09 +08:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
|
|
|
SDValue LHS = Op.getOperand(2);
|
|
|
|
SDValue RHS = Op.getOperand(3);
|
|
|
|
SDValue Dest = Op.getOperand(4);
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl (Op);
|
2009-05-03 21:19:09 +08:00
|
|
|
|
2009-10-22 03:16:49 +08:00
|
|
|
SDValue TargetCC;
|
2009-05-03 21:19:09 +08:00
|
|
|
SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG);
|
|
|
|
|
|
|
|
return DAG.getNode(MSP430ISD::BR_CC, dl, Op.getValueType(),
|
2009-10-22 03:16:49 +08:00
|
|
|
Chain, Dest, TargetCC, Flag);
|
2009-05-03 21:12:06 +08:00
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
|
2009-12-12 07:01:29 +08:00
|
|
|
SDValue LHS = Op.getOperand(0);
|
|
|
|
SDValue RHS = Op.getOperand(1);
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl (Op);
|
2009-12-12 07:01:29 +08:00
|
|
|
|
|
|
|
// If we are doing an AND and testing against zero, then the CMP
|
|
|
|
// will not be generated. The AND (or BIT) will generate the condition codes,
|
|
|
|
// but they are different from CMP.
|
2010-01-16 05:18:18 +08:00
|
|
|
// FIXME: since we're doing a post-processing, use a pseudoinstr here, so
|
|
|
|
// lowering & isel wouldn't diverge.
|
2009-12-12 07:01:29 +08:00
|
|
|
bool andCC = false;
|
|
|
|
if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
|
|
|
|
if (RHSC->isNullValue() && LHS.hasOneUse() &&
|
|
|
|
(LHS.getOpcode() == ISD::AND ||
|
|
|
|
(LHS.getOpcode() == ISD::TRUNCATE &&
|
|
|
|
LHS.getOperand(0).getOpcode() == ISD::AND))) {
|
|
|
|
andCC = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
|
|
|
|
SDValue TargetCC;
|
|
|
|
SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG);
|
|
|
|
|
|
|
|
// Get the condition codes directly from the status register, if its easy.
|
|
|
|
// Otherwise a branch will be generated. Note that the AND and BIT
|
|
|
|
// instructions generate different flags than CMP, the carry bit can be used
|
|
|
|
// for NE/EQ.
|
|
|
|
bool Invert = false;
|
|
|
|
bool Shift = false;
|
|
|
|
bool Convert = true;
|
|
|
|
switch (cast<ConstantSDNode>(TargetCC)->getZExtValue()) {
|
|
|
|
default:
|
|
|
|
Convert = false;
|
|
|
|
break;
|
|
|
|
case MSP430CC::COND_HS:
|
|
|
|
// Res = SRW & 1, no processing is required
|
|
|
|
break;
|
2010-01-16 05:18:18 +08:00
|
|
|
case MSP430CC::COND_LO:
|
2009-12-12 07:01:29 +08:00
|
|
|
// Res = ~(SRW & 1)
|
|
|
|
Invert = true;
|
|
|
|
break;
|
2010-01-16 05:18:18 +08:00
|
|
|
case MSP430CC::COND_NE:
|
2009-12-12 07:01:29 +08:00
|
|
|
if (andCC) {
|
|
|
|
// C = ~Z, thus Res = SRW & 1, no processing is required
|
|
|
|
} else {
|
2010-02-21 20:28:58 +08:00
|
|
|
// Res = ~((SRW >> 1) & 1)
|
2009-12-12 07:01:29 +08:00
|
|
|
Shift = true;
|
2010-02-21 20:28:58 +08:00
|
|
|
Invert = true;
|
2009-12-12 07:01:29 +08:00
|
|
|
}
|
|
|
|
break;
|
2010-01-16 05:18:18 +08:00
|
|
|
case MSP430CC::COND_E:
|
2010-02-21 20:28:58 +08:00
|
|
|
Shift = true;
|
|
|
|
// C = ~Z for AND instruction, thus we can put Res = ~(SRW & 1), however,
|
|
|
|
// Res = (SRW >> 1) & 1 is 1 word shorter.
|
2009-12-12 07:01:29 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
SDValue One = DAG.getConstant(1, VT);
|
|
|
|
if (Convert) {
|
|
|
|
SDValue SR = DAG.getCopyFromReg(DAG.getEntryNode(), dl, MSP430::SRW,
|
2010-01-16 05:18:18 +08:00
|
|
|
MVT::i16, Flag);
|
2009-12-12 07:01:29 +08:00
|
|
|
if (Shift)
|
|
|
|
// FIXME: somewhere this is turned into a SRL, lower it MSP specific?
|
|
|
|
SR = DAG.getNode(ISD::SRA, dl, MVT::i16, SR, One);
|
|
|
|
SR = DAG.getNode(ISD::AND, dl, MVT::i16, SR, One);
|
|
|
|
if (Invert)
|
|
|
|
SR = DAG.getNode(ISD::XOR, dl, MVT::i16, SR, One);
|
|
|
|
return SR;
|
|
|
|
} else {
|
|
|
|
SDValue Zero = DAG.getConstant(0, VT);
|
2010-12-21 10:38:05 +08:00
|
|
|
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
|
2009-12-12 07:01:29 +08:00
|
|
|
SmallVector<SDValue, 4> Ops;
|
|
|
|
Ops.push_back(One);
|
|
|
|
Ops.push_back(Zero);
|
|
|
|
Ops.push_back(TargetCC);
|
|
|
|
Ops.push_back(Flag);
|
|
|
|
return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2009-05-03 21:19:09 +08:00
|
|
|
SDValue LHS = Op.getOperand(0);
|
|
|
|
SDValue RHS = Op.getOperand(1);
|
|
|
|
SDValue TrueV = Op.getOperand(2);
|
|
|
|
SDValue FalseV = Op.getOperand(3);
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl (Op);
|
2009-05-03 21:19:09 +08:00
|
|
|
|
2009-10-22 03:16:49 +08:00
|
|
|
SDValue TargetCC;
|
2009-05-03 21:19:09 +08:00
|
|
|
SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG);
|
2009-05-03 21:12:23 +08:00
|
|
|
|
2010-12-21 10:38:05 +08:00
|
|
|
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
|
2009-05-03 21:12:23 +08:00
|
|
|
SmallVector<SDValue, 4> Ops;
|
|
|
|
Ops.push_back(TrueV);
|
|
|
|
Ops.push_back(FalseV);
|
2009-10-22 03:16:49 +08:00
|
|
|
Ops.push_back(TargetCC);
|
2009-05-03 21:19:09 +08:00
|
|
|
Ops.push_back(Flag);
|
2009-05-03 21:12:23 +08:00
|
|
|
|
2009-05-03 21:19:09 +08:00
|
|
|
return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size());
|
2009-05-03 21:12:23 +08:00
|
|
|
}
|
|
|
|
|
2009-05-03 21:17:49 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerSIGN_EXTEND(SDValue Op,
|
2010-04-17 23:26:15 +08:00
|
|
|
SelectionDAG &DAG) const {
|
2009-05-03 21:17:49 +08:00
|
|
|
SDValue Val = Op.getOperand(0);
|
2009-08-11 06:56:29 +08:00
|
|
|
EVT VT = Op.getValueType();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2009-05-03 21:17:49 +08:00
|
|
|
|
2009-08-12 04:47:22 +08:00
|
|
|
assert(VT == MVT::i16 && "Only support i16 for now!");
|
2009-05-03 21:17:49 +08:00
|
|
|
|
|
|
|
return DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, VT,
|
|
|
|
DAG.getNode(ISD::ANY_EXTEND, dl, VT, Val),
|
|
|
|
DAG.getValueType(Val.getValueType()));
|
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue
|
|
|
|
MSP430TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
|
2009-12-07 10:28:10 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>();
|
|
|
|
int ReturnAddrIndex = FuncInfo->getRAIndex();
|
|
|
|
|
|
|
|
if (ReturnAddrIndex == 0) {
|
|
|
|
// Set up a frame object for the return address.
|
Revert the majority of the next patch in the address space series:
r165941: Resubmit the changes to llvm core to update the functions to
support different pointer sizes on a per address space basis.
Despite this commit log, this change primarily changed stuff outside of
VMCore, and those changes do not carry any tests for correctness (or
even plausibility), and we have consistently found questionable or flat
out incorrect cases in these changes. Most of them are probably correct,
but we need to devise a system that makes it more clear when we have
handled the address space concerns correctly, and ideally each pass that
gets updated would receive an accompanying test case that exercises that
pass specificaly w.r.t. alternate address spaces.
However, from this commit, I have retained the new C API entry points.
Those were an orthogonal change that probably should have been split
apart, but they seem entirely good.
In several places the changes were very obvious cleanups with no actual
multiple address space code added; these I have not reverted when
I spotted them.
In a few other places there were merge conflicts due to a cleaner
solution being implemented later, often not using address spaces at all.
In those cases, I've preserved the new code which isn't address space
dependent.
This is part of my ongoing effort to clean out the partial address space
code which carries high risk and low test coverage, and not likely to be
finished before the 3.2 release looms closer. Duncan and I would both
like to see the above issues addressed before we return to these
changes.
llvm-svn: 167222
2012-11-01 17:14:31 +08:00
|
|
|
uint64_t SlotSize = TD->getPointerSize();
|
2009-12-07 10:28:10 +08:00
|
|
|
ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(SlotSize, -SlotSize,
|
2010-07-03 08:40:23 +08:00
|
|
|
true);
|
2009-12-07 10:28:10 +08:00
|
|
|
FuncInfo->setRAIndex(ReturnAddrIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy());
|
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerRETURNADDR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2010-05-22 09:47:14 +08:00
|
|
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
MFI->setReturnAddressIsTaken(true);
|
|
|
|
|
2009-12-07 10:28:10 +08:00
|
|
|
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2009-12-07 10:28:10 +08:00
|
|
|
|
|
|
|
if (Depth > 0) {
|
|
|
|
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
|
|
|
|
SDValue Offset =
|
Revert the majority of the next patch in the address space series:
r165941: Resubmit the changes to llvm core to update the functions to
support different pointer sizes on a per address space basis.
Despite this commit log, this change primarily changed stuff outside of
VMCore, and those changes do not carry any tests for correctness (or
even plausibility), and we have consistently found questionable or flat
out incorrect cases in these changes. Most of them are probably correct,
but we need to devise a system that makes it more clear when we have
handled the address space concerns correctly, and ideally each pass that
gets updated would receive an accompanying test case that exercises that
pass specificaly w.r.t. alternate address spaces.
However, from this commit, I have retained the new C API entry points.
Those were an orthogonal change that probably should have been split
apart, but they seem entirely good.
In several places the changes were very obvious cleanups with no actual
multiple address space code added; these I have not reverted when
I spotted them.
In a few other places there were merge conflicts due to a cleaner
solution being implemented later, often not using address spaces at all.
In those cases, I've preserved the new code which isn't address space
dependent.
This is part of my ongoing effort to clean out the partial address space
code which carries high risk and low test coverage, and not likely to be
finished before the 3.2 release looms closer. Duncan and I would both
like to see the above issues addressed before we return to these
changes.
llvm-svn: 167222
2012-11-01 17:14:31 +08:00
|
|
|
DAG.getConstant(TD->getPointerSize(), MVT::i16);
|
2009-12-07 10:28:10 +08:00
|
|
|
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
|
|
|
|
DAG.getNode(ISD::ADD, dl, getPointerTy(),
|
|
|
|
FrameAddr, Offset),
|
2011-11-09 02:42:53 +08:00
|
|
|
MachinePointerInfo(), false, false, false, 0);
|
2009-12-07 10:28:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Just load the return address.
|
|
|
|
SDValue RetAddrFI = getReturnAddressFrameIndex(DAG);
|
|
|
|
return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(),
|
2011-11-09 02:42:53 +08:00
|
|
|
RetAddrFI, MachinePointerInfo(), false, false, false, 0);
|
2009-12-07 10:28:10 +08:00
|
|
|
}
|
|
|
|
|
2010-04-17 23:26:15 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerFRAMEADDR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2009-12-07 10:28:10 +08:00
|
|
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
MFI->setFrameAddressIsTaken(true);
|
2010-05-22 09:47:14 +08:00
|
|
|
|
2009-12-07 10:28:10 +08:00
|
|
|
EVT VT = Op.getValueType();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op); // FIXME probably not meaningful
|
2009-12-07 10:28:10 +08:00
|
|
|
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
|
|
|
SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl,
|
|
|
|
MSP430::FPW, VT);
|
|
|
|
while (Depth--)
|
2010-09-21 14:44:06 +08:00
|
|
|
FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr,
|
|
|
|
MachinePointerInfo(),
|
2011-11-09 02:42:53 +08:00
|
|
|
false, false, false, 0);
|
2009-12-07 10:28:10 +08:00
|
|
|
return FrameAddr;
|
|
|
|
}
|
|
|
|
|
2012-11-22 01:28:27 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerVASTART(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>();
|
|
|
|
|
|
|
|
// Frame index of first vararg argument
|
|
|
|
SDValue FrameIndex = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
|
|
|
|
getPointerTy());
|
|
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
|
|
|
|
|
|
|
// Create a store of the frame index to the location operand
|
2013-05-25 10:42:55 +08:00
|
|
|
return DAG.getStore(Op.getOperand(0), SDLoc(Op), FrameIndex,
|
2012-11-22 01:28:27 +08:00
|
|
|
Op.getOperand(1), MachinePointerInfo(SV),
|
|
|
|
false, false, 0);
|
|
|
|
}
|
|
|
|
|
2013-07-02 03:44:44 +08:00
|
|
|
SDValue MSP430TargetLowering::LowerJumpTable(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
|
|
|
|
SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), getPointerTy());
|
2013-07-14 23:11:00 +08:00
|
|
|
return DAG.getNode(MSP430ISD::Wrapper, SDLoc(JT),
|
|
|
|
getPointerTy(), Result);
|
2013-07-02 03:44:44 +08:00
|
|
|
}
|
|
|
|
|
2009-11-08 01:15:06 +08:00
|
|
|
/// getPostIndexedAddressParts - returns true by value, base pointer and
|
|
|
|
/// offset pointer and addressing mode by reference if this node can be
|
|
|
|
/// combined with a load / store to form a post-indexed load / store.
|
|
|
|
bool MSP430TargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
|
|
|
|
SDValue &Base,
|
|
|
|
SDValue &Offset,
|
|
|
|
ISD::MemIndexedMode &AM,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
|
|
|
|
LoadSDNode *LD = cast<LoadSDNode>(N);
|
|
|
|
if (LD->getExtensionType() != ISD::NON_EXTLOAD)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
EVT VT = LD->getMemoryVT();
|
|
|
|
if (VT != MVT::i8 && VT != MVT::i16)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Op->getOpcode() != ISD::ADD)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
|
|
|
|
uint64_t RHSC = RHS->getZExtValue();
|
|
|
|
if ((VT == MVT::i16 && RHSC != 2) ||
|
|
|
|
(VT == MVT::i8 && RHSC != 1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Base = Op->getOperand(0);
|
|
|
|
Offset = DAG.getConstant(RHSC, VT);
|
|
|
|
AM = ISD::POST_INC;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-03 20:59:50 +08:00
|
|
|
const char *MSP430TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
|
|
switch (Opcode) {
|
|
|
|
default: return NULL;
|
|
|
|
case MSP430ISD::RET_FLAG: return "MSP430ISD::RET_FLAG";
|
2009-12-07 10:28:41 +08:00
|
|
|
case MSP430ISD::RETI_FLAG: return "MSP430ISD::RETI_FLAG";
|
2009-05-03 21:03:33 +08:00
|
|
|
case MSP430ISD::RRA: return "MSP430ISD::RRA";
|
2009-05-03 21:16:17 +08:00
|
|
|
case MSP430ISD::RLA: return "MSP430ISD::RLA";
|
|
|
|
case MSP430ISD::RRC: return "MSP430ISD::RRC";
|
2009-05-03 21:07:54 +08:00
|
|
|
case MSP430ISD::CALL: return "MSP430ISD::CALL";
|
2009-05-03 21:08:33 +08:00
|
|
|
case MSP430ISD::Wrapper: return "MSP430ISD::Wrapper";
|
2009-05-03 21:19:09 +08:00
|
|
|
case MSP430ISD::BR_CC: return "MSP430ISD::BR_CC";
|
2009-05-03 21:12:06 +08:00
|
|
|
case MSP430ISD::CMP: return "MSP430ISD::CMP";
|
2009-05-03 21:19:09 +08:00
|
|
|
case MSP430ISD::SELECT_CC: return "MSP430ISD::SELECT_CC";
|
2009-12-13 02:55:37 +08:00
|
|
|
case MSP430ISD::SHL: return "MSP430ISD::SHL";
|
|
|
|
case MSP430ISD::SRA: return "MSP430ISD::SRA";
|
2009-05-03 20:59:50 +08:00
|
|
|
}
|
|
|
|
}
|
2009-05-03 21:12:23 +08:00
|
|
|
|
2011-07-18 12:54:35 +08:00
|
|
|
bool MSP430TargetLowering::isTruncateFree(Type *Ty1,
|
|
|
|
Type *Ty2) const {
|
2010-02-16 00:12:20 +08:00
|
|
|
if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy())
|
2010-01-16 05:19:43 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return (Ty1->getPrimitiveSizeInBits() > Ty2->getPrimitiveSizeInBits());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MSP430TargetLowering::isTruncateFree(EVT VT1, EVT VT2) const {
|
|
|
|
if (!VT1.isInteger() || !VT2.isInteger())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (VT1.getSizeInBits() > VT2.getSizeInBits());
|
|
|
|
}
|
|
|
|
|
2011-07-18 12:54:35 +08:00
|
|
|
bool MSP430TargetLowering::isZExtFree(Type *Ty1, Type *Ty2) const {
|
2010-01-16 05:19:43 +08:00
|
|
|
// MSP430 implicitly zero-extends 8-bit results in 16-bit registers.
|
2010-02-16 00:12:20 +08:00
|
|
|
return 0 && Ty1->isIntegerTy(8) && Ty2->isIntegerTy(16);
|
2010-01-16 05:19:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MSP430TargetLowering::isZExtFree(EVT VT1, EVT VT2) const {
|
|
|
|
// MSP430 implicitly zero-extends 8-bit results in 16-bit registers.
|
|
|
|
return 0 && VT1 == MVT::i8 && VT2 == MVT::i16;
|
|
|
|
}
|
|
|
|
|
2012-12-19 02:21:29 +08:00
|
|
|
bool MSP430TargetLowering::isZExtFree(SDValue Val, EVT VT2) const {
|
|
|
|
return isZExtFree(Val.getValueType(), VT2);
|
|
|
|
}
|
|
|
|
|
2009-05-03 21:12:23 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Other Lowering Code
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-12-13 02:55:37 +08:00
|
|
|
MachineBasicBlock*
|
|
|
|
MSP430TargetLowering::EmitShiftInstr(MachineInstr *MI,
|
2010-05-01 08:01:06 +08:00
|
|
|
MachineBasicBlock *BB) const {
|
2009-12-13 02:55:37 +08:00
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
MachineRegisterInfo &RI = F->getRegInfo();
|
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
|
|
|
const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
|
|
|
|
|
|
|
|
unsigned Opc;
|
|
|
|
const TargetRegisterClass * RC;
|
|
|
|
switch (MI->getOpcode()) {
|
2012-02-07 10:50:20 +08:00
|
|
|
default: llvm_unreachable("Invalid shift opcode!");
|
2009-12-13 02:55:37 +08:00
|
|
|
case MSP430::Shl8:
|
|
|
|
Opc = MSP430::SHL8r1;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR8RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
case MSP430::Shl16:
|
|
|
|
Opc = MSP430::SHL16r1;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR16RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
case MSP430::Sra8:
|
|
|
|
Opc = MSP430::SAR8r1;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR8RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
case MSP430::Sra16:
|
|
|
|
Opc = MSP430::SAR16r1;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR16RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
case MSP430::Srl8:
|
|
|
|
Opc = MSP430::SAR8r1c;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR8RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
case MSP430::Srl16:
|
|
|
|
Opc = MSP430::SAR16r1c;
|
2012-04-20 15:30:17 +08:00
|
|
|
RC = &MSP430::GR16RegClass;
|
2009-12-13 02:55:37 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
|
|
|
MachineFunction::iterator I = BB;
|
|
|
|
++I;
|
|
|
|
|
|
|
|
// Create loop block
|
|
|
|
MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
|
|
|
|
F->insert(I, LoopBB);
|
|
|
|
F->insert(I, RemBB);
|
|
|
|
|
|
|
|
// Update machine-CFG edges by transferring all successors of the current
|
|
|
|
// block to the block containing instructions after shift.
|
2010-07-07 04:24:04 +08:00
|
|
|
RemBB->splice(RemBB->begin(), BB,
|
|
|
|
llvm::next(MachineBasicBlock::iterator(MI)),
|
|
|
|
BB->end());
|
|
|
|
RemBB->transferSuccessorsAndUpdatePHIs(BB);
|
2009-12-13 02:55:37 +08:00
|
|
|
|
|
|
|
// Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB
|
|
|
|
BB->addSuccessor(LoopBB);
|
|
|
|
BB->addSuccessor(RemBB);
|
|
|
|
LoopBB->addSuccessor(RemBB);
|
|
|
|
LoopBB->addSuccessor(LoopBB);
|
|
|
|
|
2012-04-20 15:30:17 +08:00
|
|
|
unsigned ShiftAmtReg = RI.createVirtualRegister(&MSP430::GR8RegClass);
|
|
|
|
unsigned ShiftAmtReg2 = RI.createVirtualRegister(&MSP430::GR8RegClass);
|
2009-12-13 02:55:37 +08:00
|
|
|
unsigned ShiftReg = RI.createVirtualRegister(RC);
|
|
|
|
unsigned ShiftReg2 = RI.createVirtualRegister(RC);
|
|
|
|
unsigned ShiftAmtSrcReg = MI->getOperand(2).getReg();
|
|
|
|
unsigned SrcReg = MI->getOperand(1).getReg();
|
|
|
|
unsigned DstReg = MI->getOperand(0).getReg();
|
|
|
|
|
|
|
|
// BB:
|
|
|
|
// cmp 0, N
|
|
|
|
// je RemBB
|
2010-01-15 09:29:49 +08:00
|
|
|
BuildMI(BB, dl, TII.get(MSP430::CMP8ri))
|
|
|
|
.addReg(ShiftAmtSrcReg).addImm(0);
|
2009-12-13 02:55:37 +08:00
|
|
|
BuildMI(BB, dl, TII.get(MSP430::JCC))
|
|
|
|
.addMBB(RemBB)
|
|
|
|
.addImm(MSP430CC::COND_E);
|
|
|
|
|
|
|
|
// LoopBB:
|
|
|
|
// ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
|
|
|
|
// ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB]
|
|
|
|
// ShiftReg2 = shift ShiftReg
|
|
|
|
// ShiftAmt2 = ShiftAmt - 1;
|
|
|
|
BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftReg)
|
|
|
|
.addReg(SrcReg).addMBB(BB)
|
|
|
|
.addReg(ShiftReg2).addMBB(LoopBB);
|
|
|
|
BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftAmtReg)
|
|
|
|
.addReg(ShiftAmtSrcReg).addMBB(BB)
|
|
|
|
.addReg(ShiftAmtReg2).addMBB(LoopBB);
|
|
|
|
BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2)
|
|
|
|
.addReg(ShiftReg);
|
|
|
|
BuildMI(LoopBB, dl, TII.get(MSP430::SUB8ri), ShiftAmtReg2)
|
|
|
|
.addReg(ShiftAmtReg).addImm(1);
|
|
|
|
BuildMI(LoopBB, dl, TII.get(MSP430::JCC))
|
|
|
|
.addMBB(LoopBB)
|
|
|
|
.addImm(MSP430CC::COND_NE);
|
|
|
|
|
|
|
|
// RemBB:
|
|
|
|
// DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
|
2010-07-07 04:24:04 +08:00
|
|
|
BuildMI(*RemBB, RemBB->begin(), dl, TII.get(MSP430::PHI), DstReg)
|
2009-12-13 02:55:37 +08:00
|
|
|
.addReg(SrcReg).addMBB(BB)
|
|
|
|
.addReg(ShiftReg2).addMBB(LoopBB);
|
|
|
|
|
2010-07-07 04:24:04 +08:00
|
|
|
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
2009-12-13 02:55:37 +08:00
|
|
|
return RemBB;
|
|
|
|
}
|
|
|
|
|
2009-05-03 21:12:23 +08:00
|
|
|
MachineBasicBlock*
|
|
|
|
MSP430TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
2010-05-01 08:01:06 +08:00
|
|
|
MachineBasicBlock *BB) const {
|
2009-12-13 02:55:37 +08:00
|
|
|
unsigned Opc = MI->getOpcode();
|
|
|
|
|
|
|
|
if (Opc == MSP430::Shl8 || Opc == MSP430::Shl16 ||
|
|
|
|
Opc == MSP430::Sra8 || Opc == MSP430::Sra16 ||
|
|
|
|
Opc == MSP430::Srl8 || Opc == MSP430::Srl16)
|
2010-05-01 08:01:06 +08:00
|
|
|
return EmitShiftInstr(MI, BB);
|
2009-12-13 02:55:37 +08:00
|
|
|
|
2009-05-03 21:12:23 +08:00
|
|
|
const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
|
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
2009-12-13 02:55:37 +08:00
|
|
|
|
|
|
|
assert((Opc == MSP430::Select16 || Opc == MSP430::Select8) &&
|
2009-05-03 21:12:23 +08:00
|
|
|
"Unexpected instr type to insert");
|
|
|
|
|
|
|
|
// To "insert" a SELECT instruction, we actually have to insert the diamond
|
|
|
|
// control-flow pattern. The incoming instruction knows the destination vreg
|
|
|
|
// to set, the condition code register to branch on, the true/false values to
|
|
|
|
// select between, and a branch opcode to use.
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
|
|
|
MachineFunction::iterator I = BB;
|
|
|
|
++I;
|
|
|
|
|
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// TrueVal = ...
|
|
|
|
// cmpTY ccX, r1, r2
|
|
|
|
// jCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *copy1MBB = F->CreateMachineBasicBlock(LLVM_BB);
|
|
|
|
F->insert(I, copy0MBB);
|
|
|
|
F->insert(I, copy1MBB);
|
|
|
|
// Update machine-CFG edges by transferring all successors of the current
|
|
|
|
// block to the new block which will contain the Phi node for the select.
|
2010-07-07 04:24:04 +08:00
|
|
|
copy1MBB->splice(copy1MBB->begin(), BB,
|
|
|
|
llvm::next(MachineBasicBlock::iterator(MI)),
|
|
|
|
BB->end());
|
|
|
|
copy1MBB->transferSuccessorsAndUpdatePHIs(BB);
|
2009-05-03 21:12:23 +08:00
|
|
|
// Next, add the true and fallthrough blocks as its successors.
|
|
|
|
BB->addSuccessor(copy0MBB);
|
|
|
|
BB->addSuccessor(copy1MBB);
|
|
|
|
|
2010-07-07 04:24:04 +08:00
|
|
|
BuildMI(BB, dl, TII.get(MSP430::JCC))
|
|
|
|
.addMBB(copy1MBB)
|
|
|
|
.addImm(MI->getOperand(3).getImm());
|
|
|
|
|
2009-05-03 21:12:23 +08:00
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
|
|
|
// # fallthrough to copy1MBB
|
|
|
|
BB = copy0MBB;
|
|
|
|
|
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(copy1MBB);
|
|
|
|
|
|
|
|
// copy1MBB:
|
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
|
|
// ...
|
|
|
|
BB = copy1MBB;
|
2010-07-07 04:24:04 +08:00
|
|
|
BuildMI(*BB, BB->begin(), dl, TII.get(MSP430::PHI),
|
2009-05-03 21:12:23 +08:00
|
|
|
MI->getOperand(0).getReg())
|
|
|
|
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB)
|
|
|
|
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB);
|
|
|
|
|
2010-07-07 04:24:04 +08:00
|
|
|
MI->eraseFromParent(); // The pseudo instruction is gone now.
|
2009-05-03 21:12:23 +08:00
|
|
|
return BB;
|
|
|
|
}
|