forked from OSchip/llvm-project
[ms-inline-asm] Add field access to MS inline asm identifier lookup
Now we can parse code like this: struct A { int field; }; int f(A o) { __asm mov eax, o.field } Fixes PR19117. llvm-svn: 246088
This commit is contained in:
parent
06c199ac9d
commit
14e96b4930
|
@ -3375,6 +3375,10 @@ public:
|
|||
bool IsUnevaluatedContext);
|
||||
bool LookupInlineAsmField(StringRef Base, StringRef Member,
|
||||
unsigned &Offset, SourceLocation AsmLoc);
|
||||
ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member,
|
||||
unsigned &Offset,
|
||||
llvm::InlineAsmIdentifierInfo &Info,
|
||||
SourceLocation AsmLoc);
|
||||
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||
ArrayRef<Token> AsmToks,
|
||||
StringRef AsmString,
|
||||
|
|
|
@ -222,6 +222,25 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
|
|||
/*AllowConstructorName=*/false,
|
||||
/*ObjectType=*/ParsedType(), TemplateKWLoc, Id);
|
||||
|
||||
// Perform the lookup.
|
||||
ExprResult Result = Actions.LookupInlineAsmIdentifier(
|
||||
SS, TemplateKWLoc, Id, Info, IsUnevaluatedContext);
|
||||
|
||||
// While the next two tokens are 'period' 'identifier', repeatedly parse it as
|
||||
// a field access. We have to avoid consuming assembler directives that look
|
||||
// like '.' 'else'.
|
||||
while (Result.isUsable() && Tok.is(tok::period)) {
|
||||
Token IdTok = PP.LookAhead(0);
|
||||
if (IdTok.isNot(tok::identifier))
|
||||
break;
|
||||
ConsumeToken(); // Consume the period.
|
||||
IdentifierInfo *Id = Tok.getIdentifierInfo();
|
||||
ConsumeToken(); // Consume the identifier.
|
||||
unsigned OffsetUnused;
|
||||
Result = Actions.LookupInlineAsmVarDeclField(
|
||||
Result.get(), Id->getName(), OffsetUnused, Info, Tok.getLocation());
|
||||
}
|
||||
|
||||
// Figure out how many tokens we are into LineToks.
|
||||
unsigned LineIndex = 0;
|
||||
if (Tok.is(EndOfStream)) {
|
||||
|
@ -254,9 +273,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
|
|||
LineToks.pop_back();
|
||||
LineToks.pop_back();
|
||||
|
||||
// Perform the lookup.
|
||||
return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
|
||||
IsUnevaluatedContext);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Turn a sequence of our tokens back into a string that we can hand
|
||||
|
|
|
@ -528,6 +528,17 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
|
||||
SourceLocation TemplateKWLoc,
|
||||
UnqualifiedId &Id,
|
||||
|
@ -575,13 +586,7 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
fillInlineAsmTypeInfo(Context, T, Info);
|
||||
|
||||
// We can work with the expression as long as it's not an r-value.
|
||||
if (!Result.get()->isRValue())
|
||||
|
@ -636,6 +641,49 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
|
|||
return false;
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, unsigned &Offset,
|
||||
llvm::InlineAsmIdentifierInfo &Info,
|
||||
SourceLocation AsmLoc) {
|
||||
Info.clear();
|
||||
|
||||
const RecordType *RT = E->getType()->getAs<RecordType>();
|
||||
// FIXME: Diagnose this as field access into a scalar type.
|
||||
if (!RT)
|
||||
return ExprResult();
|
||||
|
||||
LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc,
|
||||
LookupMemberName);
|
||||
|
||||
if (!LookupQualifiedName(FieldResult, RT->getDecl()))
|
||||
return ExprResult();
|
||||
|
||||
// Only normal and indirect field results will work.
|
||||
ValueDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
|
||||
if (!FD)
|
||||
FD = dyn_cast<IndirectFieldDecl>(FieldResult.getFoundDecl());
|
||||
if (!FD)
|
||||
return ExprResult();
|
||||
|
||||
Offset = (unsigned)Context.toCharUnitsFromBits(Context.getFieldOffset(FD))
|
||||
.getQuantity();
|
||||
|
||||
// Make an Expr to thread through OpDecl.
|
||||
ExprResult Result = BuildMemberReferenceExpr(
|
||||
E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(),
|
||||
SourceLocation(), nullptr, FieldResult, 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;
|
||||
}
|
||||
|
||||
StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
|
||||
ArrayRef<Token> AsmToks,
|
||||
StringRef AsmString,
|
||||
|
|
|
@ -563,3 +563,21 @@ void label4() {
|
|||
// CHECK-LABEL: define void @label4
|
||||
// CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.4__label:\0A\09mov eax, {{.*}}__MSASMLABEL_.4__label", "~{eax},~{dirflag},~{fpsr},~{flags}"()
|
||||
}
|
||||
|
||||
typedef union _LARGE_INTEGER {
|
||||
struct {
|
||||
unsigned int LowPart;
|
||||
unsigned int HighPart;
|
||||
};
|
||||
struct {
|
||||
unsigned int LowPart;
|
||||
unsigned int HighPart;
|
||||
} u;
|
||||
unsigned long long QuadPart;
|
||||
} LARGE_INTEGER, *PLARGE_INTEGER;
|
||||
|
||||
int test_indirect_field(LARGE_INTEGER LargeInteger) {
|
||||
__asm mov eax, LargeInteger.LowPart
|
||||
}
|
||||
// CHECK-LABEL: define i32 @test_indirect_field(
|
||||
// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1",
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// REQUIRES: x86-registered-target
|
||||
// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -fasm-blocks -emit-llvm -o - | FileCheck %s
|
||||
|
||||
struct A {
|
||||
int a1;
|
||||
int a2;
|
||||
struct B {
|
||||
int b1;
|
||||
int b2;
|
||||
} a3;
|
||||
};
|
||||
|
||||
namespace asdf {
|
||||
A a_global;
|
||||
}
|
||||
|
||||
extern "C" int test_param_field(A p) {
|
||||
// CHECK: define i32 @test_param_field(%struct.A* byval align 4 %p)
|
||||
// CHECK: getelementptr inbounds %struct.A, %struct.A* %p, i32 0, i32 0
|
||||
// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1"
|
||||
// CHECK: ret i32
|
||||
__asm mov eax, p.a1
|
||||
}
|
||||
|
||||
extern "C" int test_namespace_global() {
|
||||
// CHECK: define i32 @test_namespace_global()
|
||||
// CHECK: call i32 asm sideeffect inteldialect "mov eax, dword ptr $1", "{{.*}}"(i32* getelementptr inbounds (%struct.A, %struct.A* @_ZN4asdf8a_globalE, i32 0, i32 2, i32 1))
|
||||
// CHECK: ret i32
|
||||
__asm mov eax, asdf::a_global.a3.b2
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// REQUIRES: x86-registered-target
|
||||
// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -fasm-blocks -verify
|
||||
|
||||
struct A {
|
||||
int a1;
|
||||
int a2;
|
||||
struct B {
|
||||
int b1;
|
||||
int b2;
|
||||
enum { kValue = 42 };
|
||||
} a3;
|
||||
struct {
|
||||
int indirect_field;
|
||||
};
|
||||
};
|
||||
|
||||
namespace asdf {
|
||||
A a_global;
|
||||
}
|
||||
|
||||
// The parser combines adjacent __asm blocks into one. Avoid that by calling
|
||||
// this.
|
||||
void split_inline_asm_call();
|
||||
|
||||
void test_field_lookup() {
|
||||
__asm mov eax, asdf::a_global.a3.b2
|
||||
split_inline_asm_call();
|
||||
|
||||
// FIXME: These diagnostics are crap.
|
||||
|
||||
// expected-error@+1 {{undeclared label}}
|
||||
__asm mov eax, asdf::a_global.not_a_field.b2
|
||||
split_inline_asm_call();
|
||||
|
||||
// expected-error@+1 {{undeclared label}}
|
||||
__asm mov eax, asdf::a_global.a3.not_a_field
|
||||
split_inline_asm_call();
|
||||
|
||||
__asm mov eax, A::B::kValue
|
||||
split_inline_asm_call();
|
||||
|
||||
// expected-error@+1 {{undeclared label}}
|
||||
__asm mov eax, asdf::a_global.a3.kValue
|
||||
split_inline_asm_call();
|
||||
|
||||
__asm mov eax, asdf :: a_global.a3.b2
|
||||
split_inline_asm_call();
|
||||
|
||||
__asm mov eax, asdf::a_global . a3 . b2
|
||||
split_inline_asm_call();
|
||||
|
||||
__asm mov eax, asdf::a_global.indirect_field
|
||||
split_inline_asm_call();
|
||||
}
|
Loading…
Reference in New Issue