Files
TheRock/compiler/amd-llvm/mlir/unittests/ABI/TestTargetTest.cpp
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

328 lines
12 KiB
C++

//===- TestTargetTest.cpp - Unit tests for the test ABI target -----------===//
//
// 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 "mlir/ABI/Targets/Test/TestTarget.h"
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/MLIRContext.h"
#include <gtest/gtest.h>
using namespace mlir;
using namespace mlir::abi;
using namespace mlir::abi::test;
namespace {
class TestTargetClassifyTest : public ::testing::Test {
protected:
TestTargetClassifyTest()
: module(ModuleOp::create(UnknownLoc::get(&context))), dl(*module) {
context.loadDialect<DLTIDialect>();
}
MLIRContext context;
OwningOpRef<ModuleOp> module;
DataLayout dl;
};
TEST_F(TestTargetClassifyTest, IgnoresNoneType) {
auto noneTy = NoneType::get(&context);
FunctionClassification fc = classify({}, noneTy, dl);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Ignore);
}
TEST_F(TestTargetClassifyTest, ExtendsNarrowSignedInteger) {
auto i8 = IntegerType::get(&context, 8, IntegerType::Signed);
FunctionClassification fc = classify({i8}, NoneType::get(&context), dl);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Extend);
EXPECT_TRUE(fc.argInfos[0].signExtend);
auto coerced = dyn_cast<IntegerType>(fc.argInfos[0].coercedType);
ASSERT_TRUE(coerced);
EXPECT_EQ(coerced.getWidth(), 32u);
}
TEST_F(TestTargetClassifyTest, ExtendsNarrowSignlessIntegerAsZeroExt) {
auto i8 = IntegerType::get(&context, 8);
FunctionClassification fc = classify({i8}, NoneType::get(&context), dl);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Extend);
EXPECT_FALSE(fc.argInfos[0].signExtend);
}
TEST_F(TestTargetClassifyTest, RegisterSizedIntegerIsDirect) {
auto i32 = IntegerType::get(&context, 32);
auto i64 = IntegerType::get(&context, 64);
FunctionClassification fc = classify({i32, i64}, NoneType::get(&context), dl);
ASSERT_EQ(fc.argInfos.size(), 2u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Direct);
EXPECT_EQ(fc.argInfos[1].kind, ArgKind::Direct);
}
TEST_F(TestTargetClassifyTest, IndexTypeIsDirect) {
// The default DataLayout reports IndexType as 64 bits, which is at or above
// the extension threshold and should classify as Direct.
auto idx = IndexType::get(&context);
FunctionClassification fc = classify({idx}, idx, dl);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Direct);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Direct);
}
TEST_F(TestTargetClassifyTest, FloatIsDirect) {
auto f32 = Float32Type::get(&context);
FunctionClassification fc = classify({f32}, f32, dl);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Direct);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Direct);
}
TEST_F(TestTargetClassifyTest, FunctionLevelReturnAndArgsClassifiedTogether) {
auto i32 = IntegerType::get(&context, 32);
auto f64 = Float64Type::get(&context);
FunctionClassification fc = classify({i32, f64}, i32, dl);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Direct);
ASSERT_EQ(fc.argInfos.size(), 2u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Direct);
EXPECT_EQ(fc.argInfos[1].kind, ArgKind::Direct);
}
TEST_F(TestTargetClassifyTest,
TypeWithoutDataLayoutInterfaceClassifiedAsIgnore) {
// FunctionType does not implement DataLayoutTypeInterface. The classifier
// must treat it as Ignore rather than crashing in dl.getTypeSizeInBits().
// This guards against the same crash for dialect-specific void / sentinel
// types (e.g. cir::VoidType) used as a function's "no return value" marker.
auto i32 = IntegerType::get(&context, 32);
auto fnTy = FunctionType::get(&context, {i32}, {i32});
FunctionClassification fc = classify({}, fnTy, dl);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Ignore);
}
class TestTargetParseTest : public ::testing::Test {
protected:
TestTargetParseTest() : builder(&context) {
// Suppress diagnostic printing during tests; capture into lastError
// for assertions instead.
context.getDiagEngine().registerHandler([this](Diagnostic &diag) {
lastError = diag.str();
return success();
});
}
/// Convenience: parse and assert success, returning the result.
FunctionClassification parseOk(DictionaryAttr attr) {
auto loc = UnknownLoc::get(&context);
auto result =
parseClassificationAttr(attr, [&]() { return mlir::emitError(loc); });
EXPECT_TRUE(result.has_value())
<< "parseClassificationAttr failed: " << lastError;
return result.value_or(FunctionClassification{});
}
/// Convenience: parse and assert failure with a substring match.
void parseError(DictionaryAttr attr, StringRef expectedSubstr) {
auto loc = UnknownLoc::get(&context);
lastError.clear();
auto result =
parseClassificationAttr(attr, [&]() { return mlir::emitError(loc); });
EXPECT_FALSE(result.has_value());
EXPECT_NE(lastError.find(expectedSubstr.str()), std::string::npos)
<< "expected error containing '" << expectedSubstr << "' but got '"
<< lastError << "'";
}
DictionaryAttr makeArg(ArrayRef<NamedAttribute> entries) {
return DictionaryAttr::get(&context, entries);
}
MLIRContext context;
OpBuilder builder;
std::string lastError;
};
TEST_F(TestTargetParseTest, ParsesDirectReturnAndOneDirectArg) {
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({direct})),
});
auto fc = parseOk(attr);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Direct);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Direct);
}
TEST_F(TestTargetParseTest, ParsesExtendWithCoercedTypeAndSignExtend) {
auto i32 = IntegerType::get(&context, 32);
auto extend = makeArg({
builder.getNamedAttr("kind", builder.getStringAttr("extend")),
builder.getNamedAttr("coerced_type", TypeAttr::get(i32)),
builder.getNamedAttr("sign_extend", builder.getBoolAttr(true)),
});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({extend})),
});
auto fc = parseOk(attr);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Extend);
EXPECT_TRUE(fc.argInfos[0].signExtend);
EXPECT_EQ(fc.argInfos[0].coercedType, i32);
}
TEST_F(TestTargetParseTest, ParsesIndirectWithAlignAndByval) {
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto indirect = makeArg({
builder.getNamedAttr("kind", builder.getStringAttr("indirect")),
builder.getNamedAttr("indirect_align", builder.getI64IntegerAttr(16)),
builder.getNamedAttr("byval", builder.getBoolAttr(false)),
});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({indirect})),
});
auto fc = parseOk(attr);
ASSERT_EQ(fc.argInfos.size(), 1u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Indirect);
EXPECT_EQ(fc.argInfos[0].indirectAlign, llvm::Align(16));
EXPECT_FALSE(fc.argInfos[0].byVal);
}
TEST_F(TestTargetParseTest, ParsesIgnoreAndExpand) {
auto ignore =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("ignore"))});
auto expand =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("expand"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", ignore),
builder.getNamedAttr("args", builder.getArrayAttr({expand, ignore})),
});
auto fc = parseOk(attr);
EXPECT_EQ(fc.returnInfo.kind, ArgKind::Ignore);
ASSERT_EQ(fc.argInfos.size(), 2u);
EXPECT_EQ(fc.argInfos[0].kind, ArgKind::Expand);
EXPECT_EQ(fc.argInfos[1].kind, ArgKind::Ignore);
}
TEST_F(TestTargetParseTest, RejectsMissingReturn) {
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("args", builder.getArrayAttr({direct})),
});
parseError(attr, "missing required 'return'");
}
TEST_F(TestTargetParseTest, RejectsMissingArgs) {
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
});
parseError(attr, "missing required 'args'");
}
TEST_F(TestTargetParseTest, RejectsUnknownTopLevelKey) {
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({})),
builder.getNamedAttr("future_field", builder.getStringAttr("hello")),
});
parseError(attr, "unknown top-level key 'future_field'");
}
TEST_F(TestTargetParseTest, RejectsUnknownArgKey) {
auto badArg = makeArg({
builder.getNamedAttr("kind", builder.getStringAttr("direct")),
builder.getNamedAttr("future_field", builder.getBoolAttr(true)),
});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({badArg})),
});
parseError(attr, "unknown key 'future_field'");
}
TEST_F(TestTargetParseTest, RejectsExtendWithoutCoercedType) {
auto badExtend =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("extend"))});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({badExtend})),
});
parseError(attr, "kind='extend' requires 'coerced_type'");
}
TEST_F(TestTargetParseTest, RejectsIndirectWithoutAlign) {
auto badIndirect = makeArg(
{builder.getNamedAttr("kind", builder.getStringAttr("indirect"))});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({badIndirect})),
});
parseError(attr, "kind='indirect' requires 'indirect_align'");
}
TEST_F(TestTargetParseTest, RejectsIndirectWithNonPowerOfTwoAlign) {
auto badIndirect = makeArg({
builder.getNamedAttr("kind", builder.getStringAttr("indirect")),
builder.getNamedAttr("indirect_align", builder.getI64IntegerAttr(7)),
});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({badIndirect})),
});
parseError(attr, "must be a positive power of 2");
}
TEST_F(TestTargetParseTest, RejectsUnknownKind) {
auto bad = makeArg(
{builder.getNamedAttr("kind", builder.getStringAttr("invalid_kind"))});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({bad})),
});
parseError(attr, "unknown kind='invalid_kind'");
}
TEST_F(TestTargetParseTest, RejectsMissingKind) {
auto bad = makeArg({});
auto direct =
makeArg({builder.getNamedAttr("kind", builder.getStringAttr("direct"))});
auto attr = builder.getDictionaryAttr({
builder.getNamedAttr("return", direct),
builder.getNamedAttr("args", builder.getArrayAttr({bad})),
});
parseError(attr, "missing required 'kind'");
}
} // namespace