Vendor import of clang release_80 branch r355677:

https://llvm.org/svn/llvm-project/cfe/branches/release_80@355677
This commit is contained in:
Dimitry Andric 2019-03-08 22:44:50 +00:00
parent 1dda0966cc
commit f463519f0c
10 changed files with 108 additions and 17 deletions

View File

@ -257,6 +257,12 @@ class APValue {
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;

View File

@ -807,6 +807,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
struct {
int Min;
int Max;
bool isConstrained;
} ImmRange;
llvm::SmallSet<int, 4> ImmSet;
@ -817,6 +818,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
: 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 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
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 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
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 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
}
void setRequiresImmediate() {
Flags |= CI_ImmediateConstant;
ImmRange.Min = INT_MIN;
ImmRange.Max = INT_MAX;
}
/// Indicate that this is an input operand that is tied to

View File

@ -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">;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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());
}

View File

@ -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
}

View File

@ -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 \

View File

@ -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;
@ -67,6 +68,9 @@ void L(int i, int j) {
__asm__("xorl %0,%2"
: "=r"(i)
: "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
@ -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
}