https://github.com/RiverDave created https://github.com/llvm/llvm-project/pull/221819
## Summary - Map `__declspec(noalias)` (`NoAliasAttr`) to `SideEffect::ArgMem`. - Lower that to `nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)`, matching classic codegen (no `willreturn`). - New CIR lit `ms-declspec-noalias.c` (Linux triple + `-fms-extensions`; Windows ABI is still NYI in CIR) plus `call.cir` parse coverage. Soft overlap with the operator-new PR: both add a `SideEffect` case in `CIRAttrs.td` and a switch arm in `LowerToLLVM.cpp`. Whichever lands second should rebase those two files. ## Test plan - [x] `llvm-lit clang/test/CIR/CodeGen/ms-declspec-noalias.c clang/test/CIR/IR/call.cir clang/test/CIR/CodeGen/side-effect.cpp` - [ ] Pre-merge Clang CIR checks Made with [Cursor](https://cursor.com) >From fed6cdc99254f86936cf6fe2853cb9fe6eddb836 Mon Sep 17 00:00:00 2001 From: David Rivera <[email protected]> Date: Mon, 7 Sep 2026 16:02:50 -0400 Subject: [PATCH] [CIR] Handle __declspec(noalias) as argmem side effects Match classic codegen: NoAliasAttr becomes nounwind plus memory(argmem: readwrite, inaccessiblemem: readwrite). --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 8 ++++- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 4 +++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 23 ++++++++++++++ clang/test/CIR/CodeGen/ms-declspec-noalias.c | 30 +++++++++++++++++++ clang/test/CIR/IR/call.cir | 2 ++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGen/ms-declspec-noalias.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index fa90ceba97115..dbe311fffb67a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1875,7 +1875,8 @@ def CIR_SideEffect : CIR_I32EnumAttr< "SideEffect", "allowed side effects of a function", [ I32EnumAttrCase<"All", 0, "all">, I32EnumAttrCase<"Pure", 1, "pure">, - I32EnumAttrCase<"Const", 2, "const"> + I32EnumAttrCase<"Const", 2, "const">, + I32EnumAttrCase<"ArgMem", 4, "argmem"> ]> { let description = [{ The side effect attribute specifies the possible side effects of a function @@ -1889,6 +1890,10 @@ def CIR_SideEffect : CIR_I32EnumAttr< `__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))`. + - argmem: The function or callee may only access argument memory and + inaccessible memory. This matches LLVM + `memory(argmem: readwrite, inaccessiblemem: readwrite)` used for + `__declspec(noalias)`. Examples: @@ -1896,6 +1901,7 @@ def CIR_SideEffect : CIR_I32EnumAttr< %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 @f(%0) : (!cir.ptr<!s32i>) -> () side_effect(argmem) ``` }]; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 3a4b7cecf2e08..a8644c03c1ba7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -398,6 +398,10 @@ void CIRGenModule::constructAttributeList( } else if (targetDecl->hasAttr<PureAttr>()) { // gcc specifies that 'pure' functions cannot have infinite loops. sideEffect = cir::SideEffect::Pure; + } else if (targetDecl->hasAttr<NoAliasAttr>()) { + // __declspec(noalias): inaccessible-or-arg memory only, and nounwind. + sideEffect = cir::SideEffect::ArgMem; + addUnitAttr(cir::CIRDialect::getNoThrowAttrName()); } attrs.set(cir::CIRDialect::getSideEffectAttrName(), diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 6f7509c363fd3..894c308c3ab40 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -457,6 +457,18 @@ void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, noUnwind = true; willReturn = true; break; + + case cir::SideEffect::ArgMem: + memoryEffect = mlir::LLVM::MemoryEffectsAttr::get( + callOp->getContext(), /*other=*/ModRefInfo::NoModRef, + /*argMem=*/ModRefInfo::ModRef, + /*inaccessibleMem=*/ModRefInfo::ModRef, + /*errnoMem=*/ModRefInfo::NoModRef, + /*targetMem0=*/ModRefInfo::NoModRef, + /*targetMem1=*/ModRefInfo::NoModRef); + noUnwind = true; + willReturn = false; + break; } noReturn = callOp->hasAttr(CIRDialect::getNoReturnAttrName()); @@ -2824,6 +2836,17 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( fn.setNoUnwind(true); fn.setWillReturn(true); break; + case cir::SideEffect::ArgMem: + fn.setMemoryEffectsAttr(mlir::LLVM::MemoryEffectsAttr::get( + fn.getContext(), + /*other=*/mlir::LLVM::ModRefInfo::NoModRef, + /*argMem=*/mlir::LLVM::ModRefInfo::ModRef, + /*inaccessibleMem=*/mlir::LLVM::ModRefInfo::ModRef, + /*errnoMem=*/mlir::LLVM::ModRefInfo::NoModRef, + /*targetMem0=*/mlir::LLVM::ModRefInfo::NoModRef, + /*targetMem1=*/mlir::LLVM::ModRefInfo::NoModRef)); + fn.setNoUnwind(true); + break; } } diff --git a/clang/test/CIR/CodeGen/ms-declspec-noalias.c b/clang/test/CIR/CodeGen/ms-declspec-noalias.c new file mode 100644 index 0000000000000..fd0e8276d4fdc --- /dev/null +++ b/clang/test/CIR/CodeGen/ms-declspec-noalias.c @@ -0,0 +1,30 @@ +// CIR does not yet implement the Windows C++ ABI, so exercise __declspec(noalias) +// on a Linux triple with -fms-extensions. +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fms-extensions -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +__declspec(noalias) void noalias_callee(int *x); +void noalias_caller(int *x) { noalias_callee(x); } + +// CIR: cir.func {{.*}} @noalias_caller +// CIR: cir.call @noalias_callee(%{{.*}}) nothrow side_effect(argmem) +// CIR: cir.func {{.*}}@noalias_callee(!cir.ptr<!s32i> {{.*}}) side_effect(argmem) + +// LLVM: call void @noalias_callee({{.*}}) [[NA:#[0-9]+]] +// OGCG: call void @noalias_callee({{.*}}) [[NA:#[0-9]+]] + +__declspec(noalias) void noalias_def(int *x) {} + +// CIR: cir.func {{.*}} @noalias_def(%{{.*}}) side_effect(argmem) + +// LLVM: define dso_local void @noalias_def({{.*}}) [[NA_DEF:#[0-9]+]] +// OGCG: define dso_local void @noalias_def({{.*}}) [[NA_DEF:#[0-9]+]] + +// LLVM-DAG: attributes [[NA]] = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) +// OGCG-DAG: attributes [[NA]] = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) +// LLVM-DAG: attributes [[NA_DEF]] = { {{.*}}nounwind{{.*}}memory(argmem: readwrite, inaccessiblemem: readwrite) +// OGCG-DAG: attributes [[NA_DEF]] = { {{.*}}nounwind{{.*}}memory(argmem: readwrite, inaccessiblemem: readwrite) diff --git a/clang/test/CIR/IR/call.cir b/clang/test/CIR/IR/call.cir index 59f28be36846f..58fe1dc767307 100644 --- a/clang/test/CIR/IR/call.cir +++ b/clang/test/CIR/IR/call.cir @@ -10,6 +10,7 @@ cir.func @f2() { cir.call @f1() : () -> () cir.call @f1() side_effect(pure) : () -> () cir.call @f1() side_effect(const) : () -> () + cir.call @f1() side_effect(argmem) : () -> () cir.return } @@ -17,6 +18,7 @@ cir.func @f2() { // CHECK-NEXT: cir.call @f1() : () -> () // CHECK-NEXT: cir.call @f1() side_effect(pure) : () -> () // CHECK-NEXT: cir.call @f1() side_effect(const) : () -> () +// CHECK-NEXT: cir.call @f1() side_effect(argmem) : () -> () // CHECK-NEXT: cir.return // CHECK-NEXT: } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
