CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
624 lines
21 KiB
C++
624 lines
21 KiB
C++
//===-- 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/WasmAddressSpaces.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;
|
|
}
|
|
|
|
static LLT getLLTForWasmMVT(MVT Ty, const DataLayout &DL) {
|
|
if (Ty == MVT::externref) {
|
|
return LLT::pointer(
|
|
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF,
|
|
DL.getPointerSizeInBits(
|
|
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF));
|
|
}
|
|
|
|
if (Ty == MVT::funcref) {
|
|
return LLT::pointer(
|
|
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF,
|
|
DL.getPointerSizeInBits(
|
|
WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF));
|
|
}
|
|
|
|
return llvm::getLLTForMVT(Ty);
|
|
}
|
|
|
|
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();
|
|
|
|
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 = getLLTForWasmMVT(NewVT, DL);
|
|
|
|
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;
|
|
|
|
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 = getLLTForWasmMVT(NewVT, DL);
|
|
|
|
// 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;
|
|
|
|
// 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 = getLLTForWasmMVT(NewVT, DL);
|
|
|
|
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 = getLLTForWasmMVT(NewVT, DL);
|
|
|
|
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;
|
|
}
|