Hi rnk,
This addresses PR21035. For now, we are unable to represent the
possibility of jumping between asm IR blocks in LLVM, so these kinds of
jumps don't play well with the SSA model. This patch adds a diagnostic
that detect those kinds of jumps, based on the information that the LLVM
side patch exposes from MC.
Note that we currently lose the SourceLocation for the branch statement
and the label definition statement, so the diagnostic is at inline
assembly block granularity. This issue will be addressed in a
follow-up.
http://reviews.llvm.org/D5516
Files:
include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/Stmt.cpp
lib/Parse/ParseStmtAsm.cpp
lib/Sema/JumpDiagnostics.cpp
lib/Sema/SemaStmtAsm.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
test/Parser/ms-inline-asm.c
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -1720,10 +1720,14 @@
StringRef AsmStr;
unsigned NumAsmToks;
+ unsigned NumBranchTargets;
+ unsigned NumLabelsDefined;
Token *AsmToks;
StringRef *Constraints;
StringRef *Clobbers;
+ StringRef *BranchTargets;
+ StringRef *LabelsDefined;
friend class ASTStmtReader;
@@ -1733,11 +1737,14 @@
ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs,
ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs, StringRef asmstr,
- ArrayRef<StringRef> clobbers, SourceLocation endloc);
+ ArrayRef<StringRef> clobbers,
+ ArrayRef<StringRef> branchTargets,
+ ArrayRef<StringRef> labelsDefined, SourceLocation endloc);
/// \brief Build an empty MS-style inline-assembly statement.
explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty),
- NumAsmToks(0), AsmToks(nullptr), Constraints(nullptr), Clobbers(nullptr) { }
+ NumAsmToks(0), NumBranchTargets(0), NumLabelsDefined(0),
+ AsmToks(nullptr), Constraints(nullptr), Clobbers(nullptr) { }
SourceLocation getLBraceLoc() const { return LBraceLoc; }
void setLBraceLoc(SourceLocation L) { LBraceLoc = L; }
@@ -1790,6 +1797,12 @@
ArrayRef<StringRef> getClobbers() const {
return llvm::makeArrayRef(Clobbers, NumClobbers);
}
+ ArrayRef<StringRef> getBranchTargets() const {
+ return llvm::makeArrayRef(BranchTargets, NumBranchTargets);
+ }
+ ArrayRef<StringRef> getLabelsDefined() const {
+ return llvm::makeArrayRef(LabelsDefined, NumLabelsDefined);
+ }
ArrayRef<Expr*> getAllExprs() const {
return llvm::makeArrayRef(reinterpret_cast<Expr**>(Exprs),
NumInputs + NumOutputs);
@@ -1800,7 +1813,9 @@
private:
void initialize(const ASTContext &C, StringRef AsmString,
ArrayRef<Token> AsmToks, ArrayRef<StringRef> Constraints,
- ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers);
+ ArrayRef<Expr*> Exprs, ArrayRef<StringRef> Clobbers,
+ ArrayRef<StringRef> BranchTargets,
+ ArrayRef<StringRef> LabelsDefined);
public:
SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4137,6 +4137,10 @@
"cannot jump from this goto statement to label %0 inside an inline assembly block">;
def note_goto_ms_asm_label : Note<
"inline assembly label %0 declared here">;
+def err_cross_block_asm_jump : Error<
+ "cannot jump from one inline assembly block to label %0 defined inside another one">;
+def note_cross_block_asm_jump : Note <
+ "label %0 defined in an inline assembly block defined here">;
def warn_unused_label : Warning<"unused label %0">,
InGroup<UnusedLabel>, DefaultIgnore;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -3157,6 +3157,8 @@
unsigned NumOutputs, unsigned NumInputs,
ArrayRef<StringRef> Constraints,
ArrayRef<StringRef> Clobbers,
+ ArrayRef<StringRef> BranchTargets,
+ ArrayRef<StringRef> LabelsDefined,
ArrayRef<Expr*> Exprs,
SourceLocation EndLoc);
LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -689,12 +689,16 @@
unsigned numinputs,
ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
StringRef asmstr, ArrayRef<StringRef> clobbers,
- SourceLocation endloc)
+ ArrayRef<StringRef> branchTargets,
+ ArrayRef<StringRef> labelsDefined, SourceLocation endloc)
: AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
numinputs, clobbers.size()), LBraceLoc(lbraceloc),
- EndLoc(endloc), NumAsmToks(asmtoks.size()) {
+ EndLoc(endloc), NumAsmToks(asmtoks.size()),
+ NumBranchTargets(branchTargets.size()),
+ NumLabelsDefined(labelsDefined.size()) {
- initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
+ initialize(C, asmstr, asmtoks, constraints, exprs, clobbers,
+ branchTargets, labelsDefined);
}
static StringRef copyIntoContext(const ASTContext &C, StringRef str) {
@@ -708,9 +712,13 @@
ArrayRef<Token> asmtoks,
ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs,
- ArrayRef<StringRef> clobbers) {
+ ArrayRef<StringRef> clobbers,
+ ArrayRef<StringRef> branchTargets,
+ ArrayRef<StringRef> labelsDefined) {
assert(NumAsmToks == asmtoks.size());
assert(NumClobbers == clobbers.size());
+ assert(NumBranchTargets == branchTargets.size());
+ assert(NumLabelsDefined == labelsDefined.size());
unsigned NumExprs = exprs.size();
assert(NumExprs == NumOutputs + NumInputs);
@@ -736,6 +744,18 @@
// FIXME: Avoid the allocation/copy if at all possible.
Clobbers[i] = copyIntoContext(C, clobbers[i]);
}
+
+ BranchTargets = new (C) StringRef[NumBranchTargets];
+ for (unsigned i = 0, e = NumBranchTargets; i != e; ++i) {
+ // FIXME: Avoid the allocation/copy if at all possible.
+ BranchTargets[i] = copyIntoContext(C, branchTargets[i]);
+ }
+
+ LabelsDefined = new (C) StringRef[NumLabelsDefined];
+ for (unsigned i = 0, e = NumLabelsDefined; i != e; ++i) {
+ // FIXME: Avoid the allocation/copy if at all possible.
+ LabelsDefined[i] = copyIntoContext(C, labelsDefined[i]);
+ }
}
ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
Index: lib/Parse/ParseStmtAsm.cpp
===================================================================
--- lib/Parse/ParseStmtAsm.cpp
+++ lib/Parse/ParseStmtAsm.cpp
@@ -469,6 +469,8 @@
SmallVector<StringRef, 4> ConstraintRefs;
SmallVector<Expr *, 4> Exprs;
SmallVector<StringRef, 4> ClobberRefs;
+ SmallVector<StringRef, 4> BranchTargetRefs;
+ SmallVector<StringRef, 4> LabelsDefinedRefs;
// We need an actual supported target.
const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
@@ -493,7 +495,8 @@
if (!TheTarget || AsmToks.empty()) {
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
/*NumOutputs*/ 0, /*NumInputs*/ 0,
- ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+ ConstraintRefs, ClobberRefs, BranchTargetRefs,
+ LabelsDefinedRefs, Exprs, EndLoc);
}
// Expand the tokens into a string buffer.
@@ -548,9 +551,12 @@
SmallVector<std::pair<void *, bool>, 4> OpExprs;
SmallVector<std::string, 4> Constraints;
SmallVector<std::string, 4> Clobbers;
+ SmallVector<std::string, 4> BranchTargets;
+ SmallVector<std::string, 4> LabelsDefined;
if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
NumInputs, OpExprs, Constraints, Clobbers,
- MII.get(), IP.get(), Callback))
+ BranchTargets, LabelsDefined, MII.get(), IP.get(),
+ Callback))
return StmtError();
// Filter out "fpsw". Clang doesn't accept it, and it always lists flags and
@@ -560,6 +566,8 @@
// Build the vector of clobber StringRefs.
ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
+ BranchTargetRefs.insert(BranchTargetRefs.end(), BranchTargets.begin(), BranchTargets.end());
+ LabelsDefinedRefs.insert(LabelsDefinedRefs.end(), LabelsDefined.begin(), LabelsDefined.end());
// Recast the void pointers and build the vector of constraint StringRefs.
unsigned NumExprs = NumOutputs + NumInputs;
@@ -582,7 +590,8 @@
// FIXME: We should be passing source locations for better diagnostics.
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
NumOutputs, NumInputs, ConstraintRefs,
- ClobberRefs, Exprs, EndLoc);
+ ClobberRefs, BranchTargetRefs,
+ LabelsDefinedRefs, Exprs, EndLoc);
}
/// ParseAsmStatement - Parse a GNU extended asm statement.
Index: lib/Sema/JumpDiagnostics.cpp
===================================================================
--- lib/Sema/JumpDiagnostics.cpp
+++ lib/Sema/JumpDiagnostics.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
using namespace clang;
@@ -85,6 +86,8 @@
unsigned JumpDiag, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat);
void CheckGotoStmt(GotoStmt *GS);
+ void CheckMSAsmStmt(MSAsmStmt *AsmStmt,
+ const std::map<StringRef, MSAsmStmt*> &LabelProvider);
unsigned GetDeepestCommonScope(unsigned A, unsigned B);
};
@@ -315,6 +318,11 @@
Jumps.push_back(S);
break;
+ case Stmt::MSAsmStmtClass:
+ // Verify possible jumps from within MS inline asm blocks.
+ Jumps.push_back(S);
+ break;
+
case Stmt::CXXTryStmtClass: {
CXXTryStmt *TS = cast<CXXTryStmt>(S);
unsigned newParentScope;
@@ -485,6 +493,15 @@
/// VerifyJumps - Verify each element of the Jumps array to see if they are
/// valid, emitting diagnostics if not.
void JumpScopeChecker::VerifyJumps() {
+ std::map<StringRef, MSAsmStmt*> LabelProvider;
+ for (Stmt *J : Jumps) {
+ if (isa<MSAsmStmt>(J)) {
+ for (const auto &L : cast<MSAsmStmt>(J)->getLabelsDefined()) {
+ LabelProvider.insert(std::make_pair(L, cast<MSAsmStmt>(J)));
+ }
+ }
+ }
+
while (!Jumps.empty()) {
Stmt *Jump = Jumps.pop_back_val();
@@ -511,6 +528,11 @@
continue;
}
+ if (MSAsmStmt *AsmStmt = dyn_cast<MSAsmStmt>(Jump)) {
+ CheckMSAsmStmt(AsmStmt, LabelProvider);
+ continue;
+ }
+
SwitchStmt *SS = cast<SwitchStmt>(Jump);
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
@@ -803,6 +825,20 @@
}
}
+void JumpScopeChecker::CheckMSAsmStmt(MSAsmStmt *AsmStmt,
+ const std::map<StringRef, MSAsmStmt*> &LabelProvider) {
+ for (const auto &BT : AsmStmt->getBranchTargets()) {
+ const auto &LabelProviderStmt = LabelProvider.find(BT);
+ if (LabelProviderStmt != LabelProvider.end() &&
+ LabelProviderStmt->second != AsmStmt) {
+ S.Diag(AsmStmt->getLocStart(), diag::err_cross_block_asm_jump)
+ << S.getPreprocessor().getIdentifierInfo(BT);
+ S.Diag(LabelProviderStmt->second->getLocStart(), diag::note_cross_block_asm_jump)
+ << S.getPreprocessor().getIdentifierInfo(BT);
+ }
+ }
+}
+
void Sema::DiagnoseInvalidJumps(Stmt *Body) {
(void)JumpScopeChecker(Body, *this);
}
Index: lib/Sema/SemaStmtAsm.cpp
===================================================================
--- lib/Sema/SemaStmtAsm.cpp
+++ lib/Sema/SemaStmtAsm.cpp
@@ -518,15 +518,17 @@
unsigned NumOutputs, unsigned NumInputs,
ArrayRef<StringRef> Constraints,
ArrayRef<StringRef> Clobbers,
+ ArrayRef<StringRef> BranchTargets,
+ ArrayRef<StringRef> LabelsDefined,
ArrayRef<Expr*> Exprs,
SourceLocation EndLoc) {
bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
getCurFunction()->setHasBranchProtectedScope();
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
/*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
Constraints, Exprs, AsmString,
- Clobbers, EndLoc);
+ Clobbers, BranchTargets, LabelsDefined, EndLoc);
return NS;
}
@@ -545,6 +547,9 @@
// name.
OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName;
Label->setMSAsmLabel(OS.str());
+ // We need to check possible cross inline MS asm block jumps when we encounter an
+ // MS asm label being defined.
+ getCurFunction()->setHasIndirectGoto();
}
if (AlwaysCreate) {
// The label might have been created implicitly from a previously encountered
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -1231,11 +1231,14 @@
unsigned NumOutputs, unsigned NumInputs,
ArrayRef<StringRef> Constraints,
ArrayRef<StringRef> Clobbers,
+ ArrayRef<StringRef> BranchTargets,
+ ArrayRef<StringRef> LabelsDefined,
ArrayRef<Expr*> Exprs,
SourceLocation EndLoc) {
return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmString,
NumOutputs, NumInputs,
- Constraints, Clobbers, Exprs, EndLoc);
+ Constraints, Clobbers, BranchTargets,
+ LabelsDefined, Exprs, EndLoc);
}
/// \brief Build a new Objective-C \@try statement.
@@ -5947,6 +5950,8 @@
AsmToks, S->getAsmString(),
S->getNumOutputs(), S->getNumInputs(),
S->getAllConstraints(), S->getClobbers(),
+ S->getBranchTargets(),
+ S->getLabelsDefined(),
TransformedExprs, S->getEndLoc());
}
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -368,6 +368,8 @@
SmallVector<Expr*, 16> Exprs;
SmallVector<std::string, 16> ConstraintsData;
SmallVector<StringRef, 16> Constraints;
+ SmallVector<StringRef, 16> BranchTargets;
+ SmallVector<StringRef, 16> LabelsDefined;
Exprs.reserve(NumOperands);
ConstraintsData.reserve(NumOperands);
Constraints.reserve(NumOperands);
@@ -378,7 +380,8 @@
}
S->initialize(Reader.getContext(), AsmStr, AsmToks,
- Constraints, Exprs, Clobbers);
+ Constraints, Exprs, Clobbers, BranchTargets,
+ LabelsDefined);
}
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
Index: test/Parser/ms-inline-asm.c
===================================================================
--- test/Parser/ms-inline-asm.c
+++ test/Parser/ms-inline-asm.c
@@ -51,6 +51,37 @@
void t12() {
__asm jmp label // expected-error {{use of undeclared label 'label'}}
}
+void t13() {
+ __asm { // expected-error {{cannot jump from one inline assembly block to label 'lbl1' defined inside another one}}
+ jmp lbl1;
+ }
+ __asm { // expected-note {{label 'lbl1' defined in an inline assembly block defined here}}
+ lbl1:
+ nop
+ }
+}
+void t14() {
+ __asm { // expected-error {{cannot jump from one inline assembly block to label 'lbl2' defined inside another one}}
+ jmp lbl2;
+ }
+ for (;;) {
+ __asm { // expected-note {{label 'lbl2' defined in an inline assembly block defined here}}
+ lbl2:
+ nop
+ }
+ }
+}
+void t15() {
+ for (;;) {
+ __asm { // expected-error {{cannot jump from one inline assembly block to label 'lbl2' defined inside another one}}
+ jmp lbl2;
+ }
+ }
+ __asm { // expected-note {{label 'lbl2' defined in an inline assembly block defined here}}
+ lbl2:
+ nop
+ }
+}
int t_fail() { // expected-note {{to match this}}
__asm
__asm { // expected-error 2 {{expected}} expected-note {{to match this}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits