| //===-- WebAssemblyCallLowering.cpp - Call lowering for GlobalISel -*- 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// This file implements the lowering of LLVM calls to machine code calls for | |
| /// GlobalISel. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "WebAssemblyCallLowering.h" | |
| #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" | |
| #include "Utils/WebAssemblyTypeUtilities.h" | |
| #include "WebAssemblyISelLowering.h" | |
| #include "WebAssemblyMachineFunctionInfo.h" | |
| #include "WebAssemblyRegisterInfo.h" | |
| #include "WebAssemblySubtarget.h" | |
| #include "WebAssemblyUtilities.h" | |
| #include "llvm/CodeGen/Analysis.h" | |
| #include "llvm/CodeGen/FunctionLoweringInfo.h" | |
| #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" | |
| #include "llvm/CodeGen/LowLevelTypeUtils.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/RegisterBankInfo.h" | |
| #include "llvm/IR/DataLayout.h" | |
| #include "llvm/IR/DebugLoc.h" | |
| #include "llvm/IR/Value.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #define DEBUG_TYPE "wasm-call-lowering" | |
| using namespace llvm; | |
| // Test whether the given calling convention is supported. | |
| static bool callingConvSupported(CallingConv::ID CallConv) { | |
| // We currently support the language-independent target-independent | |
| // conventions. We don't yet have a way to annotate calls with properties like | |
| // "cold", and we don't have any call-clobbered registers, so these are mostly | |
| // all handled the same. | |
| return CallConv == CallingConv::C || CallConv == CallingConv::Fast || | |
| CallConv == CallingConv::Cold || | |
| CallConv == CallingConv::PreserveMost || | |
| CallConv == CallingConv::PreserveAll || | |
| CallConv == CallingConv::CXX_FAST_TLS || | |
| CallConv == CallingConv::WASM_EmscriptenInvoke || | |
| CallConv == CallingConv::Swift; | |
| } | |
| static unsigned extendOpFromFlags(ISD::ArgFlagsTy Flags) { | |
| if (Flags.isSExt()) | |
| return TargetOpcode::G_SEXT; | |
| if (Flags.isZExt()) | |
| return TargetOpcode::G_ZEXT; | |
| return TargetOpcode::G_ANYEXT; | |
| } | |
| // GlobalISel doesn't handle reference types. We bail out of GlobalISel for | |
| // functions passing/returning references and fall back to SDAG. | |
| static bool typeContainsReference(const Type *Ty) { | |
| if (WebAssembly::isWebAssemblyReferenceType(Ty)) | |
| return true; | |
| if (const auto *ArrTy = dyn_cast<ArrayType>(Ty)) | |
| return typeContainsReference(ArrTy->getElementType()); | |
| if (const auto *StructTy = dyn_cast<StructType>(Ty)) | |
| return any_of(StructTy->elements(), [](const Type *ElemTy) { | |
| return typeContainsReference(ElemTy); | |
| }); | |
| return false; | |
| } | |
| WebAssemblyCallLowering::WebAssemblyCallLowering( | |
| const WebAssemblyTargetLowering &TLI) | |
| : CallLowering(&TLI) {} | |
| bool WebAssemblyCallLowering::canLowerReturn(MachineFunction &MF, | |
| CallingConv::ID CallConv, | |
| SmallVectorImpl<BaseArgInfo> &Outs, | |
| bool IsVarArg) const { | |
| return WebAssembly::canLowerReturn(Outs.size(), | |
| &MF.getSubtarget<WebAssemblySubtarget>()); | |
| } | |
| bool WebAssemblyCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, | |
| const Value *Val, | |
| ArrayRef<Register> VRegs, | |
| FunctionLoweringInfo &FLI, | |
| Register SwiftErrorVReg) const { | |
| MachineFunction &MF = MIRBuilder.getMF(); | |
| const Function &F = MF.getFunction(); | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>(); | |
| const DataLayout &DL = F.getDataLayout(); | |
| if (Val && typeContainsReference(Val->getType())) | |
| return false; | |
| MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(WebAssembly::RETURN); | |
| assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) && | |
| "Return value without a vreg or vice versa"); | |
| if (Val) { | |
| LLVMContext &Ctx = Val->getType()->getContext(); | |
| if (!FLI.CanLowerReturn) { | |
| insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister); | |
| } else { | |
| SmallVector<EVT, 4> SplitEVTs; | |
| ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs); | |
| assert(VRegs.size() == SplitEVTs.size() && | |
| "For each split Type there should be exactly one VReg."); | |
| SmallVector<ArgInfo, 8> SplitRets; | |
| CallingConv::ID CallConv = F.getCallingConv(); | |
| unsigned RetIdx = 0; | |
| for (EVT SplitEVT : SplitEVTs) { | |
| Register CurVReg = VRegs[RetIdx]; | |
| ArgInfo CurRetInfo = ArgInfo{CurVReg, SplitEVT.getTypeForEVT(Ctx), 0}; | |
| setArgFlags(CurRetInfo, AttributeList::ReturnIndex, DL, F); | |
| splitToValueTypes(CurRetInfo, SplitRets, DL, CallConv); | |
| ++RetIdx; | |
| } | |
| for (ArgInfo &Ret : SplitRets) { | |
| const EVT OrigVT = TLI.getValueType(DL, Ret.Ty); | |
| const MVT NewVT = | |
| TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT); | |
| const LLT OrigLLT = | |
| getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL); | |
| const LLT NewLLT = getLLTForMVT(NewVT); | |
| const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT); | |
| // If we need to split the type over multiple regs, check it's a | |
| // scenario we currently support. | |
| const unsigned NumParts = | |
| TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT); | |
| const ISD::ArgFlagsTy OrigFlags = Ret.Flags[0]; | |
| Ret.Flags.clear(); | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| ISD::ArgFlagsTy Flags = OrigFlags; | |
| if (Part == 0) { | |
| Flags.setSplit(); | |
| } else { | |
| Flags.setOrigAlign(Align(1)); | |
| if (Part == NumParts - 1) | |
| Flags.setSplitEnd(); | |
| } | |
| Ret.Flags.push_back(Flags); | |
| } | |
| Ret.OrigRegs.assign(Ret.Regs.begin(), Ret.Regs.end()); | |
| if (NumParts != 1 || OrigLLT != NewLLT) { | |
| // If we can't directly assign the register, we need one or more | |
| // intermediate values. | |
| Ret.Regs.resize(NumParts); | |
| // For each split register, create and assign a vreg that will store | |
| // the incoming component of the larger value. These will later be | |
| // merged to form the final vreg. | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| Register NewReg = MRI.createVirtualRegister(&NewRegClass); | |
| MRI.setType(NewReg, NewLLT); | |
| MIB.addUse(NewReg); | |
| Ret.Regs[Part] = NewReg; | |
| } | |
| buildCopyToRegs(MIRBuilder, Ret.Regs, Ret.OrigRegs[0], OrigLLT, | |
| NewLLT, extendOpFromFlags(Ret.Flags[0])); | |
| } else { | |
| MIB.addUse(Ret.Regs[0]); | |
| } | |
| } | |
| } | |
| } | |
| if (SwiftErrorVReg) { | |
| reportFatalInternalError( | |
| "Wasm does not `supportSwiftError`, yet SwiftErrorVReg is " | |
| "improperly valid."); | |
| } | |
| MIRBuilder.insertInstr(MIB); | |
| return true; | |
| } | |
| static unsigned getWasmArgumentOpcode(MVT ArgType) { | |
| switch (ArgType.SimpleTy) { | |
| case MVT::i32: | |
| return WebAssembly::ARGUMENT_i32; | |
| case MVT::i64: | |
| return WebAssembly::ARGUMENT_i64; | |
| case MVT::f32: | |
| return WebAssembly::ARGUMENT_f32; | |
| case MVT::f64: | |
| return WebAssembly::ARGUMENT_f64; | |
| case MVT::funcref: | |
| return WebAssembly::ARGUMENT_funcref; | |
| case MVT::externref: | |
| return WebAssembly::ARGUMENT_externref; | |
| case MVT::exnref: | |
| return WebAssembly::ARGUMENT_exnref; | |
| case MVT::v16i8: | |
| return WebAssembly::ARGUMENT_v16i8; | |
| case MVT::v8i16: | |
| return WebAssembly::ARGUMENT_v8i16; | |
| case MVT::v4i32: | |
| return WebAssembly::ARGUMENT_v4i32; | |
| case MVT::v2i64: | |
| return WebAssembly::ARGUMENT_v2i64; | |
| case MVT::v8f16: | |
| return WebAssembly::ARGUMENT_v8f16; | |
| case MVT::v4f32: | |
| return WebAssembly::ARGUMENT_v4f32; | |
| case MVT::v2f64: | |
| return WebAssembly::ARGUMENT_v2f64; | |
| default: | |
| break; | |
| } | |
| llvm_unreachable("Found unexpected type for Wasm argument"); | |
| } | |
| static Register buildWasmArgument(unsigned Idx, MVT ArgVT, LLT ArgLLT, | |
| MachineIRBuilder &MIRBuilder, | |
| Register Def = Register()) { | |
| unsigned Op = getWasmArgumentOpcode(ArgVT); | |
| const TargetInstrInfo &TII = MIRBuilder.getTII(); | |
| MachineFunction &MF = MIRBuilder.getMF(); | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| const TargetRegisterClass &RegClass = *TII.getRegClass(TII.get(Op), 0); | |
| Register NewReg; | |
| if (Def.isValid()) { | |
| assert(MRI.getRegClassOrRegBank(Def).isNull() && | |
| "Def already has reg bank or reg class?"); | |
| MRI.setRegClass(Def, &RegClass); | |
| NewReg = Def; | |
| } else { | |
| NewReg = MRI.createVirtualRegister(&RegClass); | |
| MRI.setType(NewReg, ArgLLT); | |
| } | |
| MIRBuilder.buildInstr(Op).addDef(NewReg).addImm(Idx); | |
| return NewReg; | |
| } | |
| bool WebAssemblyCallLowering::lowerFormalArguments( | |
| MachineIRBuilder &MIRBuilder, const Function &F, | |
| ArrayRef<ArrayRef<Register>> VRegs, FunctionLoweringInfo &FLI) const { | |
| MachineFunction &MF = MIRBuilder.getMF(); | |
| MachineRegisterInfo &MRI = MF.getRegInfo(); | |
| WebAssemblyFunctionInfo *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); | |
| const DataLayout &DL = F.getDataLayout(); | |
| const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>(); | |
| LLVMContext &Ctx = MIRBuilder.getContext(); | |
| const CallingConv::ID CallConv = F.getCallingConv(); | |
| if (!callingConvSupported(CallConv)) | |
| return false; | |
| if (typeContainsReference(F.getReturnType())) | |
| return false; | |
| for (const Argument &Arg : F.args()) | |
| if (typeContainsReference(Arg.getType())) | |
| return false; | |
| MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS); | |
| MF.front().addLiveIn(WebAssembly::ARGUMENTS); | |
| SmallVector<ArgInfo, 8> SplitArgs; | |
| if (!FLI.CanLowerReturn) | |
| insertSRetIncomingArgument(F, SplitArgs, FLI.DemoteRegister, MRI, DL); | |
| unsigned ArgIdx = 0; | |
| bool HasSwiftErrorArg = false; | |
| bool HasSwiftSelfArg = false; | |
| for (const Argument &Arg : F.args()) { | |
| ArgInfo OrigArg{VRegs[ArgIdx], Arg.getType(), ArgIdx}; | |
| setArgFlags(OrigArg, ArgIdx + AttributeList::FirstArgIndex, DL, F); | |
| HasSwiftSelfArg |= Arg.hasSwiftSelfAttr(); | |
| HasSwiftErrorArg |= Arg.hasSwiftErrorAttr(); | |
| if (Arg.hasInAllocaAttr()) | |
| return false; | |
| if (Arg.hasNestAttr()) | |
| return false; | |
| splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv()); | |
| ++ArgIdx; | |
| } | |
| unsigned FinalArgIdx = 0; | |
| for (ArgInfo &Arg : SplitArgs) { | |
| const EVT OrigVT = TLI.getValueType(DL, Arg.Ty); | |
| const MVT NewVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT); | |
| const LLT OrigLLT = | |
| getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL); | |
| const LLT NewLLT = getLLTForMVT(NewVT); | |
| // If we need to split the type over multiple regs, check it's a scenario | |
| // we currently support. | |
| const unsigned NumParts = | |
| TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT); | |
| const ISD::ArgFlagsTy OrigFlags = Arg.Flags[0]; | |
| Arg.Flags.clear(); | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| ISD::ArgFlagsTy Flags = OrigFlags; | |
| if (Part == 0) { | |
| Flags.setSplit(); | |
| } else { | |
| Flags.setOrigAlign(Align(1)); | |
| if (Part == NumParts - 1) | |
| Flags.setSplitEnd(); | |
| } | |
| Arg.Flags.push_back(Flags); | |
| } | |
| Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end()); | |
| if (NumParts != 1 || OrigLLT != NewLLT) { | |
| // If we can't directly assign the register, we need one or more | |
| // intermediate values. | |
| Arg.Regs.resize(NumParts); | |
| // For each split register, create and assign a vreg that will store | |
| // the incoming component of the larger value. These will later be | |
| // merged to form the final vreg. | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| Arg.Regs[Part] = | |
| buildWasmArgument(FinalArgIdx++, NewVT, NewLLT, MIRBuilder); | |
| MFI->addParam(NewVT); | |
| } | |
| buildCopyFromRegs(MIRBuilder, Arg.OrigRegs, Arg.Regs, OrigLLT, NewLLT, | |
| Arg.Flags[0]); | |
| } else { | |
| buildWasmArgument(FinalArgIdx++, NewVT, NewLLT, MIRBuilder, Arg.Regs[0]); | |
| MFI->addParam(NewVT); | |
| } | |
| } | |
| // For swiftcc, emit additional swiftself and swifterror arguments | |
| // if there aren't. These additional arguments are also added for callee | |
| // signature They are necessary to match callee and caller signature for | |
| // indirect call. | |
| if (CallConv == CallingConv::Swift) { | |
| const MVT PtrVT = TLI.getPointerTy(DL); | |
| if (!HasSwiftSelfArg) | |
| MFI->addParam(PtrVT); | |
| if (!HasSwiftErrorArg) | |
| MFI->addParam(PtrVT); | |
| } | |
| // Varargs are copied into a buffer allocated by the caller, and a pointer to | |
| // the buffer is passed as an argument. | |
| if (F.isVarArg()) { | |
| const MVT PtrVT = TLI.getPointerTy(DL, 0); | |
| const LLT PtrLLT = LLT::pointer(0, DL.getPointerSizeInBits(0)); | |
| Register VarargVreg = | |
| buildWasmArgument(FinalArgIdx++, PtrVT, PtrLLT, MIRBuilder); | |
| MFI->setVarargBufferVreg(VarargVreg); | |
| MFI->addParam(PtrVT); | |
| ++FinalArgIdx; | |
| } | |
| // Record the number and types of arguments and results. | |
| SmallVector<MVT, 4> Params; | |
| SmallVector<MVT, 4> Results; | |
| computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(), | |
| MF.getFunction(), MF.getTarget(), Params, Results); | |
| for (MVT VT : Results) | |
| MFI->addResult(VT); | |
| // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify | |
| // the param logic here with ComputeSignatureVTs | |
| assert(MFI->getParams().size() == Params.size() && | |
| std::equal(MFI->getParams().begin(), MFI->getParams().end(), | |
| Params.begin())); | |
| return true; | |
| } | |
| bool WebAssemblyCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, | |
| CallLoweringInfo &Info) const { | |
| MachineFunction &MF = MIRBuilder.getMF(); | |
| const DataLayout &DL = MIRBuilder.getDataLayout(); | |
| LLVMContext &Ctx = MIRBuilder.getContext(); | |
| const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>(); | |
| MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); | |
| const Function &F = MF.getFunction(); | |
| CallingConv::ID CallConv = Info.CallConv; | |
| if (!callingConvSupported(CallConv)) | |
| return false; | |
| if (typeContainsReference(Info.OrigRet.Ty)) | |
| return false; | |
| for (const ArgInfo &Arg : Info.OrigArgs) | |
| if (typeContainsReference(Arg.Ty)) | |
| return false; | |
| // TODO: tail calls | |
| if (Info.IsMustTailCall) | |
| return false; | |
| // TODO: varargs | |
| if (Info.IsVarArg) | |
| return false; | |
| // TODO: swiftcc | |
| if (CallConv == CallingConv::Swift) | |
| return false; | |
| MachineInstrBuilder CallInst; | |
| // TODO: indirect calls | |
| if (Info.Callee.isReg()) | |
| return false; | |
| CallInst = MIRBuilder.buildInstrNoInsert(WebAssembly::CALL); | |
| SmallVector<ArgInfo, 8> SplitArgs; | |
| for (const ArgInfo &Arg : Info.OrigArgs) { | |
| if (Arg.Flags[0].isNest()) | |
| return false; | |
| if (Arg.Flags[0].isInAlloca()) | |
| return false; | |
| if (Arg.Flags[0].isInConsecutiveRegs()) | |
| return false; | |
| if (Arg.Flags[0].isInConsecutiveRegsLast()) | |
| return false; | |
| // TODO: bulk memory, then byval | |
| if (Arg.Flags[0].isByVal() && Arg.Flags[0].getByValSize() != 0) | |
| return false; | |
| splitToValueTypes(Arg, SplitArgs, DL, CallConv); | |
| } | |
| SmallVector<Register> CallUseRegs; | |
| for (ArgInfo &Arg : SplitArgs) { | |
| const EVT OrigVT = TLI.getValueType(DL, Arg.Ty); | |
| const MVT NewVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT); | |
| const LLT OrigLLT = | |
| getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL); | |
| const LLT NewLLT = getLLTForMVT(NewVT); | |
| const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT); | |
| // If we need to split the type over multiple regs, check it's a scenario | |
| // we currently support. | |
| const unsigned NumParts = | |
| TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT); | |
| const ISD::ArgFlagsTy OrigFlags = Arg.Flags[0]; | |
| Arg.Flags.clear(); | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| ISD::ArgFlagsTy Flags = OrigFlags; | |
| if (Part == 0) { | |
| Flags.setSplit(); | |
| } else { | |
| Flags.setOrigAlign(Align(1)); | |
| if (Part == NumParts - 1) | |
| Flags.setSplitEnd(); | |
| } | |
| Arg.Flags.push_back(Flags); | |
| } | |
| Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end()); | |
| if (NumParts != 1 || OrigLLT != NewLLT) { | |
| // If we can't directly assign the register, we need one or more | |
| // intermediate values. | |
| Arg.Regs.resize(NumParts); | |
| // For each split register, create and assign a vreg that will store | |
| // the incoming component of the larger value. These will later be | |
| // merged to form the final vreg. | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| Register NewReg = MRI.createVirtualRegister(&NewRegClass); | |
| MRI.setType(NewReg, NewLLT); | |
| CallUseRegs.push_back(NewReg); | |
| Arg.Regs[Part] = NewReg; | |
| } | |
| buildCopyToRegs(MIRBuilder, Arg.Regs, Arg.OrigRegs[0], OrigLLT, NewLLT, | |
| extendOpFromFlags(Arg.Flags[0])); | |
| } else { | |
| CallUseRegs.push_back(Arg.Regs[0]); | |
| } | |
| } | |
| // Analyze operands of the call, assigning locations to each operand. | |
| SmallVector<CCValAssign, 16> ArgLocs; | |
| CCState CCInfo(CallConv, Info.IsVarArg, MF, ArgLocs, Ctx); | |
| MIRBuilder.insertInstr(CallInst); | |
| if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) { | |
| SmallVector<EVT, 4> SplitEVTs; | |
| ComputeValueVTs(TLI, DL, Info.OrigRet.Ty, SplitEVTs); | |
| assert(Info.OrigRet.Regs.size() == SplitEVTs.size() && | |
| "For each split Type there should be exactly one VReg."); | |
| SmallVector<ArgInfo, 8> SplitRets; | |
| unsigned RetIdx = 0; | |
| for (EVT SplitEVT : SplitEVTs) { | |
| Register CurVReg = Info.OrigRet.Regs[RetIdx]; | |
| ArgInfo CurArgInfo = ArgInfo{CurVReg, SplitEVT.getTypeForEVT(Ctx), 0}; | |
| if (Info.CB) { | |
| setArgFlags(CurArgInfo, AttributeList::ReturnIndex, DL, *Info.CB); | |
| } else { | |
| // We don't have a call base, so chances are we're looking at a | |
| // libcall (external symbol). | |
| // TODO: figure out how to get ALL the correct attributes | |
| ISD::ArgFlagsTy &Flags = CurArgInfo.Flags[0]; | |
| PointerType *PtrTy = | |
| dyn_cast<PointerType>(CurArgInfo.Ty->getScalarType()); | |
| if (PtrTy) { | |
| Flags.setPointer(); | |
| Flags.setPointerAddrSpace(PtrTy->getPointerAddressSpace()); | |
| } | |
| Align MemAlign = DL.getABITypeAlign(CurArgInfo.Ty); | |
| Flags.setMemAlign(MemAlign); | |
| Flags.setOrigAlign(MemAlign); | |
| } | |
| splitToValueTypes(CurArgInfo, SplitRets, DL, CallConv); | |
| ++RetIdx; | |
| } | |
| for (ArgInfo &Ret : SplitRets) { | |
| const EVT OrigVT = TLI.getValueType(DL, Ret.Ty); | |
| const MVT NewVT = | |
| TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT); | |
| const LLT OrigLLT = | |
| getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL); | |
| const LLT NewLLT = getLLTForMVT(NewVT); | |
| const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT); | |
| // If we need to split the type over multiple regs, check it's a scenario | |
| // we currently support. | |
| const unsigned NumParts = | |
| TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT); | |
| const ISD::ArgFlagsTy OrigFlags = Ret.Flags[0]; | |
| Ret.Flags.clear(); | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| ISD::ArgFlagsTy Flags = OrigFlags; | |
| if (Part == 0) { | |
| Flags.setSplit(); | |
| } else { | |
| Flags.setOrigAlign(Align(1)); | |
| if (Part == NumParts - 1) | |
| Flags.setSplitEnd(); | |
| } | |
| Ret.Flags.push_back(Flags); | |
| } | |
| Ret.OrigRegs.assign(Ret.Regs.begin(), Ret.Regs.end()); | |
| if (NumParts != 1 || OrigLLT != NewLLT) { | |
| // If we can't directly assign the register, we need one or more | |
| // intermediate values. | |
| Ret.Regs.resize(NumParts); | |
| // For each split register, create and assign a vreg that will store | |
| // the incoming component of the larger value. These will later be | |
| // merged to form the final vreg. | |
| for (unsigned Part = 0; Part < NumParts; ++Part) { | |
| Register NewReg = MRI.createVirtualRegister(&NewRegClass); | |
| MRI.setType(NewReg, NewLLT); | |
| CallInst.addDef(NewReg); | |
| Ret.Regs[Part] = NewReg; | |
| } | |
| buildCopyFromRegs(MIRBuilder, Ret.OrigRegs, Ret.Regs, OrigLLT, NewLLT, | |
| Ret.Flags[0]); | |
| } else { | |
| MRI.setRegClass(Ret.Regs[0], &NewRegClass); | |
| CallInst.addDef(Ret.Regs[0]); | |
| } | |
| } | |
| } | |
| if (Info.Callee.isGlobal()) { | |
| CallInst.addGlobalAddress(Info.Callee.getGlobal()); | |
| } else if (Info.Callee.isSymbol()) { | |
| CallInst.addExternalSymbol(Info.Callee.getSymbolName()); | |
| } else { | |
| return false; | |
| } | |
| for (Register Reg : CallUseRegs) { | |
| CallInst.addUse(Reg); | |
| } | |
| if (!Info.CanLowerReturn) | |
| insertSRetLoads(MIRBuilder, Info.OrigRet.Ty, Info.OrigRet.Regs, | |
| Info.DemoteRegister, Info.DemoteStackIndex); | |
| return true; | |
| } |