void updated this revision to Diff 178158.
void added a comment.

The `n` constriant *requires* a known integer. Therefore, enforce this in both
Sema and CodeGen by setting the "requires immediate" flag and evaluating to a
known integer instead of random "int"..

This doesn't so much address `i`, which has other semantics. However, it
shouldn't regress how the `i` constraint is currently used.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55616/new/

https://reviews.llvm.org/D55616

Files:
  lib/Basic/TargetInfo.cpp
  lib/CodeGen/CGStmt.cpp
  lib/Sema/SemaStmtAsm.cpp
  test/CodeGen/builtin-constant-p.c

Index: test/CodeGen/builtin-constant-p.c
===================================================================
--- test/CodeGen/builtin-constant-p.c
+++ test/CodeGen/builtin-constant-p.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O2 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O2 | FileCheck --check-prefix=O2 %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -O0 | FileCheck --check-prefix=O0 %s
 
 int a = 42;
 
@@ -14,8 +15,8 @@
 struct foo f = (struct foo){ __builtin_constant_p(y), 42 };
 
 struct foo test0(int expr) {
-  // CHECK: define i64 @test0(i32 %expr)
-  // CHECK: call i1 @llvm.is.constant.i32(i32 %expr)
+  // O2: define i64 @test0(i32 %expr)
+  // O2: call i1 @llvm.is.constant.i32(i32 %expr)
   struct foo f = (struct foo){ __builtin_constant_p(expr), 42 };
   return f;
 }
@@ -27,15 +28,15 @@
 }
 
 int test1() {
-  // CHECK: define i32 @test1
-  // CHECK: add nsw i32 %0, -13
-  // CHECK-NEXT: call i1 @llvm.is.constant.i32(i32 %sub)
+  // O2: define i32 @test1
+  // O2: add nsw i32 %0, -13
+  // O2-NEXT: call i1 @llvm.is.constant.i32(i32 %sub)
   return bcp(test1_i(&a) - 13);
 }
 
 int test2() {
-  // CHECK: define i32 @test2
-  // CHECK: ret i32 0
+  // O2: define i32 @test2
+  // O2: ret i32 0
   return __builtin_constant_p(&a - 13);
 }
 
@@ -44,8 +45,8 @@
 }
 
 int test3() {
-  // CHECK: define i32 @test3
-  // CHECK: ret i32 1
+  // O2: define i32 @test3
+  // O2: ret i32 1
   return bcp(test3_i(&a) - 13);
 }
 
@@ -54,16 +55,16 @@
 int b[] = {1, 2, 3};
 
 int test4() {
-  // CHECK: define i32 @test4
-  // CHECK: ret i32 0
+  // O2: define i32 @test4
+  // O2: ret i32 0
   return __builtin_constant_p(b);
 }
 
 const char test5_c[] = {1, 2, 3, 0};
 
 int test5() {
-  // CHECK: define i32 @test5
-  // CHECK: ret i32 0
+  // O2: define i32 @test5
+  // O2: ret i32 0
   return __builtin_constant_p(test5_c);
 }
 
@@ -72,16 +73,16 @@
 }
 
 int test6() {
-  // CHECK: define i32 @test6
-  // CHECK: ret i32 0
+  // O2: define i32 @test6
+  // O2: ret i32 0
   return __builtin_constant_p(test6_i(test5_c));
 }
 
 /* --- Non-constant global variables */
 
 int test7() {
-  // CHECK: define i32 @test7
-  // CHECK: call i1 @llvm.is.constant.i32(i32 %0)
+  // O2: define i32 @test7
+  // O2: call i1 @llvm.is.constant.i32(i32 %0)
   return bcp(a);
 }
 
@@ -90,8 +91,8 @@
 const int c = 42;
 
 int test8() {
-  // CHECK: define i32 @test8
-  // CHECK: ret i32 1
+  // O2: define i32 @test8
+  // O2: ret i32 1
   return bcp(c);
 }
 
@@ -101,34 +102,34 @@
 const int c_arr[] = { 1, 2, 3 };
 
 int test9() {
-  // CHECK: define i32 @test9
-  // CHECK: call i1 @llvm.is.constant.i32(i32 %0)
+  // O2: define i32 @test9
+  // O2: call i1 @llvm.is.constant.i32(i32 %0)
   return __builtin_constant_p(arr[2]);
 }
 
 int test10() {
-  // CHECK: define i32 @test10
-  // CHECK: ret i32 1
+  // O2: define i32 @test10
+  // O2: ret i32 1
   return __builtin_constant_p(c_arr[2]);
 }
 
 int test11() {
-  // CHECK: define i32 @test11
-  // CHECK: ret i32 0
+  // O2: define i32 @test11
+  // O2: ret i32 0
   return __builtin_constant_p(c_arr);
 }
 
 /* --- Function pointers */
 
 int test12() {
-  // CHECK: define i32 @test12
-  // CHECK: ret i32 0
+  // O2: define i32 @test12
+  // O2: ret i32 0
   return __builtin_constant_p(&test10);
 }
 
 int test13() {
-  // CHECK: define i32 @test13
-  // CHECK: ret i32 1
+  // O2: define i32 @test13
+  // O2: ret i32 1
   return __builtin_constant_p(&test10 != 0);
 }
 
@@ -166,3 +167,13 @@
 
 extern char test16_v;
 struct { int a; } test16 = { __builtin_constant_p(test16_v) };
+
+extern unsigned long long test17_v;
+
+void test17() {
+  // O0: define void @test17
+  // O0: call void asm sideeffect "", {{.*}}(i32 -1) 
+  // O2: define void @test17
+  // O2: call void asm sideeffect "", {{.*}}(i32 -1) 
+  __asm__ __volatile__("" :: "n"( (__builtin_constant_p(test17_v) || 0) ? 1 : -1));
+}
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -378,17 +378,17 @@
                          << InputExpr->getSourceRange());
     } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
       if (!InputExpr->isValueDependent()) {
-        Expr::EvalResult EVResult;
-        if (!InputExpr->EvaluateAsInt(EVResult, Context))
+        llvm::SmallVector<PartialDiagnosticAt, 1> Diags;
+        llvm::APSInt Result = InputExpr->EvaluateKnownConstInt(Context, &Diags);
+        if (!Diags.empty())
           return StmtError(
               Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
               << Info.getConstraintStr() << InputExpr->getSourceRange());
-        llvm::APSInt Result = EVResult.Val.getInt();
-         if (!Info.isValidAsmImmediate(Result))
-           return StmtError(Diag(InputExpr->getBeginLoc(),
-                                 diag::err_invalid_asm_value_for_constraint)
-                            << Result.toString(10) << Info.getConstraintStr()
-                            << InputExpr->getSourceRange());
+        if (!Info.isValidAsmImmediate(Result))
+          return StmtError(Diag(InputExpr->getBeginLoc(),
+                                diag::err_invalid_asm_value_for_constraint)
+                           << Result.toString(10) << Info.getConstraintStr()
+                           << InputExpr->getSourceRange());
       }
 
     } else {
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -1820,11 +1820,14 @@
   // If this can't be a register or memory, i.e., has to be a constant
   // (immediate or symbolic), try to emit it as such.
   if (!Info.allowsRegister() && !Info.allowsMemory()) {
+    if (Info.requiresImmediateConstant()) {
+      llvm::APSInt AsmConst = InputExpr->EvaluateKnownConstInt(getContext());
+      return llvm::ConstantInt::get(getLLVMContext(), AsmConst);
+    }
+
     Expr::EvalResult Result;
     if (InputExpr->EvaluateAsInt(Result, getContext()))
       return llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt());
-    assert(!Info.requiresImmediateConstant() &&
-           "Required-immediate inlineasm arg isn't constant?");
   }
 
   if (Info.allowsRegister() || !Info.allowsMemory())
Index: lib/Basic/TargetInfo.cpp
===================================================================
--- lib/Basic/TargetInfo.cpp
+++ lib/Basic/TargetInfo.cpp
@@ -685,7 +685,9 @@
       // FIXME: Fail if % is used with the last operand.
       break;
     case 'i': // immediate integer.
+      break;
     case 'n': // immediate integer with a known value.
+      Info.setRequiresImmediate();
       break;
     case 'I':  // Various constant constraints with target-specific meanings.
     case 'J':
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to