Skip to content

Commit 954ec09

Browse files
committed
clang support gnu asm goto.
Syntax: asm [volatile] goto ( AssemblerTemplate : : InputOperands : Clobbers : GotoLabels) https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html New llvm IR is "callbr" for inline asm goto instead "call" for inline asm For: asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop); IR: callbr void asm sideeffect "testl $0, $0; jne ${1:l};", "r,X,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@foo, %label_true), i8* blockaddress(@foo, %loop)) #1 to label %asm.fallthrough [label %label_true, label %loop], !srcloc !3 asm.fallthrough: Compiler need to generate: 1> a dummy constarint 'X' for each label. 2> an unique fallthrough label for each asm goto stmt " asm.fallthrough%number". Diagnostic 1> duplicate asm operand name are used in output, input and label. 2> goto out of scope. llvm-svn: 362045
1 parent 192dd7d commit 954ec09

28 files changed

+732
-148
lines changed

clang/include/clang/AST/Stmt.h

+50-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Attr;
4646
class CapturedDecl;
4747
class Decl;
4848
class Expr;
49+
class AddrLabelExpr;
4950
class LabelDecl;
5051
class ODRHash;
5152
class PrinterHelper;
@@ -2816,13 +2817,15 @@ class GCCAsmStmt : public AsmStmt {
28162817
StringLiteral **Constraints = nullptr;
28172818
StringLiteral **Clobbers = nullptr;
28182819
IdentifierInfo **Names = nullptr;
2820+
unsigned NumLabels = 0;
28192821

28202822
public:
28212823
GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple,
28222824
bool isvolatile, unsigned numoutputs, unsigned numinputs,
28232825
IdentifierInfo **names, StringLiteral **constraints, Expr **exprs,
28242826
StringLiteral *asmstr, unsigned numclobbers,
2825-
StringLiteral **clobbers, SourceLocation rparenloc);
2827+
StringLiteral **clobbers, unsigned numlabels,
2828+
SourceLocation rparenloc);
28262829

28272830
/// Build an empty inline-assembly statement.
28282831
explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {}
@@ -2947,13 +2950,59 @@ class GCCAsmStmt : public AsmStmt {
29472950
return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
29482951
}
29492952

2953+
//===--- Labels ---===//
2954+
2955+
bool isAsmGoto() const {
2956+
return NumLabels > 0;
2957+
}
2958+
2959+
unsigned getNumLabels() const {
2960+
return NumLabels;
2961+
}
2962+
2963+
IdentifierInfo *getLabelIdentifier(unsigned i) const {
2964+
return Names[i + NumInputs];
2965+
}
2966+
2967+
AddrLabelExpr *getLabelExpr(unsigned i) const;
2968+
StringRef getLabelName(unsigned i) const;
2969+
using labels_iterator = CastIterator<AddrLabelExpr>;
2970+
using const_labels_iterator = ConstCastIterator<AddrLabelExpr>;
2971+
using labels_range = llvm::iterator_range<labels_iterator>;
2972+
using labels_const_range = llvm::iterator_range<const_labels_iterator>;
2973+
2974+
labels_iterator begin_labels() {
2975+
return &Exprs[0] + NumInputs;
2976+
}
2977+
2978+
labels_iterator end_labels() {
2979+
return &Exprs[0] + NumInputs + NumLabels;
2980+
}
2981+
2982+
labels_range labels() {
2983+
return labels_range(begin_labels(), end_labels());
2984+
}
2985+
2986+
const_labels_iterator begin_labels() const {
2987+
return &Exprs[0] + NumInputs;
2988+
}
2989+
2990+
const_labels_iterator end_labels() const {
2991+
return &Exprs[0] + NumInputs + NumLabels;
2992+
}
2993+
2994+
labels_const_range labels() const {
2995+
return labels_const_range(begin_labels(), end_labels());
2996+
}
2997+
29502998
private:
29512999
void setOutputsAndInputsAndClobbers(const ASTContext &C,
29523000
IdentifierInfo **Names,
29533001
StringLiteral **Constraints,
29543002
Stmt **Exprs,
29553003
unsigned NumOutputs,
29563004
unsigned NumInputs,
3005+
unsigned NumLabels,
29573006
StringLiteral **Clobbers,
29583007
unsigned NumClobbers);
29593008

clang/include/clang/Basic/DiagnosticParseKinds.td

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def err_msasm_unable_to_create_target : Error<
2727
"MS-style inline assembly is not available: %0">;
2828
def err_gnu_inline_asm_disabled : Error<
2929
"GNU-style inline assembly is disabled">;
30-
def err_asm_goto_not_supported_yet : Error<
31-
"'asm goto' constructs are not supported yet">;
30+
def err_asm_goto_cannot_have_output : Error<
31+
"'asm goto' cannot have output constraints">;
3232
}
3333

3434
let CategoryName = "Parse Issue" in {

clang/include/clang/Basic/DiagnosticSemaKinds.td

+7-3
Original file line numberDiff line numberDiff line change
@@ -5064,12 +5064,12 @@ def warn_cxx98_compat_switch_into_protected_scope : Warning<
50645064
def err_indirect_goto_without_addrlabel : Error<
50655065
"indirect goto in function with no address-of-label expressions">;
50665066
def err_indirect_goto_in_protected_scope : Error<
5067-
"cannot jump from this indirect goto statement to one of its possible targets">;
5067+
"cannot jump from this %select{indirect|asm}0 goto statement to one of its possible targets">;
50685068
def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning<
5069-
"jump from this indirect goto statement to one of its possible targets "
5069+
"jump from this %select{indirect|asm}0 goto statement to one of its possible targets "
50705070
"is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
50715071
def note_indirect_goto_target : Note<
5072-
"possible target of indirect goto statement">;
5072+
"possible target of %select{indirect|asm}0 goto statement">;
50735073
def note_protected_by_variable_init : Note<
50745074
"jump bypasses variable initialization">;
50755075
def note_protected_by_variable_nontriv_destructor : Note<
@@ -7497,6 +7497,10 @@ let CategoryName = "Inline Assembly Issue" in {
74977497
"use constraint modifier \"%0\"">;
74987498
def note_asm_input_duplicate_first : Note<
74997499
"constraint '%0' is already present here">;
7500+
def error_duplicate_asm_operand_name : Error<
7501+
"duplicate use of asm operand name \"%0\"">;
7502+
def note_duplicate_asm_operand_name : Note<
7503+
"asm operand name \"%0\" first referenced here">;
75007504
}
75017505

75027506
def error_inoutput_conflict_with_clobber : Error<

clang/include/clang/Sema/Sema.h

+1
Original file line numberDiff line numberDiff line change
@@ -3971,6 +3971,7 @@ class Sema {
39713971
unsigned NumInputs, IdentifierInfo **Names,
39723972
MultiExprArg Constraints, MultiExprArg Exprs,
39733973
Expr *AsmString, MultiExprArg Clobbers,
3974+
unsigned NumLabels,
39743975
SourceLocation RParenLoc);
39753976

39763977
void FillInlineAsmIdentifierInfo(Expr *Res,

clang/lib/AST/ASTImporter.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -5592,12 +5592,17 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
55925592
return InputOrErr.takeError();
55935593
}
55945594

5595-
SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs());
5595+
SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() +
5596+
S->getNumLabels());
55965597
if (Error Err = ImportContainerChecked(S->outputs(), Exprs))
55975598
return std::move(Err);
55985599

5600+
if (Error Err =
5601+
ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs()))
5602+
return std::move(Err);
5603+
55995604
if (Error Err = ImportArrayChecked(
5600-
S->inputs(), Exprs.begin() + S->getNumOutputs()))
5605+
S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs()))
56015606
return std::move(Err);
56025607

56035608
ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc());
@@ -5623,6 +5628,7 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
56235628
*AsmStrOrErr,
56245629
S->getNumClobbers(),
56255630
Clobbers.data(),
5631+
S->getNumLabels(),
56265632
*RParenLocOrErr);
56275633
}
56285634

clang/lib/AST/Stmt.cpp

+23-6
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,14 @@ void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) {
444444
Exprs[i + NumOutputs] = E;
445445
}
446446

447+
AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const {
448+
return cast<AddrLabelExpr>(Exprs[i + NumInputs]);
449+
}
450+
451+
StringRef GCCAsmStmt::getLabelName(unsigned i) const {
452+
return getLabelExpr(i)->getLabel()->getName();
453+
}
454+
447455
/// getInputConstraint - Return the specified input constraint. Unlike output
448456
/// constraints, these can be empty.
449457
StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
@@ -456,13 +464,16 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
456464
Stmt **Exprs,
457465
unsigned NumOutputs,
458466
unsigned NumInputs,
467+
unsigned NumLabels,
459468
StringLiteral **Clobbers,
460469
unsigned NumClobbers) {
461470
this->NumOutputs = NumOutputs;
462471
this->NumInputs = NumInputs;
463472
this->NumClobbers = NumClobbers;
473+
this->NumLabels = NumLabels;
474+
assert(!(NumOutputs && NumLabels) && "asm goto cannot have outputs");
464475

465-
unsigned NumExprs = NumOutputs + NumInputs;
476+
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
466477

467478
C.Deallocate(this->Names);
468479
this->Names = new (C) IdentifierInfo*[NumExprs];
@@ -497,6 +508,10 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
497508
if (getInputName(i) == SymbolicName)
498509
return getNumOutputs() + NumPlusOperands + i;
499510

511+
for (unsigned i = 0, e = getNumLabels(); i != e; ++i)
512+
if (getLabelName(i) == SymbolicName)
513+
return i + getNumInputs();
514+
500515
// Not found.
501516
return -1;
502517
}
@@ -614,8 +629,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
614629
while (CurPtr != StrEnd && isDigit(*CurPtr))
615630
N = N*10 + ((*CurPtr++)-'0');
616631

617-
unsigned NumOperands =
618-
getNumOutputs() + getNumPlusOperands() + getNumInputs();
632+
unsigned NumOperands = getNumOutputs() + getNumPlusOperands() +
633+
getNumInputs() + getNumLabels();
619634
if (N >= NumOperands) {
620635
DiagOffs = CurPtr-StrStart-1;
621636
return diag::err_asm_invalid_operand_number;
@@ -728,10 +743,12 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
728743
unsigned numinputs, IdentifierInfo **names,
729744
StringLiteral **constraints, Expr **exprs,
730745
StringLiteral *asmstr, unsigned numclobbers,
731-
StringLiteral **clobbers, SourceLocation rparenloc)
746+
StringLiteral **clobbers, unsigned numlabels,
747+
SourceLocation rparenloc)
732748
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
733-
numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
734-
unsigned NumExprs = NumOutputs + NumInputs;
749+
numinputs, numclobbers),
750+
RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) {
751+
unsigned NumExprs = NumOutputs + NumInputs + NumLabels;
735752

736753
Names = new (C) IdentifierInfo*[NumExprs];
737754
std::copy(names, names + NumExprs, Names);

clang/lib/AST/StmtPrinter.cpp

+17-3
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,15 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
414414
if (Node->isVolatile())
415415
OS << "volatile ";
416416

417+
if (Node->isAsmGoto())
418+
OS << "goto ";
419+
417420
OS << "(";
418421
VisitStringLiteral(Node->getAsmString());
419422

420423
// Outputs
421424
if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 ||
422-
Node->getNumClobbers() != 0)
425+
Node->getNumClobbers() != 0 || Node->getNumLabels() != 0)
423426
OS << " : ";
424427

425428
for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) {
@@ -439,7 +442,8 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
439442
}
440443

441444
// Inputs
442-
if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0)
445+
if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 ||
446+
Node->getNumLabels() != 0)
443447
OS << " : ";
444448

445449
for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) {
@@ -459,7 +463,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
459463
}
460464

461465
// Clobbers
462-
if (Node->getNumClobbers() != 0)
466+
if (Node->getNumClobbers() != 0 || Node->getNumLabels())
463467
OS << " : ";
464468

465469
for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) {
@@ -469,6 +473,16 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
469473
VisitStringLiteral(Node->getClobberStringLiteral(i));
470474
}
471475

476+
// Labels
477+
if (Node->getNumLabels() != 0)
478+
OS << " : ";
479+
480+
for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) {
481+
if (i != 0)
482+
OS << ", ";
483+
OS << Node->getLabelName(i);
484+
}
485+
472486
OS << ");";
473487
if (Policy.IncludeNewlines) OS << NL;
474488
}

clang/lib/AST/StmtProfile.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) {
321321
ID.AddInteger(S->getNumClobbers());
322322
for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I)
323323
VisitStringLiteral(S->getClobberStringLiteral(I));
324+
ID.AddInteger(S->getNumLabels());
325+
for (auto *L : S->labels())
326+
VisitDecl(L->getLabel());
324327
}
325328

326329
void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {

clang/lib/Analysis/CFG.cpp

+58-16
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ class CFGBuilder {
549549
CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc);
550550
CFGBlock *VisitForStmt(ForStmt *F);
551551
CFGBlock *VisitGotoStmt(GotoStmt *G);
552+
CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
552553
CFGBlock *VisitIfStmt(IfStmt *I);
553554
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
554555
CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
@@ -1478,22 +1479,38 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
14781479
E = BackpatchBlocks.end(); I != E; ++I ) {
14791480

14801481
CFGBlock *B = I->block;
1481-
const GotoStmt *G = cast<GotoStmt>(B->getTerminator());
1482-
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1483-
1484-
// If there is no target for the goto, then we are looking at an
1485-
// incomplete AST. Handle this by not registering a successor.
1486-
if (LI == LabelMap.end()) continue;
1487-
1488-
JumpTarget JT = LI->second;
1489-
prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
1490-
JT.scopePosition);
1491-
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
1492-
JT.scopePosition);
1493-
const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
1494-
B, I->scopePosition, JT.scopePosition);
1495-
appendScopeBegin(JT.block, VD, G);
1496-
addSuccessor(B, JT.block);
1482+
if (auto *G = dyn_cast<GotoStmt>(B->getTerminator())) {
1483+
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1484+
// If there is no target for the goto, then we are looking at an
1485+
// incomplete AST. Handle this by not registering a successor.
1486+
if (LI == LabelMap.end())
1487+
continue;
1488+
JumpTarget JT = LI->second;
1489+
prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
1490+
JT.scopePosition);
1491+
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
1492+
JT.scopePosition);
1493+
const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator(
1494+
B, I->scopePosition, JT.scopePosition);
1495+
appendScopeBegin(JT.block, VD, G);
1496+
addSuccessor(B, JT.block);
1497+
};
1498+
if (auto *G = dyn_cast<GCCAsmStmt>(B->getTerminator())) {
1499+
CFGBlock *Successor = (I+1)->block;
1500+
for (auto *L : G->labels()) {
1501+
LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1502+
// If there is no target for the goto, then we are looking at an
1503+
// incomplete AST. Handle this by not registering a successor.
1504+
if (LI == LabelMap.end())
1505+
continue;
1506+
JumpTarget JT = LI->second;
1507+
// Successor has been added, so skip it.
1508+
if (JT.block == Successor)
1509+
continue;
1510+
addSuccessor(B, JT.block);
1511+
}
1512+
I++;
1513+
}
14971514
}
14981515

14991516
// Add successors to the Indirect Goto Dispatch block (if we have one).
@@ -2142,6 +2159,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
21422159
case Stmt::GotoStmtClass:
21432160
return VisitGotoStmt(cast<GotoStmt>(S));
21442161

2162+
case Stmt::GCCAsmStmtClass:
2163+
return VisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
2164+
21452165
case Stmt::IfStmtClass:
21462166
return VisitIfStmt(cast<IfStmt>(S));
21472167

@@ -3146,6 +3166,28 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
31463166
return Block;
31473167
}
31483168

3169+
CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3170+
// Goto is a control-flow statement. Thus we stop processing the current
3171+
// block and create a new one.
3172+
3173+
if (!G->isAsmGoto())
3174+
return VisitStmt(G, asc);
3175+
3176+
if (Block) {
3177+
Succ = Block;
3178+
if (badCFG)
3179+
return nullptr;
3180+
}
3181+
Block = createBlock();
3182+
Block->setTerminator(G);
3183+
// We will backpatch this block later for all the labels.
3184+
BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
3185+
// Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is
3186+
// used to avoid adding "Succ" again.
3187+
BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3188+
return Block;
3189+
}
3190+
31493191
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
31503192
CFGBlock *LoopSuccessor = nullptr;
31513193

0 commit comments

Comments
 (0)