Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MipsCallLowering.cpp
35269 views
//===- MipsCallLowering.cpp -------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8/// \file9/// This file implements the lowering of LLVM calls to machine code calls for10/// GlobalISel.11//12//===----------------------------------------------------------------------===//1314#include "MipsCallLowering.h"15#include "MipsCCState.h"16#include "MipsMachineFunction.h"17#include "MipsTargetMachine.h"18#include "llvm/CodeGen/Analysis.h"19#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"20#include "llvm/CodeGen/MachineFrameInfo.h"2122using namespace llvm;2324MipsCallLowering::MipsCallLowering(const MipsTargetLowering &TLI)25: CallLowering(&TLI) {}2627namespace {28struct MipsOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner {29/// This is the name of the function being called30/// FIXME: Relying on this is unsound31const char *Func = nullptr;3233/// Is this a return value, or an outgoing call operand.34bool IsReturn;3536MipsOutgoingValueAssigner(CCAssignFn *AssignFn_, const char *Func,37bool IsReturn)38: OutgoingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}3940bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,41CCValAssign::LocInfo LocInfo,42const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,43CCState &State_) override {44MipsCCState &State = static_cast<MipsCCState &>(State_);4546if (IsReturn)47State.PreAnalyzeReturnValue(EVT::getEVT(Info.Ty));48else49State.PreAnalyzeCallOperand(Info.Ty, Info.IsFixed, Func);5051return CallLowering::OutgoingValueAssigner::assignArg(52ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);53}54};5556struct MipsIncomingValueAssigner : public CallLowering::IncomingValueAssigner {57/// This is the name of the function being called58/// FIXME: Relying on this is unsound59const char *Func = nullptr;6061/// Is this a call return value, or an incoming function argument.62bool IsReturn;6364MipsIncomingValueAssigner(CCAssignFn *AssignFn_, const char *Func,65bool IsReturn)66: IncomingValueAssigner(AssignFn_), Func(Func), IsReturn(IsReturn) {}6768bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,69CCValAssign::LocInfo LocInfo,70const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags,71CCState &State_) override {72MipsCCState &State = static_cast<MipsCCState &>(State_);7374if (IsReturn)75State.PreAnalyzeCallResult(Info.Ty, Func);76else77State.PreAnalyzeFormalArgument(Info.Ty, Flags);7879return CallLowering::IncomingValueAssigner::assignArg(80ValNo, OrigVT, ValVT, LocVT, LocInfo, Info, Flags, State);81}82};8384class MipsIncomingValueHandler : public CallLowering::IncomingValueHandler {85const MipsSubtarget &STI;8687public:88MipsIncomingValueHandler(MachineIRBuilder &MIRBuilder,89MachineRegisterInfo &MRI)90: IncomingValueHandler(MIRBuilder, MRI),91STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()) {}9293private:94void assignValueToReg(Register ValVReg, Register PhysReg,95const CCValAssign &VA) override;9697Register getStackAddress(uint64_t Size, int64_t Offset,98MachinePointerInfo &MPO,99ISD::ArgFlagsTy Flags) override;100void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,101const MachinePointerInfo &MPO,102const CCValAssign &VA) override;103104unsigned assignCustomValue(CallLowering::ArgInfo &Arg,105ArrayRef<CCValAssign> VAs,106std::function<void()> *Thunk = nullptr) override;107108virtual void markPhysRegUsed(unsigned PhysReg) {109MIRBuilder.getMRI()->addLiveIn(PhysReg);110MIRBuilder.getMBB().addLiveIn(PhysReg);111}112};113114class CallReturnHandler : public MipsIncomingValueHandler {115public:116CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,117MachineInstrBuilder &MIB)118: MipsIncomingValueHandler(MIRBuilder, MRI), MIB(MIB) {}119120private:121void markPhysRegUsed(unsigned PhysReg) override {122MIB.addDef(PhysReg, RegState::Implicit);123}124125MachineInstrBuilder &MIB;126};127128} // end anonymous namespace129130void MipsIncomingValueHandler::assignValueToReg(Register ValVReg,131Register PhysReg,132const CCValAssign &VA) {133markPhysRegUsed(PhysReg);134IncomingValueHandler::assignValueToReg(ValVReg, PhysReg, VA);135}136137Register MipsIncomingValueHandler::getStackAddress(uint64_t Size,138int64_t Offset,139MachinePointerInfo &MPO,140ISD::ArgFlagsTy Flags) {141142MachineFunction &MF = MIRBuilder.getMF();143MachineFrameInfo &MFI = MF.getFrameInfo();144145// FIXME: This should only be immutable for non-byval memory arguments.146int FI = MFI.CreateFixedObject(Size, Offset, true);147MPO = MachinePointerInfo::getFixedStack(MIRBuilder.getMF(), FI);148149return MIRBuilder.buildFrameIndex(LLT::pointer(0, 32), FI).getReg(0);150}151152void MipsIncomingValueHandler::assignValueToAddress(153Register ValVReg, Register Addr, LLT MemTy, const MachinePointerInfo &MPO,154const CCValAssign &VA) {155MachineFunction &MF = MIRBuilder.getMF();156auto MMO = MF.getMachineMemOperand(MPO, MachineMemOperand::MOLoad, MemTy,157inferAlignFromPtrInfo(MF, MPO));158MIRBuilder.buildLoad(ValVReg, Addr, *MMO);159}160161/// Handle cases when f64 is split into 2 32-bit GPRs. This is a custom162/// assignment because generic code assumes getNumRegistersForCallingConv is163/// accurate. In this case it is not because the type/number are context164/// dependent on other arguments.165unsigned166MipsIncomingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,167ArrayRef<CCValAssign> VAs,168std::function<void()> *Thunk) {169const CCValAssign &VALo = VAs[0];170const CCValAssign &VAHi = VAs[1];171172assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&173VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&174"unexpected custom value");175176auto CopyLo = MIRBuilder.buildCopy(LLT::scalar(32), VALo.getLocReg());177auto CopyHi = MIRBuilder.buildCopy(LLT::scalar(32), VAHi.getLocReg());178if (!STI.isLittle())179std::swap(CopyLo, CopyHi);180181Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());182Arg.Regs = { CopyLo.getReg(0), CopyHi.getReg(0) };183MIRBuilder.buildMergeLikeInstr(Arg.OrigRegs[0], {CopyLo, CopyHi});184185markPhysRegUsed(VALo.getLocReg());186markPhysRegUsed(VAHi.getLocReg());187return 2;188}189190namespace {191class MipsOutgoingValueHandler : public CallLowering::OutgoingValueHandler {192const MipsSubtarget &STI;193194public:195MipsOutgoingValueHandler(MachineIRBuilder &MIRBuilder,196MachineRegisterInfo &MRI, MachineInstrBuilder &MIB)197: OutgoingValueHandler(MIRBuilder, MRI),198STI(MIRBuilder.getMF().getSubtarget<MipsSubtarget>()), MIB(MIB) {}199200private:201void assignValueToReg(Register ValVReg, Register PhysReg,202const CCValAssign &VA) override;203204Register getStackAddress(uint64_t Size, int64_t Offset,205MachinePointerInfo &MPO,206ISD::ArgFlagsTy Flags) override;207208void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy,209const MachinePointerInfo &MPO,210const CCValAssign &VA) override;211unsigned assignCustomValue(CallLowering::ArgInfo &Arg,212ArrayRef<CCValAssign> VAs,213std::function<void()> *Thunk) override;214215MachineInstrBuilder &MIB;216};217} // end anonymous namespace218219void MipsOutgoingValueHandler::assignValueToReg(Register ValVReg,220Register PhysReg,221const CCValAssign &VA) {222Register ExtReg = extendRegister(ValVReg, VA);223MIRBuilder.buildCopy(PhysReg, ExtReg);224MIB.addUse(PhysReg, RegState::Implicit);225}226227Register MipsOutgoingValueHandler::getStackAddress(uint64_t Size,228int64_t Offset,229MachinePointerInfo &MPO,230ISD::ArgFlagsTy Flags) {231MachineFunction &MF = MIRBuilder.getMF();232MPO = MachinePointerInfo::getStack(MF, Offset);233234LLT p0 = LLT::pointer(0, 32);235LLT s32 = LLT::scalar(32);236auto SPReg = MIRBuilder.buildCopy(p0, Register(Mips::SP));237238auto OffsetReg = MIRBuilder.buildConstant(s32, Offset);239auto AddrReg = MIRBuilder.buildPtrAdd(p0, SPReg, OffsetReg);240return AddrReg.getReg(0);241}242243void MipsOutgoingValueHandler::assignValueToAddress(244Register ValVReg, Register Addr, LLT MemTy, const MachinePointerInfo &MPO,245const CCValAssign &VA) {246MachineFunction &MF = MIRBuilder.getMF();247uint64_t LocMemOffset = VA.getLocMemOffset();248249auto MMO = MF.getMachineMemOperand(250MPO, MachineMemOperand::MOStore, MemTy,251commonAlignment(STI.getStackAlignment(), LocMemOffset));252253Register ExtReg = extendRegister(ValVReg, VA);254MIRBuilder.buildStore(ExtReg, Addr, *MMO);255}256257unsigned258MipsOutgoingValueHandler::assignCustomValue(CallLowering::ArgInfo &Arg,259ArrayRef<CCValAssign> VAs,260std::function<void()> *Thunk) {261const CCValAssign &VALo = VAs[0];262const CCValAssign &VAHi = VAs[1];263264assert(VALo.getLocVT() == MVT::i32 && VAHi.getLocVT() == MVT::i32 &&265VALo.getValVT() == MVT::f64 && VAHi.getValVT() == MVT::f64 &&266"unexpected custom value");267268auto Unmerge =269MIRBuilder.buildUnmerge({LLT::scalar(32), LLT::scalar(32)}, Arg.Regs[0]);270Register Lo = Unmerge.getReg(0);271Register Hi = Unmerge.getReg(1);272273Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());274Arg.Regs = { Lo, Hi };275if (!STI.isLittle())276std::swap(Lo, Hi);277278// If we can return a thunk, just include the register copies. The unmerge can279// be emitted earlier.280if (Thunk) {281*Thunk = [=]() {282MIRBuilder.buildCopy(VALo.getLocReg(), Lo);283MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);284};285return 2;286}287MIRBuilder.buildCopy(VALo.getLocReg(), Lo);288MIRBuilder.buildCopy(VAHi.getLocReg(), Hi);289return 2;290}291292static bool isSupportedArgumentType(Type *T) {293if (T->isIntegerTy())294return true;295if (T->isPointerTy())296return true;297if (T->isFloatingPointTy())298return true;299return false;300}301302static bool isSupportedReturnType(Type *T) {303if (T->isIntegerTy())304return true;305if (T->isPointerTy())306return true;307if (T->isFloatingPointTy())308return true;309if (T->isAggregateType())310return true;311return false;312}313314bool MipsCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,315const Value *Val, ArrayRef<Register> VRegs,316FunctionLoweringInfo &FLI) const {317318MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(Mips::RetRA);319320if (Val != nullptr && !isSupportedReturnType(Val->getType()))321return false;322323if (!VRegs.empty()) {324MachineFunction &MF = MIRBuilder.getMF();325const Function &F = MF.getFunction();326const DataLayout &DL = MF.getDataLayout();327const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();328329SmallVector<ArgInfo, 8> RetInfos;330331ArgInfo ArgRetInfo(VRegs, *Val, 0);332setArgFlags(ArgRetInfo, AttributeList::ReturnIndex, DL, F);333splitToValueTypes(ArgRetInfo, RetInfos, DL, F.getCallingConv());334335SmallVector<CCValAssign, 16> ArgLocs;336SmallVector<ISD::OutputArg, 8> Outs;337338MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,339F.getContext());340341MipsOutgoingValueHandler RetHandler(MIRBuilder, MF.getRegInfo(), Ret);342std::string FuncName = F.getName().str();343MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForReturn(),344FuncName.c_str(), /*IsReturn*/ true);345346if (!determineAssignments(Assigner, RetInfos, CCInfo))347return false;348349if (!handleAssignments(RetHandler, RetInfos, CCInfo, ArgLocs, MIRBuilder))350return false;351}352353MIRBuilder.insertInstr(Ret);354return true;355}356357bool MipsCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,358const Function &F,359ArrayRef<ArrayRef<Register>> VRegs,360FunctionLoweringInfo &FLI) const {361362// Quick exit if there aren't any args.363if (F.arg_empty())364return true;365366for (auto &Arg : F.args()) {367if (!isSupportedArgumentType(Arg.getType()))368return false;369}370371MachineFunction &MF = MIRBuilder.getMF();372const DataLayout &DL = MF.getDataLayout();373const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();374375SmallVector<ArgInfo, 8> ArgInfos;376unsigned i = 0;377for (auto &Arg : F.args()) {378ArgInfo AInfo(VRegs[i], Arg, i);379setArgFlags(AInfo, i + AttributeList::FirstArgIndex, DL, F);380381splitToValueTypes(AInfo, ArgInfos, DL, F.getCallingConv());382++i;383}384385SmallVector<ISD::InputArg, 8> Ins;386387SmallVector<CCValAssign, 16> ArgLocs;388MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,389F.getContext());390391const MipsTargetMachine &TM =392static_cast<const MipsTargetMachine &>(MF.getTarget());393const MipsABIInfo &ABI = TM.getABI();394CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(F.getCallingConv()),395Align(1));396397const std::string FuncName = F.getName().str();398MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForCall(), FuncName.c_str(),399/*IsReturn*/ false);400if (!determineAssignments(Assigner, ArgInfos, CCInfo))401return false;402403MipsIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo());404if (!handleAssignments(Handler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))405return false;406407if (F.isVarArg()) {408ArrayRef<MCPhysReg> ArgRegs = ABI.GetVarArgRegs();409unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);410411int VaArgOffset;412unsigned RegSize = 4;413if (ArgRegs.size() == Idx)414VaArgOffset = alignTo(CCInfo.getStackSize(), RegSize);415else {416VaArgOffset =417(int)ABI.GetCalleeAllocdArgSizeInBytes(CCInfo.getCallingConv()) -418(int)(RegSize * (ArgRegs.size() - Idx));419}420421MachineFrameInfo &MFI = MF.getFrameInfo();422int FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);423MF.getInfo<MipsFunctionInfo>()->setVarArgsFrameIndex(FI);424425for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += RegSize) {426MIRBuilder.getMBB().addLiveIn(ArgRegs[I]);427LLT RegTy = LLT::scalar(RegSize * 8);428MachineInstrBuilder Copy =429MIRBuilder.buildCopy(RegTy, Register(ArgRegs[I]));430FI = MFI.CreateFixedObject(RegSize, VaArgOffset, true);431MachinePointerInfo MPO = MachinePointerInfo::getFixedStack(MF, FI);432433const LLT PtrTy = LLT::pointer(MPO.getAddrSpace(), 32);434auto FrameIndex = MIRBuilder.buildFrameIndex(PtrTy, FI);435MachineMemOperand *MMO = MF.getMachineMemOperand(436MPO, MachineMemOperand::MOStore, RegTy, Align(RegSize));437MIRBuilder.buildStore(Copy, FrameIndex, *MMO);438}439}440441return true;442}443444bool MipsCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,445CallLoweringInfo &Info) const {446447if (Info.CallConv != CallingConv::C)448return false;449450for (auto &Arg : Info.OrigArgs) {451if (!isSupportedArgumentType(Arg.Ty))452return false;453if (Arg.Flags[0].isByVal())454return false;455if (Arg.Flags[0].isSRet() && !Arg.Ty->isPointerTy())456return false;457}458459if (!Info.OrigRet.Ty->isVoidTy() && !isSupportedReturnType(Info.OrigRet.Ty))460return false;461462MachineFunction &MF = MIRBuilder.getMF();463const Function &F = MF.getFunction();464const DataLayout &DL = MF.getDataLayout();465const MipsTargetLowering &TLI = *getTLI<MipsTargetLowering>();466const MipsTargetMachine &TM =467static_cast<const MipsTargetMachine &>(MF.getTarget());468const MipsABIInfo &ABI = TM.getABI();469470MachineInstrBuilder CallSeqStart =471MIRBuilder.buildInstr(Mips::ADJCALLSTACKDOWN);472473const bool IsCalleeGlobalPIC =474Info.Callee.isGlobal() && TM.isPositionIndependent();475476MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(477Info.Callee.isReg() || IsCalleeGlobalPIC ? Mips::JALRPseudo : Mips::JAL);478MIB.addDef(Mips::SP, RegState::Implicit);479if (IsCalleeGlobalPIC) {480Register CalleeReg =481MF.getRegInfo().createGenericVirtualRegister(LLT::pointer(0, 32));482MachineInstr *CalleeGlobalValue =483MIRBuilder.buildGlobalValue(CalleeReg, Info.Callee.getGlobal());484if (!Info.Callee.getGlobal()->hasLocalLinkage())485CalleeGlobalValue->getOperand(1).setTargetFlags(MipsII::MO_GOT_CALL);486MIB.addUse(CalleeReg);487} else488MIB.add(Info.Callee);489const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();490MIB.addRegMask(TRI->getCallPreservedMask(MF, Info.CallConv));491492TargetLowering::ArgListTy FuncOrigArgs;493FuncOrigArgs.reserve(Info.OrigArgs.size());494495SmallVector<ArgInfo, 8> ArgInfos;496for (auto &Arg : Info.OrigArgs)497splitToValueTypes(Arg, ArgInfos, DL, Info.CallConv);498499SmallVector<CCValAssign, 8> ArgLocs;500bool IsCalleeVarArg = false;501if (Info.Callee.isGlobal()) {502const Function *CF = static_cast<const Function *>(Info.Callee.getGlobal());503IsCalleeVarArg = CF->isVarArg();504}505506// FIXME: Should use MipsCCState::getSpecialCallingConvForCallee, but it507// depends on looking directly at the call target.508MipsCCState CCInfo(Info.CallConv, IsCalleeVarArg, MF, ArgLocs,509F.getContext());510511CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(Info.CallConv),512Align(1));513514const char *Call =515Info.Callee.isSymbol() ? Info.Callee.getSymbolName() : nullptr;516517MipsOutgoingValueAssigner Assigner(TLI.CCAssignFnForCall(), Call,518/*IsReturn*/ false);519if (!determineAssignments(Assigner, ArgInfos, CCInfo))520return false;521522MipsOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), MIB);523if (!handleAssignments(ArgHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))524return false;525526unsigned StackSize = CCInfo.getStackSize();527unsigned StackAlignment = F.getParent()->getOverrideStackAlignment();528if (!StackAlignment) {529const TargetFrameLowering *TFL = MF.getSubtarget().getFrameLowering();530StackAlignment = TFL->getStackAlignment();531}532StackSize = alignTo(StackSize, StackAlignment);533CallSeqStart.addImm(StackSize).addImm(0);534535if (IsCalleeGlobalPIC) {536MIRBuilder.buildCopy(537Register(Mips::GP),538MF.getInfo<MipsFunctionInfo>()->getGlobalBaseRegForGlobalISel(MF));539MIB.addDef(Mips::GP, RegState::Implicit);540}541MIRBuilder.insertInstr(MIB);542if (MIB->getOpcode() == Mips::JALRPseudo) {543const MipsSubtarget &STI = MIRBuilder.getMF().getSubtarget<MipsSubtarget>();544MIB.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),545*STI.getRegBankInfo());546}547548if (!Info.OrigRet.Ty->isVoidTy()) {549ArgInfos.clear();550551CallLowering::splitToValueTypes(Info.OrigRet, ArgInfos, DL,552F.getCallingConv());553554const std::string FuncName = F.getName().str();555SmallVector<ISD::InputArg, 8> Ins;556SmallVector<CCValAssign, 8> ArgLocs;557MipsIncomingValueAssigner Assigner(TLI.CCAssignFnForReturn(),558FuncName.c_str(),559/*IsReturn*/ true);560CallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), MIB);561562MipsCCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs,563F.getContext());564565if (!determineAssignments(Assigner, ArgInfos, CCInfo))566return false;567568if (!handleAssignments(RetHandler, ArgInfos, CCInfo, ArgLocs, MIRBuilder))569return false;570}571572MIRBuilder.buildInstr(Mips::ADJCALLSTACKUP).addImm(StackSize).addImm(0);573574return true;575}576577578