https://github.com/yronglin created 
https://github.com/llvm/llvm-project/pull/90240

This PR fix the issue reported by @alexfh 

PR https://github.com/llvm/llvm-project/pull/89567 fix the `#pragma unroll N` 
crash issue in dependent context, but it's introduce an new issue:

If `N` is value dependent, the `LoopHintAttr::Option` should be 
`LoopHintAttr::UnrollCount` and `LoopHintAttr::LoopHintState` should be 
`LoopHintAttr::Numeric`, but since 
https://github.com/llvm/llvm-project/pull/89567, these two flags was ` 
(LoopHintAttr::Unroll, LoopHintAttr::Enable)`. Therefor, clang's code generator 
generated incorrect IR metadata.

```
#include <cstddef>
#include <bit>

template <bool Flag>
int FailToBuild(int n) {
  constexpr int N = 100;
  auto init = [=]() { return Flag ? n : 0UL; };
  auto cond = [=](size_t ix) { return Flag ? ix != 0 : ix < 10; };
  auto iter = [=](size_t ix) {
    return Flag ? ix & ~(1ULL << std::countr_zero(ix)) : ix + 1;
  };
#pragma unroll Flag ? 1 : N
  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
    n *= n;
  }
#pragma unroll Flag ? 0 : N // since #89567, error: invalid value '0'; must be 
positive
  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
    n *= n;
  }
  return n;
}

int foo(int n) {
    return FailToBuild<true>(n);
}

int bar(int n) {
    return FailToBuild<false>(n);
}
```

>From 131783211a23d007b5b6f1d5691306df4dec716b Mon Sep 17 00:00:00 2001
From: yronglin <yronglin...@gmail.com>
Date: Sat, 27 Apr 2024 01:38:34 +0800
Subject: [PATCH] [Clang] Fix incorrect handling of #pragma {GCC} unroll N in
 dependent context

Signed-off-by: yronglin <yronglin...@gmail.com>
---
 clang/lib/Sema/SemaStmtAttr.cpp     | 23 ++++++++++--------
 clang/test/Parser/pragma-unroll.cpp | 37 +++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 9d44c22c8ddcc3..4dfdfd7aec425f 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -109,16 +109,19 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const 
ParsedAttr &A,
     SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
   } else if (PragmaName == "unroll") {
     // #pragma unroll N
-    if (ValueExpr && !ValueExpr->isValueDependent()) {
-      llvm::APSInt ValueAPS;
-      ExprResult R = S.VerifyIntegerConstantExpression(ValueExpr, &ValueAPS);
-      assert(!R.isInvalid() && "unroll count value must be a valid value, it's 
"
-                               "should be checked in Sema::CheckLoopHintExpr");
-      (void)R;
-      // The values of 0 and 1 block any unrolling of the loop.
-      if (ValueAPS.isZero() || ValueAPS.isOne())
-        SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Disable);
-      else
+    if (ValueExpr) {
+      if (!ValueExpr->isValueDependent()) {
+        llvm::APSInt ValueAPS;
+        ExprResult R = S.VerifyIntegerConstantExpression(ValueExpr, &ValueAPS);
+        assert(!R.isInvalid() && "unroll count value must be a valid value, 
it's "
+                                "should be checked in 
Sema::CheckLoopHintExpr");
+        (void)R;
+        // The values of 0 and 1 block any unrolling of the loop.
+        if (ValueAPS.isZero() || ValueAPS.isOne())
+          SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Disable);
+        else
+          SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
+      } else
         SetHints(LoopHintAttr::UnrollCount, LoopHintAttr::Numeric);
     } else
       SetHints(LoopHintAttr::Unroll, LoopHintAttr::Enable);
diff --git a/clang/test/Parser/pragma-unroll.cpp 
b/clang/test/Parser/pragma-unroll.cpp
index f41bd7a18d5a41..e84f6ea9ad1035 100644
--- a/clang/test/Parser/pragma-unroll.cpp
+++ b/clang/test/Parser/pragma-unroll.cpp
@@ -124,3 +124,40 @@ void test(int *List, int Length) {
 
 #pragma unroll
 /* expected-error {{expected statement}} */ }
+
+using size_t = unsigned long long;
+
+template <bool Flag>
+int FailToBuild(int n) {
+  constexpr int N = 100;
+  auto init = [=]() { return Flag ? n : 0UL; };
+  auto cond = [=](size_t ix) { return Flag ? ix != 0 : ix < 10; };
+  auto iter = [=](size_t ix) {
+    return Flag ? ix & ~(1ULL << __builtin_clzll(ix)) : ix + 1;
+  };
+#pragma unroll Flag ? 1 : N
+  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
+    n *= n;
+  }
+#pragma unroll Flag ? 0 : N
+  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
+    n *= n;
+  }
+#pragma GCC unroll Flag ? 1 : N
+  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
+    n *= n;
+  }
+#pragma GCC unroll Flag ? 0 : N
+  for (size_t ix = init(); cond(ix); ix = iter(ix)) {
+    n *= n;
+  }
+  return n;
+}
+
+int foo(int n) {
+    return FailToBuild<true>(n);
+}
+
+int bar(int n) {
+    return FailToBuild<false>(n);
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to