hans created this revision.
hans added reviewers: efriedma, rnk, rsmith, void.
Herald added subscribers: jdoerfert, eraman.

Apparently GCC allows this, and there's code relying on it (see bug, which is a 
release blocker for llvm 8).

The idea is to allow expression that would have been allowed if they were cast 
to int. So I based the code on how such a cast would be done (the 
CK_PointerToIntegral case in IntExprEvaluator::VisitCastExpr()).

I'm unfamiliar with this code, especially the LValue variant of APValue, so 
please take a careful look.


https://reviews.llvm.org/D58821

Files:
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/Sema/SemaStmtAsm.cpp
  clang/test/CodeGen/x86-64-inline-asm.c
  clang/test/Sema/inline-asm-validate-x86.c

Index: clang/test/Sema/inline-asm-validate-x86.c
===================================================================
--- clang/test/Sema/inline-asm-validate-x86.c
+++ clang/test/Sema/inline-asm-validate-x86.c
@@ -137,3 +137,15 @@
           : "0"(i), "O"(64)); // expected-no-error
 }
 
+void pr40890(void) {
+  struct s {
+    int a, b;
+  };
+  static struct s s;
+  // This null pointer can be used as an integer constant expression.
+  __asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a));
+  // This offset-from-null pointer can be used as an integer constant expression.
+  __asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b));
+  // This pointer cannot be used as an integer constant expression.
+  __asm__ __volatile__("\n#define GLOBAL_A abcd%0\n" : : "n"(&s.a)); // expected-error{{constraint 'n' expects an integer constant expression}}
+}
Index: clang/test/CodeGen/x86-64-inline-asm.c
===================================================================
--- clang/test/CodeGen/x86-64-inline-asm.c
+++ clang/test/CodeGen/x86-64-inline-asm.c
@@ -1,6 +1,7 @@
 // REQUIRES: x86-registered-target
 // RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -DWARN -verify
 // RUN: %clang_cc1 -triple x86_64 %s -S -o /dev/null -Werror -verify
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -S -o - | FileCheck %s
 void f() {
   asm("movaps %xmm3, (%esi, 2)");
 // expected-note@1 {{instantiated into assembly here}}
@@ -15,3 +16,15 @@
 void g(void) { asm volatile("movd %%xmm0, %0"
                             :
                             : "m"(var)); }
+
+void pr40890(void) {
+  struct s {
+    int a, b;
+  } s;
+  __asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a));
+  __asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b));
+
+// CHECK-LABEL: pr40890
+// CHECK: #define S_A abcd$0
+// CHECK: #define S_B abcd$4
+}
Index: clang/lib/Sema/SemaStmtAsm.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAsm.cpp
+++ clang/lib/Sema/SemaStmtAsm.cpp
@@ -385,11 +385,27 @@
           return StmtError(
               Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
               << Info.getConstraintStr() << InputExpr->getSourceRange());
-        llvm::APSInt Result = EVResult.Val.getInt();
-        if (!Info.isValidAsmImmediate(Result))
+
+        // For compatibility with GCC, we also allows pointers that would be
+        // integral constant expressions if they were cast to int.
+        llvm::APSInt IntResult;
+        if (EVResult.Val.isInt())
+          IntResult = EVResult.Val.getInt();
+        else if (EVResult.Val.isNullPointer())
+          IntResult = llvm::APSInt::get(
+              Context.getTargetNullPointerValue(InputExpr->getType()));
+        else if (EVResult.Val.isLValue() && !EVResult.Val.getLValueBase())
+          IntResult =
+              llvm::APSInt::get(EVResult.Val.getLValueOffset().getQuantity());
+        else
+          return StmtError(
+              Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
+              << Info.getConstraintStr() << InputExpr->getSourceRange());
+
+        if (!Info.isValidAsmImmediate(IntResult))
           return StmtError(Diag(InputExpr->getBeginLoc(),
                                 diag::err_invalid_asm_value_for_constraint)
-                           << Result.toString(10) << Info.getConstraintStr()
+                           << IntResult.toString(10) << Info.getConstraintStr()
                            << InputExpr->getSourceRange());
       }
 
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -1838,8 +1838,22 @@
   // (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 EVResult;
+      InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
+
+      llvm::APSInt IntResult;
+      if (EVResult.Val.isInt())
+        IntResult = EVResult.Val.getInt();
+      else if (EVResult.Val.isNullPointer())
+        IntResult = llvm::APSInt::get(
+            getContext().getTargetNullPointerValue(InputExpr->getType()));
+      else if (EVResult.Val.isLValue() && !EVResult.Val.getLValueBase())
+        IntResult =
+            llvm::APSInt::get(EVResult.Val.getLValueOffset().getQuantity());
+      else
+        llvm_unreachable("Failed evaluate InputExpr as integer.");
+
+      return llvm::ConstantInt::get(getLLVMContext(), IntResult);
     }
 
     Expr::EvalResult Result;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to