r246088 - [ms-inline-asm] Add field access to MS inline asm identifier lookup

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 26 14:57:20 PDT 2015


Author: rnk
Date: Wed Aug 26 16:57:20 2015
New Revision: 246088

URL: http://llvm.org/viewvc/llvm-project?rev=246088&view=rev
Log:
[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.

Added:
    cfe/trunk/test/CodeGenCXX/ms-inline-asm-fields.cpp
    cfe/trunk/test/SemaCXX/ms-inline-asm.cpp
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseStmtAsm.cpp
    cfe/trunk/lib/Sema/SemaStmtAsm.cpp
    cfe/trunk/test/CodeGen/ms-inline-asm.c

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=246088&r1=246087&r2=246088&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Aug 26 16:57:20 2015
@@ -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,

Modified: cfe/trunk/lib/Parse/ParseStmtAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=246088&r1=246087&r2=246088&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmtAsm.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp Wed Aug 26 16:57:20 2015
@@ -222,6 +222,25 @@ ExprResult Parser::ParseMSAsmIdentifier(
                          /*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(
   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

Modified: cfe/trunk/lib/Sema/SemaStmtAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAsm.cpp?rev=246088&r1=246087&r2=246088&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAsm.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAsm.cpp Wed Aug 26 16:57:20 2015
@@ -528,6 +528,17 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceL
   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::LookupInlineAsmIdentifi
     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(StringRe
   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,

Modified: cfe/trunk/test/CodeGen/ms-inline-asm.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ms-inline-asm.c?rev=246088&r1=246087&r2=246088&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/ms-inline-asm.c (original)
+++ cfe/trunk/test/CodeGen/ms-inline-asm.c Wed Aug 26 16:57:20 2015
@@ -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",

Added: cfe/trunk/test/CodeGenCXX/ms-inline-asm-fields.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/ms-inline-asm-fields.cpp?rev=246088&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/ms-inline-asm-fields.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/ms-inline-asm-fields.cpp Wed Aug 26 16:57:20 2015
@@ -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
+}
+

Added: cfe/trunk/test/SemaCXX/ms-inline-asm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms-inline-asm.cpp?rev=246088&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/ms-inline-asm.cpp (added)
+++ cfe/trunk/test/SemaCXX/ms-inline-asm.cpp Wed Aug 26 16:57:20 2015
@@ -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 at +1 {{undeclared label}}
+  __asm mov eax, asdf::a_global.not_a_field.b2
+  split_inline_asm_call();
+
+  // expected-error at +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 at +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();
+}




More information about the cfe-commits mailing list