craig.topper updated this revision to Diff 184447.
craig.topper added a comment.

Pass FunctionType into the IRBuilder::CreateCallBr to avoid needing to make an 
opaque pointer update later


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56571/new/

https://reviews.llvm.org/D56571

Files:
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/ExprObjC.h
  include/clang/AST/Stmt.h
  include/clang/Basic/DiagnosticASTKinds.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/AST/ASTImporter.cpp
  lib/AST/Stmt.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/Analysis/CFG.cpp
  lib/CodeGen/CGStmt.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParseStmtAsm.cpp
  lib/Sema/SemaStmtAsm.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/Analysis/asm-goto.cpp
  test/CodeGen/asm-goto.c
  test/CodeGen/asm.c
  test/CodeGen/inline-asm-mixed-style.c
  test/Coverage/c-language-features.inc
  test/PCH/asm.h
  test/Parser/asm-goto.c
  test/Parser/asm-goto.cpp
  test/Parser/asm.c
  test/Parser/asm.cpp
  test/Sema/asm.c
  test/Sema/inline-asm-validate-tmpl.cpp

Index: test/Sema/inline-asm-validate-tmpl.cpp
===================================================================
--- test/Sema/inline-asm-validate-tmpl.cpp
+++ test/Sema/inline-asm-validate-tmpl.cpp
@@ -23,3 +23,13 @@
 	asm("rol %1, %0" :"=r"(value): "I"(N + 1));
 }
 int	foo() { testc<2>(10); }
+
+// these should compile without error
+template <int N> bool testd()
+{
+  __asm goto ("" : : : : lab);
+  return true;
+lab:
+  return false;
+}
+bool foox() { return testd<0> (); }
Index: test/Sema/asm.c
===================================================================
--- test/Sema/asm.c
+++ test/Sema/asm.c
@@ -295,3 +295,28 @@
   return r0 + r1;
 }
 
+void test18()
+{
+  // expected-error@+2 {{duplicate use of asm operand name "lab"}}
+  // expected-note@+1 {{asm operand name "lab" first referenced here}}
+  asm goto ("" : : : : lab, lab, lab2, lab);
+  // expected-error@+2 {{duplicate use of asm operand name "lab"}}
+  // expected-note@+1 {{asm operand name "lab" first referenced here}}
+  asm goto ("xorw %[lab], %[lab]; je %l[lab]" : : [lab] "i" (0) : : lab);
+lab:;
+lab2:;
+  int x,x1;
+  // expected-error@+2 {{duplicate use of asm operand name "lab"}}
+  // expected-note@+1 {{asm operand name "lab" first referenced here}}
+  asm ("" : [lab] "=r" (x),[lab] "+r" (x) : [lab1] "r" (x));
+  // expected-error@+2 {{duplicate use of asm operand name "lab"}}
+  // expected-note@+1 {{asm operand name "lab" first referenced here}}
+  asm ("" : [lab] "=r" (x1) : [lab] "r" (x));
+  // expected-error@+1 {{operand with 'l' modifier must refer to a label}}
+  asm ("jne %l0"::"r"(&&lab));
+  // expected-error@+1 {{invalid operand number in inline asm string}}
+  asm ("jne %l0":::);
+  // expected-error@+1 {{operand with 'l' modifier must refer to a label}}
+  asm goto ("jne %l0"::"r"(x)::lab);
+  asm goto ("jne %l0"::::lab);
+}
Index: test/Parser/asm.cpp
===================================================================
--- test/Parser/asm.cpp
+++ test/Parser/asm.cpp
@@ -7,3 +7,28 @@
 int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
 int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
 int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
+
+int zoo ()
+{
+  int x,cond,*e;
+  // expected-error@+1 {{expected ')'}}
+  asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a)
+  // expected-error@+1  {{expected ':'}}
+  asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a);
+  // expected-error@+1 {{expected identifie}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" : );
+  // expected-error@+1  {{expected ':'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" );
+  // expected-error@+1 {{use of undeclared label 'x'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" :x);
+  // expected-error@+1 {{use of undeclared label 'b'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" :b);
+  // expected-error@+1 {{invalid operand number in inline asm string}}
+  asm goto ("testl %0, %0; jne %l3;" :: "r"(cond)::label_true, loop)
+  // expected-error@+1 {{unknown symbolic operand name in inline assembly string}}
+  asm goto ("decl %0; jnz %l[b]" :: "m"(x) : "memory" : a);
+label_true:
+loop:
+a:
+  return 0;
+}
Index: test/Parser/asm.c
===================================================================
--- test/Parser/asm.c
+++ test/Parser/asm.c
@@ -16,6 +16,31 @@
   asm _Atomic (""); // expected-warning {{ignored _Atomic qualifier on asm}}
 }
 
+int zoo ()
+{
+  int x,cond,*e;
+  // expected-error@+1 {{expected ')'}}
+  asm ("mov %[e], %[e]" : : [e] "rm" (*e)::a)
+  // expected-error@+1 {{expected ':'}}
+  asm goto ("decl %0; jnz %l[a]" :"=r"(x): "m"(x) : "memory" : a);
+  // expected-error@+1 {{expected identifie}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" : );
+  // expected-error@+1 {{expected ':'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" );
+  // expected-error@+1 {{use of undeclared label 'x'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" :x);
+  // expected-error@+1 {{use of undeclared label 'b'}}
+  asm goto ("decl %0;" :: "m"(x) : "memory" :b);
+  // expected-error@+1 {{invalid operand number in inline asm string}}
+  asm goto ("testl %0, %0; jne %l3;" :: "r"(cond)::label_true, loop)
+  // expected-error@+1 {{unknown symbolic operand name in inline assembly string}}
+  asm goto ("decl %0; jnz %l[b]" :: "m"(x) : "memory" : a);
+a:
+label_true:
+loop:
+  return 0;
+}
+
 
 // rdar://5952468
 __asm ; // expected-error {{expected '(' after 'asm'}}
Index: test/Parser/asm-goto.cpp
===================================================================
--- /dev/null
+++ test/Parser/asm-goto.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 %s
+
+int a, b, c, d, e, f, g, h, i, j, k, l;
+
+void
+f1 (void)
+{
+  __asm__ volatile goto (""
+            :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d),
+               [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h),
+               [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l)
+            ::lab1,lab2);
+lab1: return;
+lab2: return;
+}
+
+void
+f2 (void)
+{
+  __asm__ volatile goto (""
+            :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d),
+               [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h),
+               [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l)
+            :: lab);
+  lab: return;
+}
Index: test/Parser/asm-goto.c
===================================================================
--- /dev/null
+++ test/Parser/asm-goto.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s
+
+int a, b, c, d, e, f, g, h, i, j, k, l;
+
+void
+f1 (void)
+{
+  __asm__ volatile goto (""
+            :: [a] "r" (a), [b] "r" (b), [c] "r" (c), [d] "r" (d),
+               [e] "r" (e), [f] "r" (f), [g] "r" (g), [h] "r" (h),
+               [i] "r" (i), [j] "r" (j), [k] "r" (k), [l] "r" (l)
+            ::lab1,lab2);
+lab1: return;
+lab2: return;
+}
+
+void
+f2 (void)
+{
+  __asm__ volatile goto (""
+            :: [a] "r,m" (a), [b] "r,m" (b), [c] "r,m" (c), [d] "r,m" (d),
+               [e] "r,m" (e), [f] "r,m" (f), [g] "r,m" (g), [h] "r,m" (h),
+               [i] "r,m" (i), [j] "r,m" (j), [k] "r,m" (k), [l] "r,m" (l)
+            :: lab);
+  lab: return;
+}
+
Index: test/PCH/asm.h
===================================================================
--- test/PCH/asm.h
+++ test/PCH/asm.h
@@ -1,10 +1,14 @@
 // Header for the PCH test asm.c
 
 void f() {
-  int i;
+  int i,cond;
 
   asm ("foo\n" : : "a" (i + 2));
   asm ("foo\n" : [symbolic_name] "=a" (i) : "[symbolic_name]" (i));
+  asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
+label_true:
+loop:
+  return;
 }
 
 void clobbers() {
Index: test/Coverage/c-language-features.inc
===================================================================
--- test/Coverage/c-language-features.inc
+++ test/Coverage/c-language-features.inc
@@ -71,7 +71,9 @@
   }
 
   asm ("nop");
-
+  int cond;
+  asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true);
+label_true:
   return;
 }
 
Index: test/CodeGen/inline-asm-mixed-style.c
===================================================================
--- test/CodeGen/inline-asm-mixed-style.c
+++ test/CodeGen/inline-asm-mixed-style.c
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -fsyntax-only -verify %s -DCHECK_ASM_GOTO
 // RUN: %clang_cc1 -triple i386-unknown-unknown -fasm-blocks -O0 -emit-llvm -S %s -o - | FileCheck %s
 // REQUIRES: x86-registered-target
 
@@ -20,10 +19,11 @@
   // CHECK: movl    %ebx, %eax
   // CHECK: movl    %ecx, %edx
 
-#ifdef CHECK_ASM_GOTO
-  __asm volatile goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}}
+  __asm volatile goto ("movl %ecx, %edx");
+  // CHECK: movl    %ecx, %edx
 
   __asm mov eax, ebx
-  __asm goto ("movl %ecx, %edx"); // expected-error {{'asm goto' constructs are not supported yet}}
-#endif
+  __asm goto ("movl %ecx, %edx");
+  // CHECK: movl    %ebx, %eax
+  // CHECK: movl    %ecx, %edx
 }
Index: test/CodeGen/asm.c
===================================================================
--- test/CodeGen/asm.c
+++ test/CodeGen/asm.c
@@ -262,3 +262,15 @@
   // CHECK: @t31
   // CHECK: call void asm sideeffect "", "=*%rm,=*rm,0,1,~{dirflag},~{fpsr},~{flags}"
 }
+
+// CHECK: @t32
+int t32(int cond)
+{
+  asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
+  // CHECK: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,X,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@t32, %label_true), i8* blockaddress(@t32, %loop)) #1
+  return 0;
+loop:
+  return 0;
+label_true:
+  return 1;
+}
Index: test/CodeGen/asm-goto.c
===================================================================
--- /dev/null
+++ test/CodeGen/asm-goto.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -O0 -emit-llvm  %s -o - | FileCheck %s
+
+int foo(int cond)
+{
+  // CHECK: callbr void asm sideeffect
+  // CHECK: to label %normal0 [label %label_true, label %loop], !srcloc !2
+  // CHECK: normal0:
+  asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
+  return 0;
+loop:
+  return 0;
+label_true:
+  return 1;
+}
Index: test/Analysis/asm-goto.cpp
===================================================================
--- /dev/null
+++ test/Analysis/asm-goto.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
+
+int foo(int cond)
+{
+label_true:
+  asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
+  return 0;
+loop:
+  return 0;
+}
+
+// CHECK-LABEL: loop
+// CHECK-NEXT: 0
+// CHECK-NEXT: return
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK-LABEL: label_true
+// CHECK-NEXT: asm goto
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -282,6 +282,7 @@
 
 void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
   VisitAsmStmt(S);
+  Record.push_back(S->getNumLabels());
   Record.AddSourceLocation(S->getRParenLoc());
   Record.AddStmt(S->getAsmString());
 
@@ -303,6 +304,9 @@
   for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
     Record.AddStmt(S->getClobberStringLiteral(I));
 
+  // Labels
+  for (auto *E : S->labels()) Record.AddStmt(E);
+
   Code = serialization::STMT_GCCASM;
 }
 
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -369,12 +369,14 @@
 
 void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
   VisitAsmStmt(S);
+  S->NumLabels = Record.readInt();
   S->setRParenLoc(ReadSourceLocation());
   S->setAsmString(cast_or_null<StringLiteral>(Record.readSubStmt()));
 
   unsigned NumOutputs = S->getNumOutputs();
   unsigned NumInputs = S->getNumInputs();
   unsigned NumClobbers = S->getNumClobbers();
+  unsigned NumLabels = S->getNumLabels();
 
   // Outputs and inputs
   SmallVector<IdentifierInfo *, 16> Names;
@@ -391,9 +393,14 @@
   for (unsigned I = 0; I != NumClobbers; ++I)
     Clobbers.push_back(cast_or_null<StringLiteral>(Record.readSubStmt()));
 
+  // Labels
+  for (unsigned I = 0, N = NumLabels; I != N; ++I)
+    Exprs.push_back(Record.readSubStmt());
+
   S->setOutputsAndInputsAndClobbers(Record.getContext(),
                                     Names.data(), Constraints.data(),
                                     Exprs.data(), NumOutputs, NumInputs,
+                                    NumLabels,
                                     Clobbers.data(), NumClobbers);
 }
 
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1356,10 +1356,11 @@
                                unsigned NumInputs, IdentifierInfo **Names,
                                MultiExprArg Constraints, MultiExprArg Exprs,
                                Expr *AsmString, MultiExprArg Clobbers,
+                               unsigned NumLabels,
                                SourceLocation RParenLoc) {
     return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs,
                                      NumInputs, Names, Constraints, Exprs,
-                                     AsmString, Clobbers, RParenLoc);
+                                     AsmString, Clobbers, NumLabels, RParenLoc);
   }
 
   /// Build a new MS style inline asm statement.
@@ -6968,6 +6969,16 @@
     Exprs.push_back(Result.get());
   }
 
+  // Go through the Labels.
+  for (unsigned I = 0, E = S->getNumLabels(); I != E; ++I) {
+    Names.push_back(S->getLabelIdentifier(I));
+
+    ExprResult Result = getDerived().TransformExpr(S->getLabelExpr(I));
+    if (Result.isInvalid())
+      return StmtError();
+    ExprsChanged |= Result.get() != S->getLabelExpr(I);
+    Exprs.push_back(Result.get());
+  }
   if (!getDerived().AlwaysRebuild() && !ExprsChanged)
     return S;
 
@@ -6981,7 +6992,8 @@
                                         S->isVolatile(), S->getNumOutputs(),
                                         S->getNumInputs(), Names.data(),
                                         Constraints, Exprs, AsmString.get(),
-                                        Clobbers, S->getRParenLoc());
+                                        Clobbers, S->getNumLabels(),
+                                        S->getRParenLoc());
 }
 
 template<typename Derived>
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -209,11 +209,12 @@
 static SourceLocation
 getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints,
                            StringLiteral **Clobbers, int NumClobbers,
+                           unsigned NumLabels,
                            const TargetInfo &Target, ASTContext &Cont) {
   llvm::StringSet<> InOutVars;
   // Collect all the input and output registers from the extended asm
   // statement in order to check for conflicts with the clobber list
-  for (unsigned int i = 0; i < Exprs.size(); ++i) {
+  for (unsigned int i = 0; i < Exprs.size() - NumLabels; ++i) {
     StringRef Constraint = Constraints[i]->getString();
     StringRef InOutReg = Target.getConstraintRegister(
         Constraint, extractRegisterName(Exprs[i], Target));
@@ -241,6 +242,7 @@
                                  unsigned NumInputs, IdentifierInfo **Names,
                                  MultiExprArg constraints, MultiExprArg Exprs,
                                  Expr *asmString, MultiExprArg clobbers,
+                                 unsigned NumLabels,
                                  SourceLocation RParenLoc) {
   unsigned NumClobbers = clobbers.size();
   StringLiteral **Constraints =
@@ -258,7 +260,8 @@
   if (!DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) {
     GCCAsmStmt *NS = new (Context) GCCAsmStmt(
         Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names,
-        Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers, RParenLoc);
+        Constraints, Exprs.data(), AsmString, NumClobbers, Clobbers,
+        NumLabels, RParenLoc);
     return NS;
   }
 
@@ -442,7 +445,8 @@
   GCCAsmStmt *NS =
     new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
                              NumInputs, Names, Constraints, Exprs.data(),
-                             AsmString, NumClobbers, Clobbers, RParenLoc);
+                             AsmString, NumClobbers, Clobbers, NumLabels,
+                             RParenLoc);
   // Validate the asm string, ensuring it makes sense given the operands we
   // have.
   SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces;
@@ -460,8 +464,10 @@
 
     // Look for the correct constraint index.
     unsigned ConstraintIdx = Piece.getOperandNo();
+    // Labels are the last in the Exprs list.
+    if (NS->isGCCAsmGoto() && ConstraintIdx >= NS->getNumInputs())
+      continue;
     unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
-
     // Look for the (ConstraintIdx - NumOperands + 1)th constraint with
     // modifier '+'.
     if (ConstraintIdx >= NumOperands) {
@@ -641,10 +647,39 @@
   // Check for conflicts between clobber list and input or output lists
   SourceLocation ConstraintLoc =
       getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers,
+                                 NumLabels,
                                  Context.getTargetInfo(), Context);
   if (ConstraintLoc.isValid())
     return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber);
 
+  // Check for duplicate asm operand name between input, output and label lists.
+  typedef std::pair <StringRef , Expr *> MyItemType;
+  SmallVector<MyItemType, 4> MyList;
+  // Build MyList which contains symbolic name and corresponding operand.
+  for (unsigned i = 0, e = NumOutputs + NumInputs + NumLabels; i != e; ++i)
+    if (NS->getIdentifier(i) && !NS->getIdentifier(i)->getName().empty())
+      MyList.emplace_back(
+          std::make_pair(NS->getIdentifier(i)->getName(), NS->getExpr(i)));
+  // Sort MyList.
+  stable_sort(MyList.begin(), MyList.end(),
+              [](const MyItemType &LHS, const MyItemType &RHS) {
+                return LHS.first < RHS.first;
+              });
+  // Find adjacent duplicate operand.
+  SmallVector<MyItemType, 4>::iterator Found =
+      std::adjacent_find(begin(MyList), end(MyList),
+                         [](const MyItemType &LHS, const MyItemType &RHS) {
+                           return LHS.first == RHS.first;
+                         });
+  if (Found != MyList.end()) {
+    Diag((Found + 1)->second->getBeginLoc(),
+         diag::error_duplicate_asm_operand_name)
+        << (Found + 1)->first;
+    Diag(Found->second->getBeginLoc(), diag::note_duplicate_asm_operand_name)
+        << Found->first;
+    return StmtError();
+  }
+
   return NS;
 }
 
Index: lib/Parse/ParseStmtAsm.cpp
===================================================================
--- lib/Parse/ParseStmtAsm.cpp
+++ lib/Parse/ParseStmtAsm.cpp
@@ -709,12 +709,12 @@
 
   // Remember if this was a volatile asm.
   bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
+  // Remember if this was a goto asm.
+  bool isGotoAsm = false;
 
-  // TODO: support "asm goto" constructs (PR#9295).
   if (Tok.is(tok::kw_goto)) {
-    Diag(Tok, diag::err_asm_goto_not_supported_yet);
-    SkipUntil(tok::r_paren, StopAtSemi);
-    return StmtError();
+    isGotoAsm = true;
+    ConsumeToken();
   }
 
   if (Tok.isNot(tok::l_paren)) {
@@ -752,7 +752,8 @@
     return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
                                    /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
                                    Constraints, Exprs, AsmString.get(),
-                                   Clobbers, T.getCloseLocation());
+                                   Clobbers, /*NumLabels*/ 0,
+                                   T.getCloseLocation());
   }
 
   // Parse Outputs, if present.
@@ -762,6 +763,12 @@
     AteExtraColon = Tok.is(tok::coloncolon);
     ConsumeToken();
 
+    if (!AteExtraColon && isGotoAsm && Tok.isNot(tok::colon)) {
+      Diag(Tok, diag::err_expected) << tok::colon;
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return StmtError();
+    }
+
     if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
       return StmtError();
   }
@@ -788,12 +795,16 @@
   unsigned NumInputs = Names.size() - NumOutputs;
 
   // Parse the clobbers, if present.
-  if (AteExtraColon || Tok.is(tok::colon)) {
-    if (!AteExtraColon)
+  if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+    if (AteExtraColon)
+      AteExtraColon = false;
+    else {
+      AteExtraColon = Tok.is(tok::coloncolon);
       ConsumeToken();
-
+    }
     // Parse the asm-string list for clobbers if present.
-    if (Tok.isNot(tok::r_paren)) {
+    if (!AteExtraColon && Tok.isNot(tok::r_paren) &&
+        isTokenStringLiteral()) {
       while (1) {
         ExprResult Clobber(ParseAsmStringLiteral());
 
@@ -807,11 +818,51 @@
       }
     }
   }
+  if (!isGotoAsm && Tok.isNot(tok::r_paren)) {
+    Diag(Tok, diag::err_expected) << tok::r_paren;
+    SkipUntil(tok::r_paren, StopAtSemi);
+    return StmtError();
+  }
+
+  // Parse the goto label, if present.
+  unsigned NumLabels = 0;
+  if (AteExtraColon || Tok.is(tok::colon)) {
+    if (!AteExtraColon)
+      ConsumeToken();
 
+    if (Tok.isNot(tok::identifier)) {
+      Diag(Tok, diag::err_expected) << tok::identifier;
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return StmtError();
+    }
+    if (Tok.isNot(tok::r_paren)) {
+      while (1) {
+        LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
+                                                     Tok.getLocation());
+        Names.push_back(Tok.getIdentifierInfo());
+        if (!LD) {
+          SkipUntil(tok::r_paren, StopAtSemi);
+          return StmtError();
+        }
+        ExprResult Res = Actions.ActOnAddrLabel(Tok.getLocation(),
+                                                Tok.getLocation(), LD);
+        Exprs.push_back(Res.get());
+        NumLabels++;
+        ConsumeToken();
+        if (!TryConsumeToken(tok::comma))
+          break;
+      }
+    }
+  } else if (isGotoAsm) {
+    Diag(Tok, diag::err_expected) << tok::colon;
+    SkipUntil(tok::r_paren, StopAtSemi);
+    return StmtError();
+  }
   T.consumeClose();
   return Actions.ActOnGCCAsmStmt(
       AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
-      Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
+      Constraints, Exprs, AsmString.get(), Clobbers, NumLabels,
+      T.getCloseLocation());
 }
 
 /// ParseAsmOperands - Parse the asm-operands production as used by
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1389,6 +1389,9 @@
   /// Count the number of simple (constant) return expressions in the function.
   unsigned NumSimpleReturnExprs = 0;
 
+  /// Count the number of Gnu inline ASM stmt in the function.
+  unsigned NumGccAsmGotoStmts = 0;
+
   /// The last regular (non-return) debug location (breakpoint) in the function.
   SourceLocation LastStopPoint;
 
@@ -2875,6 +2878,13 @@
   void EmitDefaultStmt(const DefaultStmt &S);
   void EmitCaseStmt(const CaseStmt &S);
   void EmitCaseStmtRange(const CaseStmt &S);
+  template<typename T>
+  void UpdateCallInst(T &Result,
+                      bool HasSideEffect,
+                      bool ReadOnly, bool ReadNone,
+                      const AsmStmt &S,
+                      const std::vector<llvm::Type *> &ResultRegTypes,
+                      std::vector<llvm::Value*>  &RegResults);
   void EmitAsmStmt(const AsmStmt &S);
 
   void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -1880,6 +1880,55 @@
   return llvm::MDNode::get(CGF.getLLVMContext(), Locs);
 }
 
+template <typename T>
+void CodeGenFunction::UpdateCallInst(
+    T &Result, bool HasSideEffect, bool ReadOnly, bool ReadNone,
+    const AsmStmt &S, const std::vector<llvm::Type *> &ResultRegTypes,
+    std::vector<llvm::Value *> &RegResults) {
+  Result.addAttribute(llvm::AttributeList::FunctionIndex,
+                      llvm::Attribute::NoUnwind);
+  // Attach readnone and readonly attributes.
+  if (!HasSideEffect) {
+    if (ReadNone)
+      Result.addAttribute(llvm::AttributeList::FunctionIndex,
+                          llvm::Attribute::ReadNone);
+    else if (ReadOnly)
+      Result.addAttribute(llvm::AttributeList::FunctionIndex,
+                          llvm::Attribute::ReadOnly);
+  }
+
+  // Slap the source location of the inline asm into a !srcloc metadata on the
+  // call.
+  if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S))
+    Result.setMetadata("srcloc",
+                       getAsmSrcLocInfo(gccAsmStmt->getAsmString(), *this));
+  else {
+    // At least put the line number on MS inline asm blobs.
+    llvm::Constant *Loc = llvm::ConstantInt::get(Int32Ty,
+                                        S.getAsmLoc().getRawEncoding());
+    Result.setMetadata("srcloc",
+                       llvm::MDNode::get(getLLVMContext(),
+                                         llvm::ConstantAsMetadata::get(Loc)));
+  }
+
+  if (getLangOpts().assumeFunctionsAreConvergent())
+    // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
+    // convergent (meaning, they may call an intrinsically convergent op, such
+    // as bar.sync, and so can't have certain optimizations applied around
+    // them).
+    Result.addAttribute(llvm::AttributeList::FunctionIndex,
+                        llvm::Attribute::Convergent);
+  // Extract all of the register value results from the asm.
+  if (ResultRegTypes.size() == 1) {
+    RegResults.push_back(&Result);
+  } else {
+    for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
+      llvm::Value *Tmp = Builder.CreateExtractValue(&Result, i, "asmresult");
+      RegResults.push_back(Tmp);
+    }
+  }
+}
+
 void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
   // Assemble the final asm string.
   std::string AsmString = S.generateAsmString(getContext());
@@ -2116,6 +2165,30 @@
   }
   Constraints += InOutConstraints;
 
+  // Labels
+  SmallVector<llvm::BasicBlock *, 16> Transfer;
+  llvm::BasicBlock *Fallthrough = nullptr;
+  bool IsGCCAsmGoto = false;
+  if (const auto *GS =  dyn_cast<GCCAsmStmt>(&S)) {
+    IsGCCAsmGoto = GS->isGCCAsmGoto();
+    if (IsGCCAsmGoto) {
+      for (auto *E : GS->labels()) {
+        JumpDest Dest = getJumpDestForLabel(E->getLabel());
+        Transfer.push_back(Dest.getBlock());
+        llvm::BlockAddress *BA =
+            llvm::BlockAddress::get(CurFn, Dest.getBlock());
+        Args.push_back(BA);
+        ArgTypes.push_back(BA->getType());
+        if (!Constraints.empty())
+          Constraints += ',';
+        Constraints += 'X';
+      }
+      Fallthrough = createBasicBlock(std::string("normal") +
+                                     std::to_string(NumGccAsmGotoStmts));
+      NumGccAsmGotoStmts++;
+    }
+  }
+
   // Clobbers
   for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
     StringRef Clobber = S.getClobber(i);
@@ -2158,52 +2231,18 @@
   llvm::InlineAsm *IA =
     llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
                          /* IsAlignStack */ false, AsmDialect);
-  llvm::CallInst *Result =
-      Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
-  Result->addAttribute(llvm::AttributeList::FunctionIndex,
-                       llvm::Attribute::NoUnwind);
-
-  // Attach readnone and readonly attributes.
-  if (!HasSideEffect) {
-    if (ReadNone)
-      Result->addAttribute(llvm::AttributeList::FunctionIndex,
-                           llvm::Attribute::ReadNone);
-    else if (ReadOnly)
-      Result->addAttribute(llvm::AttributeList::FunctionIndex,
-                           llvm::Attribute::ReadOnly);
-  }
-
-  // Slap the source location of the inline asm into a !srcloc metadata on the
-  // call.
-  if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
-    Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(),
-                                                   *this));
-  } else {
-    // At least put the line number on MS inline asm blobs.
-    auto Loc = llvm::ConstantInt::get(Int32Ty, S.getAsmLoc().getRawEncoding());
-    Result->setMetadata("srcloc",
-                        llvm::MDNode::get(getLLVMContext(),
-                                          llvm::ConstantAsMetadata::get(Loc)));
-  }
-
-  if (getLangOpts().assumeFunctionsAreConvergent()) {
-    // Conservatively, mark all inline asm blocks in CUDA or OpenCL as
-    // convergent (meaning, they may call an intrinsically convergent op, such
-    // as bar.sync, and so can't have certain optimizations applied around
-    // them).
-    Result->addAttribute(llvm::AttributeList::FunctionIndex,
-                         llvm::Attribute::Convergent);
-  }
-
-  // Extract all of the register value results from the asm.
   std::vector<llvm::Value*> RegResults;
-  if (ResultRegTypes.size() == 1) {
-    RegResults.push_back(Result);
+  if (IsGCCAsmGoto) {
+    llvm::CallBrInst *Result =
+        Builder.CreateCallBr(FTy, IA, Fallthrough, Transfer, Args);
+    UpdateCallInst<llvm::CallBrInst>(*Result, HasSideEffect, ReadOnly,
+                                     ReadNone, S, ResultRegTypes, RegResults);
+    EmitBlock(Fallthrough);
   } else {
-    for (unsigned i = 0, e = ResultRegTypes.size(); i != e; ++i) {
-      llvm::Value *Tmp = Builder.CreateExtractValue(Result, i, "asmresult");
-      RegResults.push_back(Tmp);
-    }
+    llvm::CallInst *Result =
+        Builder.CreateCall(IA, Args, getBundlesForFunclet(IA));
+    UpdateCallInst<llvm::CallInst>(*Result, HasSideEffect, ReadOnly, ReadNone,
+                                   S, ResultRegTypes, RegResults);
   }
 
   assert(RegResults.size() == ResultRegTypes.size());
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -548,6 +548,7 @@
   CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc);
   CFGBlock *VisitForStmt(ForStmt *F);
   CFGBlock *VisitGotoStmt(GotoStmt *G);
+  CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G);
   CFGBlock *VisitIfStmt(IfStmt *I);
   CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
   CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
@@ -1440,22 +1441,43 @@
                                    E = BackpatchBlocks.end(); I != E; ++I ) {
 
     CFGBlock *B = I->block;
-    const GotoStmt *G = cast<GotoStmt>(B->getTerminator());
-    LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
-
-    // If there is no target for the goto, then we are looking at an
-    // incomplete AST.  Handle this by not registering a successor.
-    if (LI == LabelMap.end()) continue;
+    if (auto *G = dyn_cast<GotoStmt>(B->getTerminator())) {
+      LabelMapTy::iterator LI = LabelMap.find(G->getLabel());;
+      // If there is no target for the goto, then we are looking at an
+      // incomplete AST.  Handle this by not registering a successor.
+      if (LI == LabelMap.end()) continue;
 
-    JumpTarget JT = LI->second;
-    prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
-                                              JT.scopePosition);
-    prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
-                                           JT.scopePosition);
-    const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
-        B, I->scopePosition, JT.scopePosition);
-    appendScopeBegin(JT.block, VD, G);
-    addSuccessor(B, JT.block);
+      JumpTarget JT = LI->second;
+      prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
+                                                JT.scopePosition);
+      prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
+                                             JT.scopePosition);
+      const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
+          B, I->scopePosition, JT.scopePosition);
+      appendScopeBegin(JT.block, VD, G);
+      addSuccessor(B, JT.block);
+    }
+    if (auto *G = dyn_cast<GCCAsmStmt>(B->getTerminator())) {
+      if (G->isGCCAsmGoto()) {
+        const VarDecl *VD;
+        JumpTarget JT;
+        for (auto *E : G->labels()) {
+          LabelMapTy::iterator LI = LabelMap.find(E->getLabel());
+          if (LI == LabelMap.end()) continue;
+          JT = LI->second;
+          prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
+                                                    JT.scopePosition);
+          prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
+                                                 JT.scopePosition);
+          VD = prependAutomaticObjScopeEndWithTerminator(B, I->scopePosition,
+                                                         JT.scopePosition);
+        }
+        if (VD) {
+          appendScopeBegin(JT.block, VD, G);
+          addSuccessor(B, JT.block);
+        }
+      }
+    }
   }
 
   // Add successors to the Indirect Goto Dispatch block (if we have one).
@@ -2099,6 +2121,11 @@
     case Stmt::GotoStmtClass:
       return VisitGotoStmt(cast<GotoStmt>(S));
 
+    case Stmt::GCCAsmStmtClass:
+      if (cast<GCCAsmStmt>(S)->isGCCAsmGoto())
+        return VisitGCCAsmStmt(cast<GCCAsmStmt>(S));
+      return VisitStmt(S, asc);
+
     case Stmt::IfStmtClass:
       return VisitIfStmt(cast<IfStmt>(S));
 
@@ -3103,6 +3130,26 @@
   return Block;
 }
 
+CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G) {
+  // Goto is a control-flow statement.  Thus we stop processing the current
+  // block and create a new one.
+
+  Block = createBlock(false);
+  Block->setTerminator(G);
+  for (auto *E : G->labels()) {
+    LabelMapTy::iterator I = LabelMap.find(E->getLabel());
+    if (I == LabelMap.end())
+      // We will need to backpatch this block later.
+      BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
+    else {
+      JumpTarget JT = I->second;
+      addAutomaticObjHandling(ScopePos, JT.scopePosition, G);
+      addSuccessor(Block, JT.block);
+    }
+  }
+  return Block;
+}
+
 CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
   CFGBlock *LoopSuccessor = nullptr;
 
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -321,6 +321,7 @@
   ID.AddInteger(S->getNumClobbers());
   for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
     VisitStringLiteral(S->getClobberStringLiteral(I));
+  ID.AddInteger(S->getNumLabels());
 }
 
 void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -413,12 +413,15 @@
   if (Node->isVolatile())
     OS << "volatile ";
 
+  if (Node->isGCCAsmGoto())
+    OS << "goto ";
+
   OS << "(";
   VisitStringLiteral(Node->getAsmString());
 
   // Outputs
   if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
-      Node->getNumClobbers() != 0)
+      Node->getNumClobbers() != 0 || Node->getNumLabels() != 0)
     OS << " : ";
 
   for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
@@ -438,7 +441,8 @@
   }
 
   // Inputs
-  if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
+  if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 ||
+      Node->getNumLabels() != 0)
     OS << " : ";
 
   for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
@@ -458,7 +462,7 @@
   }
 
   // Clobbers
-  if (Node->getNumClobbers() != 0)
+  if (Node->getNumClobbers() != 0 || Node->getNumLabels())
     OS << " : ";
 
   for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
@@ -468,6 +472,16 @@
     VisitStringLiteral(Node->getClobberStringLiteral(i));
   }
 
+  // Labels
+  if (Node->getNumLabels() != 0)
+    OS << " : ";
+
+  for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) {
+    if (i != 0)
+      OS << ", ";
+    OS << Node->getLabelName(i);
+  }
+
   OS << ");";
   if (Policy.IncludeNewlines) OS << NL;
 }
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -451,6 +451,18 @@
   Exprs[i + NumOutputs] = E;
 }
 
+Expr *GCCAsmStmt::getExpr(unsigned i) const {
+  return cast<Expr>(Exprs[i]);
+}
+
+AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const {
+  return cast<AddrLabelExpr>(Exprs[i + NumInputs]);
+}
+
+StringRef GCCAsmStmt::getLabelName(unsigned i) const {
+  return getLabelExpr(i)->getLabel()->getName();
+}
+
 /// getInputConstraint - Return the specified input constraint.  Unlike output
 /// constraints, these can be empty.
 StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
@@ -463,13 +475,15 @@
                                                 Stmt **Exprs,
                                                 unsigned NumOutputs,
                                                 unsigned NumInputs,
+                                                unsigned NumLabels,
                                                 StringLiteral **Clobbers,
                                                 unsigned NumClobbers) {
   this->NumOutputs = NumOutputs;
   this->NumInputs = NumInputs;
   this->NumClobbers = NumClobbers;
+  this->NumLabels = NumLabels;
 
-  unsigned NumExprs = NumOutputs + NumInputs;
+  unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
 
   C.Deallocate(this->Names);
   this->Names = new (C) IdentifierInfo*[NumExprs];
@@ -504,6 +518,10 @@
     if (getInputName(i) == SymbolicName)
       return getNumOutputs() + NumPlusOperands + i;
 
+  for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
+    if (getLabelName(i) == SymbolicName)
+      return i + getNumInputs();
+
   // Not found.
   return -1;
 }
@@ -616,17 +634,26 @@
     if (isDigit(EscapedChar)) {
       // %n - Assembler operand n
       unsigned N = 0;
+      bool CheckLabels = false;
 
       --CurPtr;
+      if (*(CurPtr - 1) == 'l')
+        CheckLabels = true;
       while (CurPtr != StrEnd && isDigit(*CurPtr))
         N = N*10 + ((*CurPtr++)-'0');
 
-      unsigned NumOperands =
-        getNumOutputs() + getNumPlusOperands() + getNumInputs();
+      unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
+                             getNumInputs() + getNumLabels();
       if (N >= NumOperands) {
         DiagOffs = CurPtr-StrStart-1;
         return diag::err_asm_invalid_operand_number;
       }
+      if (CheckLabels) {
+        if (N + 1 <= NumOperands - getNumLabels()) {
+          DiagOffs = CurPtr-StrStart-1;
+          return diag::err_asm_invalid_operand_for_goto_labels;
+        }
+      }
 
       // Str contains "x4" (Operand without the leading %).
       std::string Str(Begin, CurPtr - Begin);
@@ -735,10 +762,12 @@
                        unsigned numinputs, IdentifierInfo **names,
                        StringLiteral **constraints, Expr **exprs,
                        StringLiteral *asmstr, unsigned numclobbers,
-                       StringLiteral **clobbers, SourceLocation rparenloc)
+                       StringLiteral **clobbers, unsigned numlabels,
+                       SourceLocation rparenloc)
     : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
-              numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
-  unsigned NumExprs = NumOutputs + NumInputs;
+              numinputs, numclobbers),
+              RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
+  unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
 
   Names = new (C) IdentifierInfo*[NumExprs];
   std::copy(names, names + NumExprs, Names);
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -5623,12 +5623,17 @@
       return InputOrErr.takeError();
   }
 
-  SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs());
+  SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() +
+                               S->getNumLabels());
   if (Error Err = ImportContainerChecked(S->outputs(), Exprs))
     return std::move(Err);
 
+  if (Error Err =
+          ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs()))
+    return std::move(Err);
+
   if (Error Err = ImportArrayChecked(
-      S->inputs(), Exprs.begin() + S->getNumOutputs()))
+          S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs()))
     return std::move(Err);
 
   ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc());
@@ -5654,6 +5659,7 @@
       *AsmStrOrErr,
       S->getNumClobbers(),
       Clobbers.data(),
+      S->getNumLabels(),
       *RParenLocOrErr);
 }
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3898,6 +3898,7 @@
                              unsigned NumInputs, IdentifierInfo **Names,
                              MultiExprArg Constraints, MultiExprArg Exprs,
                              Expr *AsmString, MultiExprArg Clobbers,
+                             unsigned NumLabels,
                              SourceLocation RParenLoc);
 
   void FillInlineAsmIdentifierInfo(Expr *Res,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7418,6 +7418,10 @@
     "use constraint modifier \"%0\"">;
   def note_asm_input_duplicate_first : Note<
     "constraint '%0' is already present here">;
+ def error_duplicate_asm_operand_name : Error<
+    "duplicate use of asm operand name \"%0\"">;
+ def note_duplicate_asm_operand_name : Note<
+    "asm operand name \"%0\" first referenced here">;
 }
 
   def error_inoutput_conflict_with_clobber : Error<
Index: include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- include/clang/Basic/DiagnosticASTKinds.td
+++ include/clang/Basic/DiagnosticASTKinds.td
@@ -209,6 +209,8 @@
     "empty symbolic operand name in inline assembly string">;
   def err_asm_invalid_operand_number : Error<
     "invalid operand number in inline asm string">;
+  def err_asm_invalid_operand_for_goto_labels : Error <
+    "operand with 'l' modifier must refer to a label">;
 }
 
 // vtable related.
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -46,6 +46,7 @@
 class CapturedDecl;
 class Decl;
 class Expr;
+class AddrLabelExpr;
 class LabelDecl;
 class ODRHash;
 class PrinterHelper;
@@ -990,31 +991,42 @@
   ///
   /// This is needed because AST nodes use Stmt* arrays to store
   /// references to children (to be compatible with StmtIterator).
+
+  template <typename T = Expr>
   struct ExprIterator
-      : llvm::iterator_adaptor_base<ExprIterator, Stmt **,
-                                    std::random_access_iterator_tag, Expr *> {
+      : llvm::iterator_adaptor_base<
+            ExprIterator<T>, Stmt **, std::random_access_iterator_tag, T *> {
+    using iterator_adaptor_base =
+        llvm::iterator_adaptor_base<ExprIterator<T>, Stmt **,
+                                    std::random_access_iterator_tag, T *>;
     ExprIterator() : iterator_adaptor_base(nullptr) {}
     ExprIterator(Stmt **I) : iterator_adaptor_base(I) {}
-
-    reference operator*() const {
-      assert((*I)->getStmtClass() >= firstExprConstant &&
-             (*I)->getStmtClass() <= lastExprConstant);
-      return *reinterpret_cast<Expr **>(I);
+    typename iterator_adaptor_base::reference operator*() const {
+      assert((*iterator_adaptor_base::I)->getStmtClass() >=
+                 firstExprConstant &&
+             (*iterator_adaptor_base::I)->getStmtClass() <= lastExprConstant);
+      return *reinterpret_cast<T **>(iterator_adaptor_base::I);
     }
   };
 
   /// Const iterator for iterating over Stmt * arrays that contain only Expr *
+  template <typename T = Expr>
   struct ConstExprIterator
-      : llvm::iterator_adaptor_base<ConstExprIterator, const Stmt *const *,
+      : llvm::iterator_adaptor_base<ConstExprIterator<T>, const Stmt *const *,
                                     std::random_access_iterator_tag,
-                                    const Expr *const> {
+                                    const T *const> {
+    using iterator_adaptor_base =
+        llvm::iterator_adaptor_base<ConstExprIterator<T>, const Stmt *const *,
+                                    std::random_access_iterator_tag,
+                                    const T *const>;
     ConstExprIterator() : iterator_adaptor_base(nullptr) {}
     ConstExprIterator(const Stmt *const *I) : iterator_adaptor_base(I) {}
 
-    reference operator*() const {
-      assert((*I)->getStmtClass() >= firstExprConstant &&
-             (*I)->getStmtClass() <= lastExprConstant);
-      return *reinterpret_cast<const Expr *const *>(I);
+    typename iterator_adaptor_base::reference operator*() const {
+      assert((*iterator_adaptor_base::I)->getStmtClass() >=
+                 firstExprConstant &&
+             (*iterator_adaptor_base::I)->getStmtClass() <= lastExprConstant);
+      return *reinterpret_cast<const T *const *>(iterator_adaptor_base::I);
     }
   };
 
@@ -2618,8 +2630,8 @@
 
   // Input expr iterators.
 
-  using inputs_iterator = ExprIterator;
-  using const_inputs_iterator = ConstExprIterator;
+  using inputs_iterator = ExprIterator<>;
+  using const_inputs_iterator = ConstExprIterator<>;
   using inputs_range = llvm::iterator_range<inputs_iterator>;
   using inputs_const_range = llvm::iterator_range<const_inputs_iterator>;
 
@@ -2647,8 +2659,8 @@
 
   // Output expr iterators.
 
-  using outputs_iterator = ExprIterator;
-  using const_outputs_iterator = ConstExprIterator;
+  using outputs_iterator = ExprIterator<>;
+  using const_outputs_iterator = ConstExprIterator<>;
   using outputs_range = llvm::iterator_range<outputs_iterator>;
   using outputs_const_range = llvm::iterator_range<const_outputs_iterator>;
 
@@ -2692,13 +2704,15 @@
   StringLiteral **Constraints = nullptr;
   StringLiteral **Clobbers = nullptr;
   IdentifierInfo **Names = nullptr;
+  unsigned NumLabels = 0;
 
 public:
   GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
              bool isvolatile, unsigned numoutputs, unsigned numinputs,
              IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
              StringLiteral *asmstr, unsigned numclobbers,
-             StringLiteral **clobbers, SourceLocation rparenloc);
+             StringLiteral **clobbers, unsigned numlabels,
+             SourceLocation rparenloc);
 
   /// Build an empty inline-assembly statement.
   explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {}
@@ -2823,6 +2837,56 @@
     return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
   }
 
+  //===--- Labels ---===//
+
+  bool isGCCAsmGoto() const {
+    return NumLabels > 0;
+  }
+
+  unsigned getNumLabels() const {
+    return NumLabels;
+  }
+
+  IdentifierInfo *getLabelIdentifier(unsigned i) const {
+    return Names[i + NumInputs];
+  }
+
+  IdentifierInfo *getIdentifier(unsigned i) const {
+    return Names[i];
+  }
+
+  AddrLabelExpr *getLabelExpr(unsigned i) const;
+  StringRef getLabelName(unsigned i) const;
+  Expr *getExpr(unsigned i) const;
+  using labels_iterator = ExprIterator<AddrLabelExpr>;
+  using const_labels_iterator = ConstExprIterator<AddrLabelExpr>;
+  using labels_range = llvm::iterator_range<labels_iterator>;
+  using labels_const_range = llvm::iterator_range<const_labels_iterator>;
+
+  labels_iterator begin_labels() {
+    return &Exprs[0] + NumInputs;
+  }
+
+  labels_iterator end_labels() {
+    return &Exprs[0] + NumInputs + NumLabels;
+  }
+
+  labels_range labels() {
+    return labels_range(begin_labels(), end_labels());
+  }
+
+  const_labels_iterator begin_labels() const {
+    return &Exprs[0] + NumInputs;
+  }
+
+  const_labels_iterator end_labels() const {
+    return &Exprs[0] + NumInputs + NumLabels;
+  }
+
+  labels_const_range labels() const {
+    return labels_const_range(begin_labels(), end_labels());
+  }
+
 private:
   void setOutputsAndInputsAndClobbers(const ASTContext &C,
                                       IdentifierInfo **Names,
@@ -2830,6 +2894,7 @@
                                       Stmt **Exprs,
                                       unsigned NumOutputs,
                                       unsigned NumInputs,
+                                      unsigned NumLabels,
                                       StringLiteral **Clobbers,
                                       unsigned NumClobbers);
 
Index: include/clang/AST/ExprObjC.h
===================================================================
--- include/clang/AST/ExprObjC.h
+++ include/clang/AST/ExprObjC.h
@@ -150,7 +150,7 @@
   // Iterators
   child_range children() { return child_range(&SubExpr, &SubExpr+1); }
 
-  using const_arg_iterator = ConstExprIterator;
+  using const_arg_iterator = ConstExprIterator<>;
 
   const_arg_iterator arg_begin() const {
     return reinterpret_cast<Stmt const * const*>(&SubExpr);
@@ -1402,8 +1402,8 @@
   // Iterators
   child_range children();
 
-  using arg_iterator = ExprIterator;
-  using const_arg_iterator = ConstExprIterator;
+  using arg_iterator = ExprIterator<>;
+  using const_arg_iterator = ConstExprIterator<>;
 
   llvm::iterator_range<arg_iterator> arguments() {
     return llvm::make_range(arg_begin(), arg_end());
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -1385,8 +1385,8 @@
     CXXConstructExprBits.ConstructionKind = CK;
   }
 
-  using arg_iterator = ExprIterator;
-  using const_arg_iterator = ConstExprIterator;
+  using arg_iterator = ExprIterator<>;
+  using const_arg_iterator = ConstExprIterator<>;
   using arg_range = llvm::iterator_range<arg_iterator>;
   using const_arg_range = llvm::iterator_range<const_arg_iterator>;
 
@@ -2113,8 +2113,8 @@
     return CXXNewExprBits.UsualArrayDeleteWantsSize;
   }
 
-  using arg_iterator = ExprIterator;
-  using const_arg_iterator = ConstExprIterator;
+  using arg_iterator = ExprIterator<>;
+  using const_arg_iterator = ConstExprIterator<>;
 
   llvm::iterator_range<arg_iterator> placement_arguments() {
     return llvm::make_range(placement_arg_begin(), placement_arg_end());
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2585,8 +2585,8 @@
     NumArgs = NewNumArgs;
   }
 
-  typedef ExprIterator arg_iterator;
-  typedef ConstExprIterator const_arg_iterator;
+  typedef ExprIterator<> arg_iterator;
+  typedef ConstExprIterator<> const_arg_iterator;
   typedef llvm::iterator_range<arg_iterator> arg_range;
   typedef llvm::iterator_range<const_arg_iterator> const_arg_range;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to