jyu2 updated this revision to Diff 181702.
jyu2 added a comment.
Add code to diagnostic error for use of the "l" modifier that does not point to
a label in the label list.
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,27 @@
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 {{invalid operand number which isn't point to a goto label in asm string}}
+ asm ("jne %l0"::"r"(&&lab));
+ // expected-error@+1 {{invalid operand number in inline asm string}}
+ asm ("jne %l0":::);
+ // expected-error@+1 {{invalid operand number which isn't point to a goto label in asm string}}
+ asm goto ("jne %l0"::"r"(x)::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 or jump [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
@@ -283,6 +283,7 @@
void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
VisitAsmStmt(S);
+ Record.push_back(S->getNumLabels());
Record.AddSourceLocation(S->getRParenLoc());
Record.AddStmt(S->getAsmString());
@@ -304,6 +305,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
@@ -370,12 +370,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;
@@ -392,9 +394,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.
@@ -6967,6 +6968,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;
@@ -6980,7 +6991,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
@@ -210,11 +210,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));
@@ -242,6 +243,7 @@
unsigned NumInputs, IdentifierInfo **Names,
MultiExprArg constraints, MultiExprArg Exprs,
Expr *asmString, MultiExprArg clobbers,
+ unsigned NumLabels,
SourceLocation RParenLoc) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
@@ -259,7 +261,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;
}
@@ -443,7 +446,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;
@@ -461,8 +465,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) {
@@ -642,10 +648,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
@@ -710,12 +710,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)) {
@@ -753,7 +753,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.
@@ -763,6 +764,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();
}
@@ -789,12 +796,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());
@@ -808,11 +819,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
@@ -1390,6 +1390,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;
@@ -2861,6 +2864,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
@@ -1872,6 +1872,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());
@@ -2108,6 +2157,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);
@@ -2150,52 +2223,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(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
@@ -549,6 +549,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);
@@ -1441,22 +1442,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).
@@ -2100,6 +2122,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
@@ -322,6 +322,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
@@ -414,12 +414,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) {
@@ -439,7 +442,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) {
@@ -459,7 +463,7 @@
}
// Clobbers
- if (Node->getNumClobbers() != 0)
+ if (Node->getNumClobbers() != 0 || Node->getNumLabels())
OS << " : ";
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
@@ -469,6 +473,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
@@ -452,6 +452,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 {
@@ -464,13 +476,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];
@@ -505,6 +519,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;
}
@@ -617,17 +635,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_number_for_goto_labels;
+ }
+ }
// Str contains "x4" (Operand without the leading %).
std::string Str(Begin, CurPtr - Begin);
@@ -736,10 +763,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
@@ -5578,12 +5578,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());
@@ -5609,6 +5614,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
@@ -3865,6 +3865,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
@@ -7392,6 +7392,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
@@ -210,6 +210,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_number_for_goto_labels : Error <
+ "invalid operand number which isn't point to a goto label in asm string">;
}
// vtable related.
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -47,6 +47,7 @@
class CapturedDecl;
class Decl;
class Expr;
+class AddrLabelExpr;
class LabelDecl;
class ODRHash;
class PrinterHelper;
@@ -980,31 +981,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);
}
};
@@ -2608,8 +2620,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>;
@@ -2637,8 +2649,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>;
@@ -2682,13 +2694,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) {}
@@ -2813,6 +2827,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,
@@ -2820,6 +2884,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
@@ -151,7 +151,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
@@ -1386,8 +1386,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>;
@@ -2114,8 +2114,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
@@ -2577,8 +2577,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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits