[X86][MS-InlineAsm] Extended support for variables / identifiers on memory / immediate expressions

Allow the proper recognition of Enum values and global variables inside ms inline-asm memory / immediate expressions, as they require some additional overhead and treated incorrect if doesn't early recognized.
supersedes D33278, D35774

Differential Revision: https://reviews.llvm.org/D37413

llvm-svn: 314494
This commit is contained in:
Coby Tayree 2017-09-29 07:02:49 +00:00
parent c3d24118e8
commit 6150419d71
6 changed files with 122 additions and 47 deletions

View File

@ -1474,7 +1474,6 @@ public:
ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
unsigned &NumLineToksConsumed,
void *Info,
bool IsUnevaluated);
private:

View File

@ -3788,15 +3788,15 @@ public:
Expr *AsmString, MultiExprArg Clobbers,
SourceLocation RParenLoc);
void FillInlineAsmIdentifierInfo(Expr *Res,
llvm::InlineAsmIdentifierInfo &Info);
ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext);
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset, SourceLocation AsmLoc);
ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member,
llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc);
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
ArrayRef<Token> AsmToks,

View File

@ -54,9 +54,9 @@ public:
assert(AsmToks.size() == AsmTokOffsets.size());
}
void *LookupInlineAsmIdentifier(StringRef &LineBuf,
llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) override {
void LookupInlineAsmIdentifier(StringRef &LineBuf,
llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) override {
// Collect the desired tokens.
SmallVector<Token, 16> LineToks;
const Token *FirstOrigToken = nullptr;
@ -64,7 +64,7 @@ public:
unsigned NumConsumedToks;
ExprResult Result = TheParser.ParseMSAsmIdentifier(
LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
LineToks, NumConsumedToks, IsUnevaluatedContext);
// If we consumed the entire line, tell MC that.
// Also do this if we consumed nothing as a way of reporting failure.
@ -89,9 +89,10 @@ public:
LineBuf = LineBuf.substr(0, TotalOffset);
}
// Initialize the "decl" with the lookup result.
Info.OpDecl = static_cast<void *>(Result.get());
return Info.OpDecl;
// Initialize Info with the lookup result.
if (!Result.isUsable())
return;
TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
}
StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
@ -178,16 +179,9 @@ private:
}
/// Parse an identifier in an MS-style inline assembly block.
///
/// \param CastInfo - a void* so that we don't have to teach Parser.h
/// about the actual type.
ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
unsigned &NumLineToksConsumed,
void *CastInfo,
bool IsUnevaluatedContext) {
llvm::InlineAsmIdentifierInfo &Info =
*(llvm::InlineAsmIdentifierInfo *)CastInfo;
// Push a fake token on the end so that we don't overrun the token
// stream. We use ';' because it expression-parsing should never
// overrun it.
@ -227,7 +221,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
/*AllowDeductionGuide=*/false,
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
// Perform the lookup.
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
IsUnevaluatedContext);
}
// While the next two tokens are 'period' 'identifier', repeatedly parse it as
@ -241,7 +235,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
IdentifierInfo *Id = Tok.getIdentifierInfo();
ConsumeToken(); // Consume the identifier.
Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
Info, Tok.getLocation());
Tok.getLocation());
}
// Figure out how many tokens we are into LineToks.

View File

@ -48,10 +48,10 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) {
if (E != E2 && E2->isLValue()) {
if (!S.getLangOpts().HeinousExtensions)
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
<< E->getSourceRange();
<< E->getSourceRange();
else
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
<< E->getSourceRange();
<< E->getSourceRange();
// Accept, even if we emitted an error diagnostic.
return false;
}
@ -607,23 +607,31 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return NS;
}
static void fillInlineAsmTypeInfo(const ASTContext &Context, QualType T,
llvm::InlineAsmIdentifierInfo &Info) {
// Compute the type size (and array length if applicable?).
Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity();
if (T->isArrayType()) {
const ArrayType *ATy = Context.getAsArrayType(T);
Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
Info.Length = Info.Size / Info.Type;
void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
llvm::InlineAsmIdentifierInfo &Info) {
QualType T = Res->getType();
Expr::EvalResult Eval;
if (T->isFunctionType() || T->isDependentType())
return Info.setLabel(Res);
if (Res->isRValue()) {
if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
return Info.setEnum(Eval.Val.getInt().getSExtValue());
return Info.setLabel(Res);
}
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
unsigned Type = Size;
if (const auto *ATy = Context.getAsArrayType(T))
Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
bool IsGlobalLV = false;
if (Res->EvaluateAsLValue(Eval, Context))
IsGlobalLV = Eval.isGlobalLValue();
Info.setVar(Res, IsGlobalLV, Size, Type);
}
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) {
Info.clear();
if (IsUnevaluatedContext)
PushExpressionEvaluationContext(
@ -664,12 +672,6 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
return ExprError();
}
fillInlineAsmTypeInfo(Context, T, Info);
// We can work with the expression as long as it's not an r-value.
if (!Result.get()->isRValue())
Info.IsVarDecl = true;
return Result;
}
@ -743,9 +745,7 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
ExprResult
Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc) {
Info.clear();
QualType T = E->getType();
if (T->isDependentType()) {
@ -780,14 +780,6 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
ExprResult Result = BuildMemberReferenceExpr(
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
SourceLocation(), nullptr, FieldResult, nullptr, nullptr);
if (Result.isInvalid())
return Result;
Info.OpDecl = Result.get();
fillInlineAsmTypeInfo(Context, Result.get()->getType(), Info);
// Fields are "variables" as far as inline assembly is concerned.
Info.IsVarDecl = true;
return Result;
}

View File

@ -0,0 +1,55 @@
// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -fasm-blocks -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
namespace x {
enum { A = 12 };
struct y_t {
enum { A = 17 };
int r;
} y;
}
// CHECK-LABEL: t1
void t1() {
enum { A = 1 };
// CHECK: call void asm
// CHECK-SAME: mov eax, $$12
__asm mov eax, x::A
// CHECK-SAME: mov eax, $$17
__asm mov eax, x::y_t::A
// CHECK-NEXT: call void asm
// CHECK-SAME: mov eax, $$1
__asm {mov eax, A}
}
// CHECK-LABEL: t2
void t2() {
enum { A = 1, B };
// CHECK: call void asm
// CHECK-SAME: mov eax, $$21
__asm mov eax, (A + 9) * 2 + A
// CHECK-SAME: mov eax, $$4
__asm mov eax, A << 2
// CHECK-SAME: mov eax, $$2
__asm mov eax, B & 3
// CHECK-SAME: mov eax, $$5
__asm mov eax, 3 + (B & 3)
// CHECK-SAME: mov eax, $$8
__asm mov eax, 2 << A * B
}
// CHECK-LABEL: t3
void t3() {
int arr[4];
enum { A = 4, B };
// CHECK: call void asm
// CHECK-SAME: mov eax, [eax + $$47]
__asm { mov eax, [(x::A + 9) + A * B + 3 + 3 + eax] }
// CHECK-NEXT: call void asm
// CHECK-SAME: mov eax, dword ptr $0[$$4]
__asm { mov eax, dword ptr [arr + A] }
// CHECK-NEXT: call void asm
// CHECK-SAME: mov eax, dword ptr $0[$$8]
__asm { mov eax, dword ptr A[arr + A] }
}

View File

@ -0,0 +1,35 @@
// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -fasm-blocks -triple i386-apple-darwin10 -emit-llvm -o - | FileCheck %s
int gVar;
void t1() {
// CHECK: add eax, dword ptr gVar[eax]
__asm add eax, dword ptr gVar[eax]
// CHECK: add dword ptr gVar[eax], eax
__asm add dword ptr [eax+gVar], eax
// CHECK: add ebx, dword ptr gVar[ebx + $$270]
__asm add ebx, dword ptr gVar[271 - 82 + 81 + ebx]
// CHECK: add dword ptr gVar[ebx + $$828], ebx
__asm add dword ptr [ebx + gVar + 828], ebx
// CHECK: add ecx, dword ptr gVar[ecx + ecx * $$4 + $$4590]
__asm add ecx, dword ptr gVar[4590 + ecx + ecx*4]
// CHECK: add dword ptr gVar[ecx + ecx * $$8 + $$73], ecx
__asm add dword ptr [gVar + ecx + 45 + 23 - 53 + 60 - 2 + ecx*8], ecx
// CHECK: add gVar[ecx + ebx + $$7], eax
__asm add 1 + 1 + 2 + 3[gVar + ecx + ebx], eax
}
void t2() {
int lVar;
// CHECK: mov eax, dword ptr ${{[0-9]}}[eax]
__asm mov eax, dword ptr lVar[eax]
// CHECK: mov dword ptr ${{[0-9]}}[eax], eax
__asm mov dword ptr [eax+lVar], eax
// CHECK: mov ebx, dword ptr ${{[0-9]}}[ebx + $$270]
__asm mov ebx, dword ptr lVar[271 - 82 + 81 + ebx]
// CHECK: mov dword ptr ${{[0-9]}}[ebx + $$828], ebx
__asm mov dword ptr [ebx + lVar + 828], ebx
// CHECK: mov ${{[0-9]}}[ebx + $$47], eax
__asm mov 5 + 8 + 13 + 21[lVar + ebx], eax
}