diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 517fd1967fcabe71c97fbc642f966ef12416a2e6..bcd75e5ac47f77f42f7571571e58d82d1cd2cbf7 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -2181,6 +2181,20 @@ def Loopbound : Attr { }]; } +def PlatinaGuard : Attr { + // #pragma platina guard <str> + let Spellings = [Pragma<"platina", "guard">]; + let Args = [StringArgument<"GuardExpr">]; + + let Documentation = [Undocumented]; + + let AdditionalMembers = [{ + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const { + OS << guardExpr << "\n"; + } + }]; +} + def CapturedRecord : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index fbed8c73d6a0f84ca16af0426a660a81517512ff..b267b94c32ddb6b61759c4dcd3ef8d743fe98479 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -990,4 +990,13 @@ def err_pragma_loopbound_malformed : Error< def err_pragma_platin_malformed : Error< "platin pragma needs to be flowfact: (c1 @x + c2 @y <= c3)">; +// - #pragma platina +def err_pragma_platinaguard_no_stringliteral : Error< + "pragma platina guard is malformed; expecting " + "'#pragma platina guard \"expr\"'">; +def err_pragma_platinaguard_malformed : Error< + "pragma platina guard is malformed; " + "spurious tokens at end of pragma; expecting " + "'#pragma platina guard \"expr\"'">; + } // end of Parser diagnostics diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 97817af35f5a51bf27eb4954759f5638b28ebc7a..0d94e923baa495e225e70705791590ed41e54268 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -662,6 +662,8 @@ def err_pragma_loop_precedes_nonloop : Error< "expected a for, while, or do-while loop to follow '%0'">; def err_pragma_loopbound_invalid_values : Error< "invalid values; expected min >= 0 && max >= 0 && min <= max">; +def err_pragma_platinaguard_invalid_expr : Error< + "invalid Attribute operand; expected a StringLiteral">; /// Objective-C parser diagnostics def err_duplicate_class_def : Error< diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 02c43053039f95ee0d6bf33424957431d7880cff..1d28620b515f2a5f5b2d9939b8038c4ee0f674c4 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -770,6 +770,11 @@ ANNOTATION(pragma_loop_hint) // handles #pragma loopbound ... directives. ANNOTATION(pragma_loopbound) +// Annotations for #pragma loopbound +// The lexer produces these so that they only take effect when the parser +// handles #pragma loopbound ... directives. +ANNOTATION(pragma_platinaguard) + // Annotations for platin #pragmas ANNOTATION(pragma_platinff) ANNOTATION(pragma_platinff_end) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d501fdc50835465874ff60092e219cf46e0af7e1..6a7a77538e81f9776b0086490139fe57748fa5d8 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -22,6 +22,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Loopbound.h" #include "clang/Sema/LoopHint.h" +#include "clang/Sema/PlatinaGuard.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" @@ -167,6 +168,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr<PragmaHandler> MSRuntimeChecks; std::unique_ptr<PragmaHandler> OptimizeHandler; std::unique_ptr<PragmaHandler> LoopboundHandler; + std::unique_ptr<PragmaHandler> PlatinaGuardHandler; std::unique_ptr<PragmaHandler> PlatinHandler; std::unique_ptr<PragmaHandler> LoopHintHandler; std::unique_ptr<PragmaHandler> UnrollHintHandler; @@ -536,6 +538,10 @@ private: /// #pragma loopbound void HandlePragmaLoopbound(Loopbound &LB); + /// \brief Handle the annotation token produced for + /// #pragma platina guard + void HandlePragmaPlatinaGuard(PlatinaGuard &PG); + /// \brief Handle the annotation token produced for /// #pragma clang loop and #pragma unroll. bool HandlePragmaLoopHint(LoopHint &Hint); @@ -1702,6 +1708,10 @@ private: AllowedContsructsKind Allowed, SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs); + StmtResult ParsePragmaPlatinaGuard(StmtVector &Stmts, + AllowedContsructsKind Allowed, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs); /// \brief Describes the behavior that should be taken for an __if_exists /// block. diff --git a/include/clang/Sema/PlatinaGuard.h b/include/clang/Sema/PlatinaGuard.h new file mode 100644 index 0000000000000000000000000000000000000000..7321f2c11f7fab8aa169cc3ccb8960422382c864 --- /dev/null +++ b/include/clang/Sema/PlatinaGuard.h @@ -0,0 +1,35 @@ +//===--- PlatinaGuard.h - Types for Loopbound ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PLATINAGUARD_H +#define LLVM_CLANG_SEMA_PLATINAGUARD_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/AttributeList.h" +#include "clang/Sema/Ownership.h" + +namespace clang { + +/// \brief PlatinaGuard pragmas. +struct PlatinaGuard { + // Source range of the directive. + SourceRange Range; + // Identifier corresponding to the name of the pragma ("guard") + IdentifierLoc *PragmaNameLoc; + // String of the guardexpression + Expr * GuardExpr; + + PlatinaGuard() + : PragmaNameLoc(NULL), GuardExpr(NULL) {} +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_PLATINAGUARD_H diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index f08e3aaa08ed6920bcfdb954ba849768a061eac4..f6f9827399f033f750a1f56aefe98ce793b2d97d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -487,8 +487,34 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { EmitStmt(S.getSubStmt()); } + +void CodeGenFunction::EmitPlatinaIntrinsic(const ArrayRef<const Attr*> &Attrs) { + using namespace llvm; + for (unsigned i = 0; i < Attrs.size(); ++i) { + const Attr *A = Attrs[i]; + const PlatinaGuardAttr *PG = dyn_cast<PlatinaGuardAttr>(A); + + // Skip non PlatinaGuard attributes + if (!PG) continue; + + Function *Callee = + CGM.getIntrinsic(Intrinsic::platina); + CallInst *callsite = Builder.CreateCall(Callee); + + // Attach the guardexpr to the instruction-metadata + // We have to store our string in the LLVMContext + LLVMContext& C = callsite->getContext(); + MDNode *meta = MDNode::get(C, MDString::get(C, PG->getGuardExpr())); + callsite->setMetadata("platina.guardexpr", meta); + } +} + void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { const Stmt *SubStmt = S.getSubStmt(); + + // We translate the platina expressions to intrinsics, which should happen here + EmitPlatinaIntrinsic(S.getAttrs()); + switch (SubStmt->getStmtClass()) { case Stmt::DoStmtClass: EmitDoStmt(cast<DoStmt>(*SubStmt), S.getAttrs()); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 21fc3bd77c893e2a9eb5fc59525361505a1acae2..17118442b399f51069293e689a5a5a8aadf97ce4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2142,6 +2142,8 @@ public: void EmitHeaderBounds(llvm::BasicBlock *Header, const ArrayRef<const Attr *> &Attrs); + void EmitPlatinaIntrinsic(const ArrayRef<const Attr*> &Attrs); + void EmitWhileStmt(const WhileStmt &S, ArrayRef<const Attr *> Attrs = None); void EmitDoStmt(const DoStmt &S, ArrayRef<const Attr *> Attrs = None); diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 85db7610fe9b34f4e8f7127efcac3ff4c89555e8..1705cce40e148791dab50049a6da56eb7d65da95 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -19,8 +19,10 @@ #include "clang/Parse/Parser.h" #include "clang/Sema/Loopbound.h" #include "clang/Sema/LoopHint.h" +#include "clang/Sema/PlatinaGuard.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/StringSwitch.h" +#include <iostream> using namespace clang; namespace { @@ -151,6 +153,12 @@ struct PragmaLoopboundHandler : public PragmaHandler { Token &FirstToken) override; }; +struct PragmaPlatinaGuardHandler : public PragmaHandler { + PragmaPlatinaGuardHandler() : PragmaHandler("guard") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +}; + struct PragmaPlatinHandler : public PragmaHandler { PragmaPlatinHandler() : PragmaHandler("platin") { } void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, @@ -249,6 +257,9 @@ void Parser::initializePragmaHandlers() { LoopboundHandler.reset(new PragmaLoopboundHandler()); PP.AddPragmaHandler(LoopboundHandler.get()); + PlatinaGuardHandler.reset(new PragmaPlatinaGuardHandler()); + PP.AddPragmaHandler("platina", PlatinaGuardHandler.get()); + PlatinHandler.reset(new PragmaPlatinHandler()); PP.AddPragmaHandler(PlatinHandler.get()); @@ -329,6 +340,9 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler(LoopboundHandler.get()); LoopboundHandler.reset(); + PP.RemovePragmaHandler("platina", PlatinaGuardHandler.get()); + PlatinaGuardHandler.reset(); + PP.RemovePragmaHandler("clang", LoopHintHandler.get()); LoopHintHandler.reset(); @@ -1956,7 +1970,7 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, return; } PP.Lex(Tok); - + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument) << PP.getSpelling(Tok); @@ -2023,6 +2037,72 @@ void PragmaLoopboundHandler::HandlePragma(Preprocessor &PP, /*OwnsTokens=*/true); } +namespace { +struct PragmaPlatinaGuardInfo { + Token PragmaName; + Token GuardExpr; +}; +} // end anonymous namespace + +// #pragma platina guard "expr" +void PragmaPlatinaGuardHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &FirstTok) { + + Token Tok; + + // Get the next token, we do not want to expand it, as guardexpr + // is a language of its own + PP.LexUnexpandedToken(Tok); + + if (Tok.isNot(tok::string_literal)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_platinaguard_no_stringliteral); + return; + } + + PragmaPlatinaGuardInfo *Info = + new (PP.getPreprocessorAllocator()) PragmaPlatinaGuardInfo; + + Info->PragmaName = FirstTok; + Info->GuardExpr = Tok; + + // Lex the next token + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_platinaguard_malformed); + return; + } + + Token out; + out.startToken(); + out.setKind(tok::annot_pragma_platinaguard); + out.setLocation(FirstTok.getLocation()); + out.setAnnotationValue(static_cast<void *>(Info)); + PP.EnterToken(out); +} + +void Parser::HandlePragmaPlatinaGuard(PlatinaGuard &PG) { + assert(Tok.is(tok::annot_pragma_platinaguard)); + + PragmaPlatinaGuardInfo *Info = + static_cast<PragmaPlatinaGuardInfo *>(Tok.getAnnotationValue()); + ConsumeToken(); // The annotation token. + + PG.PragmaNameLoc = IdentifierLoc::create( + Actions.Context, + Info->PragmaName.getLocation(), + Info->PragmaName.getIdentifierInfo() + ); + + Token toks[1]; + toks[0] = Info->GuardExpr; + PG.GuardExpr = Actions.ActOnStringLiteral(toks, nullptr).get(); + + // Determine which token ends our pragms: + PG.Range = + SourceRange(Info->PragmaName.getLocation(), Info->GuardExpr.getLocation()); +} + void PragmaPlatinHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 3993b51573b46ee15235e33fd7c4a271df9d3fce..7bbb3b5cb43e5a97dc5f433342c87743a9236f67 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -377,6 +377,10 @@ Retry: ProhibitAttributes(Attrs); return ParsePlatinPragma(); + case tok::annot_pragma_platinaguard: + ProhibitAttributes(Attrs); + return ParsePragmaPlatinaGuard(Stmts, Allowed, TrailingElseLoc, Attrs); + case tok::annot_pragma_loop_hint: ProhibitAttributes(Attrs); return ParsePragmaLoopHint(Stmts, Allowed, TrailingElseLoc, Attrs); @@ -1944,6 +1948,34 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, return S; } +StmtResult Parser::ParsePragmaPlatinaGuard(StmtVector &Stmts, + AllowedContsructsKind Allowed, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs) { + // Create temporary attribute list. + ParsedAttributesWithRange TempAttrs(AttrFactory); + + // Get loop hints and consume annotated token. + while (Tok.is(tok::annot_pragma_platinaguard)) { + PlatinaGuard guard; + HandlePragmaPlatinaGuard(guard); + + ArgsUnion ArgPG[] = {ArgsUnion(guard.GuardExpr)}; + TempAttrs.addNew(guard.PragmaNameLoc->Ident, guard.Range, nullptr, + guard.PragmaNameLoc->Loc, ArgPG, 4, + AttributeList::AS_Pragma); + } + + // Get the next statement. + MaybeParseCXX11Attributes(Attrs); + + StmtResult S = ParseStatementOrDeclarationAfterAttributes( + Stmts, Allowed, TrailingElseLoc, Attrs); + + Attrs.takeAllFrom(TempAttrs); + return S; +} + Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 52e19fa3546ad1e15bbfa5d5a698034b83011f09..7315f1519bb5637985dcc06ff272496c80d3167d 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -160,6 +160,24 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, ValueExpr, A.getRange()); } +static Attr *handlePlatinaGuardAttr(Sema &S, Stmt *St, const AttributeList &A, + SourceRange Range) { + Expr *Expr = A.getArgAsExpr(0); + + assert(Expr != NULL); + + if (!StringLiteral::classof(Expr)) { + S.Diag(A.getLoc(), diag::err_pragma_platinaguard_invalid_expr); + return nullptr; + } + + StringLiteral *str = cast<StringLiteral>(Expr); + StringRef val = str->getString(); + + return ::new (S.Context) PlatinaGuardAttr(A.getRange(), S.Context, + val, A.getAttributeSpellingListIndex()); +} + static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl<const Attr *> &Attrs) { @@ -250,6 +268,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, return handleLoopboundAttr(S, St, A, Range); case AttributeList::AT_LoopHint: return handleLoopHintAttr(S, St, A, Range); + case AttributeList::AT_PlatinaGuard: + return handlePlatinaGuardAttr(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute