mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
767 lines
28 KiB
C++
767 lines
28 KiB
C++
//===- ARCISelLowering.cpp - ARC DAG Lowering Impl --------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the ARCTargetLowering class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ARCISelLowering.h"
|
|
#include "ARC.h"
|
|
#include "ARCMachineFunctionInfo.h"
|
|
#include "ARCSubtarget.h"
|
|
#include "ARCTargetMachine.h"
|
|
#include "MCTargetDesc/ARCInfo.h"
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/CodeGen/ValueTypes.h"
|
|
#include "llvm/IR/CallingConv.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include <algorithm>
|
|
|
|
#define DEBUG_TYPE "arc-lower"
|
|
|
|
using namespace llvm;
|
|
|
|
static SDValue lowerCallResult(SDValue Chain, SDValue InFlag,
|
|
const SmallVectorImpl<CCValAssign> &RVLocs,
|
|
SDLoc dl, SelectionDAG &DAG,
|
|
SmallVectorImpl<SDValue> &InVals);
|
|
|
|
static ARCCC::CondCode ISDCCtoARCCC(ISD::CondCode isdCC) {
|
|
switch (isdCC) {
|
|
case ISD::SETUEQ:
|
|
return ARCCC::EQ;
|
|
case ISD::SETUGT:
|
|
return ARCCC::HI;
|
|
case ISD::SETUGE:
|
|
return ARCCC::HS;
|
|
case ISD::SETULT:
|
|
return ARCCC::LO;
|
|
case ISD::SETULE:
|
|
return ARCCC::LS;
|
|
case ISD::SETUNE:
|
|
return ARCCC::NE;
|
|
case ISD::SETEQ:
|
|
return ARCCC::EQ;
|
|
case ISD::SETGT:
|
|
return ARCCC::GT;
|
|
case ISD::SETGE:
|
|
return ARCCC::GE;
|
|
case ISD::SETLT:
|
|
return ARCCC::LT;
|
|
case ISD::SETLE:
|
|
return ARCCC::LE;
|
|
case ISD::SETNE:
|
|
return ARCCC::NE;
|
|
default:
|
|
llvm_unreachable("Unhandled ISDCC code.");
|
|
}
|
|
}
|
|
|
|
ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM,
|
|
const ARCSubtarget &Subtarget)
|
|
: TargetLowering(TM), Subtarget(Subtarget) {
|
|
// Set up the register classes.
|
|
addRegisterClass(MVT::i32, &ARC::GPR32RegClass);
|
|
|
|
// Compute derived properties from the register classes
|
|
computeRegisterProperties(Subtarget.getRegisterInfo());
|
|
|
|
setStackPointerRegisterToSaveRestore(ARC::SP);
|
|
|
|
setSchedulingPreference(Sched::Source);
|
|
|
|
// Use i32 for setcc operations results (slt, sgt, ...).
|
|
setBooleanContents(ZeroOrOneBooleanContent);
|
|
setBooleanVectorContents(ZeroOrOneBooleanContent);
|
|
|
|
for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
|
|
setOperationAction(Opc, MVT::i32, Expand);
|
|
|
|
// Operations to get us off of the ground.
|
|
// Basic.
|
|
setOperationAction(ISD::ADD, MVT::i32, Legal);
|
|
setOperationAction(ISD::SUB, MVT::i32, Legal);
|
|
setOperationAction(ISD::AND, MVT::i32, Legal);
|
|
setOperationAction(ISD::SMAX, MVT::i32, Legal);
|
|
setOperationAction(ISD::SMIN, MVT::i32, Legal);
|
|
|
|
// Need barrel shifter.
|
|
setOperationAction(ISD::SHL, MVT::i32, Legal);
|
|
setOperationAction(ISD::SRA, MVT::i32, Legal);
|
|
setOperationAction(ISD::SRL, MVT::i32, Legal);
|
|
setOperationAction(ISD::ROTR, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::Constant, MVT::i32, Legal);
|
|
setOperationAction(ISD::UNDEF, MVT::i32, Legal);
|
|
|
|
// Need multiplier
|
|
setOperationAction(ISD::MUL, MVT::i32, Legal);
|
|
setOperationAction(ISD::MULHS, MVT::i32, Legal);
|
|
setOperationAction(ISD::MULHU, MVT::i32, Legal);
|
|
setOperationAction(ISD::LOAD, MVT::i32, Legal);
|
|
setOperationAction(ISD::STORE, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
|
|
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
|
|
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
|
|
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
|
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
|
|
|
|
// Have psuedo instruction for frame addresses.
|
|
setOperationAction(ISD::FRAMEADDR, MVT::i32, Legal);
|
|
// Custom lower global addresses.
|
|
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
|
|
|
// Expand var-args ops.
|
|
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
|
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
|
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
|
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
|
|
|
// Other expansions
|
|
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
|
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
|
|
|
// Sign extend inreg
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Custom);
|
|
}
|
|
|
|
const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
switch (Opcode) {
|
|
case ARCISD::BL:
|
|
return "ARCISD::BL";
|
|
case ARCISD::CMOV:
|
|
return "ARCISD::CMOV";
|
|
case ARCISD::CMP:
|
|
return "ARCISD::CMP";
|
|
case ARCISD::BRcc:
|
|
return "ARCISD::BRcc";
|
|
case ARCISD::RET:
|
|
return "ARCISD::RET";
|
|
case ARCISD::GAWRAPPER:
|
|
return "ARCISD::GAWRAPPER";
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Misc Lower Operation implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SDValue ARCTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
|
|
SDValue LHS = Op.getOperand(0);
|
|
SDValue RHS = Op.getOperand(1);
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
|
|
SDValue TVal = Op.getOperand(2);
|
|
SDValue FVal = Op.getOperand(3);
|
|
SDLoc dl(Op);
|
|
ARCCC::CondCode ArcCC = ISDCCtoARCCC(CC);
|
|
assert(LHS.getValueType() == MVT::i32 && "Only know how to SELECT_CC i32");
|
|
SDValue Cmp = DAG.getNode(ARCISD::CMP, dl, MVT::Glue, LHS, RHS);
|
|
return DAG.getNode(ARCISD::CMOV, dl, TVal.getValueType(), TVal, FVal,
|
|
DAG.getConstant(ArcCC, dl, MVT::i32), Cmp);
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
|
|
SelectionDAG &DAG) const {
|
|
SDValue Op0 = Op.getOperand(0);
|
|
SDLoc dl(Op);
|
|
assert(Op.getValueType() == MVT::i32 &&
|
|
"Unhandled target sign_extend_inreg.");
|
|
// These are legal
|
|
unsigned Width = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
|
|
if (Width == 16 || Width == 8)
|
|
return Op;
|
|
if (Width >= 32) {
|
|
return {};
|
|
}
|
|
SDValue LS = DAG.getNode(ISD::SHL, dl, MVT::i32, Op0,
|
|
DAG.getConstant(32 - Width, dl, MVT::i32));
|
|
SDValue SR = DAG.getNode(ISD::SRA, dl, MVT::i32, LS,
|
|
DAG.getConstant(32 - Width, dl, MVT::i32));
|
|
return SR;
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
|
|
SDValue Chain = Op.getOperand(0);
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
|
|
SDValue LHS = Op.getOperand(2);
|
|
SDValue RHS = Op.getOperand(3);
|
|
SDValue Dest = Op.getOperand(4);
|
|
SDLoc dl(Op);
|
|
ARCCC::CondCode arcCC = ISDCCtoARCCC(CC);
|
|
assert(LHS.getValueType() == MVT::i32 && "Only know how to BR_CC i32");
|
|
return DAG.getNode(ARCISD::BRcc, dl, MVT::Other, Chain, Dest, LHS, RHS,
|
|
DAG.getConstant(arcCC, dl, MVT::i32));
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
|
|
auto *N = cast<JumpTableSDNode>(Op);
|
|
SDValue GA = DAG.getTargetJumpTable(N->getIndex(), MVT::i32);
|
|
return DAG.getNode(ARCISD::GAWRAPPER, SDLoc(N), MVT::i32, GA);
|
|
}
|
|
|
|
#include "ARCGenCallingConv.inc"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Call Calling Convention Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// ARC call implementation
|
|
SDValue ARCTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
|
SelectionDAG &DAG = CLI.DAG;
|
|
SDLoc &dl = CLI.DL;
|
|
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
|
|
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
|
|
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
|
|
SDValue Chain = CLI.Chain;
|
|
SDValue Callee = CLI.Callee;
|
|
CallingConv::ID CallConv = CLI.CallConv;
|
|
bool IsVarArg = CLI.IsVarArg;
|
|
bool &IsTailCall = CLI.IsTailCall;
|
|
|
|
IsTailCall = false; // Do not support tail calls yet.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
|
|
*DAG.getContext());
|
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_ARC);
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
// Analyze return values to determine the number of bytes of stack required.
|
|
CCState RetCCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
|
|
*DAG.getContext());
|
|
RetCCInfo.AllocateStack(CCInfo.getNextStackOffset(), 4);
|
|
RetCCInfo.AnalyzeCallResult(Ins, RetCC_ARC);
|
|
|
|
// Get a count of how many bytes are to be pushed on the stack.
|
|
unsigned NumBytes = RetCCInfo.getNextStackOffset();
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);
|
|
|
|
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];
|
|
SDValue Arg = OutVals[i];
|
|
|
|
// Promote the value if needed.
|
|
switch (VA.getLocInfo()) {
|
|
default:
|
|
llvm_unreachable("Unknown loc info!");
|
|
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() && "Must be register or memory argument.");
|
|
if (!StackPtr.getNode())
|
|
StackPtr = DAG.getCopyFromReg(Chain, dl, ARC::SP,
|
|
getPointerTy(DAG.getDataLayout()));
|
|
// Calculate the stack position.
|
|
SDValue SOffset = DAG.getIntPtrConstant(VA.getLocMemOffset(), dl);
|
|
SDValue PtrOff = DAG.getNode(
|
|
ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), StackPtr, SOffset);
|
|
|
|
SDValue Store =
|
|
DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo());
|
|
MemOpChains.push_back(Store);
|
|
IsTailCall = false;
|
|
}
|
|
}
|
|
|
|
// Transform all store nodes into one single node because
|
|
// all store nodes are independent of each other.
|
|
if (!MemOpChains.empty())
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
|
|
|
|
// 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 necessary since all emitted instructions must be
|
|
// stuck together.
|
|
SDValue Glue;
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
|
|
RegsToPass[i].second, Glue);
|
|
Glue = 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.
|
|
bool IsDirect = true;
|
|
if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
|
|
else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
|
|
else
|
|
IsDirect = false;
|
|
// Branch + Link = #chain, #target_address, #opt_in_flags...
|
|
// = Chain, Callee, Reg#1, Reg#2, ...
|
|
//
|
|
// Returns a chain & a flag for retval copy to use.
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
SmallVector<SDValue, 8> Ops;
|
|
Ops.push_back(Chain);
|
|
Ops.push_back(Callee);
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
// Add a register mask operand representing the call-preserved registers.
|
|
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
|
|
const uint32_t *Mask =
|
|
TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
|
|
assert(Mask && "Missing call preserved mask for calling convention");
|
|
Ops.push_back(DAG.getRegisterMask(Mask));
|
|
|
|
if (Glue.getNode())
|
|
Ops.push_back(Glue);
|
|
|
|
Chain = DAG.getNode(IsDirect ? ARCISD::BL : ARCISD::JL, dl, NodeTys, Ops);
|
|
Glue = Chain.getValue(1);
|
|
|
|
// Create the CALLSEQ_END node.
|
|
Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, dl, PtrVT, true),
|
|
DAG.getConstant(0, dl, PtrVT, true), Glue, dl);
|
|
Glue = Chain.getValue(1);
|
|
|
|
// Handle result values, copying them out of physregs into vregs that we
|
|
// return.
|
|
if (IsTailCall)
|
|
return Chain;
|
|
return lowerCallResult(Chain, Glue, RVLocs, dl, DAG, InVals);
|
|
}
|
|
|
|
/// Lower the result values of a call into the appropriate copies out of
|
|
/// physical registers / memory locations.
|
|
static SDValue lowerCallResult(SDValue Chain, SDValue Glue,
|
|
const SmallVectorImpl<CCValAssign> &RVLocs,
|
|
SDLoc dl, SelectionDAG &DAG,
|
|
SmallVectorImpl<SDValue> &InVals) {
|
|
SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs;
|
|
// Copy results out of physical registers.
|
|
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
|
|
const CCValAssign &VA = RVLocs[i];
|
|
if (VA.isRegLoc()) {
|
|
SDValue RetValue;
|
|
RetValue =
|
|
DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(), Glue);
|
|
Chain = RetValue.getValue(1);
|
|
Glue = RetValue.getValue(2);
|
|
InVals.push_back(RetValue);
|
|
} else {
|
|
assert(VA.isMemLoc() && "Must be memory location.");
|
|
ResultMemLocs.push_back(
|
|
std::make_pair(VA.getLocMemOffset(), InVals.size()));
|
|
|
|
// Reserve space for this result.
|
|
InVals.push_back(SDValue());
|
|
}
|
|
}
|
|
|
|
// Copy results out of memory.
|
|
SmallVector<SDValue, 4> MemOpChains;
|
|
for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) {
|
|
int Offset = ResultMemLocs[i].first;
|
|
unsigned Index = ResultMemLocs[i].second;
|
|
SDValue StackPtr = DAG.getRegister(ARC::SP, MVT::i32);
|
|
SDValue SpLoc = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr,
|
|
DAG.getConstant(Offset, dl, MVT::i32));
|
|
SDValue Load =
|
|
DAG.getLoad(MVT::i32, dl, Chain, SpLoc, MachinePointerInfo());
|
|
InVals[Index] = Load;
|
|
MemOpChains.push_back(Load.getValue(1));
|
|
}
|
|
|
|
// Transform all loads nodes into one single node because
|
|
// all load nodes are independent of each other.
|
|
if (!MemOpChains.empty())
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
|
|
|
|
return Chain;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Formal Arguments Calling Convention Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
struct ArgDataPair {
|
|
SDValue SDV;
|
|
ISD::ArgFlagsTy Flags;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
/// ARC formal arguments implementation
|
|
SDValue ARCTargetLowering::LowerFormalArguments(
|
|
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
|
|
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
|
|
switch (CallConv) {
|
|
default:
|
|
llvm_unreachable("Unsupported calling convention");
|
|
case CallingConv::C:
|
|
case CallingConv::Fast:
|
|
return LowerCallArguments(Chain, CallConv, IsVarArg, Ins, dl, DAG, InVals);
|
|
}
|
|
}
|
|
|
|
/// Transform physical registers into virtual registers, and generate load
|
|
/// operations for argument places on the stack.
|
|
SDValue ARCTargetLowering::LowerCallArguments(
|
|
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG,
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
MachineRegisterInfo &RegInfo = MF.getRegInfo();
|
|
auto *AFI = MF.getInfo<ARCFunctionInfo>();
|
|
|
|
// Assign locations to all of the incoming arguments.
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
|
|
*DAG.getContext());
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_ARC);
|
|
|
|
unsigned StackSlotSize = 4;
|
|
|
|
if (!IsVarArg)
|
|
AFI->setReturnStackOffset(CCInfo.getNextStackOffset());
|
|
|
|
// All getCopyFromReg ops must precede any getMemcpys to prevent the
|
|
// scheduler clobbering a register before it has been copied.
|
|
// The stages are:
|
|
// 1. CopyFromReg (and load) arg & vararg registers.
|
|
// 2. Chain CopyFromReg nodes into a TokenFactor.
|
|
// 3. Memcpy 'byVal' args & push final InVals.
|
|
// 4. Chain mem ops nodes into a TokenFactor.
|
|
SmallVector<SDValue, 4> CFRegNode;
|
|
SmallVector<ArgDataPair, 4> ArgData;
|
|
SmallVector<SDValue, 4> MemOps;
|
|
|
|
// 1a. CopyFromReg (and load) arg registers.
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
CCValAssign &VA = ArgLocs[i];
|
|
SDValue ArgIn;
|
|
|
|
if (VA.isRegLoc()) {
|
|
// Arguments passed in registers
|
|
EVT RegVT = VA.getLocVT();
|
|
switch (RegVT.getSimpleVT().SimpleTy) {
|
|
default: {
|
|
LLVM_DEBUG(errs() << "LowerFormalArguments Unhandled argument type: "
|
|
<< (unsigned)RegVT.getSimpleVT().SimpleTy << "\n");
|
|
llvm_unreachable("Unhandled LowerFormalArguments type.");
|
|
}
|
|
case MVT::i32:
|
|
unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
|
|
RegInfo.addLiveIn(VA.getLocReg(), VReg);
|
|
ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
|
|
CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1));
|
|
}
|
|
} else {
|
|
// sanity check
|
|
assert(VA.isMemLoc());
|
|
// Load the argument to a virtual register
|
|
unsigned ObjSize = VA.getLocVT().getStoreSize();
|
|
assert((ObjSize <= StackSlotSize) && "Unhandled argument");
|
|
|
|
// 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::i32);
|
|
ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
|
|
MachinePointerInfo::getFixedStack(MF, FI));
|
|
}
|
|
const ArgDataPair ADP = {ArgIn, Ins[i].Flags};
|
|
ArgData.push_back(ADP);
|
|
}
|
|
|
|
// 1b. CopyFromReg vararg registers.
|
|
if (IsVarArg) {
|
|
// Argument registers
|
|
static const MCPhysReg ArgRegs[] = {ARC::R0, ARC::R1, ARC::R2, ARC::R3,
|
|
ARC::R4, ARC::R5, ARC::R6, ARC::R7};
|
|
auto *AFI = MF.getInfo<ARCFunctionInfo>();
|
|
unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs);
|
|
if (FirstVAReg < array_lengthof(ArgRegs)) {
|
|
int Offset = 0;
|
|
// Save remaining registers, storing higher register numbers at a higher
|
|
// address
|
|
// There are (array_lengthof(ArgRegs) - FirstVAReg) registers which
|
|
// need to be saved.
|
|
int VarFI =
|
|
MFI.CreateFixedObject((array_lengthof(ArgRegs) - FirstVAReg) * 4,
|
|
CCInfo.getNextStackOffset(), true);
|
|
AFI->setVarArgsFrameIndex(VarFI);
|
|
SDValue FIN = DAG.getFrameIndex(VarFI, MVT::i32);
|
|
for (unsigned i = FirstVAReg; i < array_lengthof(ArgRegs); i++) {
|
|
// Move argument from phys reg -> virt reg
|
|
unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
|
|
RegInfo.addLiveIn(ArgRegs[i], VReg);
|
|
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
|
|
CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1));
|
|
SDValue VAObj = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN,
|
|
DAG.getConstant(Offset, dl, MVT::i32));
|
|
// Move argument from virt reg -> stack
|
|
SDValue Store =
|
|
DAG.getStore(Val.getValue(1), dl, Val, VAObj, MachinePointerInfo());
|
|
MemOps.push_back(Store);
|
|
Offset += 4;
|
|
}
|
|
} else {
|
|
llvm_unreachable("Too many var args parameters.");
|
|
}
|
|
}
|
|
|
|
// 2. Chain CopyFromReg nodes into a TokenFactor.
|
|
if (!CFRegNode.empty())
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode);
|
|
|
|
// 3. Memcpy 'byVal' args & push final InVals.
|
|
// Aggregates passed "byVal" need to be copied by the callee.
|
|
// The callee will use a pointer to this copy, rather than the original
|
|
// pointer.
|
|
for (const auto &ArgDI : ArgData) {
|
|
if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) {
|
|
unsigned Size = ArgDI.Flags.getByValSize();
|
|
unsigned Align = std::max(StackSlotSize, ArgDI.Flags.getByValAlign());
|
|
// Create a new object on the stack and copy the pointee into it.
|
|
int FI = MFI.CreateStackObject(Size, Align, false);
|
|
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
|
InVals.push_back(FIN);
|
|
MemOps.push_back(DAG.getMemcpy(
|
|
Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32), Align,
|
|
false, false, false, MachinePointerInfo(), MachinePointerInfo()));
|
|
} else {
|
|
InVals.push_back(ArgDI.SDV);
|
|
}
|
|
}
|
|
|
|
// 4. Chain mem ops nodes into a TokenFactor.
|
|
if (!MemOps.empty()) {
|
|
MemOps.push_back(Chain);
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
|
|
}
|
|
|
|
return Chain;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Return Value Calling Convention Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool ARCTargetLowering::CanLowerReturn(
|
|
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
|
|
if (!CCInfo.CheckReturn(Outs, RetCC_ARC))
|
|
return false;
|
|
if (CCInfo.getNextStackOffset() != 0 && IsVarArg)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
SDValue
|
|
ARCTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
|
bool IsVarArg,
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
|
const SDLoc &dl, SelectionDAG &DAG) const {
|
|
auto *AFI = DAG.getMachineFunction().getInfo<ARCFunctionInfo>();
|
|
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
|
|
|
|
// CCValAssign - represent the assignment of
|
|
// the return value to a location
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
// CCState - Info about the registers and stack slot.
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
|
|
*DAG.getContext());
|
|
|
|
// Analyze return values.
|
|
if (!IsVarArg)
|
|
CCInfo.AllocateStack(AFI->getReturnStackOffset(), 4);
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_ARC);
|
|
|
|
SDValue Flag;
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
SmallVector<SDValue, 4> MemOpChains;
|
|
// Handle return values that must be copied to memory.
|
|
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
|
|
CCValAssign &VA = RVLocs[i];
|
|
if (VA.isRegLoc())
|
|
continue;
|
|
assert(VA.isMemLoc());
|
|
if (IsVarArg) {
|
|
report_fatal_error("Can't return value from vararg function in memory");
|
|
}
|
|
|
|
int Offset = VA.getLocMemOffset();
|
|
unsigned ObjSize = VA.getLocVT().getStoreSize();
|
|
// Create the frame index object for the memory location.
|
|
int FI = MFI.CreateFixedObject(ObjSize, Offset, false);
|
|
|
|
// Create a SelectionDAG node corresponding to a store
|
|
// to this memory location.
|
|
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
|
MemOpChains.push_back(DAG.getStore(
|
|
Chain, dl, OutVals[i], FIN,
|
|
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));
|
|
}
|
|
|
|
// Transform all store nodes into one single node because
|
|
// all stores are independent of each other.
|
|
if (!MemOpChains.empty())
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
|
|
|
|
// Now handle return values copied to registers.
|
|
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
|
|
CCValAssign &VA = RVLocs[i];
|
|
if (!VA.isRegLoc())
|
|
continue;
|
|
// Copy the result values into the output registers.
|
|
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag);
|
|
|
|
// guarantee that all emitted copies are
|
|
// stuck together, avoiding something bad
|
|
Flag = Chain.getValue(1);
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
|
}
|
|
|
|
RetOps[0] = Chain; // Update chain.
|
|
|
|
// Add the flag if we have it.
|
|
if (Flag.getNode())
|
|
RetOps.push_back(Flag);
|
|
|
|
// What to do with the RetOps?
|
|
return DAG.getNode(ARCISD::RET, dl, MVT::Other, RetOps);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Target Optimization Hooks
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SDValue ARCTargetLowering::PerformDAGCombine(SDNode *N,
|
|
DAGCombinerInfo &DCI) const {
|
|
return {};
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Addressing mode description hooks
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Return true if the addressing mode represented by AM is legal for this
|
|
/// target, for a load/store of the specified type.
|
|
bool ARCTargetLowering::isLegalAddressingMode(const DataLayout &DL,
|
|
const AddrMode &AM, Type *Ty,
|
|
unsigned AS,
|
|
Instruction *I) const {
|
|
return AM.Scale == 0;
|
|
}
|
|
|
|
// Don't emit tail calls for the time being.
|
|
bool ARCTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
|
|
return false;
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
|
|
const ARCRegisterInfo &ARI = *Subtarget.getRegisterInfo();
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
MFI.setFrameAddressIsTaken(true);
|
|
|
|
EVT VT = Op.getValueType();
|
|
SDLoc dl(Op);
|
|
assert(cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0 &&
|
|
"Only support lowering frame addr of current frame.");
|
|
unsigned FrameReg = ARI.getFrameRegister(MF);
|
|
return DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerGlobalAddress(SDValue Op,
|
|
SelectionDAG &DAG) const {
|
|
const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
|
|
const GlobalValue *GV = GN->getGlobal();
|
|
SDLoc dl(GN);
|
|
int64_t Offset = GN->getOffset();
|
|
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, Offset);
|
|
return DAG.getNode(ARCISD::GAWRAPPER, dl, MVT::i32, GA);
|
|
}
|
|
|
|
static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) {
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
auto *FuncInfo = MF.getInfo<ARCFunctionInfo>();
|
|
|
|
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
|
// memory location argument.
|
|
SDLoc dl(Op);
|
|
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
|
|
SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
|
return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1),
|
|
MachinePointerInfo(SV));
|
|
}
|
|
|
|
SDValue ARCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
|
switch (Op.getOpcode()) {
|
|
case ISD::GlobalAddress:
|
|
return LowerGlobalAddress(Op, DAG);
|
|
case ISD::FRAMEADDR:
|
|
return LowerFRAMEADDR(Op, DAG);
|
|
case ISD::SELECT_CC:
|
|
return LowerSELECT_CC(Op, DAG);
|
|
case ISD::BR_CC:
|
|
return LowerBR_CC(Op, DAG);
|
|
case ISD::SIGN_EXTEND_INREG:
|
|
return LowerSIGN_EXTEND_INREG(Op, DAG);
|
|
case ISD::JumpTable:
|
|
return LowerJumpTable(Op, DAG);
|
|
case ISD::VASTART:
|
|
return LowerVASTART(Op, DAG);
|
|
default:
|
|
llvm_unreachable("unimplemented operand");
|
|
}
|
|
}
|