[llvm-branch-commits] [clang] [CIR] Wire AMDGPU into the call-convention lowering pass (PR #220197)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 1 02:06:51 PDT 2026
https://github.com/skc7 created https://github.com/llvm/llvm-project/pull/220197
**Summary:**
- Route the amdgpu triple to a new `CallConvTarget::AMDGPU` and drive the LLVM ABI library's AMDGPU classifier from CallConvLowering.
**Changes:**
- The X86-only classifier helpers are generalized to any target and thread the calling convention.
- Adds an `abi-lowering/amdgpu-scalars.cir` test for the supported cases.
- Opts `amdgcn-buffer-rsrc-type.hip` out of call-conv-lowering (TODO) until the bridge supports its direct-in-registers aggregate return.
Assisted by: Claude Opus 4.8
>From c1302daffefcefc3cc7874a63093bdcd1811c981 Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Tue, 1 Sep 2026 14:31:15 +0530
Subject: [PATCH] [CIR] Wire AMDGPU into the call-convention lowering pass
---
clang/include/clang/CIR/Dialect/Passes.h | 2 +-
clang/include/clang/CIR/Dialect/Passes.td | 4 +-
.../Transforms/CallConvLoweringPass.cpp | 140 +++++++++++-------
clang/lib/CIR/Lowering/CIRPasses.cpp | 6 +-
.../CodeGenHIP/amdgcn-buffer-rsrc-type.hip | 8 +-
.../abi-lowering/amdgpu-scalars.cir | 105 +++++++++++++
.../x86_64-lang-addrspace-nyi.cir | 2 +-
7 files changed, 204 insertions(+), 63 deletions(-)
create mode 100644 clang/test/CIR/Transforms/abi-lowering/amdgpu-scalars.cir
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index 674f2180c27ab..796efff8e4d7c 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -20,7 +20,7 @@ namespace cir {
/// The ABI target whose calling-convention rules drive CallConvLowering.
/// None is the unset state used when the pass runs in classification-attr
/// mode instead of selecting a target.
-enum class CallConvTarget { None, Test, X86_64 };
+enum class CallConvTarget { None, Test, X86_64, AMDGPU };
} // namespace cir
namespace clang {
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index b983cfe59112a..fd2ae1003d35c 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -246,7 +246,9 @@ def CallConvLowering : Pass<"cir-call-conv-lowering", "mlir::ModuleOp"> {
clEnumValN(cir::CallConvTarget::Test, "test",
"MLIR test ABI target"),
clEnumValN(cir::CallConvTarget::X86_64, "x86_64",
- "x86_64 System V")
+ "x86_64 System V"),
+ clEnumValN(cir::CallConvTarget::AMDGPU, "amdgpu",
+ "AMDGPU")
)}]>,
Option<"classificationAttr", "classification-attr", "std::string",
/*default=*/"\"\"",
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 11c2a66dba7b5..c1c69947d55c5 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -80,7 +80,7 @@ namespace {
// bit-field access unit, a record holding an empty-for-ABI member that
// occupies bytes or a zero-sized one off its own alignment, a union no member
// of which spans its declared size, and a union with an empty-record member
-// are reported NYI by classifyX86_64Function so an unsupported signature
+// are reported NYI by classifyAbiSignature so an unsupported signature
// fails the pass instead of being misclassified.
//===----------------------------------------------------------------------===//
@@ -142,7 +142,7 @@ static bool reachesNamedBitFieldUnit(mlir::Type ty) {
/// whose members are all themselves supported, or an array of a supported
/// element type. Also a `_Complex`, or a fixed-width vector, of a supported
/// element type. Everything else is reported NYI at the reject() choke point
-/// in classifyX86_64Function.
+/// in classifyAbiSignature.
static bool isSupportedType(mlir::Type ty, const DataLayout &dl) {
// A pointer is only handled in the default address space (null) or an
// already-lowered target address space. A LangAddressSpaceAttr must be
@@ -314,7 +314,7 @@ static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx) {
.Default([](const llvm::abi::Type *) -> mlir::Type { return nullptr; });
}
-/// Map a CIR type to an llvm::abi::Type. classifyX86_64Function pre-filters
+/// Map a CIR type to an llvm::abi::Type. classifyAbiSignature pre-filters
/// the signature, so only the scalar and struct/array types handled here can
/// reach this function.
static const llvm::abi::Type *mapCIRType(mlir::Type type,
@@ -442,7 +442,7 @@ static const llvm::abi::Type *mapCIRType(mlir::Type type,
})
.Default([](mlir::Type) -> const llvm::abi::Type * {
llvm_unreachable(
- "mapCIRType: type not pre-filtered by classifyX86_64Function");
+ "mapCIRType: type not pre-filtered by classifyAbiSignature");
});
}
@@ -535,20 +535,31 @@ static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
return llvm::abi::RequiredArgs(fnTy.getNumInputs());
}
-/// Classify an x86_64 SysV signature (return type + argument types) using the
-/// LLVM ABI library. Shared by the cir.func path, the variadic-call path and
-/// the indirect-call path (the latter classifies from the callee function
+/// Map a cir.func calling convention to the llvm::CallingConv the ABI
+/// classifier keys on. Only the AMDGPU kernel convention changes
+/// classification today; every other convention is classified as C.
+static llvm::CallingConv::ID abiCallingConv(cir::CallingConv cc) {
+ if (cc == cir::CallingConv::AMDGPUKernel)
+ return llvm::CallingConv::AMDGPU_KERNEL;
+ return llvm::CallingConv::C;
+}
+
+/// Classify a signature (return type + argument types) for \p targetInfo using
+/// the LLVM ABI library. Shared by the cir.func path, the variadic-call path
+/// and the indirect-call path (the latter classifies from the callee function
/// pointer's pointee FuncType). \p required marks where the declared
/// parameters in \p inputs end. The classifier treats every argument past that
-/// point as passed through an ellipsis. Returns std::nullopt and emits an NYI
-/// error via \p emitError if the signature uses a type the bridge does not
-/// handle yet.
-static std::optional<FunctionClassification> classifyX86_64Signature(
- mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
- MLIRContext *ctx, const DataLayout &dl,
- mlir::abi::ABITypeMapper &typeMapper,
- const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp,
- llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
+/// point as passed through an ellipsis. \p callConv selects the ABI convention
+/// (e.g. AMDGPU_KERNEL), which some targets classify differently. Returns
+/// std::nullopt and emits an NYI error via \p emitError if the signature uses a
+/// type the bridge does not handle yet.
+static std::optional<FunctionClassification>
+classifyAbiSignature(mlir::Type retCIR, mlir::TypeRange inputs,
+ llvm::abi::RequiredArgs required, MLIRContext *ctx,
+ const DataLayout &dl, mlir::abi::ABITypeMapper &typeMapper,
+ const llvm::abi::TargetInfo &targetInfo,
+ llvm::CallingConv::ID callConv, ModuleOp modOp,
+ llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
assert(retCIR && "signature return type must be non-null");
assert((!required.allowsOptionalArgs() ||
required.getNumRequiredArgs() <= inputs.size()) &&
@@ -558,9 +569,8 @@ static std::optional<FunctionClassification> classifyX86_64Signature(
auto reject = [&](mlir::Type t) -> bool {
if (isSupportedType(t, dl))
return false;
- emitError()
- << "x86_64 calling-convention lowering not yet implemented for type "
- << t;
+ emitError() << "calling-convention lowering not yet implemented for type "
+ << t;
return true;
};
if (!voidRet && reject(retCIR))
@@ -576,15 +586,15 @@ static std::optional<FunctionClassification> classifyX86_64Signature(
for (mlir::Type a : inputs)
argAbi.push_back(mapCIRType(a, typeMapper, dl, modOp));
- std::unique_ptr<llvm::abi::FunctionInfo> fi = llvm::abi::FunctionInfo::create(
- llvm::CallingConv::C, retAbi, argAbi, required);
+ std::unique_ptr<llvm::abi::FunctionInfo> fi =
+ llvm::abi::FunctionInfo::create(callConv, retAbi, argAbi, required);
targetInfo.computeInfo(*fi);
// convertABIArgInfo returns nullopt when the classifier picks a coercion this
// bridge cannot represent.
auto nyiCoercion = [&](mlir::Type t) {
- emitError() << "x86_64 calling-convention lowering not yet "
- "implemented for the ABI coercion of type "
+ emitError() << "calling-convention lowering not yet implemented for the "
+ "ABI coercion of type "
<< t;
};
@@ -636,19 +646,19 @@ static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
return avx ? std::max(base, llvm::abi::X86AVXABILevel::AVX) : base;
}
-/// Classify a cir.func for x86_64 SysV using the LLVM ABI library. Returns
+/// Classify a cir.func for \p targetInfo using the LLVM ABI library. Returns
/// std::nullopt and emits an NYI error if the signature uses a type the bridge
/// does not handle yet.
static std::optional<FunctionClassification>
-classifyX86_64Function(cir::FuncOp func, const DataLayout &dl,
- mlir::abi::ABITypeMapper &typeMapper,
- const llvm::abi::TargetInfo &targetInfo,
- ModuleOp modOp) {
+classifyAbiFunction(cir::FuncOp func, const DataLayout &dl,
+ mlir::abi::ABITypeMapper &typeMapper,
+ const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
cir::FuncType fnTy = func.getFunctionType();
- return classifyX86_64Signature(fnTy.getReturnType(), fnTy.getInputs(),
- requiredArgs(fnTy), func->getContext(), dl,
- typeMapper, targetInfo, modOp,
- [&]() { return func.emitOpError(); });
+ return classifyAbiSignature(fnTy.getReturnType(), fnTy.getInputs(),
+ requiredArgs(fnTy), func->getContext(), dl,
+ typeMapper, targetInfo,
+ abiCallingConv(func.getCallingConv()), modOp,
+ [&]() { return func.emitOpError(); });
}
/// Classify a call that passes arguments through an ellipsis. The callee's
@@ -658,17 +668,19 @@ classifyX86_64Function(cir::FuncOp func, const DataLayout &dl,
/// small struct is passed in registers early in the list and in memory once
/// the integer registers are gone. Classifying from the call's operands
/// rather than the callee's signature is what makes that accounting right.
-static std::optional<FunctionClassification> classifyX86_64VariadicCall(
- cir::CIRCallOpInterface call, cir::FuncType calleeTy, const DataLayout &dl,
- mlir::abi::ABITypeMapper &typeMapper,
- const llvm::abi::TargetInfo &targetInfo, ModuleOp modOp) {
+static std::optional<FunctionClassification>
+classifyAbiVariadicCall(cir::CIRCallOpInterface call, cir::FuncType calleeTy,
+ const DataLayout &dl,
+ mlir::abi::ABITypeMapper &typeMapper,
+ const llvm::abi::TargetInfo &targetInfo,
+ llvm::CallingConv::ID callConv, ModuleOp modOp) {
assert(calleeTy.isVarArg() &&
"only a variadic callee can take more operands than it declares");
Operation *op = call.getOperation();
- return classifyX86_64Signature(
+ return classifyAbiSignature(
calleeTy.getReturnType(), call.getArgOperands().getTypes(),
requiredArgs(calleeTy), op->getContext(), dl, typeMapper, targetInfo,
- modOp, [&]() { return op->emitOpError(); });
+ callConv, modOp, [&]() { return op->emitOpError(); });
}
#ifndef NDEBUG
@@ -810,10 +822,18 @@ void CallConvLoweringPass::runOnOperation() {
static constexpr unsigned numAvxLevels =
static_cast<unsigned>(llvm::abi::X86AVXABILevel::Last) + 1;
bool isX86 = target == cir::CallConvTarget::X86_64;
- std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
+ bool isAMDGPU = target == cir::CallConvTarget::AMDGPU;
+ // The x86_64 and AMDGPU drivers classify with the LLVM ABI library and share
+ // the type mapper; the test and classification-attr drivers do neither.
+ bool useAbiClassifier = isX86 || isAMDGPU;
+ std::optional<mlir::abi::ABITypeMapper> abiTypeMapper;
std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
- if (isX86)
- x86TypeMapper.emplace(dl);
+ std::unique_ptr<llvm::abi::TargetInfo> amdgpuTarget;
+ if (useAbiClassifier)
+ abiTypeMapper.emplace(dl);
+ if (isAMDGPU)
+ amdgpuTarget =
+ llvm::abi::createAMDGPUTargetInfo(abiTypeMapper->getTypeBuilder());
auto x86TargetFor =
[&](llvm::abi::X86AVXABILevel level) -> const llvm::abi::TargetInfo & {
assert(static_cast<unsigned>(level) < numAvxLevels &&
@@ -822,7 +842,7 @@ void CallConvLoweringPass::runOnOperation() {
x86Targets[static_cast<unsigned>(level)];
if (!slot)
slot = llvm::abi::createX86_64TargetInfo(
- x86TypeMapper->getTypeBuilder(), level,
+ abiTypeMapper->getTypeBuilder(), level,
/*Has64BitPointers=*/true, x86AbiCompat);
return *slot;
};
@@ -832,6 +852,13 @@ void CallConvLoweringPass::runOnOperation() {
return baseAvxLevel;
return funcAvxLevel(func, baseAvxLevel);
};
+ // The classifier to use for a function/call reached from \p func. AMDGPU has
+ // a single classifier; x86_64 picks the one matching func's AVX level.
+ auto targetInfoFor = [&](cir::FuncOp func) -> const llvm::abi::TargetInfo & {
+ if (isAMDGPU)
+ return *amdgpuTarget;
+ return x86TargetFor(avxLevelFor(func));
+ };
// Classify every cir.func up front. No IR mutation happens here, so
// later walks can consult any function's classification regardless of
@@ -840,9 +867,9 @@ void CallConvLoweringPass::runOnOperation() {
bool anyFailed = false;
moduleOp.walk([&](cir::FuncOp f) {
std::optional<FunctionClassification> fc;
- if (isX86)
- fc = classifyX86_64Function(f, dl, *x86TypeMapper,
- x86TargetFor(avxLevelFor(f)), moduleOp);
+ if (useAbiClassifier)
+ fc = classifyAbiFunction(f, dl, *abiTypeMapper, targetInfoFor(f),
+ moduleOp);
else
fc = classifyFunction(f, dl, target, classificationAttr);
if (!fc) {
@@ -879,11 +906,12 @@ void CallConvLoweringPass::runOnOperation() {
return;
callers[callee].push_back(op);
- // Only the x86_64 driver classifies per call site. Under the other
+ // Only the ABI-library drivers classify per call site. Under the other
// drivers the classification comes from a fixed per-function source, so
// such a call stays short a classification and rewriteCallSite reports it.
cir::FuncType calleeTy = callee.getFunctionType();
- if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
+ if (!useAbiClassifier ||
+ call.getNumArgOperands() <= calleeTy.getNumInputs())
return;
// A callee declared without a prototype also takes more operands than it
// declares, and the verifier allows it. Those extra arguments are named
@@ -900,9 +928,9 @@ void CallConvLoweringPass::runOnOperation() {
// Classic instead arranges every call site from the caller and reports a
// caller whose level disagrees with its callee in checkFunctionCallABI,
// which has no equivalent here yet.
- std::optional<FunctionClassification> fc =
- classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
- x86TargetFor(avxLevelFor(callee)), moduleOp);
+ std::optional<FunctionClassification> fc = classifyAbiVariadicCall(
+ call, calleeTy, dl, *abiTypeMapper, targetInfoFor(callee),
+ abiCallingConv(callee.getCallingConv()), moduleOp);
if (!fc) {
anyFailed = true;
return;
@@ -995,13 +1023,13 @@ void CallConvLoweringPass::runOnOperation() {
[&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> {
// A callee resolved at run time carries no features of its own, so the
// level comes from the function containing the call, which is the
- // declaration classic arranges every call site from.
- if (isX86)
- return classifyX86_64Signature(
+ // declaration classic arranges every call site from. An indirect callee
+ // is an ordinary function pointer, so it uses the C convention.
+ if (useAbiClassifier)
+ return classifyAbiSignature(
funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
- *x86TypeMapper,
- x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
- moduleOp, [&]() { return c->emitOpError(); });
+ *abiTypeMapper, targetInfoFor(c->getParentOfType<cir::FuncOp>()),
+ llvm::CallingConv::C, moduleOp, [&]() { return c->emitOpError(); });
return withReturnVoidness(
mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
funcTy.getReturnType());
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 64d82dd4e7301..6b86ab69fd614 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -26,6 +26,8 @@ namespace cir {
static CallConvTarget getCallConvTarget(const llvm::Triple &triple) {
if (triple.getArch() == llvm::Triple::x86_64)
return CallConvTarget::X86_64;
+ if (triple.isAMDGPU())
+ return CallConvTarget::AMDGPU;
return CallConvTarget::None;
}
@@ -115,8 +117,8 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext,
if (enableCallConvLowering) {
// CallConvLowering rewrites signatures and call sites using the classifier,
// so it must run after CXXABILowering has lowered C++ ABI types to plain
- // records the classifier can handle. Only the x86_64 System V classifier
- // is implemented; other targets are left unchanged.
+ // records the classifier can handle. Only the x86_64 System V and AMDGPU
+ // classifiers are implemented; other targets are left unchanged.
const clang::TargetInfo &targetInfo = astContext.getTargetInfo();
CallConvTarget target = getCallConvTarget(targetInfo.getTriple());
if (target != CallConvTarget::None)
diff --git a/clang/test/CIR/CodeGenHIP/amdgcn-buffer-rsrc-type.hip b/clang/test/CIR/CodeGenHIP/amdgcn-buffer-rsrc-type.hip
index e03fa4db5c20d..0045a731c579f 100644
--- a/clang/test/CIR/CodeGenHIP/amdgcn-buffer-rsrc-type.hip
+++ b/clang/test/CIR/CodeGenHIP/amdgcn-buffer-rsrc-type.hip
@@ -1,12 +1,16 @@
#include "../CodeGenCUDA/Inputs/cuda.h"
// REQUIRES: amdgpu-registered-target
+
+// TODO(cir): drop -fno-clangir-call-conv-lowering once CallConvLowering
+// supports the AMDGPU direct-in-registers aggregate return of a buffer
+// resource struct.
// RUN: %clang_cc1 -triple amdgpu11.00-amd-amdhsa -x hip -std=c++11 -fclangir \
-// RUN: -fcuda-is-device -emit-cir %s -o %t.cir
+// RUN: -fcuda-is-device -fno-clangir-call-conv-lowering -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple amdgpu11.00-amd-amdhsa -x hip -std=c++11 -fclangir \
-// RUN: -fcuda-is-device -emit-llvm %s -o %t-cir.ll
+// RUN: -fcuda-is-device -fno-clangir-call-conv-lowering -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
// RUN: %clang_cc1 -triple amdgpu11.00-amd-amdhsa -x hip -std=c++11 \
diff --git a/clang/test/CIR/Transforms/abi-lowering/amdgpu-scalars.cir b/clang/test/CIR/Transforms/abi-lowering/amdgpu-scalars.cir
new file mode 100644
index 0000000000000..5b9049e119757
--- /dev/null
+++ b/clang/test/CIR/Transforms/abi-lowering/amdgpu-scalars.cir
@@ -0,0 +1,105 @@
+// RUN: cir-opt %s -cir-call-conv-lowering=target=amdgpu | FileCheck %s
+
+!s8i = !cir.int<s, 8>
+!s16i = !cir.int<s, 16>
+!u16i = !cir.int<u, 16>
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+!rec_E0 = !cir.struct<"E0" {}>
+!rec_Pair16 = !cir.struct<"Pair16" {data !s16i, data !s16i}>
+
+module attributes {
+ dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<i1, dense<8>: vector<2xi64>>,
+ #dlti.dl_entry<i8, dense<8>: vector<2xi64>>,
+ #dlti.dl_entry<i16, dense<16>: vector<2xi64>>,
+ #dlti.dl_entry<i32, dense<32>: vector<2xi64>>,
+ #dlti.dl_entry<i64, dense<64>: vector<2xi64>>>
+} {
+
+ // Register-sized integers are Direct: signature and call sites unchanged.
+ cir.func @passthrough(%arg0: !s32i, %arg1: !s64i) -> !s32i {
+ cir.return %arg0 : !s32i
+ }
+
+ // CHECK: cir.func{{.*}} @passthrough(%arg0: !s32i, %arg1: !s64i) -> !s32i
+ // CHECK-NEXT: cir.return %arg0 : !s32i
+
+ // Floating-point scalars are Direct.
+ cir.func @floats(%arg0: !cir.float, %arg1: !cir.double) -> !cir.double {
+ cir.return %arg1 : !cir.double
+ }
+
+ // CHECK: cir.func{{.*}} @floats(%arg0: !cir.float, %arg1: !cir.double) -> !cir.double
+
+ // Pointers are Direct.
+ cir.func @take_ptr(%arg0: !cir.ptr<!s32i>) -> !cir.ptr<!s32i> {
+ cir.return %arg0 : !cir.ptr<!s32i>
+ }
+
+ // CHECK: cir.func{{.*}} @take_ptr(%arg0: !cir.ptr<!s32i>) -> !cir.ptr<!s32i>
+
+ // Signed sub-register integer is sign-extended.
+ cir.func @take_s8(%arg0: !s8i) {
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @take_s8(%arg0: !s8i {llvm.signext})
+
+ // Unsigned sub-register integer is zero-extended.
+ cir.func @take_u16(%arg0: !u16i) {
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @take_u16(%arg0: !u16i {llvm.zeroext})
+
+ // bool is zero-extended.
+ cir.func @take_bool(%arg0: !cir.bool) {
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @take_bool(%arg0: !cir.bool {llvm.zeroext})
+
+ // Call site picks up the same extension attribute on the operand.
+ cir.func @call_s8(%arg0: !s8i) {
+ cir.call @take_s8(%arg0) : (!s8i) -> ()
+ cir.return
+ }
+
+ // CHECK: cir.call @take_s8(%arg0) : (!s8i {llvm.signext}) -> ()
+
+ // A sub-register integer return is also extended, not just arguments.
+ cir.func @ret_s8() -> !s8i {
+ %0 = cir.const #cir.int<0> : !s8i
+ cir.return %0 : !s8i
+ }
+
+ // CHECK: cir.func{{.*}} @ret_s8() -> (!s8i {llvm.signext})
+
+ // A zero-field record classifies as Ignore: the empty argument is dropped
+ // and the real argument shifts down to the first slot.
+ cir.func @take_empty(%arg0: !rec_E0, %arg1: !s32i) -> !s32i {
+ cir.return %arg1 : !s32i
+ }
+
+ // CHECK: cir.func{{.*}} @take_empty(%arg0: !s32i) -> !s32i
+ // CHECK-NEXT: cir.return %arg0 : !s32i
+
+ // A small aggregate (<= 32 bits) is packed into a single i32 register.
+ cir.func @takes_small(%arg0: !rec_Pair16) {
+ %0 = cir.alloca "p" align(4) : !cir.ptr<!rec_Pair16>
+ cir.store %arg0, %0 : !rec_Pair16, !cir.ptr<!rec_Pair16>
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @takes_small(%{{.*}}: !u32i)
+
+ // A kernel scalar argument stays Direct: the AMDGPU_KERNEL convention is
+ // routed to the kernel classifier and the signature is unchanged.
+ cir.func @kernel_scalar(%arg0: !s32i) cc(amdgpu_kernel) {
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @kernel_scalar(%arg0: !s32i){{.*}}cc(amdgpu_kernel)
+}
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
index a8350b421757d..285df67e53c83 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-lang-addrspace-nyi.cir
@@ -15,4 +15,4 @@ module attributes {
}
-// CHECK: op x86_64 calling-convention lowering not yet implemented for type
+// CHECK: op calling-convention lowering not yet implemented for type
More information about the llvm-branch-commits
mailing list