aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/APValue.h6
-rw-r--r--include/clang/Basic/TargetInfo.h10
-rw-r--r--include/clang/Driver/CLCompatOptions.td7
-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/Driver/cl-options.c6
-rw-r--r--test/Sema/inline-asm-validate-x86.c24
10 files changed, 108 insertions, 17 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index d4057c9da5f3..055f13f3620b 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/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 1e835d992bbe..c95cf599ffd4 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -807,6 +807,7 @@ public:
struct {
int Min;
int Max;
+ bool isConstrained;
} ImmRange;
llvm::SmallSet<int, 4> ImmSet;
@@ -817,6 +818,7 @@ public:
: Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()),
Name(Name.str()) {
ImmRange.Min = ImmRange.Max = 0;
+ ImmRange.isConstrained = false;
}
const std::string &getConstraintStr() const { return ConstraintStr; }
@@ -845,8 +847,9 @@ public:
return (Flags & CI_ImmediateConstant) != 0;
}
bool isValidAsmImmediate(const llvm::APInt &Value) const {
- return (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)) ||
- ImmSet.count(Value.getZExtValue()) != 0;
+ if (!ImmSet.empty())
+ return ImmSet.count(Value.getZExtValue()) != 0;
+ return !ImmRange.isConstrained || (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max));
}
void setIsReadWrite() { Flags |= CI_ReadWrite; }
@@ -858,6 +861,7 @@ public:
Flags |= CI_ImmediateConstant;
ImmRange.Min = Min;
ImmRange.Max = Max;
+ ImmRange.isConstrained = true;
}
void setRequiresImmediate(llvm::ArrayRef<int> Exacts) {
Flags |= CI_ImmediateConstant;
@@ -870,8 +874,6 @@ public:
}
void setRequiresImmediate() {
Flags |= CI_ImmediateConstant;
- ImmRange.Min = INT_MIN;
- ImmRange.Max = INT_MAX;
}
/// Indicate that this is an input operand that is tied to
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 3e0dc2db7d07..ca23f7b81965 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -395,7 +395,9 @@ def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">;
// Unsupported:
-def _SLASH_AI : CLJoined<"AI">;
+def _SLASH_await : CLFlag<"await">;
+def _SLASH_constexpr : CLJoined<"constexpr:">;
+def _SLASH_AI : CLJoinedOrSeparate<"AI">;
def _SLASH_Bt : CLFlag<"Bt">;
def _SLASH_Bt_plus : CLFlag<"Bt+">;
def _SLASH_clr : CLJoined<"clr">;
@@ -430,6 +432,9 @@ def _SLASH_Qfast_transcendentals : CLFlag<"Qfast_transcendentals">;
def _SLASH_QIfist : CLFlag<"QIfist">;
def _SLASH_Qimprecise_fwaits : CLFlag<"Qimprecise_fwaits">;
def _SLASH_Qpar : CLFlag<"Qpar">;
+def _SLASH_Qpar_report : CLJoined<"Qpar-report">;
+def _SLASH_Qsafe_fp_loads : CLFlag<"Qsafe_fp_loads">;
+def _SLASH_Qspectre : CLFlag<"Qspectre">;
def _SLASH_Qvec_report : CLJoined<"Qvec-report">;
def _SLASH_u : CLFlag<"u">;
def _SLASH_V : CLFlag<"V">;
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index c05b160b8e3d..0c2ba57f7986 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 da093ff22c12..1f82b4add0c4 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 0242b48659d1..b2b32759b6f7 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 9e084c99d0dd..2d8864bab171 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 bb46eda633b7..79c1bd95f38b 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/Driver/cl-options.c b/test/Driver/cl-options.c
index d8db081ac8a6..909e391cec6a 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -390,7 +390,10 @@
// Unsupported but parsed options. Check that we don't error on them.
// (/Zs is for syntax-only)
// RUN: %clang_cl /Zs \
+// RUN: /await \
+// RUN: /constexpr:depth1000 /constexpr:backtrace1000 /constexpr:steps1000 \
// RUN: /AIfoo \
+// RUN: /AI foo_does_not_exist \
// RUN: /Bt \
// RUN: /Bt+ \
// RUN: /clr:pure \
@@ -442,6 +445,9 @@
// RUN: /QIfist \
// RUN: /Qimprecise_fwaits \
// RUN: /Qpar \
+// RUN: /Qpar-report:1 \
+// RUN: /Qsafe_fp_loads \
+// RUN: /Qspectre \
// RUN: /Qvec-report:2 \
// RUN: /u \
// RUN: /V \
diff --git a/test/Sema/inline-asm-validate-x86.c b/test/Sema/inline-asm-validate-x86.c
index f21ef6940a6d..5ea20eec0599 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;
@@ -55,6 +55,7 @@ void K(int i, int j) {
void L(int i, int j) {
static const int Invalid1 = 1;
static const int Invalid2 = 42;
+ static const int Invalid3 = 0;
static const int Valid1 = 0xff;
static const int Valid2 = 0xffff;
static const int Valid3 = 0xffffffff;
@@ -69,6 +70,9 @@ void L(int i, int j) {
: "0"(i), "L"(Invalid2)); // expected-error{{value '42' out of range for constraint 'L'}}
__asm__("xorl %0,%2"
: "=r"(i)
+ : "0"(i), "L"(Invalid3)); // expected-error{{value '0' out of range for constraint 'L'}}
+ __asm__("xorl %0,%2"
+ : "=r"(i)
: "0"(i), "L"(Valid1)); // expected-no-error
__asm__("xorl %0,%2"
: "=r"(i)
@@ -129,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
+}