[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


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314494 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Coby Tayree 2017-09-29 07:02:49 +00:00
parent 8c6abdf1ba
commit 2fb39644fd
6 changed files with 122 additions and 47 deletions

View File

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

View File

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

View File

@ -54,9 +54,9 @@ public:
assert(AsmToks.size() == AsmTokOffsets.size()); assert(AsmToks.size() == AsmTokOffsets.size());
} }
void *LookupInlineAsmIdentifier(StringRef &LineBuf, void LookupInlineAsmIdentifier(StringRef &LineBuf,
llvm::InlineAsmIdentifierInfo &Info, llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) override { bool IsUnevaluatedContext) override {
// Collect the desired tokens. // Collect the desired tokens.
SmallVector<Token, 16> LineToks; SmallVector<Token, 16> LineToks;
const Token *FirstOrigToken = nullptr; const Token *FirstOrigToken = nullptr;
@ -64,7 +64,7 @@ public:
unsigned NumConsumedToks; unsigned NumConsumedToks;
ExprResult Result = TheParser.ParseMSAsmIdentifier( ExprResult Result = TheParser.ParseMSAsmIdentifier(
LineToks, NumConsumedToks, &Info, IsUnevaluatedContext); LineToks, NumConsumedToks, IsUnevaluatedContext);
// If we consumed the entire line, tell MC that. // If we consumed the entire line, tell MC that.
// Also do this if we consumed nothing as a way of reporting failure. // Also do this if we consumed nothing as a way of reporting failure.
@ -89,9 +89,10 @@ public:
LineBuf = LineBuf.substr(0, TotalOffset); LineBuf = LineBuf.substr(0, TotalOffset);
} }
// Initialize the "decl" with the lookup result. // Initialize Info with the lookup result.
Info.OpDecl = static_cast<void *>(Result.get()); if (!Result.isUsable())
return Info.OpDecl; return;
TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
} }
StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
@ -178,16 +179,9 @@ private:
} }
/// Parse an identifier in an MS-style inline assembly block. /// 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, ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
unsigned &NumLineToksConsumed, unsigned &NumLineToksConsumed,
void *CastInfo,
bool IsUnevaluatedContext) { bool IsUnevaluatedContext) {
llvm::InlineAsmIdentifierInfo &Info =
*(llvm::InlineAsmIdentifierInfo *)CastInfo;
// Push a fake token on the end so that we don't overrun the token // Push a fake token on the end so that we don't overrun the token
// stream. We use ';' because it expression-parsing should never // stream. We use ';' because it expression-parsing should never
// overrun it. // overrun it.
@ -227,7 +221,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
/*AllowDeductionGuide=*/false, /*AllowDeductionGuide=*/false,
/*ObjectType=*/nullptr, TemplateKWLoc, Id); /*ObjectType=*/nullptr, TemplateKWLoc, Id);
// Perform the lookup. // Perform the lookup.
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
IsUnevaluatedContext); IsUnevaluatedContext);
} }
// While the next two tokens are 'period' 'identifier', repeatedly parse it as // 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(); IdentifierInfo *Id = Tok.getIdentifierInfo();
ConsumeToken(); // Consume the identifier. ConsumeToken(); // Consume the identifier.
Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(), Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(),
Info, Tok.getLocation()); Tok.getLocation());
} }
// Figure out how many tokens we are into LineToks. // 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 (E != E2 && E2->isLValue()) {
if (!S.getLangOpts().HeinousExtensions) if (!S.getLangOpts().HeinousExtensions)
S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
<< E->getSourceRange(); << E->getSourceRange();
else else
S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
<< E->getSourceRange(); << E->getSourceRange();
// Accept, even if we emitted an error diagnostic. // Accept, even if we emitted an error diagnostic.
return false; return false;
} }
@ -607,23 +607,31 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return NS; return NS;
} }
static void fillInlineAsmTypeInfo(const ASTContext &Context, QualType T, void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
llvm::InlineAsmIdentifierInfo &Info) { llvm::InlineAsmIdentifierInfo &Info) {
// Compute the type size (and array length if applicable?). QualType T = Res->getType();
Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); Expr::EvalResult Eval;
if (T->isArrayType()) { if (T->isFunctionType() || T->isDependentType())
const ArrayType *ATy = Context.getAsArrayType(T); return Info.setLabel(Res);
Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); if (Res->isRValue()) {
Info.Length = Info.Size / Info.Type; 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, ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
UnqualifiedId &Id, UnqualifiedId &Id,
llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) { bool IsUnevaluatedContext) {
Info.clear();
if (IsUnevaluatedContext) if (IsUnevaluatedContext)
PushExpressionEvaluationContext( PushExpressionEvaluationContext(
@ -664,12 +672,6 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
return ExprError(); 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; return Result;
} }
@ -743,9 +745,7 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
ExprResult ExprResult
Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
llvm::InlineAsmIdentifierInfo &Info,
SourceLocation AsmLoc) { SourceLocation AsmLoc) {
Info.clear();
QualType T = E->getType(); QualType T = E->getType();
if (T->isDependentType()) { if (T->isDependentType()) {
@ -780,14 +780,6 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member,
ExprResult Result = BuildMemberReferenceExpr( ExprResult Result = BuildMemberReferenceExpr(
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(), E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
SourceLocation(), nullptr, FieldResult, nullptr, nullptr); 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; 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
}