bool ParseRepetition(Repetition *Repetition, CallExpr *Call, Assertion *A, vector<ValueDecl*>& References, ASTContext& Ctx) { unsigned Args = Call->getNumArgs(); if (Args < 3) { Report("Repetition must have at least three arguments (min, max, events)", Call->getLocStart(), Ctx) << Call->getSourceRange(); return false; } auto Min = ParseIntegerLiteral(Call->getArg(0), Ctx); Repetition->set_min(Min.getLimitedValue()); auto Max = ParseIntegerLiteral(Call->getArg(1), Ctx); if (Max != INT_MAX) Repetition->set_max(Max.getLimitedValue()); for (unsigned i = 2; i < Args; ++i) { auto Ev = Call->getArg(i); if (!ParseEvent(Repetition->add_event(), Ev, A, References, Ctx)) { Report("Failed to parse repeated event", Ev->getLocStart(), Ctx) << Ev->getSourceRange(); return false; } } return true; }
CharacterConstantExpr *CharacterConstantExpr:: CreateCopyWithCompatibleLength(ASTContext &C, QualType T) { auto CTy = T->asCharacterType(); uint64_t Len = CTy->hasLength()? CTy->getLength() : 1; StringRef Str(Data); if(Str.size() == Len) return this; else if(Str.size() > Len) // FIXME: the existing memory can be reused. return Create(C, getSourceRange(), Str.slice(0, Len), T); else { auto NewData = new (C) char[Len + 1]; std::strncpy(NewData, Str.data(), Str.size()); std::memset(NewData + Str.size(), ' ', (Len - Str.size())); NewData[Len] = '\0'; return new (C) CharacterConstantExpr(NewData, getSourceRange(), T); } }
bool ParseFunctionCall(FunctionEvent *Event, BinaryOperator *Bop, vector<ValueDecl*>& References, ASTContext& Ctx) { // TODO: better distinguishing between callee and/or caller Event->set_context(FunctionEvent::Callee); // Since we might care about the return value, we must instrument exiting // the function rather than entering it. Event->set_direction(FunctionEvent::Exit); Expr *LHS = Bop->getLHS(); bool LHSisICE = LHS->isIntegerConstantExpr(Ctx); Expr *RHS = Bop->getRHS(); if (!(LHSisICE ^ RHS->isIntegerConstantExpr(Ctx))) { Report("One of {LHS,RHS} must be ICE", Bop->getLocStart(), Ctx) << Bop->getSourceRange(); return false; } Expr *RetVal = (LHSisICE ? LHS : RHS); Expr *FnCall = (LHSisICE ? RHS : LHS); if (!ParseArgument(Event->mutable_expectedreturnvalue(), RetVal, References, Ctx)) return false; auto FnCallExpr = dyn_cast<CallExpr>(FnCall); if (!FnCallExpr) { Report("Not a function call", FnCall->getLocStart(), Ctx) << FnCall->getSourceRange(); return false; } auto Fn = FnCallExpr->getDirectCallee(); if (!Fn) { Report("Not a direct function call", FnCallExpr->getLocStart(), Ctx) << FnCallExpr->getSourceRange(); return false; } if (!ParseFunctionRef(Event->mutable_function(), Fn, Ctx)) return false; for (auto I = FnCallExpr->arg_begin(); I != FnCallExpr->arg_end(); ++I) { if (!ParseArgument(Event->add_argument(), I->IgnoreImplicit(), References, Ctx)) return false; } return true; }
/** * Checks if buffer type and specified mpi datatype matches. * * @param mpiCall call to check type correspondence for */ void MPICheckerAST::checkBufferTypeMatch(const MPICall &mpiCall) const { // one pair consists of {bufferIdx, mpiDatatypeIdx} IndexPairs indexPairs = bufferDataTypeIndices(mpiCall); // for every buffer mpi-data pair in function // check if their types match for (const auto &idxPair : indexPairs) { const VarDecl *bufferArg = mpiCall.arguments()[idxPair.first].vars().front(); // collect buffer type information const mpi::TypeVisitor typeVisitor{bufferArg->getType()}; // get mpi datatype as string auto mpiDatatype = mpiCall.arguments()[idxPair.second].stmt_; StringRef mpiDatatypeString{util::sourceRangeAsStringRef( mpiDatatype->getSourceRange(), analysisManager_)}; selectTypeMatcher(typeVisitor, mpiCall, mpiDatatypeString, idxPair); } }
bool ParseEvent(Event *Ev, Expr *E, Assertion *A, vector<ValueDecl*>& References, ASTContext& Ctx) { E = E->IgnoreImplicit(); if (auto Ref = dyn_cast<DeclRefExpr>(E)) { auto D = Ref->getDecl(); assert(D); // The __tesla_ignore "event" helps TESLA assertions look like ISO C. if (D->getName() == "__tesla_ignore") { Ev->set_type(Event::IGNORE); return true; } // The only other static __tesla_event is the "now" event. if (D->getName() != "__tesla_now") { Report("TESLA static reference must be __tesla_ignore or __tesla_now", E->getLocStart(), Ctx) << E->getSourceRange(); return false; } Ev->set_type(Event::NOW); *Ev->mutable_now()->mutable_location() = A->location(); return true; } else if (auto Bop = dyn_cast<BinaryOperator>(E)) { // This is a call-and-return like "foo(x) == y". Ev->set_type(Event::FUNCTION); return ParseFunctionCall(Ev->mutable_function(), Bop, References, Ctx); } // Otherwise, it's a call to a TESLA "function" like __tesla_predicate(). auto Call = dyn_cast<CallExpr>(E); if (!Call) { Report("Event should look like a function call", E->getLocStart(), Ctx) << E->getSourceRange(); return false; } auto Callee = Call->getDirectCallee(); if (!Callee) { Report("TESLA event referenced indirectly", Call->getLocStart(), Ctx) << Call->getSourceRange(); return false; } if (Callee->getName() == "__tesla_repeat") { Ev->set_type(Event::REPETITION); return ParseRepetition(Ev->mutable_repetition(), Call, A, References, Ctx); } typedef bool (*FnEventParser)(FunctionEvent*, CallExpr*, vector<ValueDecl*>&, ASTContext&); FnEventParser Parser = llvm::StringSwitch<FnEventParser>(Callee->getName()) .Case("__tesla_entered", &ParseFunctionEntry) .Case("__tesla_leaving", &ParseFunctionExit) .Case("__tesla_call", &ParseFunctionCall) .Default(NULL); if (!Parser) { Report("Unknown TESLA event", E->getLocStart(), Ctx) << E->getSourceRange(); return false; } Ev->set_type(Event::FUNCTION); return Parser(Ev->mutable_function(), Call, References, Ctx); }