[llvm] [WebAssembly][GlobalISel] CallLowering `lowerFormalArguments` (PR #180263)
Derek Schuff via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 10 13:52:26 PDT 2026
================
@@ -50,13 +71,222 @@ bool WebAssemblyCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
return false;
}
+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 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);
+}
+
bool WebAssemblyCallLowering::lowerFormalArguments(
MachineIRBuilder &MIRBuilder, const Function &F,
ArrayRef<ArrayRef<Register>> VRegs, FunctionLoweringInfo &FLI) const {
- if (VRegs.empty())
- return true; // allow only empty signatures for now
+ MachineFunction &MF = MIRBuilder.getMF();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ WebAssemblyFunctionInfo *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
+ const DataLayout &DL = F.getDataLayout();
+ const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>();
+ const WebAssemblySubtarget &Subtarget =
+ MF.getSubtarget<WebAssemblySubtarget>();
+ const WebAssemblyRegisterInfo &TRI = *Subtarget.getRegisterInfo();
+ const WebAssemblyInstrInfo &TII = *Subtarget.getInstrInfo();
+ const RegisterBankInfo &RBI = *Subtarget.getRegBankInfo();
- return false;
+ 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] = MRI.createGenericVirtualRegister(NewLLT);
+ }
+ }
+
+ for (unsigned Part = 0; Part < NumParts; ++Part) {
+ MachineInstrBuilder ArgInst =
+ MIRBuilder.buildInstr(getWASMArgumentOpcode(NewVT))
+ .addDef(Arg.Regs[Part])
+ .addImm(FinalArgIdx);
+
+ constrainOperandRegClass(MF, TRI, MRI, TII, RBI, *ArgInst,
+ ArgInst->getDesc(), ArgInst->getOperand(0), 0);
+ MFI->addParam(NewVT);
+ ++FinalArgIdx;
+ }
+
+ if (OrigVT != NewVT) {
+ buildCopyFromRegs(MIRBuilder, Arg.OrigRegs, Arg.Regs, OrigLLT, NewLLT,
+ Arg.Flags[0]);
+ }
+ }
+
+ // 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);
----------------
dschuff wrote:
If we're going to be doing everything in GISel as LLTs, maybe we need to extend the infrastructure for handling wasm signatures to use LLTs too. Either reimplement it, or have some way to convert or reconcile them. Signatures are fairly fundamental to wasm, but the existing code that reasons about signatures was added after most of the backend was already there, so it may well the case that more code in the existing backend should handle them explicitly anyway.
https://github.com/llvm/llvm-project/pull/180263
More information about the llvm-commits
mailing list