diff options
author | Jennifer Yu <jennifer.yu@intel.com> | 2019-05-30 01:05:46 +0000 |
---|---|---|
committer | Jennifer Yu <jennifer.yu@intel.com> | 2019-05-30 01:05:46 +0000 |
commit | 5846cacafa3a592f1745aaa20297d744c40dc56c (patch) | |
tree | fc80c301f42eca03b5b029c2d43d44a9e2eaba70 /lib/Sema/SemaStmtAsm.cpp | |
parent | e7fac8a0763b4595c1e8db743697857a93d2bf7d (diff) | |
download | clang-5846cacafa3a592f1745aaa20297d744c40dc56c.tar.gz |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362045 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmtAsm.cpp')
-rw-r--r-- | lib/Sema/SemaStmtAsm.cpp | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 8c6012573c..ec8958c3c5 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -209,11 +209,12 @@ static StringRef extractRegisterName(const Expr *Expression, 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 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg Exprs, Expr *asmString, MultiExprArg clobbers, + unsigned NumLabels, SourceLocation RParenLoc) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = @@ -269,7 +271,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, - NumClobbers, Clobbers, RParenLoc); + NumClobbers, Clobbers, NumLabels, RParenLoc); } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); @@ -330,7 +332,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, - NumClobbers, Clobbers, RParenLoc); + NumClobbers, Clobbers, NumLabels, RParenLoc); } } @@ -352,7 +354,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, - NumClobbers, Clobbers, RParenLoc); + NumClobbers, Clobbers, NumLabels, RParenLoc); } ExprResult ER = CheckPlaceholderExpr(Exprs[i]); @@ -451,14 +453,15 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs.data(), AsmString, - NumClobbers, Clobbers, RParenLoc); + NumClobbers, Clobbers, NumLabels, RParenLoc); } } 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; @@ -476,8 +479,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); + // Labels are the last in the Exprs list. + if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs()) + continue; unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); - // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { @@ -660,10 +665,39 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // 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()) targetDiag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); + // Check for duplicate asm operand name between input, output and label lists. + typedef std::pair<StringRef , Expr *> NamedOperand; + SmallVector<NamedOperand, 4> NamedOperandList; + for (unsigned i = 0, e = NumOutputs + NumInputs + NumLabels; i != e; ++i) + if (Names[i]) + NamedOperandList.emplace_back( + std::make_pair(Names[i]->getName(), Exprs[i])); + // Sort NamedOperandList. + std::stable_sort(NamedOperandList.begin(), NamedOperandList.end(), + [](const NamedOperand &LHS, const NamedOperand &RHS) { + return LHS.first < RHS.first; + }); + // Find adjacent duplicate operand. + SmallVector<NamedOperand, 4>::iterator Found = + std::adjacent_find(begin(NamedOperandList), end(NamedOperandList), + [](const NamedOperand &LHS, const NamedOperand &RHS) { + return LHS.first == RHS.first; + }); + if (Found != NamedOperandList.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(); + } + if (NS->isAsmGoto()) + setFunctionHasBranchIntoScope(); return NS; } |