summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2019-03-08 09:16:31 +0000
committerHans Wennborg <hans@hanshq.net>2019-03-08 09:16:31 +0000
commit3201dce221fc2910baee72d927f5caf2747a2ba7 (patch)
tree23b04a22970c0a6ddf6ea253d4d29a14a15b23da
parente3d833aefbb9056676510583bcccea4791408699 (diff)
Merging r355491:
------------------------------------------------------------------------ r355491 | hans | 2019-03-06 11:26:19 +0100 (Wed, 06 Mar 2019) | 9 lines Inline asm constraints: allow ICE-like pointers for the "n" constraint (PR40890) Apparently GCC allows this, and there's code relying on it (see bug). 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()). Differential Revision: https://reviews.llvm.org/D58821 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_80@355674 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/APValue.h6
-rw-r--r--lib/AST/APValue.cpp20
-rw-r--r--lib/AST/ExprConstant.cpp11
-rw-r--r--lib/CodeGen/CGStmt.cpp11
-rw-r--r--lib/Sema/SemaStmtAsm.cpp15
-rw-r--r--test/CodeGen/x86-64-inline-asm.c15
-rw-r--r--test/Sema/inline-asm-validate-x86.c20
7 files changed, 86 insertions, 12 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index d4057c9da5..055f13f362 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -257,6 +257,12 @@ public:
return const_cast<APValue*>(this)->getInt();
}
+ /// Try to convert this value to an integral constant. This works if it's an
+ /// integer, null pointer, or offset from a null pointer. Returns true on
+ /// success.
+ bool toIntegralConstant(APSInt &Result, QualType SrcTy,
+ const ASTContext &Ctx) const;
+
APFloat &getFloat() {
assert(isFloat() && "Invalid accessor");
return *(APFloat*)(char*)Data.buffer;
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index c05b160b8e..0c2ba57f79 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -600,6 +600,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
return Result;
}
+bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
+ const ASTContext &Ctx) const {
+ if (isInt()) {
+ Result = getInt();
+ return true;
+ }
+
+ if (isLValue() && isNullPointer()) {
+ Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy);
+ return true;
+ }
+
+ if (isLValue() && !getLValueBase()) {
+ Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy);
+ return true;
+ }
+
+ return false;
+}
+
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data.buffer)->Base;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index da093ff22c..1f82b4add0 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -9821,13 +9821,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return true;
}
- uint64_t V;
- if (LV.isNullPointer())
- V = Info.Ctx.getTargetNullPointerValue(SrcType);
- else
- V = LV.getLValueOffset().getQuantity();
+ APSInt AsInt;
+ APValue V;
+ LV.moveInto(V);
+ if (!V.toIntegralConstant(AsInt, SrcType, Info.Ctx))
+ llvm_unreachable("Can't cast this!");
- APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType);
return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 0242b48659..b2b32759b6 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1821,8 +1821,15 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
// (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.toIntegralConstant(IntResult, InputExpr->getType(),
+ getContext()))
+ llvm_unreachable("Invalid immediate constant!");
+
+ return llvm::ConstantInt::get(getLLVMContext(), IntResult);
}
Expr::EvalResult Result;
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 9e084c99d0..2d8864bab1 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -383,11 +383,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
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 allow pointers that would be
+ // integral constant expressions if they were cast to int.
+ llvm::APSInt IntResult;
+ if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
+ Context))
+ 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());
}
diff --git a/test/CodeGen/x86-64-inline-asm.c b/test/CodeGen/x86-64-inline-asm.c
index bb46eda633..79c1bd95f3 100644
--- a/test/CodeGen/x86-64-inline-asm.c
+++ b/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,17 @@ static unsigned var[1] = {};
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));
+ __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef));
+
+// CHECK-LABEL: pr40890
+// CHECK: #define S_A abcd$0
+// CHECK: #define S_B abcd$4
+// CHECK: #define BEEF abcd$244837814038255
+}
diff --git a/test/Sema/inline-asm-validate-x86.c b/test/Sema/inline-asm-validate-x86.c
index b238ab8a50..5ea20eec05 100644
--- a/test/Sema/inline-asm-validate-x86.c
+++ b/test/Sema/inline-asm-validate-x86.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify -DAMD64 %s
void I(int i, int j) {
static const int BelowMin = -1;
@@ -133,3 +133,21 @@ void O(int i, int j) {
: "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}}
+ // Floating-point is also not okay.
+ __asm__ __volatile__("\n#define PI abcd%0\n" : : "n"(3.14f)); // expected-error{{constraint 'n' expects an integer constant expression}}
+#ifdef AMD64
+ // This arbitrary pointer is fine.
+ __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef));
+#endif
+}