[clang] [C] Disable use of NRVO (PR #101038)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 29 10:15:49 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Aaron Ballman (AaronBallman)
<details>
<summary>Changes</summary>
Applying NRVO changes the observable behavior of the abstract machine, which makes it an invalid optimization to apply in C. This disables the functionality in C.
This is the only code path where we set the NRVO state for a local variable in C (the other code paths are in coroutines and template instantiation, neither of which are available in C).
Fixes #<!-- -->100902
---
Full diff: https://github.com/llvm/llvm-project/pull/101038.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+6)
- (modified) clang/lib/Sema/SemaDecl.cpp (+3-1)
- (added) clang/test/CodeGen/nrvo.c (+75)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ddad083571eb1..b0a8c55835868 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -156,6 +156,12 @@ Bug Fixes to Compiler Builtins
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Bug Fixes to C Support
+^^^^^^^^^^^^^^^^^^^^^^
+
+- No longer applying Named Return Value Optimization (NRVO) in C as it is a
+ non-conforming optimization in C. (#GH100902)
+
Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 694a754646f27..0697d12d2fe0d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2176,7 +2176,9 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S,
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
- S->applyNRVO();
+ // NRVO is only valid in C++, not in C.
+ if (getLangOpts().CPlusPlus)
+ S->applyNRVO();
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
diff --git a/clang/test/CodeGen/nrvo.c b/clang/test/CodeGen/nrvo.c
new file mode 100644
index 0000000000000..39796ce2144e0
--- /dev/null
+++ b/clang/test/CodeGen/nrvo.c
@@ -0,0 +1,75 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -o - %s | FileCheck --check-prefixes=C %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -o - -x c++ %s | FileCheck --check-prefixes=CXX %s
+
+// NRVO is not allowed in C as it is in C++, so validate that this results in
+// use of NRVO in C++, but not in C.
+typedef struct {
+ int i, j;
+ double a, b;
+} S;
+
+int result;
+
+// C-LABEL: define dso_local void @test(
+// C-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_S:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
+// C-NEXT: [[ENTRY:.*:]]
+// C-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
+// C-NEXT: [[Q_ADDR:%.*]] = alloca ptr, align 4
+// C-NEXT: [[S:%.*]] = alloca [[STRUCT_S]], align 4
+// C-NEXT: store ptr [[AGG_RESULT]], ptr [[RESULT_PTR]], align 4
+// C-NEXT: store ptr [[Q]], ptr [[Q_ADDR]], align 4
+// C-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[S]], i8 0, i32 24, i1 false)
+// C-NEXT: [[TMP0:%.*]] = load ptr, ptr [[Q_ADDR]], align 4
+// C-NEXT: [[CMP:%.*]] = icmp eq ptr [[S]], [[TMP0]]
+// C-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
+// C-NEXT: store i32 [[CONV]], ptr @result, align 4
+// C-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_RESULT]], ptr align 4 [[S]], i32 24, i1 false)
+// C-NEXT: ret void
+//
+// CXX-LABEL: define dso_local void @_Z4testP1S(
+// CXX-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_S:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
+// CXX-NEXT: [[ENTRY:.*:]]
+// CXX-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
+// CXX-NEXT: [[Q_ADDR:%.*]] = alloca ptr, align 4
+// CXX-NEXT: store ptr [[AGG_RESULT]], ptr [[RESULT_PTR]], align 4
+// CXX-NEXT: store ptr [[Q]], ptr [[Q_ADDR]], align 4
+// CXX-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[AGG_RESULT]], i8 0, i32 24, i1 false)
+// CXX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[Q_ADDR]], align 4
+// CXX-NEXT: [[CMP:%.*]] = icmp eq ptr [[AGG_RESULT]], [[TMP0]]
+// CXX-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32
+// CXX-NEXT: store i32 [[CONV]], ptr @result, align 4
+// CXX-NEXT: ret void
+//
+S test(S* q) {
+ S s = {0, 0, 0, 0};
+ result = &s == q;
+ return s;
+}
+
+// C-LABEL: define dso_local i32 @main(
+// C-SAME: ) #[[ATTR0]] {
+// C-NEXT: [[ENTRY:.*:]]
+// C-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// C-NEXT: [[T:%.*]] = alloca [[STRUCT_S:%.*]], align 4
+// C-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// C-NEXT: call void @test(ptr dead_on_unwind writable sret([[STRUCT_S]]) align 4 [[T]], ptr noundef [[T]])
+// C-NEXT: [[TMP0:%.*]] = load i32, ptr @result, align 4
+// C-NEXT: ret i32 [[TMP0]]
+//
+// CXX-LABEL: define dso_local noundef i32 @main(
+// CXX-SAME: ) #[[ATTR2:[0-9]+]] {
+// CXX-NEXT: [[ENTRY:.*:]]
+// CXX-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// CXX-NEXT: [[T:%.*]] = alloca [[STRUCT_S:%.*]], align 4
+// CXX-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// CXX-NEXT: call void @_Z4testP1S(ptr dead_on_unwind writable sret([[STRUCT_S]]) align 4 [[T]], ptr noundef [[T]])
+// CXX-NEXT: [[TMP0:%.*]] = load i32, ptr @result, align 4
+// CXX-NEXT: ret i32 [[TMP0]]
+//
+int main(void)
+{
+ S t = test(&t);
+ return result;
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/101038
More information about the cfe-commits
mailing list