llvm-project/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

200 lines
6.8 KiB
C++

//=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation ---===//
//
// 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 defines the interfaces that LoongArch uses to lower LLVM code into
// a selection DAG.
//
//===----------------------------------------------------------------------===//
#include "LoongArchISelLowering.h"
#include "LoongArch.h"
#include "LoongArchMachineFunctionInfo.h"
#include "LoongArchRegisterInfo.h"
#include "LoongArchSubtarget.h"
#include "LoongArchTargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
#define DEBUG_TYPE "loongarch-isel-lowering"
LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
const LoongArchSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
MVT GRLenVT = Subtarget.getGRLenVT();
// Set up the register classes.
addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
// TODO: add necessary setOperationAction calls later.
// Compute derived properties from the register classes.
computeRegisterProperties(STI.getRegisterInfo());
setStackPointerRegisterToSaveRestore(LoongArch::R3);
// Function alignments.
const Align FunctionAlignment(4);
setMinFunctionAlignment(FunctionAlignment);
}
const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch ((LoongArchISD::NodeType)Opcode) {
case LoongArchISD::FIRST_NUMBER:
break;
#define NODE_NAME_CASE(node) \
case LoongArchISD::node: \
return "LoongArchISD::" #node;
// TODO: Add more target-dependent nodes later.
NODE_NAME_CASE(RET)
}
#undef NODE_NAME_CASE
return nullptr;
}
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
// FIXME: Now, we only support CallingConv::C with fixed arguments which are
// passed with integer registers.
const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
LoongArch::R7, LoongArch::R8, LoongArch::R9,
LoongArch::R10, LoongArch::R11};
// Implements the LoongArch calling convention. Returns true upon failure.
static bool CC_LoongArch(unsigned ValNo, MVT ValVT,
CCValAssign::LocInfo LocInfo, CCState &State) {
// Allocate to a register if possible.
Register Reg = State.AllocateReg(ArgGPRs);
if (Reg) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, ValVT, LocInfo));
return false;
}
// TODO: Handle arguments passed without register.
return true;
}
void LoongArchTargetLowering::analyzeInputArgs(
CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins,
LoongArchCCAssignFn Fn) const {
for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
MVT ArgVT = Ins[i].VT;
if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
<< EVT(ArgVT).getEVTString() << '\n');
llvm_unreachable("");
}
}
}
void LoongArchTargetLowering::analyzeOutputArgs(
CCState &CCInfo, const SmallVectorImpl<ISD::OutputArg> &Outs,
LoongArchCCAssignFn Fn) const {
for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
MVT ArgVT = Outs[i].VT;
if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
<< EVT(ArgVT).getEVTString() << "\n");
llvm_unreachable("");
}
}
}
static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
const CCValAssign &VA, const SDLoc &DL,
const LoongArchTargetLowering &TLI) {
MachineFunction &MF = DAG.getMachineFunction();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
EVT LocVT = VA.getLocVT();
const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
Register VReg = RegInfo.createVirtualRegister(RC);
RegInfo.addLiveIn(VA.getLocReg(), VReg);
return DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
}
// Transform physical registers into virtual registers.
SDValue LoongArchTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
switch (CallConv) {
default:
llvm_unreachable("Unsupported calling convention");
case CallingConv::C:
break;
}
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
analyzeInputArgs(CCInfo, Ins, CC_LoongArch);
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i)
InVals.push_back(unpackFromRegLoc(DAG, Chain, ArgLocs[i], DL, *this));
return Chain;
}
bool LoongArchTargetLowering::CanLowerReturn(
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
// Any return value split in to more than two values can't be returned
// directly.
return Outs.size() <= 2;
}
SDValue LoongArchTargetLowering::LowerReturn(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
SelectionDAG &DAG) const {
// Stores the assignment of the return value to a location.
SmallVector<CCValAssign> RVLocs;
// Info about the registers and stack slot.
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
analyzeOutputArgs(CCInfo, Outs, CC_LoongArch);
SDValue Glue;
SmallVector<SDValue, 4> RetOps(1, Chain);
// Copy the result values into the output registers.
for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
// Handle a 'normal' return.
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue);
// Guarantee that all emitted copies are stuck together.
Glue = Chain.getValue(1);
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
}
RetOps[0] = Chain; // Update chain.
// Add the glue node if we have it.
if (Glue.getNode())
RetOps.push_back(Glue);
return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
}