[Mlir-commits] [llvm] [mlir] msvc abi/mlir funclet ops (PR #233257)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sun Oct 18 09:15:11 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: R-Goc
<details>
<summary>Changes</summary>
- **[LLVMABI] Implement Windows x86_64 TargetInfo and SRetAfterThis support**
- **[MLIR][LLVM] Add Windows EH funclet ops to LLVM dialect**
---
Patch is 34.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/233257.diff
11 Files Affected:
- (modified) llvm/include/llvm/ABI/FunctionInfo.h (+22-5)
- (modified) llvm/include/llvm/ABI/TargetInfo.h (+4)
- (modified) llvm/include/llvm/ABI/Types.h (+14)
- (modified) llvm/lib/ABI/Targets/X86.cpp (+81)
- (modified) llvm/unittests/ABI/CMakeLists.txt (+1)
- (modified) llvm/unittests/ABI/FunctionInfoTest.cpp (+5)
- (modified) llvm/unittests/ABI/TypesTest.cpp (+14)
- (added) llvm/unittests/ABI/WinX86_64TargetInfoTest.cpp (+250)
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td (+132-4)
- (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp (+92-3)
- (modified) mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp (+55)
``````````diff
diff --git a/llvm/include/llvm/ABI/FunctionInfo.h b/llvm/include/llvm/ABI/FunctionInfo.h
index 9edd588c480018..065d46ea638d62 100644
--- a/llvm/include/llvm/ABI/FunctionInfo.h
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -83,11 +83,12 @@ class ArgInfo {
bool CanBeFlattened : 1;
unsigned NeededIntRegs : 3;
unsigned NeededSseRegs : 3;
+ bool SRetAfterThis : 1;
ArgInfo(Kind K = Direct)
: TheKind(K), SignExt(false), ZeroExt(false), IndirectByVal(false),
IndirectRealign(false), CanBeFlattened(false), NeededIntRegs(0),
- NeededSseRegs(0) {}
+ NeededSseRegs(0), SRetAfterThis(false) {}
public:
/// \param T The type to coerce to. If null, the argument's original type is
@@ -111,7 +112,7 @@ class ArgInfo {
return AI;
}
- static ArgInfo getExtend(const Type *T) {
+ static ArgInfo getExtend(const Type *T, bool Signed) {
assert(T && "Type cannot be null");
assert(T->isInteger() && "Unexpected type - only integers can be extended");
@@ -120,8 +121,7 @@ class ArgInfo {
AI.Alignment = std::nullopt;
AI.DirectAttr.Offset = 0;
- const IntegerType *IntTy = cast<IntegerType>(T);
- if (IntTy->isSigned())
+ if (Signed)
AI.setSignExt();
else
AI.setZeroExt();
@@ -129,6 +129,13 @@ class ArgInfo {
return AI;
}
+ static ArgInfo getExtend(const Type *T) {
+ assert(T && "Type cannot be null");
+ assert(T->isInteger() && "Unexpected type - only integers can be extended");
+ const IntegerType *IntTy = cast<IntegerType>(T);
+ return getExtend(T, IntTy->isSigned());
+ }
+
/// Realign: the caller couldn't guarantee sufficient alignment - the callee
/// must copy the argument to a properly aligned temporary before use.
static ArgInfo getIndirect(Align Align, bool ByVal, unsigned AddrSpace = 0,
@@ -268,6 +275,9 @@ class ArgInfo {
return !SignExt && !ZeroExt;
}
+ bool isSRetAfterThis() const { return SRetAfterThis; }
+ void setSRetAfterThis(bool Value) { SRetAfterThis = Value; }
+
const Type *getCoerceToType() const {
assert((isDirect() || isExtend() || isCoerceAndExpand()) &&
"Invalid Kind!");
@@ -297,6 +307,8 @@ struct ArgEntry {
ArgEntry(const Type *T) : ABIType(T), Info(ArgInfo::getDirect()) {}
ArgEntry(const Type *T, ArgInfo A) : ABIType(T), Info(A) {}
+
+ const Type *getType() const { return ABIType; }
};
/// Whether a signature accepts arguments beyond its declared parameters, and
@@ -338,11 +350,13 @@ class FunctionInfo final : private TrailingObjects<FunctionInfo, ArgEntry> {
unsigned NumArgs;
CallingConv::ID CC = CallingConv::C;
RequiredArgs Required;
+ bool IsInstanceMethod : 1;
FunctionInfo(CallingConv::ID CC, const Type *RetTy, unsigned NumArguments,
RequiredArgs Required)
: ReturnType(RetTy), ReturnInfo(ArgInfo::getDirect()),
- NumArgs(NumArguments), CC(CC), Required(Required) {}
+ NumArgs(NumArguments), CC(CC), Required(Required),
+ IsInstanceMethod(false) {}
friend class TrailingObjects;
@@ -369,6 +383,9 @@ class FunctionInfo final : private TrailingObjects<FunctionInfo, ArgEntry> {
CallingConv::ID getCallingConvention() const { return CC; }
+ bool isInstanceMethod() const { return IsInstanceMethod; }
+ void setIsInstanceMethod(bool Value) { IsInstanceMethod = Value; }
+
bool isVariadic() const { return Required.allowsOptionalArgs(); }
unsigned getNumRequiredArgs() const {
diff --git a/llvm/include/llvm/ABI/TargetInfo.h b/llvm/include/llvm/ABI/TargetInfo.h
index 859eca06ba785a..4d85ed85ddbb5a 100644
--- a/llvm/include/llvm/ABI/TargetInfo.h
+++ b/llvm/include/llvm/ABI/TargetInfo.h
@@ -188,6 +188,10 @@ LLVM_ABI std::unique_ptr<TargetInfo>
createX86_64TargetInfo(TypeBuilder &TB, X86AVXABILevel AVXLevel,
bool Has64BitPointers, const X86ABICompatInfo &Compat);
+LLVM_ABI std::unique_ptr<TargetInfo>
+createWinX86_64TargetInfo(TypeBuilder &TB, X86AVXABILevel AVXLevel,
+ const ABICompatInfo &Compat);
+
enum class AArch64ABIKind {
AAPCS = 0,
DarwinPCS,
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 746e107b3a32ca..3c95d1f6950e6c 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -17,13 +17,19 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/bit.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TypeSize.h"
namespace llvm {
+
+/// Returns the largest power of two less than or equal to the given value.
+inline uint64_t PowerOf2Floor(uint64_t A) { return llvm::bit_floor(A); }
+
namespace abi {
enum class TypeKind {
@@ -482,6 +488,14 @@ class TypeBuilder {
IntegerType(BitWidth, Align, Signed, IsBitInt);
}
+ const IntegerType *getIntegerType(TypeSize Size, bool Signed = false) {
+ uint64_t BitWidth = Size.getFixedValue();
+ return getIntegerType(
+ BitWidth,
+ Align(llvm::PowerOf2Floor(std::max<uint64_t>(1, BitWidth / 8))),
+ Signed);
+ }
+
const FloatType *getFloatType(const fltSemantics &Semantics, Align Align) {
return new (Allocator.Allocate<FloatType>()) FloatType(Semantics, Align);
}
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index d57c5a0cf516f4..4c8571ac37e6f9 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -1386,5 +1386,86 @@ createX86_64TargetInfo(TypeBuilder &TB, X86AVXABILevel AVXLevel,
Compat);
}
+namespace {
+
+class WinX86_64TargetInfo : public TargetInfo {
+ [[maybe_unused]] X86AVXABILevel AVXLevel;
+ ABICompatInfo CompatInfo;
+
+ ArgInfo classify(const Type *Ty, bool IsReturn, bool IsInstanceMethod) const {
+ if (Ty->isVoid())
+ return ArgInfo::getIgnore();
+
+ if (IsReturn && IsInstanceMethod && isAggregateTypeForABI(Ty)) {
+ ArgInfo AI =
+ getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+ AI.setSRetAfterThis(true);
+ return AI;
+ }
+
+ if (const auto *RT = dyn_cast<RecordType>(Ty)) {
+ if (!RT->canPassInRegisters() || RT->hasFlexibleArrayMember())
+ return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+
+ uint64_t Width = RT->getSizeInBits().getFixedValue();
+ if (Width > 64 || !llvm::isPowerOf2_64(Width))
+ return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+
+ const Type *CoerceTy =
+ TB.getIntegerType(TypeSize::getFixed(Width), /*IsSigned=*/false);
+ return ArgInfo::getDirect(CoerceTy);
+ }
+
+ if (const auto *IT = dyn_cast<IntegerType>(Ty)) {
+ // MSVC WinX86_64 ABI only extends 1-bit booleans; other small integers are passed directly.
+ if (IT->getSizeInBits().getFixedValue() == 1)
+ return ArgInfo::getExtend(Ty, IT->isSigned());
+ if (IT->getSizeInBits().getFixedValue() > 64)
+ return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+ return ArgInfo::getDirect();
+ }
+
+ if (Ty->isFloat() || Ty->isPointer() || Ty->isVector())
+ return ArgInfo::getDirect();
+
+ if (isAggregateTypeForABI(Ty)) {
+ uint64_t Width = Ty->getSizeInBits().getFixedValue();
+ if (Width > 64 || !llvm::isPowerOf2_64(Width))
+ return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+ const Type *CoerceTy =
+ TB.getIntegerType(TypeSize::getFixed(Width), /*IsSigned=*/false);
+ return ArgInfo::getDirect(CoerceTy);
+ }
+
+ return ArgInfo::getDirect();
+ }
+
+public:
+ WinX86_64TargetInfo(TypeBuilder &TB, X86AVXABILevel AVXLevel,
+ const ABICompatInfo &Compat)
+ : TargetInfo(TB), AVXLevel(AVXLevel), CompatInfo(Compat) {}
+
+ const ABICompatInfo &getABICompatInfo() const override {
+ return CompatInfo;
+ }
+
+ void computeInfo(FunctionInfo &FI) const override {
+ FI.getReturnInfo() = classify(FI.getReturnType(), /*IsReturn=*/true,
+ FI.isInstanceMethod());
+ for (auto &Arg : FI.arguments())
+ Arg.Info = classify(Arg.getType(), /*IsReturn=*/false,
+ /*IsInstanceMethod=*/false);
+ }
+};
+
+
+} // namespace
+
+std::unique_ptr<TargetInfo>
+createWinX86_64TargetInfo(TypeBuilder &TB, X86AVXABILevel AVXLevel,
+ const ABICompatInfo &Compat) {
+ return std::make_unique<WinX86_64TargetInfo>(TB, AVXLevel, Compat);
+}
+
} // namespace abi
} // namespace llvm
diff --git a/llvm/unittests/ABI/CMakeLists.txt b/llvm/unittests/ABI/CMakeLists.txt
index eb50b88b87d2df..efa5b339603fe6 100644
--- a/llvm/unittests/ABI/CMakeLists.txt
+++ b/llvm/unittests/ABI/CMakeLists.txt
@@ -11,5 +11,6 @@ add_llvm_unittest(ABITests
TargetInfoTest.cpp
AMDGPUTargetInfoTest.cpp
X86TargetInfoTest.cpp
+ WinX86_64TargetInfoTest.cpp
TypesTest.cpp
)
diff --git a/llvm/unittests/ABI/FunctionInfoTest.cpp b/llvm/unittests/ABI/FunctionInfoTest.cpp
index 0a855edab9bb40..7db77800fa3739 100644
--- a/llvm/unittests/ABI/FunctionInfoTest.cpp
+++ b/llvm/unittests/ABI/FunctionInfoTest.cpp
@@ -132,6 +132,11 @@ TEST_F(FunctionInfoTest, IndirectAliasedSurvivesFunctionInfo) {
EXPECT_EQ(Info.getIndirectAlign(), llvm::Align(8));
}
+TEST_F(FunctionInfoTest, ArgEntryGetType) {
+ ArgEntry Entry(I32);
+ EXPECT_EQ(Entry.getType(), I32);
+}
+
#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
TEST_F(FunctionInfoTest, CanBeFlattenedIsDirectOnly) {
EXPECT_DEATH((void)ArgInfo::getIgnore().getCanBeFlattened(), "Invalid Kind");
diff --git a/llvm/unittests/ABI/TypesTest.cpp b/llvm/unittests/ABI/TypesTest.cpp
index 588d1f914db12b..f37592f01a3a92 100644
--- a/llvm/unittests/ABI/TypesTest.cpp
+++ b/llvm/unittests/ABI/TypesTest.cpp
@@ -214,6 +214,20 @@ TEST_F(ABITypesTest, ScalarABISize) {
EXPECT_EQ(TB.getComplexType(F32, Align(4))->getABISizeInBits(), 64u);
}
+TEST_F(ABITypesTest, IntegerTypeFromTypeSize) {
+ // Power-of-2 byte sizes.
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(8))->getAlignment(), Align(1));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(16))->getAlignment(), Align(2));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(32))->getAlignment(), Align(4));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(64))->getAlignment(), Align(8));
+
+ // Non-byte and non-power-of-2 byte sizes should not assert on alignment.
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(1))->getAlignment(), Align(1));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(24))->getAlignment(), Align(2));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(40))->getAlignment(), Align(4));
+ EXPECT_EQ(TB.getIntegerType(TypeSize::getFixed(48))->getAlignment(), Align(4));
+}
+
// A bool element takes one bit and a one-bit _BitInt element a whole byte. The
// total is rounded up to a power of two of at least 8 bits.
TEST_F(ABITypesTest, VectorABISize) {
diff --git a/llvm/unittests/ABI/WinX86_64TargetInfoTest.cpp b/llvm/unittests/ABI/WinX86_64TargetInfoTest.cpp
new file mode 100644
index 00000000000000..84e416887452f4
--- /dev/null
+++ b/llvm/unittests/ABI/WinX86_64TargetInfoTest.cpp
@@ -0,0 +1,250 @@
+//===- WinX86_64TargetInfoTest.cpp - Windows x86-64 ABI unit tests --------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ABI/FunctionInfo.h"
+#include "llvm/ABI/TargetInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Allocator.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using namespace llvm;
+
+using ABIType = llvm::abi::Type;
+using llvm::abi::ABICompatInfo;
+using llvm::abi::ArgInfo;
+using llvm::abi::createWinX86_64TargetInfo;
+using llvm::abi::FieldInfo;
+using llvm::abi::FunctionInfo;
+using llvm::abi::RecordFlags;
+using llvm::abi::StructPacking;
+using llvm::abi::TargetInfo;
+using llvm::abi::TypeBuilder;
+using llvm::abi::X86AVXABILevel;
+
+class WinX86_64TargetInfoTest : public ::testing::Test {
+protected:
+ llvm::BumpPtrAllocator Alloc;
+ TypeBuilder TB;
+ const ABIType *Void;
+ const ABIType *I1;
+ const ABIType *I8;
+ const ABIType *I16;
+ const ABIType *I32;
+ const ABIType *I64;
+ const ABIType *F32;
+ const ABIType *F64;
+
+ WinX86_64TargetInfoTest()
+ : TB(Alloc),
+ Void(TB.getVoidType()),
+ I1(TB.getIntegerType(1, llvm::Align(1), /*Signed=*/false)),
+ I8(TB.getIntegerType(8, llvm::Align(1), /*Signed=*/true)),
+ I16(TB.getIntegerType(16, llvm::Align(2), /*Signed=*/true)),
+ I32(TB.getIntegerType(32, llvm::Align(4), /*Signed=*/true)),
+ I64(TB.getIntegerType(64, llvm::Align(8), /*Signed=*/true)),
+ F32(TB.getFloatType(llvm::APFloat::IEEEsingle(), llvm::Align(4))),
+ F64(TB.getFloatType(llvm::APFloat::IEEEdouble(), llvm::Align(8))) {}
+
+ std::unique_ptr<TargetInfo> target() const {
+ return createWinX86_64TargetInfo(const_cast<TypeBuilder &>(TB),
+ X86AVXABILevel::None, ABICompatInfo());
+ }
+
+ const ABIType *structOfBytes(uint64_t NumBytes,
+ RecordFlags Flags = RecordFlags::CanPassInRegisters) {
+ llvm::SmallVector<FieldInfo, 8> Fields;
+ for (uint64_t I = 0; I < NumBytes; ++I)
+ Fields.emplace_back(I8, I * 8);
+ return TB.getRecordType(Fields, llvm::TypeSize::getFixed(NumBytes * 8),
+ llvm::Align(1), llvm::Align(1),
+ StructPacking::Default, {}, {}, Flags);
+ }
+
+ const ArgInfo &classifyReturn(const ABIType *RetTy,
+ std::unique_ptr<FunctionInfo> &FI,
+ std::unique_ptr<TargetInfo> &TI,
+ bool IsInstanceMethod = false) {
+ TI = target();
+ FI = FunctionInfo::create(llvm::CallingConv::C, RetTy, {});
+ FI->setIsInstanceMethod(IsInstanceMethod);
+ TI->computeInfo(*FI);
+ return FI->getReturnInfo();
+ }
+};
+
+static void expectDirectInteger(const ArgInfo &Info, unsigned Bits) {
+ ASSERT_TRUE(Info.isDirect());
+ const ABIType *Coerce = Info.getCoerceToType();
+ ASSERT_NE(Coerce, nullptr);
+ const auto *IT = llvm::dyn_cast<llvm::abi::IntegerType>(Coerce);
+ ASSERT_NE(IT, nullptr);
+ EXPECT_EQ(IT->getSizeInBits().getFixedValue(), Bits);
+}
+
+TEST_F(WinX86_64TargetInfoTest, ScalarReturns) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI;
+
+ // Void -> ignore.
+ EXPECT_TRUE(classifyReturn(Void, FI, TI).isIgnore());
+
+ // i1 -> extend (zero extend).
+ const ArgInfo &I1Info = classifyReturn(I1, FI, TI);
+ EXPECT_TRUE(I1Info.isExtend());
+ EXPECT_TRUE(I1Info.isZeroExt());
+
+ // i8 -> direct.
+ const ArgInfo &I8Info = classifyReturn(I8, FI, TI);
+ EXPECT_TRUE(I8Info.isDirect());
+ EXPECT_EQ(I8Info.getCoerceToType(), nullptr);
+
+ // i16 -> direct.
+ const ArgInfo &I16Info = classifyReturn(I16, FI, TI);
+ EXPECT_TRUE(I16Info.isDirect());
+ EXPECT_EQ(I16Info.getCoerceToType(), nullptr);
+
+ // i32 -> direct.
+ const ArgInfo &I32Info = classifyReturn(I32, FI, TI);
+ EXPECT_TRUE(I32Info.isDirect());
+ EXPECT_EQ(I32Info.getCoerceToType(), nullptr);
+
+ // i64 -> direct.
+ const ArgInfo &I64Info = classifyReturn(I64, FI, TI);
+ EXPECT_TRUE(I64Info.isDirect());
+ EXPECT_EQ(I64Info.getCoerceToType(), nullptr);
+
+ // Float -> direct.
+ const ArgInfo &F32Info = classifyReturn(F32, FI, TI);
+ EXPECT_TRUE(F32Info.isDirect());
+ EXPECT_EQ(F32Info.getCoerceToType(), nullptr);
+
+ // Double -> direct.
+ const ArgInfo &F64Info = classifyReturn(F64, FI, TI);
+ EXPECT_TRUE(F64Info.isDirect());
+ EXPECT_EQ(F64Info.getCoerceToType(), nullptr);
+}
+
+TEST_F(WinX86_64TargetInfoTest, DirectStructReturns) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI;
+
+ // 1-byte struct -> direct, coerced to i8.
+ const ABIType *S1 = structOfBytes(1);
+ expectDirectInteger(classifyReturn(S1, FI, TI), 8);
+
+ // 2-byte struct -> direct, coerced to i16.
+ const ABIType *S2 = structOfBytes(2);
+ expectDirectInteger(classifyReturn(S2, FI, TI), 16);
+
+ // 4-byte struct -> direct, coerced to i32.
+ const ABIType *S4 = structOfBytes(4);
+ expectDirectInteger(classifyReturn(S4, FI, TI), 32);
+
+ // 8-byte struct -> direct, coerced to i64.
+ const ABIType *S8 = structOfBytes(8);
+ expectDirectInteger(classifyReturn(S8, FI, TI), 64);
+}
+
+TEST_F(WinX86_64TargetInfoTest, IndirectStructReturns) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI;
+
+ for (uint64_t Bytes : {3u, 5u, 12u, 16u}) {
+ const ABIType *S = structOfBytes(Bytes);
+ const ArgInfo &Info = classifyReturn(S, FI, TI);
+ EXPECT_TRUE(Info.isIndirect());
+ EXPECT_FALSE(Info.getIndirectByVal());
+ EXPECT_FALSE(Info.isSRetAfterThis());
+ }
+}
+
+TEST_F(WinX86_64TargetInfoTest, NonTrivialStructReturn) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI;
+
+ // 4-byte struct with RecordFlags::None (cannot pass in registers).
+ const ABIType *S = structOfBytes(4, RecordFlags::None);
+ const ArgInfo &Info = classifyReturn(S, FI, TI);
+ EXPECT_TRUE(Info.isIndirect());
+ EXPECT_FALSE(Info.getIndirectByVal());
+}
+
+TEST_F(WinX86_64TargetInfoTest, InstanceMethodStructReturn) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI;
+
+ // Even a 4-byte struct returned from an instance method is indirect with SRetAfterThis = true.
+ const ABIType *S4 = structOfBytes(4);
+ const ArgInfo &Info =
+ classifyReturn(S4, FI, TI, /*IsInstanceMethod=*/true);
+ EXPECT_TRUE(Info.isIndirect());
+ EXPECT_FALSE(Info.getIndirectByVal());
+ EXPECT_TRUE(Info.isSRetAfterThis());
+}
+
+TEST_F(WinX86_64TargetInfoTest, ScalarAndStructArguments) {
+ std::unique_ptr<FunctionInfo> FI;
+ std::unique_ptr<TargetInfo> TI = target();
+
+ const ABIType *S4 = structOfBytes(4);
+ const ABIType *S16 = structOfBytes(16);
+
+ FI = FunctionInfo::create(llvm::CallingConv::C, Void,
+ {I1, I8, I16, I32, I64, S4, S16});
+ TI->computeInfo(*FI);
+
+ // Arg 0: i1 -> extend (zero extend).
+ EXPECT_EQ(FI->getArgInfo(0).getType(), I1);
+ const ArgInfo &Arg0 = FI->getArgInfo(0).Info;
+ EXPECT_TRUE(Arg0.isExtend());
+ EXPECT_TRUE(Arg0.isZeroExt());
+
+ // Arg 1: i8 -> direct.
+ EXPECT_EQ(FI->getArgInfo(1).getType(), I8);
+ const ArgInfo &Arg1 = FI->getArgInfo(1).Info;
+ EXPECT_TRUE(Arg1.isDirect());
+ EXPECT_EQ(Arg1.getCoerceToType(), nullptr);
+
+ // Arg 2: i16 -> direct.
+ EXPECT_EQ(FI->getArgInfo(2).getType(), I16);
+ const ArgInfo &Arg2 = FI->getArgInfo(2).Info;
+ EXPECT_TRUE(Arg2.isDirect());
+ EXPECT_EQ(Arg2.getCoerceToType(), nullptr);
+
+ // Arg 3: i32 -> direct.
+ EXPECT_EQ(FI->getArgInfo(3).getType(), I32);
+ const ArgInfo &Arg3 = FI->getArgInfo(3).Info;
+ EXPECT_TRUE(Arg3.isDirect());
+ EXPECT_EQ(Arg3.getCoerceToType(), nullptr);
+
+ // Arg 4: i64 -> direct.
+ EXPECT_EQ(FI->getArgInfo(4).getType(), I64);
+ const ArgInfo &Arg4 = FI->getArgInfo(4).Info;
+ EXPECT_TRUE(Arg4.isDirect());
+ EXPECT_EQ(Arg4.getCoerceToType(), nullptr);
+
+ // Arg 5: 4-byte struct -> direct, coerced to i32.
+ EXPECT_EQ(FI->getArgInfo(5).getType(), S4);
+ const ArgInfo &Arg5 = FI->getArgInfo(5).Info;
+ expectDirectInteger(Arg5, 32);
+
+ // Arg 6: 16-byte struct -> indirect, ByVal = false.
+ EXPECT_EQ(FI->getArgInfo(6).getType(), S16);
+ const ArgInfo &Arg6 = FI->getArgInfo(6).Info;
+ EXPECT_TRUE(Arg6.isIndirect());
+ EXPECT_FALSE(Arg6.getIndirectByVal());
+}
+
+} // namespace
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 9f658bc7a4b817..f4fdd802aa171d 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -760,7 +760,8 @@ def LLVM_InvokeOp
DeclareOpInterfaceMethods<CallOpInte...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/233257
More information about the Mlir-commits
mailing list