[llvm] [GlobalISel][RISCV] SelectionDAG like indirect parameter passing (PR #216724)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 09:20:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Gábor Spaits (spaits)
<details>
<summary>Changes</summary>
This pull request is created, so later on I can implement scalable vector support.
When I have first implemented indirect parameter passing back in 2024, I haven't really throght of scalable vectors. In my first implementation, the large value is loaded in one load instruction, not in separate load instruction. This one load, loading a big value from memory, can later be legalized by the backend.
This is not how SelectionDAG works. It usually loads the large value from memory in multiple loads.
This is also the way, that the calling convention handling recommends (by recommends I mean that the ArgInfo struct says that the argument is indirect and should come in multiple parts.)
Now I would like to have this working the same way in GISel as it works in SDAG. I think it's much better to follow the shape that the ArgInfo describes, than bringing my own implementation. Especially for the more complex cases, like scalable vectors. In RISC-V, it can happen, that one scalable vector value has some part in a register and some part indirectly passed.
---
Patch is 143.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/216724.diff
5 Files Affected:
- (modified) llvm/lib/CodeGen/GlobalISel/CallLowering.cpp (+136-73)
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll (+650-82)
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-lp64-lp64f-lp64d-common.ll (+356-52)
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/lround-llround.ll (+16-16)
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/shifts.ll (+30-30)
``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index 697a33d88d1da..ca674f946732c 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
@@ -19,11 +20,17 @@
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Register.h"
#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TypeSize.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include <cstdint>
#define DEBUG_TYPE "call-lowering"
@@ -839,25 +846,44 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
// Now split the registers into the assigned types.
Args[i].OrigRegs.assign(Args[i].Regs.begin(), Args[i].Regs.end());
+ int IndirectFrameIdx = 0;
+ Register IndirectPointerToStackReg{};
+ TypeSize CurrentIndirectChunkSize = TypeSize::getZero();
+ for (unsigned Part = 0; Part < NumParts; Part++) {
+ if (ArgLocs[j + Part].getLocInfo() == CCValAssign::Indirect)
+ CurrentIndirectChunkSize += ArgLocs[j + Part].getValVT().getStoreSize();
+ else if (CurrentIndirectChunkSize != 0)
+ llvm_unreachable("Indirect parameter passing where the middle part of "
+ "a parameter is indirect isn't yet supported!");
+ }
+
if (NumParts != 1 || NewLLT != OrigTy) {
- // If we can't directly assign the register, we need one or more
- // intermediate values.
- Args[i].Regs.resize(NumParts);
-
- // When we have indirect parameter passing we are receiving a pointer,
- // that points to the actual value, so we need one "temporary" pointer.
- if (VA.getLocInfo() == CCValAssign::Indirect) {
- if (Handler.isIncomingArgumentHandler())
- Args[i].Regs[0] = MRI.createGenericVirtualRegister(PointerTy);
- } else {
- // 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)
- Args[i].Regs[Part] = MRI.createGenericVirtualRegister(NewLLT);
+ Args[i].Regs.clear();
+ for (unsigned Part = 0; Part < NumParts; Part++) {
+ if (ArgLocs[j + Part].getLocInfo() == CCValAssign::Indirect)
+ Args[i].Regs.push_back(MRI.createGenericVirtualRegister(PointerTy));
+ else
+ Args[i].Regs.push_back(MRI.createGenericVirtualRegister(NewLLT));
}
}
+ // The argument has an indirect part or is entirely passed indirectly.
+ // Create space for it on the stack, so later we can store the value there.
+ if (CurrentIndirectChunkSize.isNonZero() &&
+ !Handler.isIncomingArgumentHandler()) {
+ Align AlignmentForStored = DL.getPrefTypeAlign(Args[i].Ty);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+ int StackID = 0;
+ if (CurrentIndirectChunkSize.isScalable())
+ StackID = TFI->getStackIDForScalableVectors();
+ IndirectFrameIdx =
+ MFI.CreateStackObject(CurrentIndirectChunkSize.getKnownMinValue(),
+ AlignmentForStored, false, nullptr, StackID);
+ IndirectPointerToStackReg =
+ MIRBuilder.buildFrameIndex(PointerTy, IndirectFrameIdx).getReg(0);
+ }
+
assert((j + (NumParts - 1)) < ArgLocs.size() &&
"Too many regs for number of args");
@@ -869,52 +895,62 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
ValTy, extendOpFromFlags(Args[i].Flags[0]));
}
- bool IndirectParameterPassingHandled = false;
bool BigEndianPartOrdering = TLI->hasBigEndianPartOrdering(OrigVT, DL);
+ unsigned IndirectIdx = 0;
+ Register IncomingIndirectValuePointer;
for (unsigned Part = 0; Part < NumParts; ++Part) {
- assert((VA.getLocInfo() != CCValAssign::Indirect || Part == 0) &&
- "Only the first parameter should be processed when "
- "handling indirect passing!");
- Register ArgReg = Args[i].Regs[Part];
+ std::optional<Register> ArgReg{};
+ if (Part < Args[i].Regs.size()) {
+ ArgReg = Args[i].Regs[Part];
+ }
// There should be Regs.size() ArgLocs per argument.
unsigned Idx = BigEndianPartOrdering ? NumParts - 1 - Part : Part;
CCValAssign &VA = ArgLocs[j + Idx];
const ISD::ArgFlagsTy Flags = Args[i].Flags[Part];
+ const bool IsIndirect = VA.getLocInfo() == CCValAssign::Indirect;
+ const bool IsFirstIndirectPart = IsIndirect && IndirectIdx == 0;
+
+ // Handle indirectly passed values.
+ if (IsIndirect && !Handler.isIncomingArgumentHandler()) {
+ Register StoreAddr = IndirectPointerToStackReg;
+ TypeSize OffsetBytes =
+ NewLLT.getSizeInBytes().multiplyCoefficientBy(IndirectIdx);
+
+ if (OffsetBytes.isNonZero()) {
+ LLT OffsetTy =
+ LLT::scalar(PointerTy.getSizeInBits().getKnownMinValue());
+ auto OffsetConst = MIRBuilder.buildConstant(
+ OffsetTy, OffsetBytes.getKnownMinValue());
+ StoreAddr = MIRBuilder
+ .buildPtrAdd(PointerTy, IndirectPointerToStackReg,
+ OffsetConst)
+ .getReg(0);
+ }
- // We found an indirect parameter passing, and we have an
- // OutgoingValueHandler as our handler (so we are at the call site or the
- // return value). In this case, start the construction of the following
- // GMIR, that is responsible for the preparation of indirect parameter
- // passing:
- //
- // %1(indirectly passed type) = The value to pass
- // %3(pointer) = G_FRAME_INDEX %stack.0
- // G_STORE %1, %3 :: (store (s128), align 8)
- //
- // After this GMIR, the remaining part of the loop body will decide how
- // to get the value to the caller and we break out of the loop.
- if (VA.getLocInfo() == CCValAssign::Indirect &&
- !Handler.isIncomingArgumentHandler()) {
- Align AlignmentForStored = DL.getPrefTypeAlign(Args[i].Ty);
- MachineFrameInfo &MFI = MF.getFrameInfo();
- // Get some space on the stack for the value, so later we can pass it
- // as a reference.
- int FrameIdx = MFI.CreateStackObject(OrigTy.getScalarSizeInBits(),
- AlignmentForStored, false);
- Register PointerToStackReg =
- MIRBuilder.buildFrameIndex(PointerTy, FrameIdx).getReg(0);
- MachinePointerInfo StackPointerMPO =
- MachinePointerInfo::getFixedStack(MF, FrameIdx);
- // Store the value in the previously created stack space.
- MIRBuilder.buildStore(Args[i].OrigRegs[Part], PointerToStackReg,
- StackPointerMPO,
+ Register PartToStore = Args[i].OrigRegs[0];
+ if (NumParts != 1 || NewLLT != OrigTy)
+ PartToStore =
+ MIRBuilder
+ .buildExtract(NewLLT, Args[i].OrigRegs[0],
+ NewLLT.getSizeInBits()
+ .multiplyCoefficientBy(IndirectIdx)
+ .getKnownMinValue())
+ .getReg(0);
+
+ auto StackPointerMPO = MachinePointerInfo::getFixedStack(
+ MF, IndirectFrameIdx, OffsetBytes);
+ MIRBuilder.buildStore(PartToStore, StoreAddr, StackPointerMPO,
inferAlignFromPtrInfo(MF, StackPointerMPO));
- ArgReg = PointerToStackReg;
- IndirectParameterPassingHandled = true;
+ IndirectIdx++;
+ ArgReg = IndirectPointerToStackReg;
}
- if (VA.isMemLoc() && !Flags.isByVal()) {
+ // The calling convention emits one identical location assignment for
+ // every part of an indirect argument. Assign the pointer to that
+ // location only once, while still loading or storing every value part.
+ const bool AssignLocation = !IsIndirect || IsFirstIndirectPart;
+ if (ArgReg && AssignLocation && VA.isMemLoc() && !Flags.isByVal()) {
// Individual pieces may have been spilled to the stack and others
// passed in registers.
@@ -934,11 +970,11 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
// This branch is needed, so the pointer to the value is loaded onto the
// stack.
if (VA.getLocInfo() == CCValAssign::Indirect)
- Handler.assignValueToAddress(ArgReg, StackAddr, PointerTy, MPO, VA);
+ Handler.assignValueToAddress(*ArgReg, StackAddr, PointerTy, MPO, VA);
else
Handler.assignValueToAddress(Args[i], Part, StackAddr, MemTy, MPO,
VA);
- } else if (VA.isMemLoc() && Flags.isByVal()) {
+ } else if (ArgReg && AssignLocation && VA.isMemLoc() && Flags.isByVal()) {
assert(Args[i].Regs.size() == 1 && "didn't expect split byval pointer");
if (Handler.isIncomingArgumentHandler()) {
@@ -976,45 +1012,72 @@ bool CallLowering::handleAssignments(ValueHandler &Handler,
DstMPO, DstAlign, SrcMPO, SrcAlign,
MemSize, VA);
}
- } else if (i == 0 && !ThisReturnRegs.empty() &&
+ } else if (ArgReg && AssignLocation && i == 0 &&
+ !ThisReturnRegs.empty() &&
Handler.isIncomingArgumentHandler() &&
isTypeIsValidForThisReturn(ValVT)) {
- Handler.assignValueToReg(ArgReg, ThisReturnRegs[Part], VA, Flags);
- } else if (Handler.isIncomingArgumentHandler()) {
- Handler.assignValueToReg(ArgReg, VA.getLocReg(), VA, Flags);
- } else {
+ Handler.assignValueToReg(*ArgReg, ThisReturnRegs[Part], VA, Flags);
+ } else if (ArgReg && AssignLocation &&
+ Handler.isIncomingArgumentHandler()) {
+ Handler.assignValueToReg(*ArgReg, VA.getLocReg(), VA, Flags);
+ } else if (ArgReg && AssignLocation) {
DelayedOutgoingRegAssignments.emplace_back([=, &Handler]() {
- Handler.assignValueToReg(ArgReg, VA.getLocReg(), VA, Flags);
+ Handler.assignValueToReg(*ArgReg, VA.getLocReg(), VA, Flags);
});
}
// Finish the handling of indirect parameter passing when receiving
// the value (we are in the called function or the caller when receiving
// the return value).
- if (VA.getLocInfo() == CCValAssign::Indirect &&
- Handler.isIncomingArgumentHandler()) {
- Align Alignment = DL.getABITypeAlign(Args[i].Ty);
+ if (IsIndirect && Handler.isIncomingArgumentHandler()) {
+ if (IsFirstIndirectPart)
+ IncomingIndirectValuePointer = *ArgReg;
+
+ uint64_t OffsetBytes = NewLLT.getSizeInBytes()
+ .multiplyCoefficientBy(IndirectIdx)
+ .getKnownMinValue();
+ Align Alignment =
+ commonAlignment(DL.getABITypeAlign(Args[i].Ty), OffsetBytes);
MachinePointerInfo MPO = MachinePointerInfo::getUnknownStack(MF);
-
+ Register PartPtrReg = IncomingIndirectValuePointer;
+ if (IndirectIdx > 0) {
+ LLT OffsetTy = LLT::scalar(PointerTy.getSizeInBits());
+ auto PartOffset = MIRBuilder.buildConstant(OffsetTy, OffsetBytes);
+ PartPtrReg = MIRBuilder
+ .buildPtrAdd(PointerTy, IncomingIndirectValuePointer,
+ PartOffset)
+ .getReg(0);
+ }
// Since we are doing indirect parameter passing, we know that the value
// in the temporary register is not the value passed to the function,
// but rather a pointer to that value. Let's load that value into the
// virtual register where the parameter should go.
- MIRBuilder.buildLoad(Args[i].OrigRegs[0], Args[i].Regs[0], MPO,
- Alignment);
-
- IndirectParameterPassingHandled = true;
+ LLT LoadedPartTy = getLLTForMVT(VA.getValVT());
+ Register LoadedPart;
+ if (NumParts == 1 && LoadedPartTy == OrigTy) {
+ LoadedPart = Args[i].OrigRegs[0];
+ MIRBuilder.buildLoad(LoadedPart, PartPtrReg, MPO, Alignment);
+ } else {
+ LoadedPart =
+ MIRBuilder.buildLoad(LoadedPartTy, PartPtrReg, MPO, Alignment)
+ .getReg(0);
+ }
+ if (Part < Args[i].Regs.size())
+ Args[i].Regs[Part] = LoadedPart;
+ else
+ Args[i].Regs.push_back(LoadedPart);
+ IndirectIdx++;
}
-
- if (IndirectParameterPassingHandled)
- break;
}
- // Now that all pieces have been assigned, re-pack the register typed values
- // into the original value typed registers. This is only necessary, when
- // the value was passed in multiple registers, not indirectly.
+ // Now that all pieces have been assigned, re-pack the register typed
+ // values into the original value typed registers. An indirect value loaded
+ // in one piece already has the original type and needs no repacking.
+ const bool IndirectValueLoadedInOnePiece =
+ IndirectIdx == 1 && Args[i].Regs.size() == 1 &&
+ MRI.getType(Args[i].Regs[0]) == OrigTy;
if (Handler.isIncomingArgumentHandler() && OrigVT != LocVT &&
- !IndirectParameterPassingHandled) {
+ !IndirectValueLoadedInOnePiece) {
// Merge the split registers into the expected larger result vregs of
// the original call.
buildCopyFromRegs(MIRBuilder, Args[i].OrigRegs, Args[i].Regs, OrigTy,
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll
index cc73e19f5b60b..912686d82b0d0 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/calling-conv-ilp32-ilp32f-ilp32d-common.ll
@@ -104,11 +104,28 @@ define i64 @callee_128i_indirect_reference_in_stack(i64 %x1, i64 %x2, i64 %x3, i
; RV32I-NEXT: [[MV3:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY6]](s32), [[COPY7]](s32)
; RV32I-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.1
; RV32I-NEXT: [[LOAD:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX]](p0) :: (load (p0) from %fixed-stack.1, align 16)
- ; RV32I-NEXT: [[LOAD1:%[0-9]+]]:_(s128) = G_LOAD [[LOAD]](p0) :: (load (s128), align 8)
+ ; RV32I-NEXT: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[LOAD]](p0) :: (load (s32), align 8)
+ ; RV32I-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+ ; RV32I-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C]](s32)
+ ; RV32I-NEXT: [[LOAD2:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD]](p0) :: (load (s32))
+ ; RV32I-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+ ; RV32I-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C1]](s32)
+ ; RV32I-NEXT: [[LOAD3:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD1]](p0) :: (load (s32), align 8)
+ ; RV32I-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
+ ; RV32I-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD]], [[C2]](s32)
+ ; RV32I-NEXT: [[LOAD4:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD2]](p0) :: (load (s32))
+ ; RV32I-NEXT: [[MV4:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[LOAD1]](s32), [[LOAD2]](s32), [[LOAD3]](s32), [[LOAD4]](s32)
; RV32I-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.0
- ; RV32I-NEXT: [[LOAD2:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX1]](p0) :: (load (p0) from %fixed-stack.0)
- ; RV32I-NEXT: [[LOAD3:%[0-9]+]]:_(s128) = G_LOAD [[LOAD2]](p0) :: (load (s128), align 8)
- ; RV32I-NEXT: [[ADD:%[0-9]+]]:_(s128) = G_ADD [[LOAD1]], [[LOAD3]]
+ ; RV32I-NEXT: [[LOAD5:%[0-9]+]]:_(p0) = G_LOAD [[FRAME_INDEX1]](p0) :: (load (p0) from %fixed-stack.0)
+ ; RV32I-NEXT: [[LOAD6:%[0-9]+]]:_(s32) = G_LOAD [[LOAD5]](p0) :: (load (s32), align 8)
+ ; RV32I-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD5]], [[C]](s32)
+ ; RV32I-NEXT: [[LOAD7:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD3]](p0) :: (load (s32))
+ ; RV32I-NEXT: [[PTR_ADD4:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD5]], [[C1]](s32)
+ ; RV32I-NEXT: [[LOAD8:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD4]](p0) :: (load (s32), align 8)
+ ; RV32I-NEXT: [[PTR_ADD5:%[0-9]+]]:_(p0) = G_PTR_ADD [[LOAD5]], [[C2]](s32)
+ ; RV32I-NEXT: [[LOAD9:%[0-9]+]]:_(s32) = G_LOAD [[PTR_ADD5]](p0) :: (load (s32))
+ ; RV32I-NEXT: [[MV5:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[LOAD6]](s32), [[LOAD7]](s32), [[LOAD8]](s32), [[LOAD9]](s32)
+ ; RV32I-NEXT: [[ADD:%[0-9]+]]:_(s128) = G_ADD [[MV4]], [[MV5]]
; RV32I-NEXT: [[TRUNC:%[0-9]+]]:_(s64) = G_TRUNC [[ADD]](s128)
; RV32I-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[TRUNC]](s64)
; RV32I-NEXT: $x10 = COPY [[UV]](s32)
@@ -131,16 +148,38 @@ define i32 @callee_128i_indirect_refernce_in_stack( ) {
; ILP32-NEXT: [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
; ILP32-NEXT: [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C]](s64)
; ILP32-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
- ; ILP32-NEXT: G_STORE [[C1]](s128), [[FRAME_INDEX]](p0) :: (store (s128) into %stack.0, align 8)
+ ; ILP32-NEXT: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s128), 0
+ ; ILP32-NEXT: G_STORE [[EXTRACT]](s32), [[FRAME_INDEX]](p0) :: (store (s32) into %stack.0, align 8)
; ILP32-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x2
; ILP32-NEXT: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
; ILP32-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C3]](s32)
; ILP32-NEXT: G_STORE [[FRAME_INDEX]](p0), [[PTR_ADD]](p0) :: (store (p0) into stack, align 16)
- ; ILP32-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1
- ; ILP32-NEXT: G_STORE [[C2]](s128), [[FRAME_INDEX1]](p0) :: (store (s128) into %stack.1, align 8)
; ILP32-NEXT: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
- ; ILP32-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C4]](s32)
- ; ILP32-NEXT: G_STORE [[FRAME_INDEX1]](p0), [[PTR_ADD1]](p0) :: (store (p0) into stack + 4)
+ ; ILP32-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C4]](s32)
+ ; ILP32-NEXT: [[EXTRACT1:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s128), 32
+ ; ILP32-NEXT: G_STORE [[EXTRACT1]](s32), [[PTR_ADD1]](p0) :: (store (s32) into %stack.0 + 4)
+ ; ILP32-NEXT: [[C5:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+ ; ILP32-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C5]](s32)
+ ; ILP32-NEXT: [[EXTRACT2:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s128), 64
+ ; ILP32-NEXT: G_STORE [[EXTRACT2]](s32), [[PTR_ADD2]](p0) :: (store (s32) into %stack.0 + 8, align 8)
+ ; ILP32-NEXT: [[C6:%[0-9]+]]:_(s32) = G_CONSTANT i32 12
+ ; ILP32-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX]], [[C6]](s32)
+ ; ILP32-NEXT: [[EXTRACT3:%[0-9]+]]:_(s32) = G_EXTRACT [[C1]](s128), 96
+ ; ILP32-NEXT: G_STORE [[EXTRACT3]](s32), [[PTR_ADD3]](p0) :: (store (s32) into %stack.0 + 12)
+ ; ILP32-NEXT: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1
+ ; ILP32-NEXT: [[EXTRACT4:%[0-9]+]]:_(s32) = G_EXTRACT [[C2]](s128), 0
+ ; ILP32-NEXT: G_STORE [[EXTRACT4]](s32), [[FRAME_INDEX1]](p0) :: (store (s32) into %stack.1, align 8)
+ ; ILP32-NEXT: [[PTR_ADD4:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C4]](s32)
+ ; ILP32-NEXT: G_STORE [[FRAME_INDEX1]](p0), [[PTR_ADD4]](p0) :: (store (p0) into stack + 4)
+ ; ILP32-NEXT: [[PTR_ADD5:%[0-9]+]]:_(p0) = G_PTR_ADD [[FRAME_INDEX1]], [[C4]](s32)
+ ; ILP32-...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/216724
More information about the llvm-commits
mailing list