[clang] [CIR] Widen const/pure side effects for ABI argument memory (PR #221067)
Adam Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 16 11:48:04 PDT 2026
https://github.com/adams381 updated https://github.com/llvm/llvm-project/pull/221067
>From 708017d2380314bb8bfec88e0fd2aac2a865bc2f Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Thu, 3 Sep 2026 15:13:17 -0700
Subject: [PATCH 1/3] [CIR] Widen memory effects for ABI-introduced argument
memory
Both memory-effect sites in LowerToLLVM now check `arg_attrs` and add
argument memory, as classic does in `AddPotentialArgAccess`. Variadic
definitions widen too, since their parameters do not cover every
argument. CallConvLowering also carries `side_effect` across when it
rebuilds a call.
Assisted-by: Cursor / claude-opus-5
---
.../TargetLowering/CIRABIRewriteContext.cpp | 23 ++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 118 +++++++--------
clang/test/CIR/CodeGen/side-effect.cpp | 139 +++++++++++++++---
.../abi-lowering/side-effect-argmem.cir | 132 +++++++++++++++++
4 files changed, 326 insertions(+), 86 deletions(-)
create mode 100644 clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index 918f3f17b9933..4e8a04cb8ffbf 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -811,7 +811,8 @@ SmallVector<mlir::NamedAttribute> buildSretSlotAttrs(mlir::OpBuilder &builder,
// it, and once the CIR `!cir.ptr<retTy>` lowers to an opaque LLVM `ptr` the
// pointee type can no longer be recovered from the pointer.
attrs.push_back(
- builder.getNamedAttr("llvm.sret", mlir::TypeAttr::get(retTy)));
+ builder.getNamedAttr(mlir::LLVM::LLVMDialect::getStructRetAttrName(),
+ mlir::TypeAttr::get(retTy)));
attrs.push_back(
builder.getNamedAttr("llvm.align", builder.getI64IntegerAttr(align)));
if (withNoalias)
@@ -823,6 +824,18 @@ SmallVector<mlir::NamedAttribute> buildSretSlotAttrs(mlir::OpBuilder &builder,
return attrs;
}
+/// Carry \p call's attributes over to the rewritten \p newCall, leaving
+/// attributes already on \p newCall, such as its callee, alone.
+///
+/// side_effect is set explicitly because it is a DefaultValuedAttr: a fresh
+/// call already carries `all`, so the copy sees it as present and skips it.
+void carryCallAttrs(cir::CallOp call, cir::CallOp newCall) {
+ for (mlir::NamedAttribute attr : call->getAttrs())
+ if (!newCall->hasAttr(attr.getName()))
+ newCall->setAttr(attr.getName(), attr.getValue());
+ newCall.setSideEffect(call.getSideEffect());
+}
+
/// Prepend the sret slot's attrs at position 0 of newCall's arg_attrs.
/// Called after the call has been rewritten with the sret pointer at
/// operand 0, so the operand count now includes the sret slot. \p argAttrs
@@ -937,9 +950,7 @@ void rewriteIndirectReturnCall(cir::CallOp call,
prependIndirectCallee(call, sretArgs, sretVoidTy, builder);
auto newCall = cir::CallOp::create(
builder, call.getLoc(), call.getCalleeAttr(), sretVoidTy, sretArgs);
- for (mlir::NamedAttribute attr : call->getAttrs())
- if (!newCall->hasAttr(attr.getName()))
- newCall->setAttr(attr.getName(), attr.getValue());
+ carryCallAttrs(call, newCall);
// Shape the per-argument attrs exactly as the non-sret path does
// (signext / zeroext for Extend, drop Ignore slots, byval / align for
@@ -1300,9 +1311,7 @@ CIRABIRewriteContext::rewriteCallSite(mlir::Operation *callOp,
prependIndirectCallee(call, newArgs, callRetTy, builder);
auto newCall = cir::CallOp::create(builder, call.getLoc(),
call.getCalleeAttr(), callRetTy, newArgs);
- for (mlir::NamedAttribute attr : call->getAttrs())
- if (!newCall->hasAttr(attr.getName()))
- newCall->setAttr(attr.getName(), attr.getValue());
+ carryCallAttrs(call, newCall);
// Direct return with coercion: the new call returns the coerced type;
// emit a coercion back to the original type for the call's existing uses.
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 233e6aaa15adb..2cc8bc31a8176 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -410,45 +410,66 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
return value;
}
-void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
- cir::SideEffect sideEffect,
- mlir::LLVM::MemoryEffectsAttr &memoryEffect,
- bool &noUnwind, bool &willReturn,
- bool &noReturn) {
+/// Whether the ABI hands the callee memory through a pointer argument: an
+/// sret slot for an indirect return, or byval / byref for an indirect
+/// argument. Such a function reaches argument memory no matter what its
+/// source-level attributes say, so `const` and `pure` cannot lower to a
+/// memory effect that excludes it.
+static bool hasABIIndirectMemoryArg(mlir::ArrayAttr argAttrs) {
+ if (!argAttrs)
+ return false;
+ return llvm::any_of(argAttrs, [](mlir::Attribute a) {
+ auto dict = mlir::cast<mlir::DictionaryAttr>(a);
+ return dict.contains(mlir::LLVM::LLVMDialect::getStructRetAttrName()) ||
+ dict.contains(mlir::LLVM::LLVMDialect::getByValAttrName()) ||
+ dict.contains(mlir::LLVM::LLVMDialect::getByRefAttrName());
+ });
+}
+
+/// Lower a CIR `side_effect` to an LLVM memory effect, widening argument
+/// memory to ModRef when \p accessesArgMemory, since a widened slot may be
+/// either written or read. A null result means unknown effects, which is
+/// how `All` is represented.
+static mlir::LLVM::MemoryEffectsAttr
+buildMemoryEffects(mlir::MLIRContext *ctx, cir::SideEffect sideEffect,
+ bool accessesArgMemory) {
using mlir::LLVM::ModRefInfo;
+ ModRefInfo other;
switch (sideEffect) {
case cir::SideEffect::All:
- memoryEffect = {};
- noUnwind = isNothrow;
- willReturn = false;
- break;
-
+ return {};
case cir::SideEffect::Pure:
- memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
- callOp->getContext(), /*other=*/ModRefInfo::Ref,
- /*argMem=*/ModRefInfo::Ref,
- /*inaccessibleMem=*/ModRefInfo::Ref,
- /*errnoMem=*/ModRefInfo::Ref,
- /*targetMem0=*/ModRefInfo::Ref,
- /*targetMem1=*/ModRefInfo::Ref);
- noUnwind = true;
- willReturn = true;
+ other = ModRefInfo::Ref;
break;
-
case cir::SideEffect::Const:
- memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
- callOp->getContext(), /*other=*/ModRefInfo::NoModRef,
- /*argMem=*/ModRefInfo::NoModRef,
- /*inaccessibleMem=*/ModRefInfo::NoModRef,
- /*errnoMem=*/ModRefInfo::NoModRef,
- /*targetMem0=*/ModRefInfo::NoModRef,
- /*targetMem1=*/ModRefInfo::NoModRef);
- noUnwind = true;
- willReturn = true;
+ other = ModRefInfo::NoModRef;
break;
}
+ ModRefInfo argMem = accessesArgMemory ? ModRefInfo::ModRef : other;
+ return mlir::LLVM::MemoryEffectsAttr::get(ctx, /*other=*/other,
+ /*argMem=*/argMem,
+ /*inaccessibleMem=*/other,
+ /*errnoMem=*/other,
+ /*targetMem0=*/other,
+ /*targetMem1=*/other);
+}
+
+void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
+ cir::SideEffect sideEffect,
+ mlir::LLVM::MemoryEffectsAttr &memoryEffect,
+ bool &noUnwind, bool &willReturn,
+ bool &noReturn) {
+ bool accessesArgMemory =
+ hasABIIndirectMemoryArg(callOp->getAttrOfType<mlir::ArrayAttr>(
+ CIRDialect::getArgAttrsAttrName()));
+ memoryEffect =
+ buildMemoryEffects(callOp->getContext(), sideEffect, accessesArgMemory);
+
+ bool isConstOrPure = sideEffect != cir::SideEffect::All;
+ noUnwind = isConstOrPure || isNothrow;
+ willReturn = isConstOrPure;
noReturn = callOp->hasAttr(CIRDialect::getNoReturnAttrName());
}
@@ -2752,35 +2773,16 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
- if (std::optional<cir::SideEffect> sideEffectKind = op.getSideEffect()) {
- switch (*sideEffectKind) {
- case cir::SideEffect::All:
- break;
- case cir::SideEffect::Pure:
- fn.setMemoryEffectsAttr(mlir::LLVM::MemoryEffectsAttr::get(
- fn.getContext(),
- /*other=*/mlir::LLVM::ModRefInfo::Ref,
- /*argMem=*/mlir::LLVM::ModRefInfo::Ref,
- /*inaccessibleMem=*/mlir::LLVM::ModRefInfo::Ref,
- /*errnoMem=*/mlir::LLVM::ModRefInfo::Ref,
- /*targetMem0=*/mlir::LLVM::ModRefInfo::Ref,
- /*targetMem1=*/mlir::LLVM::ModRefInfo::Ref));
- fn.setNoUnwind(true);
- fn.setWillReturn(true);
- break;
- case cir::SideEffect::Const:
- fn.setMemoryEffectsAttr(mlir::LLVM::MemoryEffectsAttr::get(
- fn.getContext(),
- /*other=*/mlir::LLVM::ModRefInfo::NoModRef,
- /*argMem=*/mlir::LLVM::ModRefInfo::NoModRef,
- /*inaccessibleMem=*/mlir::LLVM::ModRefInfo::NoModRef,
- /*errnoMem=*/mlir::LLVM::ModRefInfo::NoModRef,
- /*targetMem0=*/mlir::LLVM::ModRefInfo::NoModRef,
- /*targetMem1=*/mlir::LLVM::ModRefInfo::NoModRef));
- fn.setNoUnwind(true);
- fn.setWillReturn(true);
- break;
- }
+ if (std::optional<cir::SideEffect> sideEffectKind = op.getSideEffect();
+ sideEffectKind && *sideEffectKind != cir::SideEffect::All) {
+ // A variadic callee's declared parameters do not cover every argument, so
+ // its argument memory widens too.
+ bool accessesArgMemory = hasABIIndirectMemoryArg(op.getArgAttrsAttr()) ||
+ op.getFunctionType().isVarArg();
+ fn.setMemoryEffectsAttr(buildMemoryEffects(fn.getContext(), *sideEffectKind,
+ accessesArgMemory));
+ fn.setNoUnwind(true);
+ fn.setWillReturn(true);
}
if (op->hasAttr(CIRDialect::getNoReturnAttrName()))
diff --git a/clang/test/CIR/CodeGen/side-effect.cpp b/clang/test/CIR/CodeGen/side-effect.cpp
index a1e0fbbeb0e2c..a53f5b3376e86 100644
--- a/clang/test/CIR/CodeGen/side-effect.cpp
+++ b/clang/test/CIR/CodeGen/side-effect.cpp
@@ -1,43 +1,140 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+struct Big { long a, b, c, d; };
+struct Small { int x; };
+
extern "C" {
+__attribute__((const)) Big const_sret();
+__attribute__((pure)) Big pure_sret();
+__attribute__((const)) int const_byval(Big b);
+__attribute__((pure)) int pure_byval(Big b);
+__attribute__((const)) Small const_small();
+__attribute__((const)) int const_ptr(const int *p);
+__attribute__((const)) int const_variadic_decl(int n, ...);
+__attribute__((const)) int const_byval2(int n, Big b);
+__attribute__((const)) int const_bigref(const Big &b);
+
// FIXME: We should figure out how to better print this on functions in the
// future.
// CIR: cir.func{{.*}}@pure_func() -> !s32i side_effect(pure) attributes {{{.*}}nothrow} {
-// LLVM: Function Attrs: {{.*}}nounwind{{.*}}willreturn{{.*}}memory(read)
-// LLVM: define{{.*}} @pure_func() #{{.*}} {
-// OGCG: Function Attrs: {{.*}}nounwind{{.*}}willreturn{{.*}}memory(read)
-// OGCG: define{{.*}} @pure_func() #{{.*}} {
__attribute__((pure))
int pure_func() { return 2;}
// CIR: cir.func{{.*}}@const_func() -> !s32i side_effect(const) attributes {{{.*}}nothrow} {
-// LLVM: Function Attrs: {{.*}}nounwind{{.*}}willreturn{{.*}}memory(none)
-// LLVM: define{{.*}} @const_func() #{{.*}} {
-// OGCG: Function Attrs: {{.*}}nounwind{{.*}}willreturn{{.*}}memory(none)
-// OGCG: define{{.*}} @const_func() #{{.*}} {
__attribute__((const))
int const_func() { return 1;}
+// Variadic definition: widened with no indirect slot in the signature.
+// CIR: cir.func{{.*}}@const_variadic(%arg0: !s32i {{.*}}, ...) -> !s32i side_effect(const)
+__attribute__((const))
+int const_variadic(int n, ...) { return n; }
+
+// A definition also gets llvm.noalias on the sret slot, so this is where
+// noalias, writable and the widened effect have to coexist.
+// CIR: cir.func{{.*}}@const_sret_def(%arg0: !cir.ptr<!rec_Big> {{{.*}}llvm.noalias{{.*}}llvm.sret = !rec_Big{{.*}}llvm.writable{{.*}}) side_effect(const)
+__attribute__((const))
+Big const_sret_def() { Big r{}; return r; }
+
void use() {
- // CIR: cir.call @pure_func() side_effect(pure) : () -> !s32i
- // LLVM: call i32 @pure_func() #[[PURE_ATTR:.*]]
- // OGCG: call i32 @pure_func() #[[PURE_ATTR:.*]]
+ // Unwidened at a call site: neither takes an indirect slot.
+ // CIR: cir.call @pure_func() side_effect(pure)
pure_func();
- // CIR: cir.call @const_func() side_effect(const) : () -> !s32i
- // LLVM: call i32 @const_func() #[[CONST_ATTR:.*]]
- // OGCG: call i32 @const_func() #[[CONST_ATTR:.*]]
+ // CIR: cir.call @const_func() side_effect(const)
const_func();
+
+ // The pass has already given these calls their sret operand.
+ // CIR: cir.call @const_sret(%{{.+}}) side_effect(const)
+ const_sret();
+ // CIR: cir.call @pure_sret(%{{.+}}) side_effect(pure)
+ pure_sret();
+
+ Big b{};
+ int i = 0;
+ // CIR: cir.call @const_byval({{.*}}) side_effect(const)
+ const_byval(b);
+ // CIR: cir.call @pure_byval({{.*}}) side_effect(pure)
+ pure_byval(b);
+
+ // CIR: cir.call @const_small() side_effect(const)
+ const_small();
+ // A source-level pointer is not ABI-introduced memory, so the effect stays
+ // memory(none).
+ // CIR: cir.call @const_ptr({{.*}}) side_effect(const)
+ const_ptr(&i);
+
+ // A call site sees the arguments it passes, so it is not widened for being
+ // variadic.
+ // CIR: cir.call @const_variadic({{.*}}) side_effect(const)
+ const_variadic(1);
+ // CIR: cir.call @const_variadic_decl({{.*}}) side_effect(const)
+ const_variadic_decl(1);
+
+ // CIR: cir.call @const_byval2({{.*}}) side_effect(const) : (!s32i{{.*}}, !cir.ptr<!rec_Big> {{{.*}}llvm.byval{{.*}}}) -> !s32i
+ const_byval2(1, b);
+ // CIR: cir.call @const_sret_def(%{{.+}}) side_effect(const)
+ const_sret_def();
+
+ // A reference is a direct pointer slot that still carries align, so neither
+ // align nor a record pointee can stand in for an indirect slot.
+ // CIR: cir.call @const_bigref({{.*}}) side_effect(const)
+ const_bigref(b);
}
-// LLVM: attributes #[[PURE_ATTR]] = {{{.*}}nounwind{{.*}}willreturn{{.*}}memory(read) }
-// OGCG: attributes #[[PURE_ATTR]] = {{{.*}}nounwind{{.*}}willreturn{{.*}}memory(read) }
-// LLVM: attributes #[[CONST_ATTR]] = {{{.*}}nounwind{{.*}}willreturn{{.*}}memory(none) }
-// OGCG: attributes #[[CONST_ATTR]] = {{{.*}}nounwind{{.*}}willreturn{{.*}}memory(none) }
}
+// The named functions appear in the same relative order in both emits, so
+// these checks are ordered. The intrinsic declarations do not, so each
+// attribute group is captured off its own define or declare line instead of
+// matched adjacent to it.
+
+// Definitions.
+// LLVM: define{{.*}} i32 @pure_func() #[[READ_DEF:[0-9]+]] {
+// LLVM: define{{.*}} i32 @const_func() #[[NONE_DEF:[0-9]+]] {
+// LLVM: define{{.*}} i32 @const_variadic(i32 noundef %{{[^,)]+}}, ...) #[[ARGMEM_DEF:[0-9]+]] {
+// LLVM: define{{.*}} void @const_sret_def(ptr dead_on_unwind noalias writable sret(%struct.Big) align 8 %{{[^,)]+}}) #[[ARGMEM_DEF]] {
+
+// Call sites.
+// LLVM: define{{.*}} void @use()
+// LLVM: call i32 @pure_func() #[[READ_CALL:[0-9]+]]
+// LLVM: call i32 @const_func() #[[NONE_CALL:[0-9]+]]
+// LLVM: call void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL:[0-9]+]]
+// LLVM: call void @pure_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[READ_ARGMEM_CALL:[0-9]+]]
+// LLVM: call i32 @const_byval(ptr noundef byval(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL]]
+// LLVM: call i32 @pure_byval(ptr noundef byval(%struct.Big) align 8 %{{.+}}) #[[READ_ARGMEM_CALL]]
+// LLVM: call i32 @const_small() #[[NONE_CALL]]
+// LLVM: call i32 @const_ptr(ptr noundef %{{.+}}) #[[NONE_CALL]]
+// LLVM: call i32 (i32, ...) @const_variadic(i32 noundef 1) #[[NONE_CALL]]
+// LLVM: call i32 (i32, ...) @const_variadic_decl(i32 noundef 1) #[[NONE_CALL]]
+// LLVM: call i32 @const_byval2(i32 noundef 1, ptr noundef byval(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL]]
+// LLVM: call void @const_sret_def(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL]]
+// LLVM: call i32 @const_bigref(ptr noundef nonnull align 8 dereferenceable(32) %{{.+}}) #[[NONE_CALL]]
+
+// Declarations.
+// LLVM: declare void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8) #[[ARGMEM_DECL:[0-9]+]]
+// LLVM: declare void @pure_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8) #[[READ_ARGMEM_DECL:[0-9]+]]
+// LLVM: declare i32 @const_byval(ptr noundef byval(%struct.Big) align 8) #[[ARGMEM_DECL]]
+// LLVM: declare i32 @pure_byval(ptr noundef byval(%struct.Big) align 8) #[[READ_ARGMEM_DECL]]
+// LLVM: declare i32 @const_small() #[[NONE_DECL:[0-9]+]]
+// LLVM: declare i32 @const_ptr(ptr noundef) #[[NONE_DECL]]
+// LLVM: declare i32 @const_variadic_decl(i32 noundef, ...) #[[ARGMEM_DECL]]
+// LLVM: declare i32 @const_byval2(i32 noundef, ptr noundef byval(%struct.Big) align 8) #[[ARGMEM_DECL]]
+// LLVM: declare i32 @const_bigref(ptr noundef nonnull align 8 dereferenceable(32)) #[[NONE_DECL]]
+
+// The trailing wildcard covers target-features and the other codegen-option
+// strings, which differ between the emits.
+// LLVM-DAG: attributes #[[READ_DEF]] = { {{.*}}nounwind{{.*}}willreturn memory(read) {{.*}}}
+// LLVM-DAG: attributes #[[NONE_DEF]] = { {{.*}}nounwind{{.*}}willreturn memory(none) {{.*}}}
+// LLVM-DAG: attributes #[[ARGMEM_DEF]] = { {{.*}}nounwind{{.*}}willreturn memory(argmem: readwrite) {{.*}}}
+// LLVM-DAG: attributes #[[ARGMEM_DECL]] = { nounwind willreturn memory(argmem: readwrite) {{.*}}}
+// LLVM-DAG: attributes #[[READ_ARGMEM_DECL]] = { nounwind willreturn memory(read, argmem: readwrite) {{.*}}}
+// LLVM-DAG: attributes #[[NONE_DECL]] = { nounwind willreturn memory(none) {{.*}}}
+// LLVM-DAG: attributes #[[READ_CALL]] = { nounwind willreturn memory(read) }
+// LLVM-DAG: attributes #[[NONE_CALL]] = { nounwind willreturn memory(none) }
+// LLVM-DAG: attributes #[[ARGMEM_CALL]] = { nounwind willreturn memory(argmem: readwrite) }
+// LLVM-DAG: attributes #[[READ_ARGMEM_CALL]] = { nounwind willreturn memory(read, argmem: readwrite) }
diff --git a/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
new file mode 100644
index 0000000000000..b213dbf13f9db
--- /dev/null
+++ b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
@@ -0,0 +1,132 @@
+// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
+// RUN: | FileCheck %s
+// The pass leaves test_classify on the lowered func, and its coerced_type is a
+// CIR type, so the alias outlives every cir op and mlir-translate has to
+// accept it.
+// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
+// RUN: -cir-to-llvm -o - \
+// RUN: | mlir-translate -mlir-to-llvmir --allow-unregistered-dialect \
+// RUN: | FileCheck %s --check-prefix=LLVM
+
+!s8i = !cir.int<s, 8>
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+!rec_Big = !cir.struct<"Big" {data !s64i, data !s64i, data !s64i}>
+
+// The leading direct argument puts the byval slot at index 1.
+#byval_arg = {
+ return = { kind = "direct" },
+ args = [ { kind = "direct" },
+ { kind = "indirect", indirect_align = 8 } ]
+}
+
+#byref_arg = {
+ return = { kind = "direct" },
+ args = [ { kind = "indirect", indirect_align = 8, byval = false } ]
+}
+
+#sret_ret = {
+ return = { kind = "indirect", indirect_align = 8 },
+ args = [ ]
+}
+
+#extend_arg = {
+ return = { kind = "direct" },
+ args = [ { kind = "extend",
+ coerced_type = !cir.int<s, 32>,
+ sign_extend = true } ]
+}
+
+#passthrough = {
+ return = { kind = "direct" },
+ args = [ ]
+}
+
+module attributes {
+ cir.triple = "x86_64-unknown-linux-gnu",
+ dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<i8, dense<8>: vector<2xi64>>,
+ #dlti.dl_entry<i32, dense<32>: vector<2xi64>>,
+ #dlti.dl_entry<i64, dense<64>: vector<2xi64>>>
+} {
+
+ cir.func private @const_sret() -> !rec_Big side_effect(const)
+ attributes { test_classify = #sret_ret }
+
+ // CHECK: cir.func{{.*}} @const_sret(!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) side_effect(const)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
+ // LLVM-NEXT: declare void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
+
+ cir.func private @pure_sret() -> !rec_Big side_effect(pure)
+ attributes { test_classify = #sret_ret }
+
+ // CHECK: cir.func{{.*}} @pure_sret(!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) side_effect(pure)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(read, argmem: readwrite)
+ // LLVM-NEXT: declare void @pure_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
+
+ cir.func private @const_byval(!s32i, !rec_Big) side_effect(const)
+ attributes { test_classify = #byval_arg }
+
+ // CHECK: cir.func{{.*}} @const_byval(!s32i, !cir.ptr<!rec_Big> {{{.*}}llvm.byval = !rec_Big{{.*}}}) side_effect(const)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
+ // LLVM-NEXT: declare void @const_byval(i32, ptr noundef byval(%struct.Big) align 8)
+
+ cir.func private @const_byref(!rec_Big) side_effect(const)
+ attributes { test_classify = #byref_arg }
+
+ // CHECK: cir.func{{.*}} @const_byref(!cir.ptr<!rec_Big> {{{.*}}llvm.byref = !rec_Big{{.*}}}) side_effect(const)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
+ // LLVM-NEXT: declare void @const_byref(ptr byref(%struct.Big) align 8)
+
+ cir.func private @const_variadic(!s8i, ...) -> !s32i side_effect(const)
+ attributes { test_classify = #extend_arg }
+
+ // CHECK: cir.func{{.*}} @const_variadic(!s8i {{{.*}}llvm.signext{{.*}}}, ...) -> !s32i side_effect(const)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
+ // LLVM-NEXT: declare i32 @const_variadic(i8 signext, ...)
+
+ // Negative: an Extend argument carries a non-empty attribute dictionary but
+ // no ABI-introduced memory, so the effect stays memory(none).
+ cir.func private @const_extend(!s8i) -> !s32i side_effect(const)
+ attributes { test_classify = #extend_arg }
+
+ // CHECK: cir.func{{.*}} @const_extend(!s8i {{{.*}}llvm.signext{{.*}}}) -> !s32i side_effect(const)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(none)
+ // LLVM-NEXT: declare i32 @const_extend(i8 signext)
+
+ // A callee with no side_effect must still come out with none, so that
+ // forwarding the original is distinguishable from hard-coding a value.
+ cir.func private @plain_sret() -> !rec_Big
+ attributes { test_classify = #sret_ret }
+
+ cir.func @call_plain_sret() attributes { test_classify = #passthrough } {
+ %r = cir.call @plain_sret() : () -> !rec_Big
+ cir.return
+ }
+
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) : (!cir.ptr<!rec_Big>{{.*}}) -> ()
+ // LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}){{$}}
+
+ // nothrow without const or pure still reaches nounwind, and still gets no
+ // memory effect.
+ cir.func @call_plain_sret_nothrow() attributes { test_classify = #passthrough } {
+ %r = cir.call @plain_sret() nothrow : () -> !rec_Big
+ cir.return
+ }
+
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) nothrow : (!cir.ptr<!rec_Big>{{.*}}) -> ()
+ // LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[NOTHROW_CALL:[0-9]+]]
+
+ // The call site keeps its side_effect across the rewrite.
+ cir.func @call_const_sret() attributes { test_classify = #passthrough } {
+ %r = cir.call @const_sret() side_effect(const) : () -> !rec_Big
+ cir.return
+ }
+
+ // CHECK: cir.func{{.*}} @call_const_sret()
+ // CHECK: cir.call @const_sret(%{{.+}}) side_effect(const)
+ // LLVM: define void @call_const_sret()
+ // LLVM: call void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[CALL_ATTRS:[0-9]+]]
+ // LLVM-DAG: attributes #[[CALL_ATTRS]] = { nounwind willreturn memory(argmem: readwrite) }
+ // LLVM-DAG: attributes #[[NOTHROW_CALL]] = { nounwind }
+}
>From 2058c570d5f0f4636f5eff658c94de85bcfb4231 Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Mon, 14 Sep 2026 13:39:49 -0700
Subject: [PATCH 2/3] [CIR] Record the ABI slot kind and widen memory effects
for it
A const or pure function handed an sret, byval or non-byval slot reaches
argument memory whatever its source attributes say, so memory(none) or
memory(read) on it is false. The verifier catches that on sret. On the
others the IR verifies and the optimizer is free to delete stores the callee
reads.
Lowering could not tell which arguments were the ABI's own. With llvm.byref
gone, a non-byval slot carries nothing a plain pointer parameter does not, so
the pass now records the slot kind it created and lowering reads that rather
than guessing from LLVM attribute names.
And side-effect-argmem.cir moves off mlir-translate, which is not built here,
onto cir-translate like every other test in that directory.
Assisted-by: Cursor / claude-opus-5
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 52 ++++++++++++
.../clang/CIR/Dialect/IR/CIRDialect.td | 1 +
.../TargetLowering/CIRABIRewriteContext.cpp | 9 +++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 81 ++++++++++---------
clang/test/CIR/CodeGen/arg-attrs.cpp | 4 +-
clang/test/CIR/CodeGen/array-ctor.cpp | 4 +-
.../CIR/CodeGen/bind-temporary-lvalue.cpp | 2 +-
.../call-conv-lowering-x86_64-empty.cpp | 8 +-
.../call-conv-lowering-x86_64-indirect.c | 4 +-
.../call-conv-lowering-x86_64-non-byval.cpp | 12 +--
.../call-conv-lowering-x86_64-packed.c | 14 ++--
.../call-conv-lowering-x86_64-padded.c | 6 +-
.../call-conv-lowering-x86_64-variadic.c | 12 +--
.../call-conv-lowering-x86_64-vptr.cpp | 22 ++---
...conv-lowering-x86_64-zero-width-bitfield.c | 2 +-
clang/test/CIR/CodeGen/call.c | 4 +-
.../cleanup-conditional-with-wrapper-eh.cpp | 8 +-
.../cleanup-conditional-with-wrapper.cpp | 8 +-
.../test/CIR/CodeGen/paren-list-agg-init.cpp | 6 +-
.../CIR/CodeGen/partial-array-cleanup.cpp | 2 +-
clang/test/CIR/CodeGen/side-effect.cpp | 34 +++++++-
.../test/CIR/CodeGenOpenACC/declare-copy.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-copyin.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-copyout.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-create.cpp | 6 +-
.../CodeGenOpenACC/declare-deviceresident.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-present.cpp | 6 +-
.../byval-sret-arg-attr-lowering.cir | 17 ++++
.../abi-lowering/indirect-byval.cir | 24 +++---
.../Transforms/abi-lowering/indirect-call.cir | 4 +-
.../indirect-non-byval-forward-param.cir | 32 ++++----
.../abi-lowering/side-effect-argmem.cir | 49 +++++++----
.../abi-lowering/x86_64-bitfield.cir | 2 +-
.../Transforms/abi-lowering/x86_64-bitint.cir | 6 +-
.../abi-lowering/x86_64-empty-class.cir | 8 +-
.../abi-lowering/x86_64-record-packed.cir | 2 +-
.../abi-lowering/x86_64-struct-indirect.cir | 10 +--
.../abi-lowering/x86_64-struct-padded.cir | 4 +-
.../Transforms/abi-lowering/x86_64-union.cir | 12 +--
.../abi-lowering/x86_64-variadic-call.cir | 16 ++--
.../Transforms/abi-lowering/x86_64-vptr.cir | 8 +-
41 files changed, 328 insertions(+), 197 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index f263cd30eb458..1f3424daaa3c5 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -159,6 +159,58 @@ def CIR_OffloadKindAttr : CIR_EnumAttr<CIR_OffloadKind, "offload"> {
}];
}
+//===----------------------------------------------------------------------===//
+// ABISlotKindAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_ABISlotKind : CIR_I32Enum<
+ "ABISlotKind", "kind of pointer slot the ABI introduced", [
+ I32EnumCase<"Byval", 0, "byval">,
+ I32EnumCase<"NonByval", 1, "non_byval">,
+ I32EnumCase<"Sret", 2, "sret">
+]> {
+ let description = [{
+ Which kind of pointer slot CallConvLowering introduced for a parameter
+ that the source declared by value, or for a return value the ABI returns
+ in memory.
+
+ - byval: the callee receives a pointer to its own copy.
+ - non_byval: the callee receives a pointer to the caller's object, used
+ when the type cannot be copied freely.
+ - sret: the return value is written through a pointer the ABI inserts as
+ argument 0.
+ }];
+}
+
+def CIR_ABISlotKindAttr : CIR_EnumAttr<CIR_ABISlotKind, "abi_slot"> {
+ let summary = "Marks an argument as a pointer slot the ABI introduced";
+ let description = [{
+ CallConvLowering rewrites a by-value parameter or an in-memory return
+ into a pointer argument, then records here which kind of slot it made.
+ The memory-effect lowering uses this to widen argument memory on a
+ `const` or `pure` callee.
+
+ A `non_byval` slot is the case the rewritten signature cannot otherwise
+ express: it is a plain `!cir.ptr<T>` carrying `llvm.align`,
+ `llvm.dereferenceable`, `llvm.nofreeobj` and `llvm.noundef`. Each of
+ those states a property of the pointer or of the object, not who created
+ the slot, so none of them is reserved to an ABI slot. A `byval` or
+ `sret` slot is for now also identifiable by the `llvm.byval` or
+ `llvm.sret` in the same dictionary, so this attribute overlaps those
+ two, and a producer that writes one without the other leaves the memory
+ effect disagreeing with the signature.
+
+ Example, on the argument dictionary of the slot it describes:
+
+ ```mlir
+ cir.func private @f(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>,
+ llvm.align = 8 : i64,
+ llvm.byval = !rec_Big,
+ llvm.noundef})
+ ```
+ }];
+}
+
//===----------------------------------------------------------------------===//
// ArgPassingKind + RecordLayoutAttr
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 7c5c2d20bbaf4..5acfc6fd8c5f8 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -83,6 +83,7 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getUniformWorkGroupSizeAttrName() { return "uniform_work_group_size"; }
static llvm::StringRef getResAttrsAttrName() { return "res_attrs"; }
static llvm::StringRef getArgAttrsAttrName() { return "arg_attrs"; }
+ static llvm::StringRef getABISlotAttrName() { return "cir.abi_slot"; }
static llvm::StringRef getRecordLayoutsAttrName() { return "cir.record_layouts"; }
static llvm::StringRef getTargetCPUAttrName() { return "cir.target-cpu"; }
static llvm::StringRef getTuneCPUAttrName() { return "cir.tune-cpu"; }
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index 1d24b830d91b1..e8b327bdd5e24 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -227,6 +227,12 @@ mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx,
// across the call.
mlir::Type pointeeTy = origArgTypes[oldIdx];
mlir::NamedAttrList attrs(existing);
+ // Record that the ABI introduced this pointer, and which kind of slot
+ // it is.
+ attrs.set(CIRDialect::getABISlotAttrName(),
+ cir::ABISlotKindAttr::get(
+ ctx, ac.byVal ? cir::ABISlotKind::Byval
+ : cir::ABISlotKind::NonByval));
attrs.set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
builder.getI64IntegerAttr(ac.indirectAlign.value()));
attrs.set(mlir::LLVM::LLVMDialect::getNoUndefAttrName(),
@@ -889,6 +895,9 @@ SmallVector<mlir::NamedAttribute> buildSretSlotAttrs(mlir::OpBuilder &builder,
uint64_t align,
bool withNoalias) {
SmallVector<mlir::NamedAttribute> attrs;
+ attrs.push_back(builder.getNamedAttr(
+ CIRDialect::getABISlotAttrName(),
+ cir::ABISlotKindAttr::get(builder.getContext(), cir::ABISlotKind::Sret)));
// The sret type must be carried explicitly: LLVM's sret attribute requires
// it, and once the CIR `!cir.ptr<retTy>` lowers to an opaque LLVM `ptr` the
// pointee type can no longer be recovered from the pointer.
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 889c7000109dd..404012349e3da 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -420,19 +420,16 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
return value;
}
-/// Whether the ABI hands the callee memory through a pointer argument: an
-/// sret slot for an indirect return, or byval / byref for an indirect
-/// argument. Such a function reaches argument memory no matter what its
-/// source-level attributes say, so `const` and `pure` cannot lower to a
-/// memory effect that excludes it.
-static bool hasABIIndirectMemoryArg(mlir::ArrayAttr argAttrs) {
+/// Whether any argument is a pointer slot the ABI introduced, which
+/// CallConvLowering marks with cir.abi_slot. Such a callee reaches that
+/// memory whatever its source-level attributes say, so `const` and `pure`
+/// cannot lower to a memory effect that excludes argument memory.
+static bool hasABISlotArg(mlir::ArrayAttr argAttrs) {
if (!argAttrs)
return false;
return llvm::any_of(argAttrs, [](mlir::Attribute a) {
- auto dict = mlir::cast<mlir::DictionaryAttr>(a);
- return dict.contains(mlir::LLVM::LLVMDialect::getStructRetAttrName()) ||
- dict.contains(mlir::LLVM::LLVMDialect::getByValAttrName()) ||
- dict.contains(mlir::LLVM::LLVMDialect::getByRefAttrName());
+ return mlir::cast<mlir::DictionaryAttr>(a).contains(
+ CIRDialect::getABISlotAttrName());
});
}
@@ -471,9 +468,8 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
bool &noUnwind, bool &willReturn,
bool &noReturn) {
- bool accessesArgMemory =
- hasABIIndirectMemoryArg(callOp->getAttrOfType<mlir::ArrayAttr>(
- CIRDialect::getArgAttrsAttrName()));
+ bool accessesArgMemory = hasABISlotArg(callOp->getAttrOfType<mlir::ArrayAttr>(
+ CIRDialect::getArgAttrsAttrName()));
memoryEffect =
buildMemoryEffects(callOp->getContext(), sideEffect, accessesArgMemory);
@@ -2121,15 +2117,13 @@ mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(
return mlir::LogicalResult::success();
}
-/// The `llvm.byval`, `llvm.sret`, and `llvm.byref` argument attributes carry
-/// the pointee type as a TypeAttr. After the CallConvLowering pass that type
-/// is still a CIR record; remap it to the lowered LLVM type so translation to
-/// LLVM IR does not encounter a CIR type in an attribute. Returns the input
-/// unchanged when there is nothing to convert.
-static mlir::ArrayAttr
-convertTypedArgAttrs(mlir::ArrayAttr argAttrs,
- const mlir::TypeConverter &converter,
- mlir::MLIRContext *ctx) {
+/// `llvm.byval` and `llvm.sret` carry their pointee type as a TypeAttr, which
+/// arrives as a CIR record, so remap it to the lowered type.
+/// cir.abi_slot has no LLVM counterpart and is dropped. The memory-effect
+/// sites read it from the CIR op, which this leaves untouched.
+static mlir::ArrayAttr lowerArgAttrs(mlir::ArrayAttr argAttrs,
+ const mlir::TypeConverter &converter,
+ mlir::MLIRContext *ctx) {
if (!argAttrs)
return argAttrs;
bool changed = false;
@@ -2137,21 +2131,29 @@ convertTypedArgAttrs(mlir::ArrayAttr argAttrs,
loweredArgAttrs.reserve(argAttrs.size());
for (mlir::Attribute a : argAttrs) {
auto dict = cast<mlir::DictionaryAttr>(a);
- SmallVector<mlir::NamedAttribute> entries(dict.begin(), dict.end());
- for (mlir::NamedAttribute &entry : entries) {
+ SmallVector<mlir::NamedAttribute> entries;
+ entries.reserve(dict.size());
+ for (mlir::NamedAttribute entry : dict) {
StringRef name = entry.getName().strref();
- if (name != mlir::LLVM::LLVMDialect::getByValAttrName() &&
- name != mlir::LLVM::LLVMDialect::getStructRetAttrName() &&
- name != mlir::LLVM::LLVMDialect::getByRefAttrName())
- continue;
- auto typeAttr = dyn_cast<mlir::TypeAttr>(entry.getValue());
- if (!typeAttr)
- continue;
- mlir::Type lowered = converter.convertType(typeAttr.getValue());
- if (lowered && lowered != typeAttr.getValue()) {
- entry.setValue(mlir::TypeAttr::get(lowered));
+ if (name == CIRDialect::getABISlotAttrName()) {
changed = true;
+ continue;
}
+ if (name == mlir::LLVM::LLVMDialect::getByValAttrName() ||
+ name == mlir::LLVM::LLVMDialect::getStructRetAttrName()) {
+ if (auto typeAttr = dyn_cast<mlir::TypeAttr>(entry.getValue())) {
+ mlir::Type lowered = converter.convertType(typeAttr.getValue());
+ if (lowered && lowered != typeAttr.getValue()) {
+ entry.setValue(mlir::TypeAttr::get(lowered));
+ changed = true;
+ }
+ }
+ }
+ // MLIR routes attribute verification to the dialect named by the prefix,
+ // so no verifier is ever asked about a surviving `cir.` key.
+ assert(!name.starts_with("cir.") &&
+ "CIR argument attribute leaked into the LLVM dialect");
+ entries.push_back(entry);
}
loweredArgAttrs.push_back(mlir::DictionaryAttr::get(ctx, entries));
}
@@ -2174,9 +2176,8 @@ static void lowerCallAttributes(cir::CIRCallOpInterface op,
assert(!cir::MissingFeatures::opFuncExtraAttrs());
if (attr.getName() == CIRDialect::getArgAttrsAttrName()) {
auto argAttrs = cast<mlir::ArrayAttr>(attr.getValue());
- result.emplace_back(
- attr.getName(),
- convertTypedArgAttrs(argAttrs, converter, op->getContext()));
+ result.emplace_back(attr.getName(),
+ lowerArgAttrs(argAttrs, converter, op->getContext()));
continue;
}
result.push_back(attr);
@@ -2715,7 +2716,7 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
auto argAttrs = cast<mlir::ArrayAttr>(attr.getValue());
result.emplace_back(
attr.getName(),
- convertTypedArgAttrs(argAttrs, *getTypeConverter(), getContext()));
+ lowerArgAttrs(argAttrs, *getTypeConverter(), getContext()));
continue;
}
result.push_back(attr);
@@ -2802,8 +2803,8 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
sideEffectKind && *sideEffectKind != cir::SideEffect::All) {
// A variadic callee's declared parameters do not cover every argument, so
// its argument memory widens too.
- bool accessesArgMemory = hasABIIndirectMemoryArg(op.getArgAttrsAttr()) ||
- op.getFunctionType().isVarArg();
+ bool accessesArgMemory =
+ hasABISlotArg(op.getArgAttrsAttr()) || op.getFunctionType().isVarArg();
fn.setMemoryEffectsAttr(buildMemoryEffects(fn.getContext(), *sideEffectKind,
accessesArgMemory));
fn.setNoUnwind(true);
diff --git a/clang/test/CIR/CodeGen/arg-attrs.cpp b/clang/test/CIR/CodeGen/arg-attrs.cpp
index 8960de7345baf..94d53256fd61a 100644
--- a/clang/test/CIR/CodeGen/arg-attrs.cpp
+++ b/clang/test/CIR/CodeGen/arg-attrs.cpp
@@ -18,7 +18,7 @@ void Struct::this_func(){}
// CIR: cir.func {{.*}}@_ZN6Struct9this_funcEv(%{{.*}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
// BOTH: define {{.*}}void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
void Struct::arg_attr(Struct s, int &i, Incomplete &j){}
- // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
+ // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!rec_Struct> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
// BOTH: define {{.*}}void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{[^,)]+}}, ptr noundef byval(%struct.Struct) align 8 %{{[^,)]+}}, ptr noundef nonnull align 4 dereferenceable(4) %{{[^,)]+}}, ptr noundef nonnull align 1 %{{[^,)]+}})
struct __attribute__((aligned(32))) Aligned32 {
@@ -50,7 +50,7 @@ void caller(Struct s, int i, Incomplete &inc) {
// CIR: cir.call @_ZN6Struct9this_funcEv(%{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef})
// BOTH: call void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
s.arg_attr(s, i, inc);
- // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Struct> {llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef})
+ // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Struct> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef})
// BOTH: call void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, ptr noundef byval(%struct.Struct) align 8 %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
}
diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp
index 16eb8a57ee6d8..48024b2a1411c 100644
--- a/clang/test/CIR/CodeGen/array-ctor.cpp
+++ b/clang/test/CIR/CodeGen/array-ctor.cpp
@@ -206,7 +206,7 @@ void TempInArray() {
// CIR: cir.do {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ITER:.*]] : !cir.ptr<!cir.ptr<!rec_CausesTemp>>, !cir.ptr<!rec_CausesTemp>
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN10CausesTempC1E4Temp(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN10CausesTempC1E4Temp(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup normal {
// CIR-NEXT: cir.call @_ZN4TempD1Ev(%[[TMP]]) nothrow
@@ -291,7 +291,7 @@ void Temp2InArray() {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ITER:.*]] : !cir.ptr<!cir.ptr<!rec_CausesTemp2>>, !cir.ptr<!rec_CausesTemp2>
// CIR-NEXT: cir.call @_ZN5Temp2C1Ev(%[[TMP]])
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup normal {
// CIR-NEXT: cir.call @_ZN5Temp2D1Ev(%[[TMP]]) nothrow
diff --git a/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp b/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
index 44893f3f9cab0..f42de67a3c90a 100644
--- a/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
+++ b/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
@@ -17,7 +17,7 @@ int f() { return getS().x; }
// CIR: cir.func {{.*}}@_Z1fv()
// CIR: %[[RET:.*]] = cir.alloca "__retval"
// CIR: %[[TMP:.*]] = cir.alloca "temp.lvalue"
-// CIR: cir.call @_Z4getSv(%[[TMP]]) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_S, llvm.writable}) -> ()
+// CIR: cir.call @_Z4getSv(%[[TMP]]) : (!cir.ptr<!rec_S> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_S, llvm.writable}) -> ()
// CIR: cir.cleanup.scope {
// CIR: %[[X:.*]] = cir.get_member %[[TMP]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[VAL:.*]] = cir.load{{.*}} %[[X]] : !cir.ptr<!s32i>, !s32i
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
index 499714bc895f5..a86ebe5ce0c18 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
@@ -224,13 +224,13 @@ long callerHiWord(long hi) {
// this size is passed indirectly at its declared alignment.
int takeBig32(Big32 v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z9takeBig325Big32i(%arg0: !cir.ptr<!rec_Big32> {llvm.align = 32 : i64, llvm.byval = !rec_Big32, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z9takeBig325Big32i(%arg0: !cir.ptr<!rec_Big32> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_Big32, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z9takeBig325Big32i(ptr noundef byval(%struct.Big32) align 32 %{{[^,]+}}, i32 noundef %{{[^,]+}})
// The same class returned uses sret at that alignment.
Big32 retBig32() { return Big32{}; }
-// CIR: cir.func {{.*}}@_Z8retBig32v(%arg0: !cir.ptr<!rec_Big32> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big32, llvm.writable}
+// CIR: cir.func {{.*}}@_Z8retBig32v(%arg0: !cir.ptr<!rec_Big32> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big32, llvm.writable}
// LLVM: define dso_local void @_Z8retBig32v(ptr dead_on_unwind noalias writable sret(%struct.Big32) align 32 %{{[^,]+}})
// A zero-width unnamed bit-field reserves no storage for the classifier to
@@ -305,13 +305,13 @@ int takeUEmptyBytes(UEmptyBytes v) { return v.c[0]; }
// member changes nothing here.
int takeUBigEmpty(UBigEmpty v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z13takeUBigEmpty9UBigEmptyi(%arg0: !cir.ptr<!rec_UBigEmpty> {llvm.align = 32 : i64, llvm.byval = !rec_UBigEmpty, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z13takeUBigEmpty9UBigEmptyi(%arg0: !cir.ptr<!rec_UBigEmpty> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigEmpty, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z13takeUBigEmpty9UBigEmptyi(ptr noundef byval(%union.UBigEmpty) align 32 %{{[^,]+}}, i32 noundef %{{[^,]+}})
// The same union returned uses sret at that alignment.
UBigEmpty retUBigEmpty() { return UBigEmpty{}; }
-// CIR: cir.func {{.*}}@_Z12retUBigEmptyv(%arg0: !cir.ptr<!rec_UBigEmpty> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBigEmpty, llvm.writable}
+// CIR: cir.func {{.*}}@_Z12retUBigEmptyv(%arg0: !cir.ptr<!rec_UBigEmpty> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBigEmpty, llvm.writable}
// LLVM: define dso_local void @_Z12retUBigEmptyv(ptr dead_on_unwind noalias writable sret(%union.UBigEmpty) align 32 %{{[^,]+}})
// Emptiness reaches the union member through a base class as well.
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
index 922b1325491a8..743241fa3863e 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
@@ -32,7 +32,7 @@ long call_byval(long (*fp)(Big), Big b) { return fp(b); }
// CIR: cir.func {{.*}}@call_byval(%arg0: !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> {{.*}}, %arg1: !cir.ptr<!rec_Big> {{.*}}llvm.byval = !rec_Big{{.*}}) -> !s64i
// CIR: %[[CAST:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>
-// CIR: %{{.+}} = cir.call %[[CAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+// CIR: %{{.+}} = cir.call %[[CAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// LLVM: define dso_local i64 @call_byval(ptr noundef %{{.+}}, ptr noundef byval(%struct.Big) align 8 %{{.+}})
// LLVM: call i64 %{{.+}}(ptr noundef byval(%struct.Big) align 8 %{{.+}})
@@ -42,6 +42,6 @@ Big call_sret(Big (*fp)(void)) { return fp(); }
// CIR: cir.func {{.*}}@call_sret(%arg0: !cir.ptr<!rec_Big> {{.*}}llvm.sret = !rec_Big{{.*}}, %arg1: !cir.ptr<!cir.func<() -> !rec_Big>> {{.*}})
// CIR: %[[SCAST:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!cir.func<() -> !rec_Big>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>
-// CIR: cir.call %[[SCAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+// CIR: cir.call %[[SCAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
// LLVM: define dso_local void @call_sret(ptr dead_on_unwind noalias writable sret(%struct.Big) align 8 %{{.+}}, ptr noundef %{{.+}})
// LLVM: call void %{{.+}}(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
index a01414569e6fa..24bd9972572ee 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
@@ -36,7 +36,7 @@ void callNonByval() {
// CIR: %[[TMP:.*]] = cir.alloca "agg.tmp0" align(4) : !cir.ptr<!rec_WithDtor>
// CIR: cir.copy %[[T]] align(4) to %[[TMP]] align(4) : !cir.ptr<!rec_WithDtor>
// CIR-NOT: cir.load
-// CIR: cir.call @_Z12takeNonByval8WithDtor(%[[TMP]]) : (!cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z12takeNonByval8WithDtor(%[[TMP]]) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP]])
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[T]])
@@ -58,7 +58,7 @@ void callTwoNonByval() {
// CIR: %[[TMP_A:.*]] = cir.alloca "agg.tmp0" align(4) : !cir.ptr<!rec_WithDtor>
// CIR: %[[TMP_B:.*]] = cir.alloca "agg.tmp1" align(4) : !cir.ptr<!rec_WithDtor>
// CIR-NOT: cir.load
-// CIR: cir.call @_Z15takeTwoNonByval8WithDtorS_(%[[TMP_A]], %[[TMP_B]]) : (!cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z15takeTwoNonByval8WithDtorS_(%[[TMP_A]], %[[TMP_B]]) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP_B]])
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP_A]])
@@ -84,7 +84,7 @@ void callCopyCtorNonByval() {
// CIR: cir.call @_ZN12WithCopyCtorC1Ev(%[[C]])
// CIR: cir.call @_ZN12WithCopyCtorC1ERKS_(%[[TMP]], %[[C]])
// CIR-NOT: cir.load
-// CIR: cir.call @_Z20takeCopyCtorNonByval12WithCopyCtor(%[[TMP]]) : (!cir.ptr<!rec_WithCopyCtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z20takeCopyCtorNonByval12WithCopyCtor(%[[TMP]]) : (!cir.ptr<!rec_WithCopyCtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// LLVM-LABEL: define dso_local void @_Z20callCopyCtorNonByvalv()
// LLVM: call void @_ZN12WithCopyCtorC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %[[C:[^)]+]])
@@ -103,7 +103,7 @@ void callByval() {
// CIR: %[[V:.*]] = cir.load align(8) %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CIR: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR: cir.store %[[V]], %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR: cir.call @_Z9takeByval3Big(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
+// CIR: cir.call @_Z9takeByval3Big(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
// LLVM-LABEL: define dso_local void @_Z9callByvalv()
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TMP:[^,]+]], ptr align 8 %{{[^,]+}}, i64 32, i1 false)
@@ -136,12 +136,12 @@ void callInheritedCtor(WithDtor t) { Derived d(t); }
// Both inheriting constructor variants hand their own parameter on unchanged.
// CIR-LABEL: cir.func {{.*}}@_ZN7DerivedCI14BaseE8WithDtor
-// CIR-SAME: %[[CI1ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
+// CIR-SAME: %[[CI1ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
// CIR-NOT: cir.copy
// CIR: cir.call @_ZN7DerivedCI24BaseE8WithDtor(%{{.*}}, %[[CI1ARG]])
// CIR-LABEL: cir.func {{.*}}@_ZN7DerivedCI24BaseE8WithDtor
-// CIR-SAME: %[[ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
+// CIR-SAME: %[[ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
// CIR-NOT: cir.copy
// CIR: cir.call @_ZN4BaseC2E8WithDtor(%{{.*}}, %[[ARG]])
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
index 082488b6ba4d9..a57bcb19b5929 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
@@ -59,8 +59,8 @@ typedef struct { char c; int i; } PragmaPacked;
int take_char_int(CharInt v) { return v.i; }
CharInt ret_char_int(int x) { CharInt v = {0, x}; return v; }
-// CIR: cir.func{{.*}} @take_char_int(%arg0: !cir.ptr<!rec_CharInt> {llvm.align = 8 : i64, llvm.byval = !rec_CharInt, llvm.noundef}{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @ret_char_int(%arg0: !cir.ptr<!rec_CharInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_CharInt, llvm.writable}{{.*}}, %arg1: !s32i {llvm.noundef}{{.*}})
+// CIR: cir.func{{.*}} @take_char_int(%arg0: !cir.ptr<!rec_CharInt> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_CharInt, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @ret_char_int(%arg0: !cir.ptr<!rec_CharInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_CharInt, llvm.writable}{{.*}}, %arg1: !s32i {llvm.noundef}{{.*}})
// LLVM: define dso_local i32 @take_char_int(ptr noundef byval(%struct.CharInt) align 8 %{{.+}})
// LLVM: define dso_local void @ret_char_int(ptr dead_on_unwind noalias writable sret(%struct.CharInt) align 1 %{{.+}}, i32 noundef %{{.+}})
@@ -162,14 +162,14 @@ TwoFloatChar ret_two_float_char(float x) { TwoFloatChar v = {x, x, 0}; return v;
// two eightbytes that decides.
int take_seventeen(Seventeen v) { return v.a[3]; }
-// CIR: cir.func{{.*}} @take_seventeen(%arg0: !cir.ptr<!rec_Seventeen> {llvm.align = 8 : i64, llvm.byval = !rec_Seventeen, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_seventeen(%arg0: !cir.ptr<!rec_Seventeen> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Seventeen, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_seventeen(ptr noundef byval(%struct.Seventeen) align 8 %{{.+}})
// Packed and over-aligned at once, so the record carries a pad member and the
// packed mark together. The misaligned int still decides it.
int take_packed_ov(PackedOv v) { return v.i; }
-// CIR: cir.func{{.*}} @take_packed_ov(%arg0: !cir.ptr<!rec_PackedOv> {llvm.align = 8 : i64, llvm.byval = !rec_PackedOv, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_packed_ov(%arg0: !cir.ptr<!rec_PackedOv> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_PackedOv, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_packed_ov(ptr noundef byval(%struct.PackedOv) align 8 %{{.+}})
// A packed member reaches the classifier through an enclosing record and
@@ -180,8 +180,8 @@ int take_arr_packed(ArrPacked v) { return v.a[1].i; }
int take_nest_nine(NestNine v) { return v.n.b; }
int take_arr_nine(ArrNine v) { return v.n[0].b; }
-// CIR: cir.func{{.*}} @take_nest_packed(%arg0: !cir.ptr<!rec_NestPacked> {llvm.align = 8 : i64, llvm.byval = !rec_NestPacked, llvm.noundef}{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @take_arr_packed(%arg0: !cir.ptr<!rec_ArrPacked> {llvm.align = 8 : i64, llvm.byval = !rec_ArrPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_nest_packed(%arg0: !cir.ptr<!rec_NestPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_NestPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_arr_packed(%arg0: !cir.ptr<!rec_ArrPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_ArrPacked, llvm.noundef}{{.*}}) -> !s32i
// CIR: cir.func{{.*}} @take_nest_nine(%arg0: !u64i{{.*}}, %arg1: !s8i{{.*}}) -> !s32i
// CIR: cir.func{{.*}} @take_arr_nine(%arg0: !u64i{{.*}}, %arg1: !s8i{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_nest_packed(ptr noundef byval(%struct.NestPacked) align 8 %{{.+}})
@@ -199,5 +199,5 @@ int take_upacked(UPacked v) { return v.i; }
// #pragma pack reaches the same layout as the attribute.
int take_pragma_packed(PragmaPacked v) { return v.i; }
-// CIR: cir.func{{.*}} @take_pragma_packed(%arg0: !cir.ptr<!rec_PragmaPacked> {llvm.align = 8 : i64, llvm.byval = !rec_PragmaPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_pragma_packed(%arg0: !cir.ptr<!rec_PragmaPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_PragmaPacked, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_pragma_packed(ptr noundef byval(%struct.PragmaPacked) align 8 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
index 65f50b41c4d5b..fdb65a3c339a2 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
@@ -93,8 +93,8 @@ TwoFloat ret_twof(float v) { TwoFloat t = {v, v}; return t; }
int take_big(BigPad b) { return b.b; }
BigPad ret_big(int v) { BigPad b = {0, v}; return b; }
-// CIR: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_BigPad> {llvm.align = 16 : i64, llvm.byval = !rec_BigPad, llvm.noundef} loc{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_BigPad> {llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_BigPad, llvm.writable} loc{{.*}}, %arg1: !s32i {llvm.noundef} loc{{.*}})
+// CIR: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_BigPad> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_BigPad, llvm.noundef} loc{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_BigPad> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_BigPad, llvm.writable} loc{{.*}}, %arg1: !s32i {llvm.noundef} loc{{.*}})
// LLVM: define dso_local i32 @take_big(ptr noundef byval(%struct.BigPad) align 16 %{{.+}})
// LLVM: define dso_local void @ret_big(ptr dead_on_unwind noalias writable sret(%struct.BigPad) align 16 %{{.+}}, i32 noundef %{{.+}})
@@ -104,7 +104,7 @@ int take_nest(NestOv n) { return n.o.x; }
int take_arr(ArrOv a) { return a.a[1].x; }
// CIR: cir.func{{.*}} @take_nest(%arg0: !s32i loc{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @take_arr(%arg0: !cir.ptr<!rec_ArrOv> {llvm.align = 16 : i64, llvm.byval = !rec_ArrOv, llvm.noundef} loc{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_arr(%arg0: !cir.ptr<!rec_ArrOv> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_ArrOv, llvm.noundef} loc{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_nest(i32 %{{.+}})
// LLVM: define dso_local i32 @take_arr(ptr noundef byval(%struct.ArrOv) align 16 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
index c7d3d4aa8c335..3f251e46ef047 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
@@ -66,12 +66,12 @@ int call_small(Pair2 p, Pair16 q) { return vf(p, q); }
// Larger than two eightbytes is MEMORY regardless of register availability.
int call_big(Pair2 p, Big b) { return vf(p, b); }
-// CIR-LABEL: cir.func {{.*}}@call_big(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_big(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: %{{[0-9]+}} = cir.load %arg1 : !cir.ptr<!rec_Big>, !rec_Big
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
// CIR copies the incoming byval slot before forwarding it. OGCG does not.
// LLVM-CIR-LABEL: define dso_local i32 @call_big(
@@ -94,7 +94,7 @@ int call_exhausted(Pair2 p, long a, long b, long c, long d, Pair16 q) {
return vf(p, a, b, c, d, q);
}
-// CIR-LABEL: cir.func {{.*}}@call_exhausted(%arg0: !u64i loc({{.+}}), %arg1: !s64i {llvm.noundef} loc({{.+}}), %arg2: !s64i {llvm.noundef} loc({{.+}}), %arg3: !s64i {llvm.noundef} loc({{.+}}), %arg4: !s64i {llvm.noundef} loc({{.+}}), %arg5: !cir.ptr<!rec_Pair16> {llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_exhausted(%arg0: !u64i loc({{.+}}), %arg1: !s64i {llvm.noundef} loc({{.+}}), %arg2: !s64i {llvm.noundef} loc({{.+}}), %arg3: !s64i {llvm.noundef} loc({{.+}}), %arg4: !s64i {llvm.noundef} loc({{.+}}), %arg5: !cir.ptr<!rec_Pair16> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: cir.store %arg1, %[[AS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
// CIR: cir.store %arg2, %[[BS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
// CIR: cir.store %arg3, %[[CS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
@@ -106,7 +106,7 @@ int call_exhausted(Pair2 p, long a, long b, long c, long d, Pair16 q) {
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Pair16>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_Pair16, !cir.ptr<!rec_Pair16>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[AV]], %[[BV]], %[[CV]], %[[DV]], %[[COPY]]) : (!u64i, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !cir.ptr<!rec_Pair16> {llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[AV]], %[[BV]], %[[CV]], %[[DV]], %[[COPY]]) : (!u64i, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !cir.ptr<!rec_Pair16> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef}) -> !s32i
// LLVM-CIR-LABEL: define dso_local i32 @call_exhausted(
// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], i64 noundef %[[A:[0-9a-zA-Z._]+]], i64 noundef %[[B:[0-9a-zA-Z._]+]], i64 noundef %[[C:[0-9a-zA-Z._]+]], i64 noundef %[[D:[0-9a-zA-Z._]+]], ptr noundef byval(%struct.Pair16) align 8 %[[Q:[0-9a-zA-Z._]+]])
@@ -177,12 +177,12 @@ int call_wide(Pair2 p, Wide w) { return vf(p, w); }
// memory, and the 128-bit member keeps the slot at 16-byte alignment.
int call_wide_char(Pair2 p, WideChar w) { return vf(p, w); }
-// CIR-LABEL: cir.func {{.*}}@call_wide_char(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_WideChar> {llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_wide_char(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_WideChar> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: %{{[0-9]+}} = cir.load %arg1 : !cir.ptr<!rec_WideChar>, !rec_WideChar
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(16) : !cir.ptr<!rec_WideChar>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_WideChar, !cir.ptr<!rec_WideChar>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_WideChar> {llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_WideChar> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef}) -> !s32i
// LLVM-CIR-LABEL: define dso_local i32 @call_wide_char(
// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], ptr noundef byval(%struct.WideChar) align 16 %[[W:[0-9a-zA-Z._]+]])
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
index e55fca949bc14..d76e3b90be91c 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
@@ -20,13 +20,13 @@ struct VirtInherit : virtual VBase { long b; };
// passed by invisible reference whatever its eightbytes classify as.
int takePoly(Poly v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z8takePoly4Polyi(%arg0: !cir.ptr<!rec_Poly> {llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z8takePoly4Polyi(%arg0: !cir.ptr<!rec_Poly> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z8takePoly4Polyi(ptr nofreeobj noundef align 8 dereferenceable(8) %{{[^,]+}}, i32 noundef %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z8takePoly4Polyi(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(8) %{{[^,]+}}, i32 noundef %{{[^,)]+}})
int takePolyLong(PolyLong v) { return 0; }
-// CIR: cir.func {{.*}}@_Z12takePolyLong8PolyLong(%arg0: !cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z12takePolyLong8PolyLong(%arg0: !cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
@@ -34,14 +34,14 @@ int takePolyLong(PolyLong v) { return 0; }
// would have classified as on their own.
int takePolyTwoInt(PolyTwoInt v) { return v.y; }
-// CIR: cir.func {{.*}}@_Z14takePolyTwoInt10PolyTwoInt(%arg0: !cir.ptr<!rec_PolyTwoInt> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z14takePolyTwoInt10PolyTwoInt(%arg0: !cir.ptr<!rec_PolyTwoInt> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z14takePolyTwoInt10PolyTwoInt(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z14takePolyTwoInt10PolyTwoInt(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
// Past two eightbytes SysV says memory on its own, so the two rules agree here.
int takePolyBig(PolyBig v) { return 0; }
-// CIR: cir.func {{.*}}@_Z11takePolyBig7PolyBig(%arg0: !cir.ptr<!rec_PolyBig> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z11takePolyBig7PolyBig(%arg0: !cir.ptr<!rec_PolyBig> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z11takePolyBig7PolyBig(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z11takePolyBig7PolyBig(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -49,7 +49,7 @@ int takePolyBig(PolyBig v) { return 0; }
// declared here.
int takePolyDerived(PolyDerived v) { return 0; }
-// CIR: cir.func {{.*}}@_Z15takePolyDerived11PolyDerived(%arg0: !cir.ptr<!rec_PolyDerived> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z15takePolyDerived11PolyDerived(%arg0: !cir.ptr<!rec_PolyDerived> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z15takePolyDerived11PolyDerived(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z15takePolyDerived11PolyDerived(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -57,7 +57,7 @@ int takePolyDerived(PolyDerived v) { return 0; }
// vtable pointer and the non-trivial copy constructor with it.
int takeHasPoly(HasPoly v) { return 0; }
-// CIR: cir.func {{.*}}@_Z11takeHasPoly7HasPoly(%arg0: !cir.ptr<!rec_HasPoly> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z11takeHasPoly7HasPoly(%arg0: !cir.ptr<!rec_HasPoly> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z11takeHasPoly7HasPoly(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z11takeHasPoly7HasPoly(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
@@ -65,7 +65,7 @@ int takeHasPoly(HasPoly v) { return 0; }
// though it declares no virtual function of its own.
int takeVirtInherit(VirtInherit v) { return 0; }
-// CIR: cir.func {{.*}}@_Z15takeVirtInherit11VirtInherit(%arg0: !cir.ptr<!rec_VirtInherit> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z15takeVirtInherit11VirtInherit(%arg0: !cir.ptr<!rec_VirtInherit> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z15takeVirtInherit11VirtInherit(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z15takeVirtInherit11VirtInherit(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -75,7 +75,7 @@ PolyLong makePolyLong() {
return p;
}
-// CIR: cir.func {{.*}}@_Z12makePolyLongv(%arg0: !cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_PolyLong, llvm.writable}
+// CIR: cir.func {{.*}}@_Z12makePolyLongv(%arg0: !cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_PolyLong, llvm.writable}
// LLVM: define dso_local void @_Z12makePolyLongv(ptr dead_on_unwind noalias writable sret(%struct.PolyLong) align 8 %{{[^,)]+}})
PolyLong retPolyLong();
@@ -86,13 +86,13 @@ int caller(int k) {
}
// CIR: cir.func {{.*}}@_Z6calleri(%arg0: !s32i {{.*}}) -> (!s32i
-// CIR: cir.call @_Z11retPolyLongv(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable}) -> ()
-// CIR: cir.call @_Z12takePolyLong8PolyLong(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}) -> (!s32i
+// CIR: cir.call @_Z11retPolyLongv(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable}) -> ()
+// CIR: cir.call @_Z12takePolyLong8PolyLong(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z6calleri(i32 noundef %{{[^,)]+}})
// LLVM: call void @_Z11retPolyLongv(ptr dead_on_unwind writable sret(%struct.PolyLong) align 8 %{{[^,)]+}})
// LLVM-CIR: call noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: call noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
// Returned, the class uses sret at its declared alignment.
-// CIR: cir.func private @_Z11retPolyLongv(!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable})
+// CIR: cir.func private @_Z11retPolyLongv(!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable})
// LLVM: declare void @_Z11retPolyLongv(ptr dead_on_unwind writable sret(%struct.PolyLong) align 8)
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
index f2766ae511641..31b5147a818f8 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
@@ -198,7 +198,7 @@ void take_union(ZeroWidthUnion u) {}
// Past two eightbytes the record goes to memory, where the widened coerce type
// no longer applies.
void take_too_big(TooBig b) {}
-// CIR: cir.func{{.*}} @take_too_big(%arg0: !cir.ptr<!rec_TooBig> {llvm.align = 8 : i64, llvm.byval = !rec_TooBig, llvm.noundef}
+// CIR: cir.func{{.*}} @take_too_big(%arg0: !cir.ptr<!rec_TooBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_TooBig, llvm.noundef}
// LLVM: define{{.*}} void @take_too_big(ptr noundef byval(%struct.TooBig) align 8 %{{.+}})
Tail ret_tail(void) { Tail t = {3}; return t; }
diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c
index ebc811b7a2aa4..87ec0e7e14e9e 100644
--- a/clang/test/CIR/CodeGen/call.c
+++ b/clang/test/CIR/CodeGen/call.c
@@ -75,7 +75,7 @@ void f7(void) {
// CIR: %[[B:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!rec_Big>, !rec_Big
// CIR-NEXT: %[[SLOT:.+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR-NEXT: cir.store %[[B]], %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR-NEXT: cir.call @f5(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @f5(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
// LLVM-LABEL: define{{.*}} void @f7(){{.*}} {
// LLVM: %[[B:.+]] = load %struct.Big, ptr %{{.+}}, align 4
@@ -93,7 +93,7 @@ void f8(void) {
// CIR-LABEL: cir.func{{.*}} @f8(){{.*}} {
// CIR: %[[B:.+]] = cir.alloca "b" align(4) init : !cir.ptr<!rec_Big>
-// CIR-NEXT: cir.call @f6(%[[B]]) : (!cir.ptr<!rec_Big> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+// CIR-NEXT: cir.call @f6(%[[B]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
// LLVM-LABEL: define{{.*}} void @f8(){{.*}} {
// LLVM: %[[B:.+]] = alloca %struct.Big, align 4
diff --git a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
index 323ced9c2d521..eca145bd71213 100644
--- a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
@@ -39,7 +39,7 @@ Wrapper makeWrapper() {
: Wrapper::empty();
}
-// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
+// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
// CIR: %[[CLEANUP_COND:.*]] = cir.alloca "cleanup.cond" {{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[AGG_TMP0:.*]] = cir.alloca "agg.tmp0" {{.*}} : !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E>
// CIR: cir.cleanup.scope {
@@ -51,7 +51,7 @@ Wrapper makeWrapper() {
// CIR: cir.call @_ZNSt10unique_ptrI4BaseEC1EPS0_(%[[AGG_TMP0]], %[[SOURCE]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: } else {
// CIR: cir.call @_ZN7Wrapper5emptyEv(%[[RETVAL]])
// CIR: }
@@ -204,7 +204,7 @@ void APFixedPoint::add(int x) const {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_TRUE]]
// CIR: } else {
-// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
+// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_FALSE]]
// CIR: }
@@ -361,7 +361,7 @@ void makeEntry() {
// CIR: %{{.*}} = cir.get_global @g_path
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: }
// CIR: cir.yield
// CIR: } cleanup all {
diff --git a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
index 825172ad5b43c..003b23eeda8a2 100644
--- a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
@@ -39,7 +39,7 @@ Wrapper makeWrapper() {
: Wrapper::empty();
}
-// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
+// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
// CIR: %[[CLEANUP_COND:.*]] = cir.alloca "cleanup.cond" {{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[AGG_TMP0:.*]] = cir.alloca "agg.tmp0" {{.*}} : !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E>
// CIR: cir.cleanup.scope {
@@ -51,7 +51,7 @@ Wrapper makeWrapper() {
// CIR: cir.call @_ZNSt10unique_ptrI4BaseEC1EPS0_(%[[AGG_TMP0]], %[[SOURCE]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: } else {
// CIR: cir.call @_ZN7Wrapper5emptyEv(%[[RETVAL]])
// CIR: }
@@ -157,7 +157,7 @@ void APFixedPoint::add(int x) const {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_TRUE]]
// CIR: } else {
-// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
+// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_FALSE]]
// CIR: }
@@ -282,7 +282,7 @@ void makeEntry() {
// CIR: %{{.*}} = cir.get_global @g_path
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: }
// CIR: cir.yield
// CIR: } cleanup normal {
diff --git a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
index de1863b3cdfec..8893d47fd0f21 100644
--- a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
+++ b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
@@ -172,7 +172,7 @@ A foo1() {
// LLVM: define dso_local {{.*}}@{{.*foo2.*}}
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[B1]], i64 24, i1 false)
-// CIR: cir.func {{.*}}@_Z4foo2v(%[[B_RETVAL:.*]]: !cir.ptr<![[STRUCT_B]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_B]], llvm.writable}{{.*}})
+// CIR: cir.func {{.*}}@_Z4foo2v(%[[B_RETVAL:.*]]: !cir.ptr<![[STRUCT_B]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_B]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2b1 : !cir.ptr<![[STRUCT_B]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[B_RETVAL]] align(8) : !cir.ptr<![[STRUCT_B]]>
B foo2() {
@@ -181,7 +181,7 @@ B foo2() {
// LLVM: define dso_local {{.*}}@{{.*foo3.*}}
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[C1]], i64 48, i1 false)
-// CIR: cir.func {{.*}}@_Z4foo3v(%[[C_RETVAL:.*]]: !cir.ptr<![[STRUCT_C]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_C]], llvm.writable}{{.*}})
+// CIR: cir.func {{.*}}@_Z4foo3v(%[[C_RETVAL:.*]]: !cir.ptr<![[STRUCT_C]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_C]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2c1 : !cir.ptr<![[STRUCT_C]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[C_RETVAL]] align(8) : !cir.ptr<![[STRUCT_C]]>
C foo3() {
@@ -317,7 +317,7 @@ void foo7() {
// LLVM: dso_local {{.*}}@{{.*foo8.*}}(
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[D1]], i64 56, i1 false)
// CIR-LABEL: cir.func no_inline dso_local @_Z4foo8v(
-// CIR: %[[D_RETVAL:.*]]: !cir.ptr<![[STRUCT_D]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_D]], llvm.writable}{{.*}})
+// CIR: %[[D_RETVAL:.*]]: !cir.ptr<![[STRUCT_D]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_D]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2d1 : !cir.ptr<![[STRUCT_D]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[D_RETVAL]] align(8) : !cir.ptr<![[STRUCT_D]]>
D foo8() {
diff --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
index 3cdf30906f36e..b316021ce1de6 100644
--- a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
@@ -1237,7 +1237,7 @@ void Temp2InArray() {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ARR_IDX]] : !cir.ptr<!cir.ptr<!rec_CausesTemp2>>, !cir.ptr<!rec_CausesTemp2>
// CIR-NEXT: cir.call @_ZN5Temp2C1Ev(%[[TMP]])
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup all {
// CIR-NEXT: cir.call @_ZN5Temp2D1Ev(%[[TMP]]) nothrow
diff --git a/clang/test/CIR/CodeGen/side-effect.cpp b/clang/test/CIR/CodeGen/side-effect.cpp
index a53f5b3376e86..446883046f97c 100644
--- a/clang/test/CIR/CodeGen/side-effect.cpp
+++ b/clang/test/CIR/CodeGen/side-effect.cpp
@@ -7,6 +7,10 @@
struct Big { long a, b, c, d; };
struct Small { int x; };
+struct WithDtor { int x; ~WithDtor(); };
+struct Empty {};
+struct SmallPair { int a, b; };
+struct TwoLong { long a, b; };
extern "C" {
@@ -19,6 +23,10 @@ __attribute__((const)) int const_ptr(const int *p);
__attribute__((const)) int const_variadic_decl(int n, ...);
__attribute__((const)) int const_byval2(int n, Big b);
__attribute__((const)) int const_bigref(const Big &b);
+__attribute__((const)) int const_non_byval(WithDtor w);
+__attribute__((const)) int const_ignore(Empty e);
+__attribute__((const)) int const_coerced(SmallPair p);
+__attribute__((const)) int const_flattened(TwoLong t);
// FIXME: We should figure out how to better print this on functions in the
// future.
@@ -82,8 +90,24 @@ void use() {
// A reference is a direct pointer slot that still carries align, so neither
// align nor a record pointee can stand in for an indirect slot.
- // CIR: cir.call @const_bigref({{.*}}) side_effect(const)
+ // CIR: cir.call @const_bigref({{.*}}) side_effect(const) : (!cir.ptr<!rec_Big> {llvm.align{{.*}}) -> !s32i
const_bigref(b);
+
+ // A non-trivially-destructible class passes indirectly without byval, and
+ // its slot carries no LLVM attribute that names it as the ABI's own.
+ WithDtor w{};
+ // CIR: cir.call @const_non_byval({{.*}}) side_effect(const) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>{{.*}}}) -> !s32i
+ const_non_byval(w);
+
+ // An argument the ABI rewrites without handing over memory keeps
+ // memory(none): the slot is dropped, coerced into a register, or flattened
+ // into registers. No argument dictionary means no slot mark.
+ // CIR: cir.call @const_ignore() side_effect(const) : () -> !s32i
+ const_ignore(Empty{});
+ // CIR: cir.call @const_coerced(%{{.+}}) side_effect(const) : (!u64i) -> !s32i
+ const_coerced(SmallPair{});
+ // CIR: cir.call @const_flattened(%{{.+}}, %{{.+}}) side_effect(const) : (!s64i, !s64i) -> !s32i
+ const_flattened(TwoLong{});
}
}
@@ -114,6 +138,10 @@ void use() {
// LLVM: call i32 @const_byval2(i32 noundef 1, ptr noundef byval(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL]]
// LLVM: call void @const_sret_def(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[ARGMEM_CALL]]
// LLVM: call i32 @const_bigref(ptr noundef nonnull align 8 dereferenceable(32) %{{.+}}) #[[NONE_CALL]]
+// LLVM: call i32 @const_non_byval(ptr nofreeobj noundef align 4 dereferenceable(4) %{{.+}}) #[[ARGMEM_CALL]]
+// LLVM: call i32 @const_ignore() #[[NONE_CALL]]
+// LLVM: call i32 @const_coerced(i64 %{{.+}}) #[[NONE_CALL]]
+// LLVM: call i32 @const_flattened(i64 %{{.+}}, i64 %{{.+}}) #[[NONE_CALL]]
// Declarations.
// LLVM: declare void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8) #[[ARGMEM_DECL:[0-9]+]]
@@ -125,6 +153,10 @@ void use() {
// LLVM: declare i32 @const_variadic_decl(i32 noundef, ...) #[[ARGMEM_DECL]]
// LLVM: declare i32 @const_byval2(i32 noundef, ptr noundef byval(%struct.Big) align 8) #[[ARGMEM_DECL]]
// LLVM: declare i32 @const_bigref(ptr noundef nonnull align 8 dereferenceable(32)) #[[NONE_DECL]]
+// LLVM: declare i32 @const_non_byval(ptr nofreeobj noundef align 4 dereferenceable(4)) #[[ARGMEM_DECL]]
+// LLVM: declare i32 @const_ignore() #[[NONE_DECL]]
+// LLVM: declare i32 @const_coerced(i64) #[[NONE_DECL]]
+// LLVM: declare i32 @const_flattened(i64, i64) #[[NONE_DECL]]
// The trailing wildcard covers target-features and the other codegen-option
// strings, which differ between the emits.
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
index 49e83b763f521..0a1b027fdfd1e 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
@@ -11,7 +11,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -73,7 +73,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -142,7 +142,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
index 5d2d27f472b98..72dd576229bab 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
@@ -259,7 +259,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -321,7 +321,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -390,7 +390,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
index 00dafcd95371b..c85c0dc3a3e5c 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
@@ -11,7 +11,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -73,7 +73,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -142,7 +142,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-create.cpp b/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
index d55a60519a4ce..24ae03dfee46f 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
@@ -260,7 +260,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -322,7 +322,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -391,7 +391,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp b/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
index 9cda9d8bec285..78a525c77d3e4 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
@@ -259,7 +259,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -321,7 +321,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -390,7 +390,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-present.cpp b/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
index b54dbe7b2b63a..06bc449e01de8 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
@@ -12,7 +12,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -74,7 +74,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -143,7 +143,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir b/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
index b0df1caa5416b..061658e11412b 100644
--- a/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
@@ -2,6 +2,9 @@
// RUN: | FileCheck %s
// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
// RUN: -cir-to-llvm -o - 2>/dev/null \
+// RUN: | FileCheck %s --check-prefix=MLIR
+// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
+// RUN: -cir-to-llvm -o - 2>/dev/null \
// RUN: | cir-translate -mlir-to-llvmir --allow-unregistered-dialect \
// RUN: | FileCheck %s --check-prefix=LLVM
@@ -82,4 +85,18 @@ module attributes {
// LLVM: define void @caller_sret()
// LLVM: call void @ret_big(ptr {{.*}}sret(%struct.Big) align 8 %{{.+}})
+
+ // cir.abi_slot in the input, on a signature the pass leaves alone, so the
+ // attribute is parsed here rather than only printed. It still reaches
+ // cir-to-llvm, which is what the MLIR checks below observe.
+ cir.func private @pre_marked(!cir.ptr<!rec_Big>
+ {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64})
+ attributes { test_classify = #passthrough }
+
+ // CHECK: cir.func{{.*}} @pre_marked(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64})
}
+
+// cir.abi_slot is a CIR-level fact, so nothing carries it past cir-to-llvm.
+// The positive check first, so the prefix cannot pass on empty input.
+// MLIR: llvm.func @takes_big(%{{.+}}: !llvm.ptr {llvm.align = 8 : i64, llvm.byval = !llvm.struct<"struct.Big"
+// MLIR-NOT: cir.abi_slot
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
index 90322dc342568..65fd9e2cc64ff 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
@@ -209,7 +209,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[L:.*]] = cir.load %[[PTR]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK-NEXT: cir.return %[[L]] : !rec_Big
@@ -225,7 +225,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval_field(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[M:.*]] = cir.get_member %[[PTR]][0] {name = "a"} : !cir.ptr<!rec_Big> -> !cir.ptr<!s64i>
// CHECK-NEXT: %[[V:.*]] = cir.load %[[M]] : !cir.ptr<!s64i>, !s64i
@@ -259,7 +259,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval_unused(%{{.*}}: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: %[[R:.*]] = cir.const #cir.int<0> : !s32i
@@ -270,7 +270,7 @@ module attributes {
attributes { test_classify = #non_byval_arg }
// CHECK: cir.func{{.*}} @takes_big_non_byval_decl(!cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The call site forwards the caller's temporary instead of copying it.
cir.func @caller_non_byval(%s: !rec_Big) -> !rec_Big
@@ -287,7 +287,7 @@ module attributes {
// CHECK-NEXT: cir.store %[[S]], %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The whole-record load survives when a reader other than the call needs it.
cir.func @caller_non_byval_load_reused(%s: !rec_Big) -> !rec_Big
@@ -303,7 +303,7 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[V:.*]] = cir.load %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK: cir.return %[[V]] : !rec_Big
// CIRGen emits the load immediately before the call, so nothing can write
@@ -326,7 +326,7 @@ module attributes {
// CHECK-NEXT: cir.store %[[T]], %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// A non-byval argument between two Direct ones keeps its operand slot.
cir.func private @takes_mixed_non_byval(%a: !s32i, %b: !rec_Big, %c: !s32i)
@@ -344,7 +344,7 @@ module attributes {
// CHECK: cir.func{{.*}} @caller_mixed_non_byval(%[[X:.*]]: !s32i
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.call @takes_mixed_non_byval(%[[X]], %[[TMP]], %[[X]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
// One load feeding two non-byval operands is erased once, not twice.
cir.func private @takes_two_non_byval(%a: !rec_Big, %b: !rec_Big)
@@ -364,7 +364,7 @@ module attributes {
// CHECK-NEXT: cir.store %{{.*}}, %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_two_non_byval(%[[TMP]], %[[TMP]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The Direct operand keeps reading the load, so the load survives the rewrite.
cir.func private @takes_non_byval_then_direct(%a: !rec_Big, %b: !rec_Big)
@@ -383,7 +383,7 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[V:.*]] = cir.load %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: cir.call @takes_non_byval_then_direct(%[[TMP]], %[[V]]) :
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
// The dead load is erased on the sret early-return path too.
cir.func @non_byval_and_sret(%arg0: !rec_Big) -> !rec_Big
@@ -413,7 +413,7 @@ module attributes {
// CHECK: %[[RET:.*]] = cir.alloca "sret" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.call @non_byval_and_sret(%[[RET]], %[[TMP]]) :
// CHECK-SAME: llvm.sret = !rec_Big
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// A slot aligned above the record's own alignment, matching an
// indirect_align that also exceeds it, is still forwarded.
@@ -433,6 +433,6 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(16) : !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval16(%[[TMP]]) :
- // CHECK-SAME: {llvm.align = 16 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 16 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
index eca64c5975ea1..73449905a47fd 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
@@ -89,7 +89,7 @@ module attributes {
// CHECK: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.store %{{.+}}, %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK: %[[CAST:.*]] = cir.cast bitcast %arg0 : !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>
- // CHECK: cir.call %[[CAST]](%[[SLOT]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+ // CHECK: cir.call %[[CAST]](%[[SLOT]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// Indirect call returning a large struct: an sret pointer slot is prepended
// and the callee is bitcast to the void-returning sret signature.
@@ -101,5 +101,5 @@ module attributes {
// CHECK: cir.func{{.*}} @call_sret(%arg0: !cir.ptr<!cir.func<() -> !rec_Big>>)
// CHECK: %[[SRET:.*]] = cir.alloca "sret" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[SCAST:.*]] = cir.cast bitcast %arg0 : !cir.ptr<!cir.func<() -> !rec_Big>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>
- // CHECK: cir.call %[[SCAST]](%[[SRET]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+ // CHECK: cir.call %[[SCAST]](%[[SRET]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
index 2fd34fd3aaedd..b90c7ffd868b6 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
@@ -30,11 +30,11 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_non_byval_param(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -72,11 +72,11 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_non_byval_param_via_slot(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -114,17 +114,17 @@ module attributes {
}
// CHECK: cir.func{{.*}} @ping(%[[PING:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @pong(%[[PING]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CHECK: cir.func{{.*}} @pong(%[[PONG:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @ping(%[[PONG]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -163,10 +163,10 @@ module attributes {
}
// CHECK: cir.func{{.*}} @expand_ahead_of_non_byval(%{{.*}}: !s64i, %{{.*}}: !s64i, %[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -217,7 +217,7 @@ module attributes {
// CHECK: %[[MID:.*]] = cir.cast bitcast %[[RAW]] : !cir.ptr<!cir.array<!s8i x 32>> -> !cir.ptr<!s8i>
// CHECK: %[[SLOT:.*]] = cir.cast bitcast %[[MID]] : !cir.ptr<!s8i> -> !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load %[[SLOT]] : !cir.ptr<!rec_Big>
- // CHECK: cir.call @takes_big_non_byval(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK: cir.call @takes_big_non_byval(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -259,10 +259,10 @@ module attributes {
// CHECK: cir.func{{.*}} @sret_forwards_non_byval_param(
// CHECK-SAME: llvm.sret = !rec_Big
// CHECK-SAME: %[[PTR:[^:]*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca "arg0"
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -301,10 +301,10 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_param_over_underaligned_slot(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -384,7 +384,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @expands_non_byval_param(%[[PTR:.*]]: !cir.ptr<!rec_Two>
- // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[F0:.*]] = cir.get_member %[[PTR]][0]
// CHECK: %[[V0:.*]] = cir.load %[[F0]]
diff --git a/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
index b213dbf13f9db..c5a2e99ca7fdb 100644
--- a/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
@@ -1,11 +1,11 @@
// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
// RUN: | FileCheck %s
// The pass leaves test_classify on the lowered func, and its coerced_type is a
-// CIR type, so the alias outlives every cir op and mlir-translate has to
+// CIR type, so the alias outlives every cir op and the translation has to
// accept it.
// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
// RUN: -cir-to-llvm -o - \
-// RUN: | mlir-translate -mlir-to-llvmir --allow-unregistered-dialect \
+// RUN: | cir-translate -mlir-to-llvmir --allow-unregistered-dialect \
// RUN: | FileCheck %s --check-prefix=LLVM
!s8i = !cir.int<s, 8>
@@ -20,7 +20,7 @@
{ kind = "indirect", indirect_align = 8 } ]
}
-#byref_arg = {
+#non_byval_arg = {
return = { kind = "direct" },
args = [ { kind = "indirect", indirect_align = 8, byval = false } ]
}
@@ -37,6 +37,11 @@
sign_extend = true } ]
}
+#expand_arg = {
+ return = { kind = "direct" },
+ args = [ { kind = "expand" } ]
+}
+
#passthrough = {
return = { kind = "direct" },
args = [ ]
@@ -53,35 +58,40 @@ module attributes {
cir.func private @const_sret() -> !rec_Big side_effect(const)
attributes { test_classify = #sret_ret }
- // CHECK: cir.func{{.*}} @const_sret(!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) side_effect(const)
+ // Dictionaries print sorted by name, so these pins are in key order.
+ // CHECK: cir.func{{.*}} @const_sret(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
cir.func private @pure_sret() -> !rec_Big side_effect(pure)
attributes { test_classify = #sret_ret }
- // CHECK: cir.func{{.*}} @pure_sret(!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) side_effect(pure)
+ // CHECK: cir.func{{.*}} @pure_sret(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(pure)
// LLVM: ; Function Attrs: nounwind willreturn memory(read, argmem: readwrite)
// LLVM-NEXT: declare void @pure_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
cir.func private @const_byval(!s32i, !rec_Big) side_effect(const)
attributes { test_classify = #byval_arg }
- // CHECK: cir.func{{.*}} @const_byval(!s32i, !cir.ptr<!rec_Big> {{{.*}}llvm.byval = !rec_Big{{.*}}}) side_effect(const)
+ // CHECK: cir.func{{.*}} @const_byval(!s32i, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare void @const_byval(i32, ptr noundef byval(%struct.Big) align 8)
- cir.func private @const_byref(!rec_Big) side_effect(const)
- attributes { test_classify = #byref_arg }
+ // No LLVM attribute on a non-byval slot names it as the ABI's own, so
+ // cir.abi_slot is what identifies it.
+ cir.func private @const_non_byval(!rec_Big) side_effect(const)
+ attributes { test_classify = #non_byval_arg }
- // CHECK: cir.func{{.*}} @const_byref(!cir.ptr<!rec_Big> {{{.*}}llvm.byref = !rec_Big{{.*}}}) side_effect(const)
+ // CHECK: cir.func{{.*}} @const_non_byval(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}) side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
- // LLVM-NEXT: declare void @const_byref(ptr byref(%struct.Big) align 8)
+ // LLVM-NEXT: declare void @const_non_byval(ptr nofreeobj noundef align 8 dereferenceable(24))
cir.func private @const_variadic(!s8i, ...) -> !s32i side_effect(const)
attributes { test_classify = #extend_arg }
- // CHECK: cir.func{{.*}} @const_variadic(!s8i {{{.*}}llvm.signext{{.*}}}, ...) -> !s32i side_effect(const)
+ // Widened for being variadic, which lowering decides from the signature,
+ // not from a slot mark.
+ // CHECK: cir.func{{.*}} @const_variadic(!s8i {llvm.signext}, ...) -> !s32i side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare i32 @const_variadic(i8 signext, ...)
@@ -90,10 +100,19 @@ module attributes {
cir.func private @const_extend(!s8i) -> !s32i side_effect(const)
attributes { test_classify = #extend_arg }
- // CHECK: cir.func{{.*}} @const_extend(!s8i {{{.*}}llvm.signext{{.*}}}) -> !s32i side_effect(const)
+ // CHECK: cir.func{{.*}} @const_extend(!s8i {llvm.signext}) -> !s32i side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(none)
// LLVM-NEXT: declare i32 @const_extend(i8 signext)
+ // Negative: Expand replaces the record with its fields, handing the callee
+ // no memory. Only the hook reaches this, since no x86_64 classification
+ // produces Expand.
+ cir.func private @const_expand(!rec_Big) -> !s32i side_effect(const)
+ attributes { test_classify = #expand_arg }
+
+ // LLVM: ; Function Attrs: nounwind willreturn memory(none)
+ // LLVM-NEXT: declare i32 @const_expand(i64, i64, i64)
+
// A callee with no side_effect must still come out with none, so that
// forwarding the original is distinguishable from hard-coding a value.
cir.func private @plain_sret() -> !rec_Big
@@ -104,7 +123,7 @@ module attributes {
cir.return
}
- // CHECK: cir.call @plain_sret(%{{[^)]+}}) : (!cir.ptr<!rec_Big>{{.*}}) -> ()
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
// LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}){{$}}
// nothrow without const or pure still reaches nounwind, and still gets no
@@ -114,7 +133,7 @@ module attributes {
cir.return
}
- // CHECK: cir.call @plain_sret(%{{[^)]+}}) nothrow : (!cir.ptr<!rec_Big>{{.*}}) -> ()
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) nothrow : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
// LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[NOTHROW_CALL:[0-9]+]]
// The call site keeps its side_effect across the rewrite.
@@ -124,7 +143,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @call_const_sret()
- // CHECK: cir.call @const_sret(%{{.+}}) side_effect(const)
+ // CHECK: cir.call @const_sret(%{{.+}}) side_effect(const) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
// LLVM: define void @call_const_sret()
// LLVM: call void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[CALL_ATTRS:[0-9]+]]
// LLVM-DAG: attributes #[[CALL_ATTRS]] = { nounwind willreturn memory(argmem: readwrite) }
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
index adff98cb043fb..3da68d91a8e3f 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
@@ -71,7 +71,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_bf_pad(%arg0: !cir.ptr<!rec_BFPad> {llvm.align = 8 : i64, llvm.byval = !rec_BFPad, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_bf_pad(%arg0: !cir.ptr<!rec_BFPad> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_BFPad, llvm.noundef})
// A zero-width bit-field takes no part in assigning eightbyte classes, but
// the type it was declared with still marks the bits it sits in as read, so
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
index 883e52f408b9e..f5ac22148df39 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
@@ -762,7 +762,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_o(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_O, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_O>, !rec_O
// CHECK-NEXT: cir.return
@@ -783,7 +783,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @ret_o(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64
// CHECK-SAME: , llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_O
// CHECK-SAME: , llvm.writable})
// CHECK-NEXT: %[[Z:[0-9]+]] = cir.const #cir.zero : !rec_O
@@ -803,7 +803,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_arr(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_Arr> {llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_Arr> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_Arr, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_Arr>, !rec_Arr
// CHECK-NEXT: cir.return
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
index 9f443a7e70e7e..885db2ff782cb 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
@@ -199,7 +199,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef})
// LLVM: define void @take_ntc_empty(ptr nofreeobj noundef align 1 dereferenceable(1) %{{.*}})
// The same record returned goes through sret rather than being dropped.
@@ -209,7 +209,7 @@ module attributes {
cir.return %1 : !rec_NTCE
}
- // CHECK: cir.func{{.*}} @ret_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NTCE, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NTCE, llvm.writable})
// LLVM: define void @ret_ntc_empty(ptr dead_on_unwind noalias writable sret(%struct.NTCE) align 1 %{{.*}})
// At exactly two eightbytes an empty class is still dropped.
@@ -237,7 +237,7 @@ module attributes {
cir.return %arg1 : !s32i
}
- // CHECK: cir.func{{.*}} @take_empty_big(%arg0: !cir.ptr<!rec_EBig> {llvm.align = 32 : i64, llvm.byval = !rec_EBig, llvm.noundef}, %arg1: !s32i) -> !s32i
+ // CHECK: cir.func{{.*}} @take_empty_big(%arg0: !cir.ptr<!rec_EBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_EBig, llvm.noundef}, %arg1: !s32i) -> !s32i
// LLVM: define i32 @take_empty_big(ptr noundef byval(%struct.EBig) align 32 %{{.*}}, i32 %{{.*}})
// The same record returned uses sret at that alignment.
@@ -247,7 +247,7 @@ module attributes {
cir.return %1 : !rec_EBig
}
- // CHECK: cir.func{{.*}} @ret_empty_big(%arg0: !cir.ptr<!rec_EBig> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_EBig, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_empty_big(%arg0: !cir.ptr<!rec_EBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_EBig, llvm.writable})
// LLVM: define void @ret_empty_big(ptr dead_on_unwind noalias writable sret(%struct.EBig) align 32 %{{.*}})
// A call site drops the operand as well as the parameter.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
index 90eca9f09b3e5..66131e731ca1e 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
@@ -79,7 +79,7 @@ module attributes {
cir.return
}
- // CHECK-LABEL: cir.func{{.*}} @take_p(%arg0: !cir.ptr<!rec_P> {llvm.align = 1 : i64, llvm.dereferenceable = 5 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-LABEL: cir.func{{.*}} @take_p(%arg0: !cir.ptr<!rec_P> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 5 : i64, llvm.nofreeobj, llvm.noundef})
// A union coerces through the same one-register path as FiveShort.
cir.func @take_upacked(%arg0: !rec_UPacked) {
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
index c843ff0026604..f57bee7b0ca9a 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
@@ -30,7 +30,7 @@ module attributes {
cir.return %2 : !s64i
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// CHECK: %[[VAL:.*]] = cir.load %arg0 : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: %[[LOCAL:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!rec_Big>
// CHECK: cir.store %[[VAL]], %[[LOCAL]] : !rec_Big, !cir.ptr<!rec_Big>
@@ -44,7 +44,7 @@ module attributes {
cir.return %1 : !rec_Big
}
- // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable})
// A small struct that cannot pass in registers (non-trivial for ABI) is
// passed indirectly even though its size would otherwise fit a register.
@@ -52,7 +52,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_noregs(%arg0: !cir.ptr<!rec_NoRegs> {llvm.align = 4 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_noregs(%arg0: !cir.ptr<!rec_NoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef})
// {__int128, char} spans more than two eightbytes, so it does not fit in
// registers: the argument is byval and the return uses sret.
@@ -60,7 +60,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big128(%arg0: !cir.ptr<!rec_Big128> {llvm.align = 16 : i64, llvm.byval = !rec_Big128, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big128(%arg0: !cir.ptr<!rec_Big128> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_Big128, llvm.noundef})
cir.func @ret_big128() -> !rec_Big128 {
%0 = cir.alloca "r" align(16) : !cir.ptr<!rec_Big128>
@@ -68,5 +68,5 @@ module attributes {
cir.return %1 : !rec_Big128
}
- // CHECK: cir.func{{.*}} @ret_big128(%arg0: !cir.ptr<!rec_Big128> {llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big128, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_big128(%arg0: !cir.ptr<!rec_Big128> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big128, llvm.writable})
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
index de30f61c0a329..6308a622f16c6 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
@@ -78,7 +78,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 16 : i64, llvm.byval = !rec_Big, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_Big, llvm.noundef})
// A record the caller must destroy is passed by reference rather than copied,
// so it takes the non-byval form instead of byval even though the size rule
@@ -87,7 +87,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_NoRegs> {llvm.align = 16 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_NoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 16 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// An anonymous record has no entry in cir.record_layouts, so both the
// register-passing decision and the alignment come from the fallbacks.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
index e41f9b451f379..f6d4260a48b73 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
@@ -182,7 +182,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_UBig> {llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
// CHECK: %{{.*}} = cir.load %arg0 : !cir.ptr<!rec_UBig>, !rec_UBig
// The byval alignment comes from the record's declared alignment, which the
@@ -192,7 +192,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big_over_aligned(%arg0: !cir.ptr<!rec_UBigOverAligned> {llvm.align = 32 : i64, llvm.byval = !rec_UBigOverAligned, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big_over_aligned(%arg0: !cir.ptr<!rec_UBigOverAligned> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigOverAligned, llvm.noundef})
// The same declared-alignment source feeds every accepted record, not just
// unions: an over-aligned STRUCT gets the same byval alignment fix, since
@@ -201,7 +201,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_struct_over_aligned(%arg0: !cir.ptr<!rec_SOverAligned> {llvm.align = 32 : i64, llvm.byval = !rec_SOverAligned, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_struct_over_aligned(%arg0: !cir.ptr<!rec_SOverAligned> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_SOverAligned, llvm.noundef})
// A union with no members classifies Ignore and is dropped from the
// signature.
@@ -298,7 +298,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big_empty_int(%arg0: !cir.ptr<!rec_UBigEmptyInt> {llvm.align = 32 : i64, llvm.byval = !rec_UBigEmptyInt, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big_empty_int(%arg0: !cir.ptr<!rec_UBigEmptyInt> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigEmptyInt, llvm.noundef})
// More than one empty member is skipped the same way.
cir.func @take_two_empty(%arg0: !rec_UTwoEmpty) {
@@ -392,7 +392,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_UNoRegs> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_UNoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
// A struct member that is itself a union is mapped through the same union
// handling, so the enclosing 8-byte struct coerces to one i64.
@@ -426,7 +426,7 @@ module attributes {
cir.return %1 : !rec_UBig
}
- // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_UBig> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBig, llvm.writable}, %arg1: !cir.ptr<!rec_UBig> {llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBig, llvm.writable}, %arg1: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
// CHECK: %[[VAL:.*]] = cir.load %arg1 : !cir.ptr<!rec_UBig>, !rec_UBig
// CHECK: cir.store %[[VAL]], %arg0 : !rec_UBig, !cir.ptr<!rec_UBig>
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
index dc3130d5e5d66..8125794327232 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
@@ -28,7 +28,7 @@ module attributes {
// A rewritten variadic declaration keeps its ellipsis.
// CHECK: cir.func private @variadic_pair(!u64i, ...) -> !s32i
- // CHECK: cir.func private @variadic_big(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, ...)
+ // CHECK: cir.func private @variadic_big(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, ...)
// Passing nothing through the ellipsis leaves the call at the callee's
// declared parameters.
@@ -86,7 +86,7 @@ module attributes {
// CHECK: cir.func{{.*}} @pass_two_exhausted(%arg0: !cir.ptr<!s8i>, %arg1: !s32i, %arg2: !s64i, %arg3: !s64i)
// CHECK: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Two>
- // CHECK: cir.call @variadic(%arg0, %arg1, %arg1, %arg1, %arg1, %arg1, %[[SLOT]]) : (!cir.ptr<!s8i>, !s32i, !s32i, !s32i, !s32i, !s32i, !cir.ptr<!rec_Two> {llvm.align = 8 : i64, llvm.byval = !rec_Two, llvm.noundef}) -> !s32i
+ // CHECK: cir.call @variadic(%arg0, %arg1, %arg1, %arg1, %arg1, %arg1, %[[SLOT]]) : (!cir.ptr<!s8i>, !s32i, !s32i, !s32i, !s32i, !s32i, !cir.ptr<!rec_Two> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Two, llvm.noundef}) -> !s32i
// A record larger than two eightbytes is memory class no matter how many
// registers are free.
@@ -95,9 +95,9 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @pass_big(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef})
+ // CHECK: cir.func{{.*}} @pass_big(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef})
// CHECK: %[[BSLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
- // CHECK: cir.call @variadic(%arg0, %[[BSLOT]]) : (!cir.ptr<!s8i>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
+ // CHECK: cir.call @variadic(%arg0, %[[BSLOT]]) : (!cir.ptr<!s8i>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
// An empty record occupies no register and is dropped, without displacing
// the argument behind it.
@@ -129,8 +129,8 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @pass_wide_vector(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!cir.vector<8 x !cir.float>> {llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef})
- // CHECK: cir.call @variadic(%arg0, %{{.*}}) : (!cir.ptr<!s8i>, !cir.ptr<!cir.vector<8 x !cir.float>> {llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef}) -> !s32i
+ // CHECK: cir.func{{.*}} @pass_wide_vector(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!cir.vector<8 x !cir.float>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef})
+ // CHECK: cir.call @variadic(%arg0, %{{.*}}) : (!cir.ptr<!s8i>, !cir.ptr<!cir.vector<8 x !cir.float>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef}) -> !s32i
// A declared parameter is coerced the same way whether or not the call also
// passes ellipsis arguments.
@@ -149,8 +149,8 @@ module attributes {
cir.return %0 : !rec_Big
}
- // CHECK: cir.func{{.*}} @pass_sret_return(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable}, %arg1: !cir.ptr<!s8i>, %arg2: !s32i)
- // CHECK: cir.call @variadic_big(%arg0, %arg1, %arg2) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, !s32i) -> ()
+ // CHECK: cir.func{{.*}} @pass_sret_return(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable}, %arg1: !cir.ptr<!s8i>, %arg2: !s32i)
+ // CHECK: cir.call @variadic_big(%arg0, %arg1, %arg2) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, !s32i) -> ()
// An indirect variadic call whose ellipsis arguments all pass as written
// needs no rewrite, and the callee pointer keeps its ellipsis.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
index 0a662367695e5..33ffbb017e177 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
@@ -188,7 +188,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_vp_big(%arg0: !cir.ptr<!rec_VPBig> {llvm.align = 8 : i64, llvm.byval = !rec_VPBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_vp_big(%arg0: !cir.ptr<!rec_VPBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_VPBig, llvm.noundef})
// LLVM: define void @take_vp_big(ptr noundef byval(%struct.VPBig) align 8 %{{[^,)]+}})
// Returned at that size it uses sret instead.
@@ -198,7 +198,7 @@ module attributes {
cir.return %1 : !rec_VPBig
}
- // CHECK: cir.func{{.*}} @ret_vp_big(%arg0: !cir.ptr<!rec_VPBig> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPBig, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_vp_big(%arg0: !cir.ptr<!rec_VPBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPBig, llvm.writable})
// LLVM: define void @ret_vp_big(ptr dead_on_unwind noalias writable sret(%struct.VPBig) align 8 %{{[^,)]+}})
// A declared argument-passing kind of cannot-pass-in-registers sends the
@@ -208,7 +208,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// LLVM: define void @take_vp_no_regs(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// The same record returned takes sret rather than the non-byval form.
@@ -218,7 +218,7 @@ module attributes {
cir.return %1 : !rec_VPNoRegs
}
- // CHECK: cir.func{{.*}} @ret_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPNoRegs, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPNoRegs, llvm.writable})
// LLVM: define void @ret_vp_no_regs(ptr dead_on_unwind noalias writable sret(%struct.VPNoRegs) align 8 %{{[^,)]+}})
// A call site is decomposed into the same two registers the callee now takes.
>From f23949a7914850fbca8b8eb067a090469e486d6d Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Mon, 14 Sep 2026 19:30:52 -0700
Subject: [PATCH 3/3] [CIR] Widen const/pure side effects for ABI argument
memory
A const or pure callee that the ABI rewrites to take an sret slot or a
byval pointer reaches argument memory whatever the source declared, and
a variadic callee does too since its declared parameters do not cover
every argument. CallConvLowering was leaving side_effect untouched, so
LowerToLLVM emitted memory(none) or memory(read) for functions that do
touch that memory.
This adds const_argmem and pure_argmem to CIR_SideEffect.
CallConvLowering widens into them once it knows the signature.
Assisted-by: Cursor / claude-opus-5
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 71 +++++--------------
.../clang/CIR/Dialect/IR/CIRDialect.td | 1 -
.../clang/CIR/Interfaces/CIROpInterfaces.td | 6 ++
.../Transforms/CallConvLoweringPass.cpp | 51 +++++++++++++
.../TargetLowering/CIRABIRewriteContext.cpp | 9 ---
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 64 ++++++-----------
clang/test/CIR/CodeGen/arg-attrs.cpp | 4 +-
clang/test/CIR/CodeGen/array-ctor.cpp | 4 +-
.../CIR/CodeGen/bind-temporary-lvalue.cpp | 2 +-
clang/test/CIR/CodeGen/bitint.c | 2 +-
.../call-conv-lowering-x86_64-bitint.c | 2 +-
.../call-conv-lowering-x86_64-empty.cpp | 8 +--
.../call-conv-lowering-x86_64-indirect.c | 4 +-
.../call-conv-lowering-x86_64-non-byval.cpp | 12 ++--
.../call-conv-lowering-x86_64-packed.c | 14 ++--
.../call-conv-lowering-x86_64-padded.c | 6 +-
...call-conv-lowering-x86_64-union-bitfield.c | 4 +-
...ll-conv-lowering-x86_64-union-bitfield.cpp | 2 +-
.../call-conv-lowering-x86_64-variadic.c | 12 ++--
.../call-conv-lowering-x86_64-vptr.cpp | 22 +++---
...conv-lowering-x86_64-zero-width-bitfield.c | 2 +-
clang/test/CIR/CodeGen/call.c | 4 +-
.../cleanup-conditional-with-wrapper-eh.cpp | 8 +--
.../cleanup-conditional-with-wrapper.cpp | 8 +--
.../test/CIR/CodeGen/paren-list-agg-init.cpp | 6 +-
.../CIR/CodeGen/partial-array-cleanup.cpp | 2 +-
clang/test/CIR/CodeGen/side-effect.cpp | 34 +++++----
.../test/CIR/CodeGenOpenACC/declare-copy.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-copyin.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-copyout.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-create.cpp | 6 +-
.../CodeGenOpenACC/declare-deviceresident.cpp | 6 +-
.../CIR/CodeGenOpenACC/declare-present.cpp | 6 +-
.../byval-sret-arg-attr-lowering.cir | 17 -----
.../abi-lowering/indirect-byval.cir | 24 +++----
.../Transforms/abi-lowering/indirect-call.cir | 4 +-
.../indirect-non-byval-forward-param.cir | 32 ++++-----
.../abi-lowering/side-effect-argmem.cir | 42 +++++++----
.../abi-lowering/x86_64-bitfield.cir | 2 +-
.../Transforms/abi-lowering/x86_64-bitint.cir | 28 ++++----
.../abi-lowering/x86_64-empty-class.cir | 8 +--
.../abi-lowering/x86_64-record-packed.cir | 2 +-
.../abi-lowering/x86_64-struct-indirect.cir | 10 +--
.../abi-lowering/x86_64-struct-padded.cir | 4 +-
.../Transforms/abi-lowering/x86_64-union.cir | 14 ++--
.../abi-lowering/x86_64-variadic-call.cir | 16 ++---
.../Transforms/abi-lowering/x86_64-vptr.cir | 8 +--
47 files changed, 300 insertions(+), 311 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1f3424daaa3c5..8e3114723793e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -159,58 +159,6 @@ def CIR_OffloadKindAttr : CIR_EnumAttr<CIR_OffloadKind, "offload"> {
}];
}
-//===----------------------------------------------------------------------===//
-// ABISlotKindAttr
-//===----------------------------------------------------------------------===//
-
-def CIR_ABISlotKind : CIR_I32Enum<
- "ABISlotKind", "kind of pointer slot the ABI introduced", [
- I32EnumCase<"Byval", 0, "byval">,
- I32EnumCase<"NonByval", 1, "non_byval">,
- I32EnumCase<"Sret", 2, "sret">
-]> {
- let description = [{
- Which kind of pointer slot CallConvLowering introduced for a parameter
- that the source declared by value, or for a return value the ABI returns
- in memory.
-
- - byval: the callee receives a pointer to its own copy.
- - non_byval: the callee receives a pointer to the caller's object, used
- when the type cannot be copied freely.
- - sret: the return value is written through a pointer the ABI inserts as
- argument 0.
- }];
-}
-
-def CIR_ABISlotKindAttr : CIR_EnumAttr<CIR_ABISlotKind, "abi_slot"> {
- let summary = "Marks an argument as a pointer slot the ABI introduced";
- let description = [{
- CallConvLowering rewrites a by-value parameter or an in-memory return
- into a pointer argument, then records here which kind of slot it made.
- The memory-effect lowering uses this to widen argument memory on a
- `const` or `pure` callee.
-
- A `non_byval` slot is the case the rewritten signature cannot otherwise
- express: it is a plain `!cir.ptr<T>` carrying `llvm.align`,
- `llvm.dereferenceable`, `llvm.nofreeobj` and `llvm.noundef`. Each of
- those states a property of the pointer or of the object, not who created
- the slot, so none of them is reserved to an ABI slot. A `byval` or
- `sret` slot is for now also identifiable by the `llvm.byval` or
- `llvm.sret` in the same dictionary, so this attribute overlaps those
- two, and a producer that writes one without the other leaves the memory
- effect disagreeing with the signature.
-
- Example, on the argument dictionary of the slot it describes:
-
- ```mlir
- cir.func private @f(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>,
- llvm.align = 8 : i64,
- llvm.byval = !rec_Big,
- llvm.noundef})
- ```
- }];
-}
-
//===----------------------------------------------------------------------===//
// ArgPassingKind + RecordLayoutAttr
//===----------------------------------------------------------------------===//
@@ -2012,7 +1960,9 @@ def CIR_SideEffect : CIR_I32Enum<
"SideEffect", "allowed side effects of a function", [
I32EnumCase<"All", 0, "all">,
I32EnumCase<"Pure", 1, "pure">,
- I32EnumCase<"Const", 2, "const">
+ I32EnumCase<"Const", 2, "const">,
+ I32EnumCase<"ConstArgMem", 3, "const_argmem">,
+ I32EnumCase<"PureArgMem", 4, "pure_argmem">
]> {
let description = [{
The side effect attribute specifies the possible side effects of a function
@@ -2026,13 +1976,24 @@ def CIR_SideEffect : CIR_I32Enum<
`__attribute__((pure))`.
- const: The function or callee may not read or write data from memory. This
has the same effect as the GNU C/C++ attribute `__attribute__((const))`.
+ - const_argmem: As const, except that the callee may read and write the
+ memory its pointer arguments address.
+ - pure_argmem: As pure, except that the callee may also write the memory
+ its pointer arguments address.
+
+ The two argmem values have no source-level spelling. CallConvLowering
+ produces them: a `const` or `pure` function or call whose ABI-lowered
+ signature carries a pointer the ABI introduced reaches that argument
+ memory whatever the source declared, so `const` or `pure` alone would
+ describe it incorrectly.
Examples:
```
%2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i
- %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(pure)
- %2 = cir.call @add(%0, %1) : (!s32i, !s32i) -> !s32i side_effect(const)
+ %2 = cir.call @add(%0, %1) side_effect(pure) : (!s32i, !s32i) -> !s32i
+ %2 = cir.call @add(%0, %1) side_effect(const) : (!s32i, !s32i) -> !s32i
+ cir.call @big(%0) side_effect(const_argmem) : (!cir.ptr<!rec_Big>) -> ()
```
}];
}
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 6b0611bd22522..e323eff0b9aa6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -85,7 +85,6 @@ def CIR_Dialect : Dialect {
static llvm::StringRef getUniformWorkGroupSizeAttrName() { return "uniform_work_group_size"; }
static llvm::StringRef getResAttrsAttrName() { return "res_attrs"; }
static llvm::StringRef getArgAttrsAttrName() { return "arg_attrs"; }
- static llvm::StringRef getABISlotAttrName() { return "cir.abi_slot"; }
static llvm::StringRef getRecordLayoutsAttrName() { return "cir.record_layouts"; }
static llvm::StringRef getTargetCPUAttrName() { return "cir.target-cpu"; }
static llvm::StringRef getTuneCPUAttrName() { return "cir.tune-cpu"; }
diff --git a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
index c39a9c7818da7..6cff29bc16053 100644
--- a/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
+++ b/clang/include/clang/CIR/Interfaces/CIROpInterfaces.td
@@ -45,6 +45,12 @@ let cppNamespace = "::cir" in {
"bool", "getNothrow", (ins)>,
InterfaceMethod<"Return the side effects of the call operation",
"cir::SideEffect", "getSideEffect", (ins)>,
+ InterfaceMethod<"Set the side effects of the call operation",
+ "void", "setSideEffect",
+ (ins "cir::SideEffect":$effect), [{}],
+ /*defaultImplementation=*/[{
+ $_op.setSideEffect(effect);
+ }]>,
InterfaceMethod<[{"Set the inline-kind of a call operation"}],
"void", "setInlineKind",
(ins "std::optional<cir::InlineKind>":$kind), [{}],
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 3d878fd7866ef..cfcd5356773f7 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -756,6 +756,33 @@ static std::optional<FunctionClassification> classifyX86_64VariadicCall(
modOp, [&]() { return op->emitOpError(); });
}
+/// Whether \p fc gives the callee access to memory through a pointer the ABI
+/// introduced: an sret slot for an indirect return, or an indirect argument.
+static bool hasIndirectSlot(const FunctionClassification &fc) {
+ if (fc.returnInfo.kind == ArgKind::Indirect)
+ return true;
+ return llvm::any_of(fc.argInfos, [](const ArgClassification &ac) {
+ return ac.kind == ArgKind::Indirect;
+ });
+}
+
+/// The side effect that describes a callee once the ABI has given it access
+/// to the memory its pointer arguments address. `all` already allows that,
+/// so the function is idempotent.
+static cir::SideEffect widenForArgMemory(cir::SideEffect current) {
+ switch (current) {
+ case cir::SideEffect::Const:
+ return cir::SideEffect::ConstArgMem;
+ case cir::SideEffect::Pure:
+ return cir::SideEffect::PureArgMem;
+ case cir::SideEffect::All:
+ case cir::SideEffect::ConstArgMem:
+ case cir::SideEffect::PureArgMem:
+ return current;
+ }
+ llvm_unreachable("unhandled cir::SideEffect");
+}
+
#ifndef NDEBUG
/// Whether \p callFc classifies a call's leading arguments and its return
/// exactly as \p calleeFc classifies the callee's declared parameters and
@@ -1041,6 +1068,19 @@ void CallConvLoweringPass::runOnOperation() {
for (auto &kv : classifications)
rewriteCtx.normalizeParameterSlotAlignments(kv.first, kv.second);
+ // A const or pure callee that the ABI hands memory through a pointer
+ // argument reaches that memory whatever its source-level attribute said, so
+ // the attribute has to be widened to match. A variadic callee counts as
+ // well, since its declared parameters do not cover every argument.
+ for (auto &kv : classifications) {
+ cir::FuncOp func = kv.first;
+ std::optional<cir::SideEffect> sideEffect = func.getSideEffect();
+ if (!sideEffect)
+ continue;
+ if (hasIndirectSlot(kv.second) || func.getFunctionType().isVarArg())
+ func.setSideEffect(widenForArgMemory(*sideEffect));
+ }
+
// Rewrite each function together with every direct call to it and every op
// holding its address. By the time we move on to function F+1, F's
// signature and every reference to F have already been brought into
@@ -1069,6 +1109,13 @@ void CallConvLoweringPass::runOnOperation() {
"a call site's declared parameters must be classified the same "
"way as the callee's");
}
+ // A call site sees the arguments it passes, so it widens only for a
+ // slot, never for being variadic. Widening before the rewrite lets
+ // the rewritten call carry the attribute across with the others.
+ if (hasIndirectSlot(*callFc)) {
+ auto call = cast<cir::CIRCallOpInterface>(callOp);
+ call.setSideEffect(widenForArgMemory(call.getSideEffect()));
+ }
if (failed(rewriteCtx.rewriteCallSite(callOp, *callFc, builder))) {
signalPassFailure();
return;
@@ -1143,6 +1190,10 @@ void CallConvLoweringPass::runOnOperation() {
signalPassFailure();
return;
}
+ // Widening before the rewrite lets the rewritten call carry the attribute
+ // across with the others.
+ if (hasIndirectSlot(*fc))
+ c.setSideEffect(widenForArgMemory(c.getSideEffect()));
if (failed(rewriteCtx.rewriteCallSite(c.getOperation(), *fc, builder))) {
signalPassFailure();
return;
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index 7fdf902dcda04..63c37b544529a 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -227,12 +227,6 @@ mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx,
// across the call.
mlir::Type pointeeTy = origArgTypes[oldIdx];
mlir::NamedAttrList attrs(existing);
- // Record that the ABI introduced this pointer, and which kind of slot
- // it is.
- attrs.set(CIRDialect::getABISlotAttrName(),
- cir::ABISlotKindAttr::get(
- ctx, ac.byVal ? cir::ABISlotKind::Byval
- : cir::ABISlotKind::NonByval));
attrs.set(mlir::LLVM::LLVMDialect::getAlignAttrName(),
builder.getI64IntegerAttr(ac.indirectAlign.value()));
attrs.set(mlir::LLVM::LLVMDialect::getNoUndefAttrName(),
@@ -895,9 +889,6 @@ SmallVector<mlir::NamedAttribute> buildSretSlotAttrs(mlir::OpBuilder &builder,
uint64_t align,
bool withNoalias) {
SmallVector<mlir::NamedAttribute> attrs;
- attrs.push_back(builder.getNamedAttr(
- CIRDialect::getABISlotAttrName(),
- cir::ABISlotKindAttr::get(builder.getContext(), cir::ABISlotKind::Sret)));
// The sret type must be carried explicitly: LLVM's sret attribute requires
// it, and once the CIR `!cir.ptr<retTy>` lowers to an opaque LLVM `ptr` the
// pointee type can no longer be recovered from the pointer.
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index b8e5e7c67dc75..03ad440a124c0 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -420,41 +420,35 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
return value;
}
-/// Whether any argument is a pointer slot the ABI introduced, which
-/// CallConvLowering marks with cir.abi_slot. Such a callee reaches that
-/// memory whatever its source-level attributes say, so `const` and `pure`
-/// cannot lower to a memory effect that excludes argument memory.
-static bool hasABISlotArg(mlir::ArrayAttr argAttrs) {
- if (!argAttrs)
- return false;
- return llvm::any_of(argAttrs, [](mlir::Attribute a) {
- return mlir::cast<mlir::DictionaryAttr>(a).contains(
- CIRDialect::getABISlotAttrName());
- });
-}
-
-/// Lower a CIR `side_effect` to an LLVM memory effect, widening argument
-/// memory to ModRef when \p accessesArgMemory, since a widened slot may be
-/// either written or read. A null result means unknown effects, which is
-/// how `All` is represented.
+/// Lower a CIR `side_effect` to an LLVM memory effect. A null result means
+/// unknown effects, which is how `All` is represented. The argmem values
+/// lower to ModRef because they do not say whether the slot is read or
+/// written.
static mlir::LLVM::MemoryEffectsAttr
-buildMemoryEffects(mlir::MLIRContext *ctx, cir::SideEffect sideEffect,
- bool accessesArgMemory) {
+buildMemoryEffects(mlir::MLIRContext *ctx, cir::SideEffect sideEffect) {
using mlir::LLVM::ModRefInfo;
ModRefInfo other;
+ ModRefInfo argMem;
switch (sideEffect) {
case cir::SideEffect::All:
return {};
case cir::SideEffect::Pure:
- other = ModRefInfo::Ref;
+ other = argMem = ModRefInfo::Ref;
break;
case cir::SideEffect::Const:
+ other = argMem = ModRefInfo::NoModRef;
+ break;
+ case cir::SideEffect::PureArgMem:
+ other = ModRefInfo::Ref;
+ argMem = ModRefInfo::ModRef;
+ break;
+ case cir::SideEffect::ConstArgMem:
other = ModRefInfo::NoModRef;
+ argMem = ModRefInfo::ModRef;
break;
}
- ModRefInfo argMem = accessesArgMemory ? ModRefInfo::ModRef : other;
return mlir::LLVM::MemoryEffectsAttr::get(ctx, /*other=*/other,
/*argMem=*/argMem,
/*inaccessibleMem=*/other,
@@ -468,14 +462,11 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
mlir::LLVM::MemoryEffectsAttr &memoryEffect,
bool &noUnwind, bool &willReturn,
bool &noReturn) {
- bool accessesArgMemory = hasABISlotArg(callOp->getAttrOfType<mlir::ArrayAttr>(
- CIRDialect::getArgAttrsAttrName()));
- memoryEffect =
- buildMemoryEffects(callOp->getContext(), sideEffect, accessesArgMemory);
-
- bool isConstOrPure = sideEffect != cir::SideEffect::All;
- noUnwind = isConstOrPure || isNothrow;
- willReturn = isConstOrPure;
+ memoryEffect = buildMemoryEffects(callOp->getContext(), sideEffect);
+
+ bool hasKnownEffects = sideEffect != cir::SideEffect::All;
+ noUnwind = hasKnownEffects || isNothrow;
+ willReturn = hasKnownEffects;
noReturn = callOp->hasAttr(CIRDialect::getNoReturnAttrName());
}
@@ -2124,9 +2115,6 @@ mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(
/// integer would otherwise understate both. Returns std::nullopt when a
/// pointee has no memory representation, leaving the caller to emit the NYI
/// error.
-///
-/// cir.abi_slot has no LLVM counterpart and is dropped. The memory-effect
-/// sites read it from the CIR op, which this leaves untouched.
static std::optional<mlir::ArrayAttr>
lowerArgAttrs(mlir::ArrayAttr argAttrs, const mlir::TypeConverter &converter,
const mlir::DataLayout &dataLayout, mlir::MLIRContext *ctx) {
@@ -2141,10 +2129,6 @@ lowerArgAttrs(mlir::ArrayAttr argAttrs, const mlir::TypeConverter &converter,
entries.reserve(dict.size());
for (mlir::NamedAttribute entry : dict) {
StringRef name = entry.getName().strref();
- if (name == CIRDialect::getABISlotAttrName()) {
- changed = true;
- continue;
- }
if (name == mlir::LLVM::LLVMDialect::getByValAttrName() ||
name == mlir::LLVM::LLVMDialect::getStructRetAttrName()) {
if (auto typeAttr = dyn_cast<mlir::TypeAttr>(entry.getValue())) {
@@ -2831,12 +2815,8 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
if (std::optional<cir::SideEffect> sideEffectKind = op.getSideEffect();
sideEffectKind && *sideEffectKind != cir::SideEffect::All) {
- // A variadic callee's declared parameters do not cover every argument, so
- // its argument memory widens too.
- bool accessesArgMemory =
- hasABISlotArg(op.getArgAttrsAttr()) || op.getFunctionType().isVarArg();
- fn.setMemoryEffectsAttr(buildMemoryEffects(fn.getContext(), *sideEffectKind,
- accessesArgMemory));
+ fn.setMemoryEffectsAttr(
+ buildMemoryEffects(fn.getContext(), *sideEffectKind));
fn.setNoUnwind(true);
fn.setWillReturn(true);
}
diff --git a/clang/test/CIR/CodeGen/arg-attrs.cpp b/clang/test/CIR/CodeGen/arg-attrs.cpp
index 94d53256fd61a..8960de7345baf 100644
--- a/clang/test/CIR/CodeGen/arg-attrs.cpp
+++ b/clang/test/CIR/CodeGen/arg-attrs.cpp
@@ -18,7 +18,7 @@ void Struct::this_func(){}
// CIR: cir.func {{.*}}@_ZN6Struct9this_funcEv(%{{.*}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
// BOTH: define {{.*}}void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
void Struct::arg_attr(Struct s, int &i, Incomplete &j){}
- // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!rec_Struct> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
+ // CIR: cir.func {{.*}}@_ZN6Struct8arg_attrES_RiR10Incomplete(%{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!rec_Struct> {llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef} {{.*}}, %{{[^,)]+}}: !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef} {{.*}}, %arg3: !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef} {{.*}}) {{.*}} {
// BOTH: define {{.*}}void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{[^,)]+}}, ptr noundef byval(%struct.Struct) align 8 %{{[^,)]+}}, ptr noundef nonnull align 4 dereferenceable(4) %{{[^,)]+}}, ptr noundef nonnull align 1 %{{[^,)]+}})
struct __attribute__((aligned(32))) Aligned32 {
@@ -50,7 +50,7 @@ void caller(Struct s, int i, Incomplete &inc) {
// CIR: cir.call @_ZN6Struct9this_funcEv(%{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef})
// BOTH: call void @_ZN6Struct9this_funcEv(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}})
s.arg_attr(s, i, inc);
- // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Struct> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef})
+ // CIR: cir.call @_ZN6Struct8arg_attrES_RiR10Incomplete(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!cir.ptr<!rec_Struct> {llvm.align = 4 : i64, llvm.dereferenceable = 20 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Struct> {llvm.align = 8 : i64, llvm.byval = !rec_Struct, llvm.noundef}, !cir.ptr<!s32i> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nonnull, llvm.noundef}, !cir.ptr<!rec_Incomplete> {llvm.align = 1 : i64, llvm.nonnull, llvm.noundef})
// BOTH: call void @_ZN6Struct8arg_attrES_RiR10Incomplete(ptr noundef nonnull align 4 dereferenceable(20) %{{.*}}, ptr noundef byval(%struct.Struct) align 8 %{{.*}}, ptr noundef nonnull align 4 dereferenceable(4) %{{.*}}, ptr noundef nonnull align 1 %{{.*}})
}
diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp
index 48024b2a1411c..16eb8a57ee6d8 100644
--- a/clang/test/CIR/CodeGen/array-ctor.cpp
+++ b/clang/test/CIR/CodeGen/array-ctor.cpp
@@ -206,7 +206,7 @@ void TempInArray() {
// CIR: cir.do {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ITER:.*]] : !cir.ptr<!cir.ptr<!rec_CausesTemp>>, !cir.ptr<!rec_CausesTemp>
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN10CausesTempC1E4Temp(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN10CausesTempC1E4Temp(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup normal {
// CIR-NEXT: cir.call @_ZN4TempD1Ev(%[[TMP]]) nothrow
@@ -291,7 +291,7 @@ void Temp2InArray() {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ITER:.*]] : !cir.ptr<!cir.ptr<!rec_CausesTemp2>>, !cir.ptr<!rec_CausesTemp2>
// CIR-NEXT: cir.call @_ZN5Temp2C1Ev(%[[TMP]])
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup normal {
// CIR-NEXT: cir.call @_ZN5Temp2D1Ev(%[[TMP]]) nothrow
diff --git a/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp b/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
index f42de67a3c90a..44893f3f9cab0 100644
--- a/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
+++ b/clang/test/CIR/CodeGen/bind-temporary-lvalue.cpp
@@ -17,7 +17,7 @@ int f() { return getS().x; }
// CIR: cir.func {{.*}}@_Z1fv()
// CIR: %[[RET:.*]] = cir.alloca "__retval"
// CIR: %[[TMP:.*]] = cir.alloca "temp.lvalue"
-// CIR: cir.call @_Z4getSv(%[[TMP]]) : (!cir.ptr<!rec_S> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_S, llvm.writable}) -> ()
+// CIR: cir.call @_Z4getSv(%[[TMP]]) : (!cir.ptr<!rec_S> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_S, llvm.writable}) -> ()
// CIR: cir.cleanup.scope {
// CIR: %[[X:.*]] = cir.get_member %[[TMP]][0] {name = "x"} : !cir.ptr<!rec_S> -> !cir.ptr<!s32i>
// CIR: %[[VAL:.*]] = cir.load{{.*}} %[[X]] : !cir.ptr<!s32i>, !s32i
diff --git a/clang/test/CIR/CodeGen/bitint.c b/clang/test/CIR/CodeGen/bitint.c
index 94b7d0606b1cb..edd7b91cae49a 100644
--- a/clang/test/CIR/CodeGen/bitint.c
+++ b/clang/test/CIR/CodeGen/bitint.c
@@ -54,7 +54,7 @@ void take_unsigned_bitint(unsigned _BitInt(64) x) {}
void take_bitint_254(signed _BitInt(254) x) {}
// CIR: cir.func {{.*}} @take_bitint_254(%arg0: !cir.ptr<!cir.int<s, 254, bitint>>
-// CIR-SAME: {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !cir.int<s, 254, bitint>, llvm.noundef}
+// CIR-SAME: {llvm.align = 8 : i64, llvm.byval = !cir.int<s, 254, bitint>, llvm.noundef}
// LLVM: define {{.*}} void @take_bitint_254(ptr noundef byval(i256) align 8 {{.*}})
// OGCG: define {{.*}} void @take_bitint_254(ptr noundef byval(i256) align 8 {{.*}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-bitint.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-bitint.c
index 4c48add63e4cd..9334724773f89 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-bitint.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-bitint.c
@@ -8,7 +8,7 @@
void take_wide(_BitInt(200) x) {}
// CIR: cir.func{{.*}} @take_wide(
-// CIR-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+// CIR-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CIR-SAME: , llvm.byval = !cir.int<s, 200, bitint>, llvm.noundef} loc{{.*}})
// The byval copy is sized from the padded storage type (i256), matching
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
index a86ebe5ce0c18..499714bc895f5 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-empty.cpp
@@ -224,13 +224,13 @@ long callerHiWord(long hi) {
// this size is passed indirectly at its declared alignment.
int takeBig32(Big32 v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z9takeBig325Big32i(%arg0: !cir.ptr<!rec_Big32> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_Big32, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z9takeBig325Big32i(%arg0: !cir.ptr<!rec_Big32> {llvm.align = 32 : i64, llvm.byval = !rec_Big32, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z9takeBig325Big32i(ptr noundef byval(%struct.Big32) align 32 %{{[^,]+}}, i32 noundef %{{[^,]+}})
// The same class returned uses sret at that alignment.
Big32 retBig32() { return Big32{}; }
-// CIR: cir.func {{.*}}@_Z8retBig32v(%arg0: !cir.ptr<!rec_Big32> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big32, llvm.writable}
+// CIR: cir.func {{.*}}@_Z8retBig32v(%arg0: !cir.ptr<!rec_Big32> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big32, llvm.writable}
// LLVM: define dso_local void @_Z8retBig32v(ptr dead_on_unwind noalias writable sret(%struct.Big32) align 32 %{{[^,]+}})
// A zero-width unnamed bit-field reserves no storage for the classifier to
@@ -305,13 +305,13 @@ int takeUEmptyBytes(UEmptyBytes v) { return v.c[0]; }
// member changes nothing here.
int takeUBigEmpty(UBigEmpty v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z13takeUBigEmpty9UBigEmptyi(%arg0: !cir.ptr<!rec_UBigEmpty> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigEmpty, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z13takeUBigEmpty9UBigEmptyi(%arg0: !cir.ptr<!rec_UBigEmpty> {llvm.align = 32 : i64, llvm.byval = !rec_UBigEmpty, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z13takeUBigEmpty9UBigEmptyi(ptr noundef byval(%union.UBigEmpty) align 32 %{{[^,]+}}, i32 noundef %{{[^,]+}})
// The same union returned uses sret at that alignment.
UBigEmpty retUBigEmpty() { return UBigEmpty{}; }
-// CIR: cir.func {{.*}}@_Z12retUBigEmptyv(%arg0: !cir.ptr<!rec_UBigEmpty> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBigEmpty, llvm.writable}
+// CIR: cir.func {{.*}}@_Z12retUBigEmptyv(%arg0: !cir.ptr<!rec_UBigEmpty> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBigEmpty, llvm.writable}
// LLVM: define dso_local void @_Z12retUBigEmptyv(ptr dead_on_unwind noalias writable sret(%union.UBigEmpty) align 32 %{{[^,]+}})
// Emptiness reaches the union member through a base class as well.
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
index 743241fa3863e..922b1325491a8 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-indirect.c
@@ -32,7 +32,7 @@ long call_byval(long (*fp)(Big), Big b) { return fp(b); }
// CIR: cir.func {{.*}}@call_byval(%arg0: !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> {{.*}}, %arg1: !cir.ptr<!rec_Big> {{.*}}llvm.byval = !rec_Big{{.*}}) -> !s64i
// CIR: %[[CAST:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>
-// CIR: %{{.+}} = cir.call %[[CAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+// CIR: %{{.+}} = cir.call %[[CAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// LLVM: define dso_local i64 @call_byval(ptr noundef %{{.+}}, ptr noundef byval(%struct.Big) align 8 %{{.+}})
// LLVM: call i64 %{{.+}}(ptr noundef byval(%struct.Big) align 8 %{{.+}})
@@ -42,6 +42,6 @@ Big call_sret(Big (*fp)(void)) { return fp(); }
// CIR: cir.func {{.*}}@call_sret(%arg0: !cir.ptr<!rec_Big> {{.*}}llvm.sret = !rec_Big{{.*}}, %arg1: !cir.ptr<!cir.func<() -> !rec_Big>> {{.*}})
// CIR: %[[SCAST:.*]] = cir.cast bitcast %{{.+}} : !cir.ptr<!cir.func<() -> !rec_Big>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>
-// CIR: cir.call %[[SCAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+// CIR: cir.call %[[SCAST]](%{{.+}}) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
// LLVM: define dso_local void @call_sret(ptr dead_on_unwind noalias writable sret(%struct.Big) align 8 %{{.+}}, ptr noundef %{{.+}})
// LLVM: call void %{{.+}}(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
index 24bd9972572ee..a01414569e6fa 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-non-byval.cpp
@@ -36,7 +36,7 @@ void callNonByval() {
// CIR: %[[TMP:.*]] = cir.alloca "agg.tmp0" align(4) : !cir.ptr<!rec_WithDtor>
// CIR: cir.copy %[[T]] align(4) to %[[TMP]] align(4) : !cir.ptr<!rec_WithDtor>
// CIR-NOT: cir.load
-// CIR: cir.call @_Z12takeNonByval8WithDtor(%[[TMP]]) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z12takeNonByval8WithDtor(%[[TMP]]) : (!cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP]])
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[T]])
@@ -58,7 +58,7 @@ void callTwoNonByval() {
// CIR: %[[TMP_A:.*]] = cir.alloca "agg.tmp0" align(4) : !cir.ptr<!rec_WithDtor>
// CIR: %[[TMP_B:.*]] = cir.alloca "agg.tmp1" align(4) : !cir.ptr<!rec_WithDtor>
// CIR-NOT: cir.load
-// CIR: cir.call @_Z15takeTwoNonByval8WithDtorS_(%[[TMP_A]], %[[TMP_B]]) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z15takeTwoNonByval8WithDtorS_(%[[TMP_A]], %[[TMP_B]]) : (!cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP_B]])
// CIR: cir.call @_ZN8WithDtorD1Ev(%[[TMP_A]])
@@ -84,7 +84,7 @@ void callCopyCtorNonByval() {
// CIR: cir.call @_ZN12WithCopyCtorC1Ev(%[[C]])
// CIR: cir.call @_ZN12WithCopyCtorC1ERKS_(%[[TMP]], %[[C]])
// CIR-NOT: cir.load
-// CIR: cir.call @_Z20takeCopyCtorNonByval12WithCopyCtor(%[[TMP]]) : (!cir.ptr<!rec_WithCopyCtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_Z20takeCopyCtorNonByval12WithCopyCtor(%[[TMP]]) : (!cir.ptr<!rec_WithCopyCtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// LLVM-LABEL: define dso_local void @_Z20callCopyCtorNonByvalv()
// LLVM: call void @_ZN12WithCopyCtorC1Ev(ptr noundef nonnull align 4 dereferenceable(4) %[[C:[^)]+]])
@@ -103,7 +103,7 @@ void callByval() {
// CIR: %[[V:.*]] = cir.load align(8) %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CIR: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR: cir.store %[[V]], %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR: cir.call @_Z9takeByval3Big(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
+// CIR: cir.call @_Z9takeByval3Big(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
// LLVM-LABEL: define dso_local void @_Z9callByvalv()
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TMP:[^,]+]], ptr align 8 %{{[^,]+}}, i64 32, i1 false)
@@ -136,12 +136,12 @@ void callInheritedCtor(WithDtor t) { Derived d(t); }
// Both inheriting constructor variants hand their own parameter on unchanged.
// CIR-LABEL: cir.func {{.*}}@_ZN7DerivedCI14BaseE8WithDtor
-// CIR-SAME: %[[CI1ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
+// CIR-SAME: %[[CI1ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
// CIR-NOT: cir.copy
// CIR: cir.call @_ZN7DerivedCI24BaseE8WithDtor(%{{.*}}, %[[CI1ARG]])
// CIR-LABEL: cir.func {{.*}}@_ZN7DerivedCI24BaseE8WithDtor
-// CIR-SAME: %[[ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
+// CIR-SAME: %[[ARG:[^:]*]]: !cir.ptr<!rec_WithDtor> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef}
// CIR-NOT: cir.copy
// CIR: cir.call @_ZN4BaseC2E8WithDtor(%{{.*}}, %[[ARG]])
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
index a57bcb19b5929..082488b6ba4d9 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
@@ -59,8 +59,8 @@ typedef struct { char c; int i; } PragmaPacked;
int take_char_int(CharInt v) { return v.i; }
CharInt ret_char_int(int x) { CharInt v = {0, x}; return v; }
-// CIR: cir.func{{.*}} @take_char_int(%arg0: !cir.ptr<!rec_CharInt> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_CharInt, llvm.noundef}{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @ret_char_int(%arg0: !cir.ptr<!rec_CharInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_CharInt, llvm.writable}{{.*}}, %arg1: !s32i {llvm.noundef}{{.*}})
+// CIR: cir.func{{.*}} @take_char_int(%arg0: !cir.ptr<!rec_CharInt> {llvm.align = 8 : i64, llvm.byval = !rec_CharInt, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @ret_char_int(%arg0: !cir.ptr<!rec_CharInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_CharInt, llvm.writable}{{.*}}, %arg1: !s32i {llvm.noundef}{{.*}})
// LLVM: define dso_local i32 @take_char_int(ptr noundef byval(%struct.CharInt) align 8 %{{.+}})
// LLVM: define dso_local void @ret_char_int(ptr dead_on_unwind noalias writable sret(%struct.CharInt) align 1 %{{.+}}, i32 noundef %{{.+}})
@@ -162,14 +162,14 @@ TwoFloatChar ret_two_float_char(float x) { TwoFloatChar v = {x, x, 0}; return v;
// two eightbytes that decides.
int take_seventeen(Seventeen v) { return v.a[3]; }
-// CIR: cir.func{{.*}} @take_seventeen(%arg0: !cir.ptr<!rec_Seventeen> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Seventeen, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_seventeen(%arg0: !cir.ptr<!rec_Seventeen> {llvm.align = 8 : i64, llvm.byval = !rec_Seventeen, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_seventeen(ptr noundef byval(%struct.Seventeen) align 8 %{{.+}})
// Packed and over-aligned at once, so the record carries a pad member and the
// packed mark together. The misaligned int still decides it.
int take_packed_ov(PackedOv v) { return v.i; }
-// CIR: cir.func{{.*}} @take_packed_ov(%arg0: !cir.ptr<!rec_PackedOv> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_PackedOv, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_packed_ov(%arg0: !cir.ptr<!rec_PackedOv> {llvm.align = 8 : i64, llvm.byval = !rec_PackedOv, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_packed_ov(ptr noundef byval(%struct.PackedOv) align 8 %{{.+}})
// A packed member reaches the classifier through an enclosing record and
@@ -180,8 +180,8 @@ int take_arr_packed(ArrPacked v) { return v.a[1].i; }
int take_nest_nine(NestNine v) { return v.n.b; }
int take_arr_nine(ArrNine v) { return v.n[0].b; }
-// CIR: cir.func{{.*}} @take_nest_packed(%arg0: !cir.ptr<!rec_NestPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_NestPacked, llvm.noundef}{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @take_arr_packed(%arg0: !cir.ptr<!rec_ArrPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_ArrPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_nest_packed(%arg0: !cir.ptr<!rec_NestPacked> {llvm.align = 8 : i64, llvm.byval = !rec_NestPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_arr_packed(%arg0: !cir.ptr<!rec_ArrPacked> {llvm.align = 8 : i64, llvm.byval = !rec_ArrPacked, llvm.noundef}{{.*}}) -> !s32i
// CIR: cir.func{{.*}} @take_nest_nine(%arg0: !u64i{{.*}}, %arg1: !s8i{{.*}}) -> !s32i
// CIR: cir.func{{.*}} @take_arr_nine(%arg0: !u64i{{.*}}, %arg1: !s8i{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_nest_packed(ptr noundef byval(%struct.NestPacked) align 8 %{{.+}})
@@ -199,5 +199,5 @@ int take_upacked(UPacked v) { return v.i; }
// #pragma pack reaches the same layout as the attribute.
int take_pragma_packed(PragmaPacked v) { return v.i; }
-// CIR: cir.func{{.*}} @take_pragma_packed(%arg0: !cir.ptr<!rec_PragmaPacked> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_PragmaPacked, llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_pragma_packed(%arg0: !cir.ptr<!rec_PragmaPacked> {llvm.align = 8 : i64, llvm.byval = !rec_PragmaPacked, llvm.noundef}{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_pragma_packed(ptr noundef byval(%struct.PragmaPacked) align 8 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
index fdb65a3c339a2..65f50b41c4d5b 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-padded.c
@@ -93,8 +93,8 @@ TwoFloat ret_twof(float v) { TwoFloat t = {v, v}; return t; }
int take_big(BigPad b) { return b.b; }
BigPad ret_big(int v) { BigPad b = {0, v}; return b; }
-// CIR: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_BigPad> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_BigPad, llvm.noundef} loc{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_BigPad> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_BigPad, llvm.writable} loc{{.*}}, %arg1: !s32i {llvm.noundef} loc{{.*}})
+// CIR: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_BigPad> {llvm.align = 16 : i64, llvm.byval = !rec_BigPad, llvm.noundef} loc{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_BigPad> {llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_BigPad, llvm.writable} loc{{.*}}, %arg1: !s32i {llvm.noundef} loc{{.*}})
// LLVM: define dso_local i32 @take_big(ptr noundef byval(%struct.BigPad) align 16 %{{.+}})
// LLVM: define dso_local void @ret_big(ptr dead_on_unwind noalias writable sret(%struct.BigPad) align 16 %{{.+}}, i32 noundef %{{.+}})
@@ -104,7 +104,7 @@ int take_nest(NestOv n) { return n.o.x; }
int take_arr(ArrOv a) { return a.a[1].x; }
// CIR: cir.func{{.*}} @take_nest(%arg0: !s32i loc{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @take_arr(%arg0: !cir.ptr<!rec_ArrOv> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_ArrOv, llvm.noundef} loc{{.*}}) -> !s32i
+// CIR: cir.func{{.*}} @take_arr(%arg0: !cir.ptr<!rec_ArrOv> {llvm.align = 16 : i64, llvm.byval = !rec_ArrOv, llvm.noundef} loc{{.*}}) -> !s32i
// LLVM: define dso_local i32 @take_nest(i32 %{{.+}})
// LLVM: define dso_local i32 @take_arr(ptr noundef byval(%struct.ArrOv) align 16 %{{.+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.c
index 5f2dc71c586f3..33fb1c470c4af 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.c
@@ -94,7 +94,7 @@ Wrap16 ret_wrap16(void) {
// LLVM: define{{.*}} { i64, i64 } @ret_wrap16()
void take_wrap40(Wrap40 s) {}
-// CIR: cir.func{{.*}} @take_wrap40(%arg0: !cir.ptr<!rec_Wrap40> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Wrap40, llvm.noundef} loc
+// CIR: cir.func{{.*}} @take_wrap40(%arg0: !cir.ptr<!rec_Wrap40> {llvm.align = 8 : i64, llvm.byval = !rec_Wrap40, llvm.noundef} loc
// LLVM: define{{.*}} void @take_wrap40(ptr noundef byval(%struct.Wrap40) align 8 %{{[^,)]+}})
Wrap40 ret_wrap40(void) {
@@ -102,7 +102,7 @@ Wrap40 ret_wrap40(void) {
s.u.x = 1;
return s;
}
-// CIR: cir.func{{.*}} @ret_wrap40(%arg0: !cir.ptr<!rec_Wrap40> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrap40, llvm.writable} loc
+// CIR: cir.func{{.*}} @ret_wrap40(%arg0: !cir.ptr<!rec_Wrap40> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrap40, llvm.writable} loc
// LLVM: define{{.*}} void @ret_wrap40(ptr dead_on_unwind noalias writable sret(%struct.Wrap40) align 4 %{{[^,)]+}})
// The declared extent has to be found through the array.
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.cpp
index d57df707ff900..1014801df5dd6 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-union-bitfield.cpp
@@ -30,5 +30,5 @@ void take_bit_empty_span(BitEmptySpan u) {}
// A union that cannot pass in registers is returned through an sret slot, so
// the declared extent decides only whether it can be classified at all.
NoRegs ret_no_regs() { return NoRegs(); }
-// CIR: cir.func{{.*}} @_Z11ret_no_regsv(%arg0: !cir.ptr<!rec_NoRegs> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NoRegs, llvm.writable} loc
+// CIR: cir.func{{.*}} @_Z11ret_no_regsv(%arg0: !cir.ptr<!rec_NoRegs> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NoRegs, llvm.writable} loc
// LLVM: define{{.*}} void @_Z11ret_no_regsv(ptr dead_on_unwind noalias writable sret(%union.NoRegs) align 4 %{{[^,)]+}})
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
index 3f251e46ef047..c7d3d4aa8c335 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
@@ -66,12 +66,12 @@ int call_small(Pair2 p, Pair16 q) { return vf(p, q); }
// Larger than two eightbytes is MEMORY regardless of register availability.
int call_big(Pair2 p, Big b) { return vf(p, b); }
-// CIR-LABEL: cir.func {{.*}}@call_big(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_big(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: %{{[0-9]+}} = cir.load %arg1 : !cir.ptr<!rec_Big>, !rec_Big
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
// CIR copies the incoming byval slot before forwarding it. OGCG does not.
// LLVM-CIR-LABEL: define dso_local i32 @call_big(
@@ -94,7 +94,7 @@ int call_exhausted(Pair2 p, long a, long b, long c, long d, Pair16 q) {
return vf(p, a, b, c, d, q);
}
-// CIR-LABEL: cir.func {{.*}}@call_exhausted(%arg0: !u64i loc({{.+}}), %arg1: !s64i {llvm.noundef} loc({{.+}}), %arg2: !s64i {llvm.noundef} loc({{.+}}), %arg3: !s64i {llvm.noundef} loc({{.+}}), %arg4: !s64i {llvm.noundef} loc({{.+}}), %arg5: !cir.ptr<!rec_Pair16> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_exhausted(%arg0: !u64i loc({{.+}}), %arg1: !s64i {llvm.noundef} loc({{.+}}), %arg2: !s64i {llvm.noundef} loc({{.+}}), %arg3: !s64i {llvm.noundef} loc({{.+}}), %arg4: !s64i {llvm.noundef} loc({{.+}}), %arg5: !cir.ptr<!rec_Pair16> {llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: cir.store %arg1, %[[AS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
// CIR: cir.store %arg2, %[[BS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
// CIR: cir.store %arg3, %[[CS:[0-9]+]] : !s64i, !cir.ptr<!s64i>
@@ -106,7 +106,7 @@ int call_exhausted(Pair2 p, long a, long b, long c, long d, Pair16 q) {
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Pair16>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_Pair16, !cir.ptr<!rec_Pair16>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[AV]], %[[BV]], %[[CV]], %[[DV]], %[[COPY]]) : (!u64i, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !cir.ptr<!rec_Pair16> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[AV]], %[[BV]], %[[CV]], %[[DV]], %[[COPY]]) : (!u64i, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !s64i {llvm.noundef}, !cir.ptr<!rec_Pair16> {llvm.align = 8 : i64, llvm.byval = !rec_Pair16, llvm.noundef}) -> !s32i
// LLVM-CIR-LABEL: define dso_local i32 @call_exhausted(
// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], i64 noundef %[[A:[0-9a-zA-Z._]+]], i64 noundef %[[B:[0-9a-zA-Z._]+]], i64 noundef %[[C:[0-9a-zA-Z._]+]], i64 noundef %[[D:[0-9a-zA-Z._]+]], ptr noundef byval(%struct.Pair16) align 8 %[[Q:[0-9a-zA-Z._]+]])
@@ -177,12 +177,12 @@ int call_wide(Pair2 p, Wide w) { return vf(p, w); }
// memory, and the 128-bit member keeps the slot at 16-byte alignment.
int call_wide_char(Pair2 p, WideChar w) { return vf(p, w); }
-// CIR-LABEL: cir.func {{.*}}@call_wide_char(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_WideChar> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@call_wide_char(%arg0: !u64i loc({{.+}}), %arg1: !cir.ptr<!rec_WideChar> {llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef} loc({{.+}})) -> !s32i
// CIR: %{{[0-9]+}} = cir.load %arg1 : !cir.ptr<!rec_WideChar>, !rec_WideChar
// CIR: %[[PV:[0-9]+]] = cir.load %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
// CIR-NEXT: %[[COPY:[0-9]+]] = cir.alloca "byval" align(16) : !cir.ptr<!rec_WideChar>
// CIR-NEXT: cir.store %{{[0-9]+}}, %[[COPY]] : !rec_WideChar, !cir.ptr<!rec_WideChar>
-// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_WideChar> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef}) -> !s32i
+// CIR-NEXT: %{{[0-9]+}} = cir.call @vf(%[[PV]], %[[COPY]]) : (!u64i, !cir.ptr<!rec_WideChar> {llvm.align = 16 : i64, llvm.byval = !rec_WideChar, llvm.noundef}) -> !s32i
// LLVM-CIR-LABEL: define dso_local i32 @call_wide_char(
// LLVM-CIR-SAME: i64 %[[P:[0-9a-zA-Z._]+]], ptr noundef byval(%struct.WideChar) align 16 %[[W:[0-9a-zA-Z._]+]])
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
index d76e3b90be91c..e55fca949bc14 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-vptr.cpp
@@ -20,13 +20,13 @@ struct VirtInherit : virtual VBase { long b; };
// passed by invisible reference whatever its eightbytes classify as.
int takePoly(Poly v, int k) { return k; }
-// CIR: cir.func {{.*}}@_Z8takePoly4Polyi(%arg0: !cir.ptr<!rec_Poly> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z8takePoly4Polyi(%arg0: !cir.ptr<!rec_Poly> {llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}, %arg1: !s32i {{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z8takePoly4Polyi(ptr nofreeobj noundef align 8 dereferenceable(8) %{{[^,]+}}, i32 noundef %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z8takePoly4Polyi(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(8) %{{[^,]+}}, i32 noundef %{{[^,)]+}})
int takePolyLong(PolyLong v) { return 0; }
-// CIR: cir.func {{.*}}@_Z12takePolyLong8PolyLong(%arg0: !cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z12takePolyLong8PolyLong(%arg0: !cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
@@ -34,14 +34,14 @@ int takePolyLong(PolyLong v) { return 0; }
// would have classified as on their own.
int takePolyTwoInt(PolyTwoInt v) { return v.y; }
-// CIR: cir.func {{.*}}@_Z14takePolyTwoInt10PolyTwoInt(%arg0: !cir.ptr<!rec_PolyTwoInt> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z14takePolyTwoInt10PolyTwoInt(%arg0: !cir.ptr<!rec_PolyTwoInt> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z14takePolyTwoInt10PolyTwoInt(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z14takePolyTwoInt10PolyTwoInt(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
// Past two eightbytes SysV says memory on its own, so the two rules agree here.
int takePolyBig(PolyBig v) { return 0; }
-// CIR: cir.func {{.*}}@_Z11takePolyBig7PolyBig(%arg0: !cir.ptr<!rec_PolyBig> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z11takePolyBig7PolyBig(%arg0: !cir.ptr<!rec_PolyBig> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z11takePolyBig7PolyBig(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z11takePolyBig7PolyBig(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -49,7 +49,7 @@ int takePolyBig(PolyBig v) { return 0; }
// declared here.
int takePolyDerived(PolyDerived v) { return 0; }
-// CIR: cir.func {{.*}}@_Z15takePolyDerived11PolyDerived(%arg0: !cir.ptr<!rec_PolyDerived> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z15takePolyDerived11PolyDerived(%arg0: !cir.ptr<!rec_PolyDerived> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z15takePolyDerived11PolyDerived(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z15takePolyDerived11PolyDerived(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -57,7 +57,7 @@ int takePolyDerived(PolyDerived v) { return 0; }
// vtable pointer and the non-trivial copy constructor with it.
int takeHasPoly(HasPoly v) { return 0; }
-// CIR: cir.func {{.*}}@_Z11takeHasPoly7HasPoly(%arg0: !cir.ptr<!rec_HasPoly> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z11takeHasPoly7HasPoly(%arg0: !cir.ptr<!rec_HasPoly> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z11takeHasPoly7HasPoly(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z11takeHasPoly7HasPoly(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
@@ -65,7 +65,7 @@ int takeHasPoly(HasPoly v) { return 0; }
// though it declares no virtual function of its own.
int takeVirtInherit(VirtInherit v) { return 0; }
-// CIR: cir.func {{.*}}@_Z15takeVirtInherit11VirtInherit(%arg0: !cir.ptr<!rec_VirtInherit> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
+// CIR: cir.func {{.*}}@_Z15takeVirtInherit11VirtInherit(%arg0: !cir.ptr<!rec_VirtInherit> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}{{.*}}) -> (!s32i
// LLVM-CIR: define dso_local noundef i32 @_Z15takeVirtInherit11VirtInherit(ptr nofreeobj noundef align 8 dereferenceable(24) %{{[^,)]+}})
// LLVM-OGCG: define dso_local noundef i32 @_Z15takeVirtInherit11VirtInherit(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(24) %{{[^,)]+}})
@@ -75,7 +75,7 @@ PolyLong makePolyLong() {
return p;
}
-// CIR: cir.func {{.*}}@_Z12makePolyLongv(%arg0: !cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_PolyLong, llvm.writable}
+// CIR: cir.func {{.*}}@_Z12makePolyLongv(%arg0: !cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_PolyLong, llvm.writable}
// LLVM: define dso_local void @_Z12makePolyLongv(ptr dead_on_unwind noalias writable sret(%struct.PolyLong) align 8 %{{[^,)]+}})
PolyLong retPolyLong();
@@ -86,13 +86,13 @@ int caller(int k) {
}
// CIR: cir.func {{.*}}@_Z6calleri(%arg0: !s32i {{.*}}) -> (!s32i
-// CIR: cir.call @_Z11retPolyLongv(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable}) -> ()
-// CIR: cir.call @_Z12takePolyLong8PolyLong(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}) -> (!s32i
+// CIR: cir.call @_Z11retPolyLongv(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable}) -> ()
+// CIR: cir.call @_Z12takePolyLong8PolyLong(%{{[0-9]+}}) : (!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef}) -> (!s32i
// LLVM: define dso_local noundef i32 @_Z6calleri(i32 noundef %{{[^,)]+}})
// LLVM: call void @_Z11retPolyLongv(ptr dead_on_unwind writable sret(%struct.PolyLong) align 8 %{{[^,)]+}})
// LLVM-CIR: call noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// LLVM-OGCG: call noundef i32 @_Z12takePolyLong8PolyLong(ptr nofreeobj noundef align 8 dead_on_return dereferenceable(16) %{{[^,)]+}})
// Returned, the class uses sret at its declared alignment.
-// CIR: cir.func private @_Z11retPolyLongv(!cir.ptr<!rec_PolyLong> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable})
+// CIR: cir.func private @_Z11retPolyLongv(!cir.ptr<!rec_PolyLong> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_PolyLong, llvm.writable})
// LLVM: declare void @_Z11retPolyLongv(ptr dead_on_unwind writable sret(%struct.PolyLong) align 8)
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
index 31b5147a818f8..f2766ae511641 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-zero-width-bitfield.c
@@ -198,7 +198,7 @@ void take_union(ZeroWidthUnion u) {}
// Past two eightbytes the record goes to memory, where the widened coerce type
// no longer applies.
void take_too_big(TooBig b) {}
-// CIR: cir.func{{.*}} @take_too_big(%arg0: !cir.ptr<!rec_TooBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_TooBig, llvm.noundef}
+// CIR: cir.func{{.*}} @take_too_big(%arg0: !cir.ptr<!rec_TooBig> {llvm.align = 8 : i64, llvm.byval = !rec_TooBig, llvm.noundef}
// LLVM: define{{.*}} void @take_too_big(ptr noundef byval(%struct.TooBig) align 8 %{{.+}})
Tail ret_tail(void) { Tail t = {3}; return t; }
diff --git a/clang/test/CIR/CodeGen/call.c b/clang/test/CIR/CodeGen/call.c
index 87ec0e7e14e9e..ebc811b7a2aa4 100644
--- a/clang/test/CIR/CodeGen/call.c
+++ b/clang/test/CIR/CodeGen/call.c
@@ -75,7 +75,7 @@ void f7(void) {
// CIR: %[[B:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!rec_Big>, !rec_Big
// CIR-NEXT: %[[SLOT:.+]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CIR-NEXT: cir.store %[[B]], %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
-// CIR-NEXT: cir.call @f5(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @f5(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> ()
// LLVM-LABEL: define{{.*}} void @f7(){{.*}} {
// LLVM: %[[B:.+]] = load %struct.Big, ptr %{{.+}}, align 4
@@ -93,7 +93,7 @@ void f8(void) {
// CIR-LABEL: cir.func{{.*}} @f8(){{.*}} {
// CIR: %[[B:.+]] = cir.alloca "b" align(4) init : !cir.ptr<!rec_Big>
-// CIR-NEXT: cir.call @f6(%[[B]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+// CIR-NEXT: cir.call @f6(%[[B]]) : (!cir.ptr<!rec_Big> {llvm.align = 4 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
// LLVM-LABEL: define{{.*}} void @f8(){{.*}} {
// LLVM: %[[B:.+]] = alloca %struct.Big, align 4
diff --git a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
index eca145bd71213..323ced9c2d521 100644
--- a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper-eh.cpp
@@ -39,7 +39,7 @@ Wrapper makeWrapper() {
: Wrapper::empty();
}
-// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
+// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
// CIR: %[[CLEANUP_COND:.*]] = cir.alloca "cleanup.cond" {{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[AGG_TMP0:.*]] = cir.alloca "agg.tmp0" {{.*}} : !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E>
// CIR: cir.cleanup.scope {
@@ -51,7 +51,7 @@ Wrapper makeWrapper() {
// CIR: cir.call @_ZNSt10unique_ptrI4BaseEC1EPS0_(%[[AGG_TMP0]], %[[SOURCE]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: } else {
// CIR: cir.call @_ZN7Wrapper5emptyEv(%[[RETVAL]])
// CIR: }
@@ -204,7 +204,7 @@ void APFixedPoint::add(int x) const {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_TRUE]]
// CIR: } else {
-// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
+// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_FALSE]]
// CIR: }
@@ -361,7 +361,7 @@ void makeEntry() {
// CIR: %{{.*}} = cir.get_global @g_path
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: }
// CIR: cir.yield
// CIR: } cleanup all {
diff --git a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
index 003b23eeda8a2..825172ad5b43c 100644
--- a/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-conditional-with-wrapper.cpp
@@ -39,7 +39,7 @@ Wrapper makeWrapper() {
: Wrapper::empty();
}
-// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
+// CIR: cir.func {{.*}} @_Z11makeWrapperv(%[[RETVAL:.*]]: !cir.ptr<!rec_Wrapper> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Wrapper, llvm.writable}{{.*}})
// CIR: %[[CLEANUP_COND:.*]] = cir.alloca "cleanup.cond" {{.*}} : !cir.ptr<!cir.bool>
// CIR: %[[AGG_TMP0:.*]] = cir.alloca "agg.tmp0" {{.*}} : !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E>
// CIR: cir.cleanup.scope {
@@ -51,7 +51,7 @@ Wrapper makeWrapper() {
// CIR: cir.call @_ZNSt10unique_ptrI4BaseEC1EPS0_(%[[AGG_TMP0]], %[[SOURCE]])
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN7WrapperC1ESt10unique_ptrI4BaseE(%[[RETVAL]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_std3A3Aunique_ptr3CBase3E> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: } else {
// CIR: cir.call @_ZN7Wrapper5emptyEv(%[[RETVAL]])
// CIR: }
@@ -157,7 +157,7 @@ void APFixedPoint::add(int x) const {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_TRUE]]
// CIR: } else {
-// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
+// CIR: cir.call @_ZN5APInt8uadd_satEv(%[[AGG_TMP]], %[[THISVAL]]) : (!cir.ptr<!rec_APInt> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.sret = !rec_APInt, llvm.writable}, {{.*}}) -> ()
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND_FALSE]]
// CIR: }
@@ -282,7 +282,7 @@ void makeEntry() {
// CIR: %{{.*}} = cir.get_global @g_path
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.store %[[TRUE]], %[[CLEANUP_COND]]
-// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR: cir.call @_ZN5EntryC1E4Path(%[[ENSURED_F]], %[[AGG_TMP0]]) : ({{.*}}, !cir.ptr<!rec_Path> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR: }
// CIR: cir.yield
// CIR: } cleanup normal {
diff --git a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
index 16cac27b96fc7..c9b91f8b552f8 100644
--- a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
+++ b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp
@@ -172,7 +172,7 @@ A foo1() {
// LLVM: define dso_local {{.*}}@{{.*foo2.*}}
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[B1]], i64 24, i1 false)
-// CIR: cir.func {{.*}}@_Z4foo2v(%[[B_RETVAL:.*]]: !cir.ptr<![[STRUCT_B]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_B]], llvm.writable}{{.*}})
+// CIR: cir.func {{.*}}@_Z4foo2v(%[[B_RETVAL:.*]]: !cir.ptr<![[STRUCT_B]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_B]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2b1 : !cir.ptr<![[STRUCT_B]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[B_RETVAL]] align(8) : !cir.ptr<![[STRUCT_B]]>
B foo2() {
@@ -181,7 +181,7 @@ B foo2() {
// LLVM: define dso_local {{.*}}@{{.*foo3.*}}
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[C1]], i64 48, i1 false)
-// CIR: cir.func {{.*}}@_Z4foo3v(%[[C_RETVAL:.*]]: !cir.ptr<![[STRUCT_C]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_C]], llvm.writable}{{.*}})
+// CIR: cir.func {{.*}}@_Z4foo3v(%[[C_RETVAL:.*]]: !cir.ptr<![[STRUCT_C]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_C]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2c1 : !cir.ptr<![[STRUCT_C]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[C_RETVAL]] align(8) : !cir.ptr<![[STRUCT_C]]>
C foo3() {
@@ -317,7 +317,7 @@ void foo7() {
// LLVM: dso_local {{.*}}@{{.*foo8.*}}(
// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{.*}}, ptr align 8 [[D1]], i64 56, i1 false)
// CIR-LABEL: cir.func no_inline dso_local @_Z4foo8v(
-// CIR: %[[D_RETVAL:.*]]: !cir.ptr<![[STRUCT_D]]> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_D]], llvm.writable}{{.*}})
+// CIR: %[[D_RETVAL:.*]]: !cir.ptr<![[STRUCT_D]]> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = ![[STRUCT_D]], llvm.writable}{{.*}})
// CIR: %[[GET_GLOB:.*]] = cir.get_global @_ZL2d1 : !cir.ptr<![[STRUCT_D]]>
// CIR: cir.copy %[[GET_GLOB]] align(8) to %[[D_RETVAL]] align(8) : !cir.ptr<![[STRUCT_D]]>
D foo8() {
diff --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
index b316021ce1de6..3cdf30906f36e 100644
--- a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
@@ -1237,7 +1237,7 @@ void Temp2InArray() {
// CIR-NEXT: %[[CURRENT:.*]] = cir.load %[[ARR_IDX]] : !cir.ptr<!cir.ptr<!rec_CausesTemp2>>, !cir.ptr<!rec_CausesTemp2>
// CIR-NEXT: cir.call @_ZN5Temp2C1Ev(%[[TMP]])
// CIR-NEXT: cir.cleanup.scope {
-// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+// CIR-NEXT: cir.call @_ZN11CausesTemp2C1E5Temp2(%[[CURRENT]], %[[TMP]]) : ({{.*}}, !cir.ptr<!rec_Temp2> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CIR-NEXT: cir.yield
// CIR-NEXT: } cleanup all {
// CIR-NEXT: cir.call @_ZN5Temp2D1Ev(%[[TMP]]) nothrow
diff --git a/clang/test/CIR/CodeGen/side-effect.cpp b/clang/test/CIR/CodeGen/side-effect.cpp
index 446883046f97c..6d32287969e6f 100644
--- a/clang/test/CIR/CodeGen/side-effect.cpp
+++ b/clang/test/CIR/CodeGen/side-effect.cpp
@@ -39,16 +39,20 @@ __attribute__((const))
int const_func() { return 1;}
// Variadic definition: widened with no indirect slot in the signature.
-// CIR: cir.func{{.*}}@const_variadic(%arg0: !s32i {{.*}}, ...) -> !s32i side_effect(const)
+// CIR: cir.func{{.*}}@const_variadic(%arg0: !s32i {{.*}}, ...) -> !s32i side_effect(const_argmem)
__attribute__((const))
int const_variadic(int n, ...) { return n; }
// A definition also gets llvm.noalias on the sret slot, so this is where
// noalias, writable and the widened effect have to coexist.
-// CIR: cir.func{{.*}}@const_sret_def(%arg0: !cir.ptr<!rec_Big> {{{.*}}llvm.noalias{{.*}}llvm.sret = !rec_Big{{.*}}llvm.writable{{.*}}) side_effect(const)
+// CIR: cir.func{{.*}}@const_sret_def(%arg0: !cir.ptr<!rec_Big> {{{.*}}llvm.noalias{{.*}}llvm.sret = !rec_Big{{.*}}llvm.writable{{.*}}) side_effect(const_argmem)
__attribute__((const))
Big const_sret_def() { Big r{}; return r; }
+// CIR: cir.func{{.*}}@pure_sret_def(%arg0: !cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}) side_effect(pure_argmem)
+__attribute__((pure))
+Big pure_sret_def() { Big r{}; return r; }
+
void use() {
// Unwidened at a call site: neither takes an indirect slot.
// CIR: cir.call @pure_func() side_effect(pure)
@@ -57,16 +61,16 @@ void use() {
const_func();
// The pass has already given these calls their sret operand.
- // CIR: cir.call @const_sret(%{{.+}}) side_effect(const)
+ // CIR: cir.call @const_sret(%{{.+}}) side_effect(const_argmem)
const_sret();
- // CIR: cir.call @pure_sret(%{{.+}}) side_effect(pure)
+ // CIR: cir.call @pure_sret(%{{.+}}) side_effect(pure_argmem)
pure_sret();
Big b{};
int i = 0;
- // CIR: cir.call @const_byval({{.*}}) side_effect(const)
+ // CIR: cir.call @const_byval({{.*}}) side_effect(const_argmem) : (!cir.ptr<!rec_Big> {{{.*}}llvm.byval = !rec_Big{{.*}}}) -> !s32i
const_byval(b);
- // CIR: cir.call @pure_byval({{.*}}) side_effect(pure)
+ // CIR: cir.call @pure_byval({{.*}}) side_effect(pure_argmem) : (!cir.ptr<!rec_Big> {{{.*}}llvm.byval = !rec_Big{{.*}}}) -> !s32i
pure_byval(b);
// CIR: cir.call @const_small() side_effect(const)
@@ -83,25 +87,24 @@ void use() {
// CIR: cir.call @const_variadic_decl({{.*}}) side_effect(const)
const_variadic_decl(1);
- // CIR: cir.call @const_byval2({{.*}}) side_effect(const) : (!s32i{{.*}}, !cir.ptr<!rec_Big> {{{.*}}llvm.byval{{.*}}}) -> !s32i
+ // CIR: cir.call @const_byval2({{.*}}) side_effect(const_argmem) : (!s32i{{.*}}, !cir.ptr<!rec_Big> {{{.*}}llvm.byval{{.*}}}) -> !s32i
const_byval2(1, b);
- // CIR: cir.call @const_sret_def(%{{.+}}) side_effect(const)
+ // CIR: cir.call @const_sret_def(%{{.+}}) side_effect(const_argmem)
const_sret_def();
- // A reference is a direct pointer slot that still carries align, so neither
- // align nor a record pointee can stand in for an indirect slot.
+ // A reference parameter is a pointer the source wrote, not a slot the ABI
+ // introduced, so it is not widened.
// CIR: cir.call @const_bigref({{.*}}) side_effect(const) : (!cir.ptr<!rec_Big> {llvm.align{{.*}}) -> !s32i
const_bigref(b);
- // A non-trivially-destructible class passes indirectly without byval, and
- // its slot carries no LLVM attribute that names it as the ABI's own.
+ // A non-trivially-destructible class passes indirectly without byval.
WithDtor w{};
- // CIR: cir.call @const_non_byval({{.*}}) side_effect(const) : (!cir.ptr<!rec_WithDtor> {cir.abi_slot = #cir.abi_slot<non_byval>{{.*}}}) -> !s32i
+ // CIR: cir.call @const_non_byval({{.*}}) side_effect(const_argmem) : (!cir.ptr<!rec_WithDtor> {{{.*}}llvm.nofreeobj{{.*}}}) -> !s32i
const_non_byval(w);
// An argument the ABI rewrites without handing over memory keeps
// memory(none): the slot is dropped, coerced into a register, or flattened
- // into registers. No argument dictionary means no slot mark.
+ // into registers.
// CIR: cir.call @const_ignore() side_effect(const) : () -> !s32i
const_ignore(Empty{});
// CIR: cir.call @const_coerced(%{{.+}}) side_effect(const) : (!u64i) -> !s32i
@@ -110,6 +113,9 @@ void use() {
const_flattened(TwoLong{});
}
+// Declarations print after @use(), so this follows the call sites.
+// CIR: cir.func private @const_variadic_decl(!s32i {{.*}}, ...) -> !s32i side_effect(const_argmem)
+
}
// The named functions appear in the same relative order in both emits, so
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
index 0a1b027fdfd1e..49e83b763f521 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copy.cpp
@@ -11,7 +11,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -73,7 +73,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -142,7 +142,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
index 72dd576229bab..5d2d27f472b98 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copyin.cpp
@@ -259,7 +259,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -321,7 +321,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -390,7 +390,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp b/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
index c85c0dc3a3e5c..00dafcd95371b 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-copyout.cpp
@@ -11,7 +11,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -73,7 +73,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -142,7 +142,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-create.cpp b/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
index 24ae03dfee46f..d55a60519a4ce 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-create.cpp
@@ -260,7 +260,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -322,7 +322,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -391,7 +391,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp b/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
index 78a525c77d3e4..9cda9d8bec285 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-deviceresident.cpp
@@ -259,7 +259,7 @@ struct Struct {
// CHECK-NEXT: }
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -321,7 +321,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -390,7 +390,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/CodeGenOpenACC/declare-present.cpp b/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
index 06bc449e01de8..b54dbe7b2b63a 100644
--- a/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/declare-present.cpp
@@ -12,7 +12,7 @@ struct Struct {
static const int StaticMemInt;
void MemFunc1(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc1{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca "this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -74,7 +74,7 @@ void use() {
}
void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}MemFunc2{{.*}}(%{{.*}}: !cir.ptr<!rec_Struct>{{.*}}, %[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: cir.alloca{{.*}}"this"
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
@@ -143,7 +143,7 @@ void Struct::MemFunc2(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEP
extern "C" void do_thing();
extern "C" void NormalFunc(HasSideEffects ArgHSE, int ArgInt, HasSideEffects *ArgHSEPtr) {
- // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
+ // CHECK: cir.func {{.*}}NormalFunc(%[[ARG_HSE:.*]]: !cir.ptr<!rec_HasSideEffects> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef{{.*}}, %[[ARG_INT:.*]]: !s32i {{.*}}, %[[ARG_HSE_PTR:.*]]: !cir.ptr<!rec_HasSideEffects>{{.*}})
// CHECK-NEXT: %[[ARG_INT_ALLOCA:.*]] = cir.alloca "ArgInt" {{.*}} : !cir.ptr<!s32i>
// CHECK-NEXT: %[[ARG_HSE_PTR_ALLOCA:.*]] = cir.alloca "ArgHSEPtr" {{.*}} : !cir.ptr<!cir.ptr<!rec_HasSideEffects>>
// CHECK-NEXT: %[[LOC_HSE_ALLOCA:.*]] = cir.alloca "LocalHSE" {{.*}} : !cir.ptr<!rec_HasSideEffects>
diff --git a/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir b/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
index 061658e11412b..b0df1caa5416b 100644
--- a/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/byval-sret-arg-attr-lowering.cir
@@ -2,9 +2,6 @@
// RUN: | FileCheck %s
// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
// RUN: -cir-to-llvm -o - 2>/dev/null \
-// RUN: | FileCheck %s --check-prefix=MLIR
-// RUN: cir-opt %s -cir-call-conv-lowering="classification-attr=test_classify" \
-// RUN: -cir-to-llvm -o - 2>/dev/null \
// RUN: | cir-translate -mlir-to-llvmir --allow-unregistered-dialect \
// RUN: | FileCheck %s --check-prefix=LLVM
@@ -85,18 +82,4 @@ module attributes {
// LLVM: define void @caller_sret()
// LLVM: call void @ret_big(ptr {{.*}}sret(%struct.Big) align 8 %{{.+}})
-
- // cir.abi_slot in the input, on a signature the pass leaves alone, so the
- // attribute is parsed here rather than only printed. It still reaches
- // cir-to-llvm, which is what the MLIR checks below observe.
- cir.func private @pre_marked(!cir.ptr<!rec_Big>
- {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64})
- attributes { test_classify = #passthrough }
-
- // CHECK: cir.func{{.*}} @pre_marked(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64})
}
-
-// cir.abi_slot is a CIR-level fact, so nothing carries it past cir-to-llvm.
-// The positive check first, so the prefix cannot pass on empty input.
-// MLIR: llvm.func @takes_big(%{{.+}}: !llvm.ptr {llvm.align = 8 : i64, llvm.byval = !llvm.struct<"struct.Big"
-// MLIR-NOT: cir.abi_slot
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
index 65fd9e2cc64ff..90322dc342568 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-byval.cir
@@ -209,7 +209,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[L:.*]] = cir.load %[[PTR]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK-NEXT: cir.return %[[L]] : !rec_Big
@@ -225,7 +225,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval_field(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[M:.*]] = cir.get_member %[[PTR]][0] {name = "a"} : !cir.ptr<!rec_Big> -> !cir.ptr<!s64i>
// CHECK-NEXT: %[[V:.*]] = cir.load %[[M]] : !cir.ptr<!s64i>, !s64i
@@ -259,7 +259,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @takes_big_non_byval_unused(%{{.*}}: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: %[[R:.*]] = cir.const #cir.int<0> : !s32i
@@ -270,7 +270,7 @@ module attributes {
attributes { test_classify = #non_byval_arg }
// CHECK: cir.func{{.*}} @takes_big_non_byval_decl(!cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The call site forwards the caller's temporary instead of copying it.
cir.func @caller_non_byval(%s: !rec_Big) -> !rec_Big
@@ -287,7 +287,7 @@ module attributes {
// CHECK-NEXT: cir.store %[[S]], %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The whole-record load survives when a reader other than the call needs it.
cir.func @caller_non_byval_load_reused(%s: !rec_Big) -> !rec_Big
@@ -303,7 +303,7 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[V:.*]] = cir.load %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK: cir.return %[[V]] : !rec_Big
// CIRGen emits the load immediately before the call, so nothing can write
@@ -326,7 +326,7 @@ module attributes {
// CHECK-NEXT: cir.store %[[T]], %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: %{{.*}} = cir.call @takes_big_non_byval(%[[TMP]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// A non-byval argument between two Direct ones keeps its operand slot.
cir.func private @takes_mixed_non_byval(%a: !s32i, %b: !rec_Big, %c: !s32i)
@@ -344,7 +344,7 @@ module attributes {
// CHECK: cir.func{{.*}} @caller_mixed_non_byval(%[[X:.*]]: !s32i
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.call @takes_mixed_non_byval(%[[X]], %[[TMP]], %[[X]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
// One load feeding two non-byval operands is erased once, not twice.
cir.func private @takes_two_non_byval(%a: !rec_Big, %b: !rec_Big)
@@ -364,7 +364,7 @@ module attributes {
// CHECK-NEXT: cir.store %{{.*}}, %[[TMP]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_two_non_byval(%[[TMP]], %[[TMP]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// The Direct operand keeps reading the load, so the load survives the rewrite.
cir.func private @takes_non_byval_then_direct(%a: !rec_Big, %b: !rec_Big)
@@ -383,7 +383,7 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[V:.*]] = cir.load %[[TMP]] : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: cir.call @takes_non_byval_then_direct(%[[TMP]], %[[V]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef},
// The dead load is erased on the sret early-return path too.
cir.func @non_byval_and_sret(%arg0: !rec_Big) -> !rec_Big
@@ -413,7 +413,7 @@ module attributes {
// CHECK: %[[RET:.*]] = cir.alloca "sret" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.call @non_byval_and_sret(%[[RET]], %[[TMP]]) :
// CHECK-SAME: llvm.sret = !rec_Big
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// A slot aligned above the record's own alignment, matching an
// indirect_align that also exceeds it, is still forwarded.
@@ -433,6 +433,6 @@ module attributes {
// CHECK: %[[TMP:.*]] = cir.alloca "agg.tmp" align(16) : !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval16(%[[TMP]]) :
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 16 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 16 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
index 73449905a47fd..eca64c5975ea1 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-call.cir
@@ -89,7 +89,7 @@ module attributes {
// CHECK: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
// CHECK: cir.store %{{.+}}, %[[SLOT]] : !rec_Big, !cir.ptr<!rec_Big>
// CHECK: %[[CAST:.*]] = cir.cast bitcast %arg0 : !cir.ptr<!cir.func<(!rec_Big) -> !s64i>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>
- // CHECK: cir.call %[[CAST]](%[[SLOT]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+ // CHECK: cir.call %[[CAST]](%[[SLOT]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>) -> !s64i>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// Indirect call returning a large struct: an sret pointer slot is prepended
// and the callee is bitcast to the void-returning sret signature.
@@ -101,5 +101,5 @@ module attributes {
// CHECK: cir.func{{.*}} @call_sret(%arg0: !cir.ptr<!cir.func<() -> !rec_Big>>)
// CHECK: %[[SRET:.*]] = cir.alloca "sret" align(8) : !cir.ptr<!rec_Big>
// CHECK: %[[SCAST:.*]] = cir.cast bitcast %arg0 : !cir.ptr<!cir.func<() -> !rec_Big>> -> !cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>
- // CHECK: cir.call %[[SCAST]](%[[SRET]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
+ // CHECK: cir.call %[[SCAST]](%[[SRET]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Big>)>>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) -> ()
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir b/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
index b90c7ffd868b6..2fd34fd3aaedd 100644
--- a/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/indirect-non-byval-forward-param.cir
@@ -30,11 +30,11 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_non_byval_param(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -72,11 +72,11 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_non_byval_param_via_slot(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -114,17 +114,17 @@ module attributes {
}
// CHECK: cir.func{{.*}} @ping(%[[PING:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @pong(%[[PING]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
// CHECK: cir.func{{.*}} @pong(%[[PONG:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK-NOT: cir.load
// CHECK: cir.call @ping(%[[PONG]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -163,10 +163,10 @@ module attributes {
}
// CHECK: cir.func{{.*}} @expand_ahead_of_non_byval(%{{.*}}: !s64i, %{{.*}}: !s64i, %[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -217,7 +217,7 @@ module attributes {
// CHECK: %[[MID:.*]] = cir.cast bitcast %[[RAW]] : !cir.ptr<!cir.array<!s8i x 32>> -> !cir.ptr<!s8i>
// CHECK: %[[SLOT:.*]] = cir.cast bitcast %[[MID]] : !cir.ptr<!s8i> -> !cir.ptr<!rec_Big>
// CHECK-NOT: cir.load %[[SLOT]] : !cir.ptr<!rec_Big>
- // CHECK: cir.call @takes_big_non_byval(%[[SLOT]]) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK: cir.call @takes_big_non_byval(%[[SLOT]]) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -259,10 +259,10 @@ module attributes {
// CHECK: cir.func{{.*}} @sret_forwards_non_byval_param(
// CHECK-SAME: llvm.sret = !rec_Big
// CHECK-SAME: %[[PTR:[^:]*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca "arg0"
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
cir.func private @takes_big_non_byval(%arg0: !rec_Big)
attributes { test_classify = #non_byval_arg }
@@ -301,10 +301,10 @@ module attributes {
}
// CHECK: cir.func{{.*}} @forwards_param_over_underaligned_slot(%[[PTR:.*]]: !cir.ptr<!rec_Big>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: cir.call @takes_big_non_byval(%[[PTR]]) :
- // CHECK-SAME: (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
+ // CHECK-SAME: (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 32 : i64, llvm.nofreeobj, llvm.noundef}) -> ()
}
@@ -384,7 +384,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @expands_non_byval_param(%[[PTR:.*]]: !cir.ptr<!rec_Two>
- // CHECK-SAME: {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-SAME: {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// CHECK-NOT: cir.alloca
// CHECK: %[[F0:.*]] = cir.get_member %[[PTR]][0]
// CHECK: %[[V0:.*]] = cir.load %[[F0]]
diff --git a/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
index c5a2e99ca7fdb..6cecb929048dd 100644
--- a/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/side-effect-argmem.cir
@@ -55,48 +55,46 @@ module attributes {
#dlti.dl_entry<i64, dense<64>: vector<2xi64>>>
} {
+ // Dictionaries print sorted by name, so these pins are in key order.
cir.func private @const_sret() -> !rec_Big side_effect(const)
attributes { test_classify = #sret_ret }
- // Dictionaries print sorted by name, so these pins are in key order.
- // CHECK: cir.func{{.*}} @const_sret(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(const)
+ // CHECK: cir.func{{.*}} @const_sret(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(const_argmem)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
cir.func private @pure_sret() -> !rec_Big side_effect(pure)
attributes { test_classify = #sret_ret }
- // CHECK: cir.func{{.*}} @pure_sret(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(pure)
+ // CHECK: cir.func{{.*}} @pure_sret(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(pure_argmem)
// LLVM: ; Function Attrs: nounwind willreturn memory(read, argmem: readwrite)
// LLVM-NEXT: declare void @pure_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
cir.func private @const_byval(!s32i, !rec_Big) side_effect(const)
attributes { test_classify = #byval_arg }
- // CHECK: cir.func{{.*}} @const_byval(!s32i, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) side_effect(const)
+ // CHECK: cir.func{{.*}} @const_byval(!s32i, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) side_effect(const_argmem)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare void @const_byval(i32, ptr noundef byval(%struct.Big) align 8)
- // No LLVM attribute on a non-byval slot names it as the ABI's own, so
- // cir.abi_slot is what identifies it.
+ // An indirect argument without byval widens the same as byval.
cir.func private @const_non_byval(!rec_Big) side_effect(const)
attributes { test_classify = #non_byval_arg }
- // CHECK: cir.func{{.*}} @const_non_byval(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}) side_effect(const)
+ // CHECK: cir.func{{.*}} @const_non_byval(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dereferenceable = 24 : i64, llvm.nofreeobj, llvm.noundef}) side_effect(const_argmem)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare void @const_non_byval(ptr nofreeobj noundef align 8 dereferenceable(24))
cir.func private @const_variadic(!s8i, ...) -> !s32i side_effect(const)
attributes { test_classify = #extend_arg }
- // Widened for being variadic, which lowering decides from the signature,
- // not from a slot mark.
- // CHECK: cir.func{{.*}} @const_variadic(!s8i {llvm.signext}, ...) -> !s32i side_effect(const)
+ // Variadic with no indirect slot in the signature.
+ // CHECK: cir.func{{.*}} @const_variadic(!s8i {llvm.signext}, ...) -> !s32i side_effect(const_argmem)
// LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
// LLVM-NEXT: declare i32 @const_variadic(i8 signext, ...)
- // Negative: an Extend argument carries a non-empty attribute dictionary but
- // no ABI-introduced memory, so the effect stays memory(none).
+ // Negative: an Extend argument is rewritten but hands the callee no memory,
+ // so the effect stays memory(none).
cir.func private @const_extend(!s8i) -> !s32i side_effect(const)
attributes { test_classify = #extend_arg }
@@ -110,20 +108,34 @@ module attributes {
cir.func private @const_expand(!rec_Big) -> !s32i side_effect(const)
attributes { test_classify = #expand_arg }
+ // CHECK: cir.func{{.*}} @const_expand(!s64i, !s64i, !s64i) -> !s32i side_effect(const)
// LLVM: ; Function Attrs: nounwind willreturn memory(none)
// LLVM-NEXT: declare i32 @const_expand(i64, i64, i64)
+ // Already widened in the input, on a signature the pass still rewrites, so
+ // the value is parsed here rather than only printed, and widening it again
+ // changes nothing.
+ cir.func private @prewidened_sret() -> !rec_Big side_effect(const_argmem)
+ attributes { test_classify = #sret_ret }
+
+ // CHECK: cir.func{{.*}} @prewidened_sret(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) side_effect(const_argmem)
+ // LLVM: ; Function Attrs: nounwind willreturn memory(argmem: readwrite)
+ // LLVM-NEXT: declare void @prewidened_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8)
+
// A callee with no side_effect must still come out with none, so that
// forwarding the original is distinguishable from hard-coding a value.
cir.func private @plain_sret() -> !rec_Big
attributes { test_classify = #sret_ret }
+ // CHECK: cir.func{{.*}} @plain_sret(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}) attributes
+ // LLVM: declare void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8){{$}}
+
cir.func @call_plain_sret() attributes { test_classify = #passthrough } {
%r = cir.call @plain_sret() : () -> !rec_Big
cir.return
}
- // CHECK: cir.call @plain_sret(%{{[^)]+}}) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) : (!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) -> ()
// LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}){{$}}
// nothrow without const or pure still reaches nounwind, and still gets no
@@ -133,7 +145,7 @@ module attributes {
cir.return
}
- // CHECK: cir.call @plain_sret(%{{[^)]+}}) nothrow : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
+ // CHECK: cir.call @plain_sret(%{{[^)]+}}) nothrow : (!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) -> ()
// LLVM: call void @plain_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[NOTHROW_CALL:[0-9]+]]
// The call site keeps its side_effect across the rewrite.
@@ -143,7 +155,7 @@ module attributes {
}
// CHECK: cir.func{{.*}} @call_const_sret()
- // CHECK: cir.call @const_sret(%{{.+}}) side_effect(const) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>{{.*}}}) -> ()
+ // CHECK: cir.call @const_sret(%{{.+}}) side_effect(const_argmem) : (!cir.ptr<!rec_Big> {{{.*}}llvm.sret = !rec_Big{{.*}}}) -> ()
// LLVM: define void @call_const_sret()
// LLVM: call void @const_sret(ptr dead_on_unwind writable sret(%struct.Big) align 8 %{{.+}}) #[[CALL_ATTRS:[0-9]+]]
// LLVM-DAG: attributes #[[CALL_ATTRS]] = { nounwind willreturn memory(argmem: readwrite) }
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
index 3da68d91a8e3f..adff98cb043fb 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitfield.cir
@@ -71,7 +71,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_bf_pad(%arg0: !cir.ptr<!rec_BFPad> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_BFPad, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_bf_pad(%arg0: !cir.ptr<!rec_BFPad> {llvm.align = 8 : i64, llvm.byval = !rec_BFPad, llvm.noundef})
// A zero-width bit-field takes no part in assigning eightbyte classes, but
// the type it was declared with still marks the bits it sits in as read, so
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
index 3fbc65943b9ca..03f93ce4bc49c 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
@@ -768,7 +768,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_o(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_O, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_O>, !rec_O
// CHECK-NEXT: cir.return
@@ -789,7 +789,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @ret_o(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_O> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_O
// CHECK-SAME: , llvm.writable})
// CHECK-NEXT: %[[Z:[0-9]+]] = cir.const #cir.zero : !rec_O
@@ -809,7 +809,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_arr(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_Arr> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_Arr> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_Arr, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_Arr>, !rec_Arr
// CHECK-NEXT: cir.return
@@ -827,7 +827,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_b200(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !cir.int<s, 200, bitint>, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0
// CHECK-SAME: : !cir.ptr<!cir.int<s, 200, bitint>>, !cir.int<s, 200, bitint>
@@ -851,14 +851,14 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @call_b200(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !cir.int<s, 200, bitint>, llvm.noundef})
// CHECK: %[[SLOT:[0-9]+]] = cir.alloca "byval" align(8)
// CHECK-SAME: : !cir.ptr<!cir.int<s, 200, bitint>>
// CHECK-NEXT: cir.store %{{[0-9]+}}, %[[SLOT]]
// CHECK-SAME: : !cir.int<s, 200, bitint>, !cir.ptr<!cir.int<s, 200, bitint>>
// CHECK-NEXT: cir.call @take_b200(%[[SLOT]])
- // CHECK-SAME: : (!cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: : (!cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !cir.int<s, 200, bitint>, llvm.noundef}) -> ()
// LLVM-LABEL: define void @call_b200(
@@ -876,7 +876,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_b201(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 201, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 201, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !cir.int<s, 201, bitint>, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0
// CHECK-SAME: : !cir.ptr<!cir.int<s, 201, bitint>>, !cir.int<s, 201, bitint>
@@ -895,7 +895,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_ub200(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<u, 200, bitint>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<u, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !cir.int<u, 200, bitint>, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0
// CHECK-SAME: : !cir.ptr<!cir.int<u, 200, bitint>>, !cir.int<u, 200, bitint>
@@ -921,7 +921,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @ret_b200(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.dead_on_unwind, llvm.noalias, llvm.sret = !cir.int<s, 200, bitint>
// CHECK-SAME: , llvm.writable})
// CHECK-NEXT: %[[C:[0-9]+]] = cir.const #cir.int<5> : !cir.int<s, 200, bitint>
@@ -947,11 +947,11 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @call_ret_b200(
- // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.dead_on_unwind, llvm.noalias, llvm.sret = !cir.int<s, 200, bitint>
// CHECK-SAME: , llvm.writable})
// CHECK-NEXT: cir.call @ret_b200(%arg0)
- // CHECK-SAME: : (!cir.ptr<!cir.int<s, 200, bitint>> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64
+ // CHECK-SAME: : (!cir.ptr<!cir.int<s, 200, bitint>> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.dead_on_unwind, llvm.sret = !cir.int<s, 200, bitint>, llvm.writable}) -> ()
// CHECK-NEXT: cir.return
@@ -969,7 +969,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_d(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_D> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_D> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_D, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_D>, !rec_D
// CHECK-NEXT: cir.return
@@ -987,7 +987,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_ud(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_UD> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_UD> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_UD, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_UD>, !rec_UD
// CHECK-NEXT: cir.return
@@ -1004,7 +1004,7 @@ module attributes {
}
// CHECK-LABEL: cir.func{{.*}} @take_ad(
- // CHECK-SAME: %arg0: !cir.ptr<!rec_AD> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64
+ // CHECK-SAME: %arg0: !cir.ptr<!rec_AD> {llvm.align = 8 : i64
// CHECK-SAME: , llvm.byval = !rec_AD, llvm.noundef})
// CHECK-NEXT: %{{[0-9]+}} = cir.load %arg0 : !cir.ptr<!rec_AD>, !rec_AD
// CHECK-NEXT: cir.return
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
index 885db2ff782cb..9f443a7e70e7e 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
@@ -199,7 +199,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nofreeobj, llvm.noundef})
// LLVM: define void @take_ntc_empty(ptr nofreeobj noundef align 1 dereferenceable(1) %{{.*}})
// The same record returned goes through sret rather than being dropped.
@@ -209,7 +209,7 @@ module attributes {
cir.return %1 : !rec_NTCE
}
- // CHECK: cir.func{{.*}} @ret_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NTCE, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_ntc_empty(%arg0: !cir.ptr<!rec_NTCE> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_NTCE, llvm.writable})
// LLVM: define void @ret_ntc_empty(ptr dead_on_unwind noalias writable sret(%struct.NTCE) align 1 %{{.*}})
// At exactly two eightbytes an empty class is still dropped.
@@ -237,7 +237,7 @@ module attributes {
cir.return %arg1 : !s32i
}
- // CHECK: cir.func{{.*}} @take_empty_big(%arg0: !cir.ptr<!rec_EBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_EBig, llvm.noundef}, %arg1: !s32i) -> !s32i
+ // CHECK: cir.func{{.*}} @take_empty_big(%arg0: !cir.ptr<!rec_EBig> {llvm.align = 32 : i64, llvm.byval = !rec_EBig, llvm.noundef}, %arg1: !s32i) -> !s32i
// LLVM: define i32 @take_empty_big(ptr noundef byval(%struct.EBig) align 32 %{{.*}}, i32 %{{.*}})
// The same record returned uses sret at that alignment.
@@ -247,7 +247,7 @@ module attributes {
cir.return %1 : !rec_EBig
}
- // CHECK: cir.func{{.*}} @ret_empty_big(%arg0: !cir.ptr<!rec_EBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_EBig, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_empty_big(%arg0: !cir.ptr<!rec_EBig> {llvm.align = 32 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_EBig, llvm.writable})
// LLVM: define void @ret_empty_big(ptr dead_on_unwind noalias writable sret(%struct.EBig) align 32 %{{.*}})
// A call site drops the operand as well as the parameter.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
index 66131e731ca1e..90eca9f09b3e5 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-record-packed.cir
@@ -79,7 +79,7 @@ module attributes {
cir.return
}
- // CHECK-LABEL: cir.func{{.*}} @take_p(%arg0: !cir.ptr<!rec_P> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 1 : i64, llvm.dereferenceable = 5 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK-LABEL: cir.func{{.*}} @take_p(%arg0: !cir.ptr<!rec_P> {llvm.align = 1 : i64, llvm.dereferenceable = 5 : i64, llvm.nofreeobj, llvm.noundef})
// A union coerces through the same one-register path as FiveShort.
cir.func @take_upacked(%arg0: !rec_UPacked) {
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
index f57bee7b0ca9a..c843ff0026604 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-indirect.cir
@@ -30,7 +30,7 @@ module attributes {
cir.return %2 : !s64i
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s64i
// CHECK: %[[VAL:.*]] = cir.load %arg0 : !cir.ptr<!rec_Big>, !rec_Big
// CHECK: %[[LOCAL:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!rec_Big>
// CHECK: cir.store %[[VAL]], %[[LOCAL]] : !rec_Big, !cir.ptr<!rec_Big>
@@ -44,7 +44,7 @@ module attributes {
cir.return %1 : !rec_Big
}
- // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable})
// A small struct that cannot pass in registers (non-trivial for ABI) is
// passed indirectly even though its size would otherwise fit a register.
@@ -52,7 +52,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_noregs(%arg0: !cir.ptr<!rec_NoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_noregs(%arg0: !cir.ptr<!rec_NoRegs> {llvm.align = 4 : i64, llvm.dereferenceable = 8 : i64, llvm.nofreeobj, llvm.noundef})
// {__int128, char} spans more than two eightbytes, so it does not fit in
// registers: the argument is byval and the return uses sret.
@@ -60,7 +60,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big128(%arg0: !cir.ptr<!rec_Big128> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_Big128, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big128(%arg0: !cir.ptr<!rec_Big128> {llvm.align = 16 : i64, llvm.byval = !rec_Big128, llvm.noundef})
cir.func @ret_big128() -> !rec_Big128 {
%0 = cir.alloca "r" align(16) : !cir.ptr<!rec_Big128>
@@ -68,5 +68,5 @@ module attributes {
cir.return %1 : !rec_Big128
}
- // CHECK: cir.func{{.*}} @ret_big128(%arg0: !cir.ptr<!rec_Big128> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big128, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_big128(%arg0: !cir.ptr<!rec_Big128> {llvm.align = 16 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big128, llvm.writable})
}
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
index 6308a622f16c6..de30f61c0a329 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-struct-padded.cir
@@ -78,7 +78,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 16 : i64, llvm.byval = !rec_Big, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_Big> {llvm.align = 16 : i64, llvm.byval = !rec_Big, llvm.noundef})
// A record the caller must destroy is passed by reference rather than copied,
// so it takes the non-byval form instead of byval even though the size rule
@@ -87,7 +87,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_NoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 16 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_NoRegs> {llvm.align = 16 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// An anonymous record has no entry in cir.record_layouts, so both the
// register-passing decision and the alignment come from the fallbacks.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
index 47ec432e6a662..d3d3ca779afb3 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-union.cir
@@ -195,7 +195,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big(%arg0: !cir.ptr<!rec_UBig> {llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
// CHECK: %{{.*}} = cir.load %arg0 : !cir.ptr<!rec_UBig>, !rec_UBig
// The byval alignment comes from the record's declared alignment, which the
@@ -205,7 +205,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big_over_aligned(%arg0: !cir.ptr<!rec_UBigOverAligned> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigOverAligned, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big_over_aligned(%arg0: !cir.ptr<!rec_UBigOverAligned> {llvm.align = 32 : i64, llvm.byval = !rec_UBigOverAligned, llvm.noundef})
// The same declared-alignment source feeds every accepted record, not just
// unions: an over-aligned STRUCT gets the same byval alignment fix, since
@@ -214,7 +214,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_struct_over_aligned(%arg0: !cir.ptr<!rec_SOverAligned> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_SOverAligned, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_struct_over_aligned(%arg0: !cir.ptr<!rec_SOverAligned> {llvm.align = 32 : i64, llvm.byval = !rec_SOverAligned, llvm.noundef})
// A union with no members classifies Ignore and is dropped from the
// signature.
@@ -311,7 +311,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_big_empty_int(%arg0: !cir.ptr<!rec_UBigEmptyInt> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !rec_UBigEmptyInt, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_big_empty_int(%arg0: !cir.ptr<!rec_UBigEmptyInt> {llvm.align = 32 : i64, llvm.byval = !rec_UBigEmptyInt, llvm.noundef})
// More than one empty member is skipped the same way.
cir.func @take_two_empty(%arg0: !rec_UTwoEmpty) {
@@ -495,7 +495,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_UNoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_no_regs(%arg0: !cir.ptr<!rec_UNoRegs> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
// A union that covers itself only through a bit-field's declared type is
// classified like take_no_regs above, and its argument-passing kind still
@@ -504,7 +504,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_bit_no_regs(%arg0: !cir.ptr<!rec_UBitNoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_bit_no_regs(%arg0: !cir.ptr<!rec_UBitNoRegs> {llvm.align = 4 : i64, llvm.dereferenceable = 4 : i64, llvm.nofreeobj, llvm.noundef})
// A struct member that is itself a union is mapped through the same union
// handling, so the enclosing 8-byte struct coerces to one i64.
@@ -538,7 +538,7 @@ module attributes {
cir.return %1 : !rec_UBig
}
- // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBig, llvm.writable}, %arg1: !cir.ptr<!rec_UBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @ret_big(%arg0: !cir.ptr<!rec_UBig> {llvm.align = 1 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_UBig, llvm.writable}, %arg1: !cir.ptr<!rec_UBig> {llvm.align = 8 : i64, llvm.byval = !rec_UBig, llvm.noundef})
// CHECK: %[[VAL:.*]] = cir.load %arg1 : !cir.ptr<!rec_UBig>, !rec_UBig
// CHECK: cir.store %[[VAL]], %arg0 : !rec_UBig, !cir.ptr<!rec_UBig>
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
index 8125794327232..dc3130d5e5d66 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
@@ -28,7 +28,7 @@ module attributes {
// A rewritten variadic declaration keeps its ellipsis.
// CHECK: cir.func private @variadic_pair(!u64i, ...) -> !s32i
- // CHECK: cir.func private @variadic_big(!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, ...)
+ // CHECK: cir.func private @variadic_big(!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, ...)
// Passing nothing through the ellipsis leaves the call at the callee's
// declared parameters.
@@ -86,7 +86,7 @@ module attributes {
// CHECK: cir.func{{.*}} @pass_two_exhausted(%arg0: !cir.ptr<!s8i>, %arg1: !s32i, %arg2: !s64i, %arg3: !s64i)
// CHECK: %[[SLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Two>
- // CHECK: cir.call @variadic(%arg0, %arg1, %arg1, %arg1, %arg1, %arg1, %[[SLOT]]) : (!cir.ptr<!s8i>, !s32i, !s32i, !s32i, !s32i, !s32i, !cir.ptr<!rec_Two> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Two, llvm.noundef}) -> !s32i
+ // CHECK: cir.call @variadic(%arg0, %arg1, %arg1, %arg1, %arg1, %arg1, %[[SLOT]]) : (!cir.ptr<!s8i>, !s32i, !s32i, !s32i, !s32i, !s32i, !cir.ptr<!rec_Two> {llvm.align = 8 : i64, llvm.byval = !rec_Two, llvm.noundef}) -> !s32i
// A record larger than two eightbytes is memory class no matter how many
// registers are free.
@@ -95,9 +95,9 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @pass_big(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef})
+ // CHECK: cir.func{{.*}} @pass_big(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef})
// CHECK: %[[BSLOT:.*]] = cir.alloca "byval" align(8) : !cir.ptr<!rec_Big>
- // CHECK: cir.call @variadic(%arg0, %[[BSLOT]]) : (!cir.ptr<!s8i>, !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
+ // CHECK: cir.call @variadic(%arg0, %[[BSLOT]]) : (!cir.ptr<!s8i>, !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.byval = !rec_Big, llvm.noundef}) -> !s32i
// An empty record occupies no register and is dropped, without displacing
// the argument behind it.
@@ -129,8 +129,8 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @pass_wide_vector(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!cir.vector<8 x !cir.float>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef})
- // CHECK: cir.call @variadic(%arg0, %{{.*}}) : (!cir.ptr<!s8i>, !cir.ptr<!cir.vector<8 x !cir.float>> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef}) -> !s32i
+ // CHECK: cir.func{{.*}} @pass_wide_vector(%arg0: !cir.ptr<!s8i>, %arg1: !cir.ptr<!cir.vector<8 x !cir.float>> {llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef})
+ // CHECK: cir.call @variadic(%arg0, %{{.*}}) : (!cir.ptr<!s8i>, !cir.ptr<!cir.vector<8 x !cir.float>> {llvm.align = 32 : i64, llvm.byval = !cir.vector<8 x !cir.float>, llvm.noundef}) -> !s32i
// A declared parameter is coerced the same way whether or not the call also
// passes ellipsis arguments.
@@ -149,8 +149,8 @@ module attributes {
cir.return %0 : !rec_Big
}
- // CHECK: cir.func{{.*}} @pass_sret_return(%arg0: !cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable}, %arg1: !cir.ptr<!s8i>, %arg2: !s32i)
- // CHECK: cir.call @variadic_big(%arg0, %arg1, %arg2) : (!cir.ptr<!rec_Big> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, !s32i) -> ()
+ // CHECK: cir.func{{.*}} @pass_sret_return(%arg0: !cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_Big, llvm.writable}, %arg1: !cir.ptr<!s8i>, %arg2: !s32i)
+ // CHECK: cir.call @variadic_big(%arg0, %arg1, %arg2) : (!cir.ptr<!rec_Big> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.sret = !rec_Big, llvm.writable}, !cir.ptr<!s8i>, !s32i) -> ()
// An indirect variadic call whose ellipsis arguments all pass as written
// needs no rewrite, and the callee pointer keeps its ellipsis.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
index 33ffbb017e177..0a662367695e5 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-vptr.cir
@@ -188,7 +188,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_vp_big(%arg0: !cir.ptr<!rec_VPBig> {cir.abi_slot = #cir.abi_slot<byval>, llvm.align = 8 : i64, llvm.byval = !rec_VPBig, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_vp_big(%arg0: !cir.ptr<!rec_VPBig> {llvm.align = 8 : i64, llvm.byval = !rec_VPBig, llvm.noundef})
// LLVM: define void @take_vp_big(ptr noundef byval(%struct.VPBig) align 8 %{{[^,)]+}})
// Returned at that size it uses sret instead.
@@ -198,7 +198,7 @@ module attributes {
cir.return %1 : !rec_VPBig
}
- // CHECK: cir.func{{.*}} @ret_vp_big(%arg0: !cir.ptr<!rec_VPBig> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPBig, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_vp_big(%arg0: !cir.ptr<!rec_VPBig> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPBig, llvm.writable})
// LLVM: define void @ret_vp_big(ptr dead_on_unwind noalias writable sret(%struct.VPBig) align 8 %{{[^,)]+}})
// A declared argument-passing kind of cannot-pass-in-registers sends the
@@ -208,7 +208,7 @@ module attributes {
cir.return
}
- // CHECK: cir.func{{.*}} @take_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {cir.abi_slot = #cir.abi_slot<non_byval>, llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
+ // CHECK: cir.func{{.*}} @take_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {llvm.align = 8 : i64, llvm.dereferenceable = 16 : i64, llvm.nofreeobj, llvm.noundef})
// LLVM: define void @take_vp_no_regs(ptr nofreeobj noundef align 8 dereferenceable(16) %{{[^,)]+}})
// The same record returned takes sret rather than the non-byval form.
@@ -218,7 +218,7 @@ module attributes {
cir.return %1 : !rec_VPNoRegs
}
- // CHECK: cir.func{{.*}} @ret_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {cir.abi_slot = #cir.abi_slot<sret>, llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPNoRegs, llvm.writable})
+ // CHECK: cir.func{{.*}} @ret_vp_no_regs(%arg0: !cir.ptr<!rec_VPNoRegs> {llvm.align = 8 : i64, llvm.dead_on_unwind, llvm.noalias, llvm.sret = !rec_VPNoRegs, llvm.writable})
// LLVM: define void @ret_vp_no_regs(ptr dead_on_unwind noalias writable sret(%struct.VPNoRegs) align 8 %{{[^,)]+}})
// A call site is decomposed into the same two registers the callee now takes.
More information about the cfe-commits
mailing list