[llvm] [WebAssembly][GlobalISel] CallLowering `lowerFormalArguments` (PR #180263)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 2 10:52:09 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);
----------------
arsenm wrote:
That probably won't happen. I more meant there should be GIsel native infrastructure instead of reusing the DAG pieces
https://github.com/llvm/llvm-project/pull/180263
More information about the llvm-commits
mailing list