[clang] [C] Disable use of NRVO (PR #101038)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 29 10:14:39 PDT 2024


https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/101038

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

>From 6a30cf86754bd6f2f2fb124db027054166223ad1 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Mon, 29 Jul 2024 13:10:32 -0400
Subject: [PATCH] [C] Disable use of NRVO

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
---
 clang/docs/ReleaseNotes.rst |  6 +++
 clang/lib/Sema/SemaDecl.cpp |  4 +-
 clang/test/CodeGen/nrvo.c   | 75 +++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/nrvo.c

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;
+}
+



More information about the cfe-commits mailing list