bool VarCollector::VisitBinaryOperator(BinaryOperator *e) { CompilerInstance &CI = FullDirectives->GetCI(e->getLocStart()); // If it's not an assignment, no contamination can occur if (!e->isAssignmentOp()) { return true; } // If we're not changing a pointer, no contamination can occur if (!e->getLHS()->getType()->isPointerType()) { return true; } assert(!e->getLHS()->getType()->isArrayType()); // Get Dominant LHS DeclRef and its expr DeclRefExpr * LDominantRef = NULL; Expr * LDominantExpr = NULL; VarTraverser lvt(e->getLHS(), LDominantRef, LDominantExpr, CI); lvt.TraverseStmt(e->getLHS()); // Shouldn't get this!! // But if there isn't a dominant variable being written to just return // Where on earth is it writing to!? // TODO: Convert to actual error! if (!LDominantRef) { llvm::errs() << "Warning: Found a pointer being modified that we have no " << "idea where came from. Can't determine if private or not!\n"; return true; } // Get Dominant RHS DeclRef and its expr DeclRefExpr * RDominantRef = NULL; Expr * RDominantExpr = NULL; VarTraverser rvt(e->getRHS(), RDominantRef, RDominantExpr, CI); rvt.TraverseStmt(e->getRHS()); // If there isn't a dominant variable now being pointed to, just return if (!RDominantRef) { llvm::errs() << "No dominant right ref\n"; return true; } VarDecl * VDLHS = dyn_cast<VarDecl>(LDominantRef->getDecl()); VarDecl * VDRHS = dyn_cast<VarDecl>(RDominantRef->getDecl()); const Type * T = LDominantExpr->getType().getTypePtr(); string LT = GetType(LDominantExpr); string RT = GetType(RDominantExpr); maybeContaminated(VDLHS, LT, VDRHS, RT, T, e->getLocStart()); return true; }
bool VisitBinAssign(const BinaryOperator *assign) { DeclRefExpr *lhs = llvm::dyn_cast<DeclRefExpr>(assign->getLHS()); if (lhs && lhs->getDecl() == _Decl) { _Set.insert(assign->getRHS()->IgnoreParenImpCasts()); } return true; }
void VarCollector::HandleArrayInitList(VarDecl *VDLHS, string TLHS, InitListExpr * Inits, SourceLocation StmtLoc) { CompilerInstance &CI = FullDirectives->GetCI(Inits->getLocStart()); for (unsigned i = 0; i < Inits->getNumInits(); i++) { Expr * Current = Inits->getInit(i); InitListExpr * InitList = dyn_cast<InitListExpr>(Current); if (InitList) { HandleArrayInitList(VDLHS, TLHS, InitList, StmtLoc); } else { // Get Dominant RHS DeclRef and its expr DeclRefExpr * RDominantRef = NULL; Expr * RDominantExpr = NULL; VarTraverser rvt(Current, RDominantRef, RDominantExpr, CI); rvt.TraverseStmt(Current); // If there isn't a dominant variable now being pointed to, just return if (!RDominantRef) { continue; } // DEBUG: // Print out the dominant LHS and RHS /* llvm::errs() << "Found init of a pointer:\n"; llvm::errs() << "RHS Ref " << RDominantRef->getDecl()->getName() << " -> " << GetStmtString(RDominantExpr) << " (" << RDominantExpr->getType().getAsString() << ")\n";*/ VarDecl * VDRHS = dyn_cast<VarDecl>(RDominantRef->getDecl()); string TRHS = GetType(RDominantExpr); const Type * T = RDominantExpr->getType()->getUnqualifiedDesugaredType(); maybeContaminated(VDLHS, TLHS, VDRHS, TRHS, T, StmtLoc); } } }
void Fix(CompoundStmt* CS) { if (!CS->size()) return; typedef llvm::SmallVector<Stmt*, 32> Statements; Statements Stmts; Stmts.append(CS->body_begin(), CS->body_end()); for (Statements::iterator I = Stmts.begin(); I != Stmts.end(); ++I) { if (!TraverseStmt(*I) && !m_HandledDecls.count(m_FoundDRE->getDecl())) { Sema::DeclGroupPtrTy VDPtrTy = m_Sema->ConvertDeclToDeclGroup(m_FoundDRE->getDecl()); StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, m_FoundDRE->getLocStart(), m_FoundDRE->getLocEnd()); assert(!DS.isInvalid() && "Invalid DeclStmt."); I = Stmts.insert(I, DS.take()); m_HandledDecls.insert(m_FoundDRE->getDecl()); } } CS->setStmts(m_Sema->getASTContext(), Stmts.data(), Stmts.size()); }
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( SourceLocation Loc, ArrayRef<Expr *> VarList) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { DeclRefExpr *DE = cast<DeclRefExpr>(*I); VarDecl *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), diag::err_omp_threadprivate_incomplete_type)) { continue; } // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // Check if this is a TLS variable. if (VD->getTLSKind()) { Diag(ILoc, diag::err_omp_var_thread_local) << VD; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } Vars.push_back(*I); } OMPThreadPrivateDecl *D = 0; if (!Vars.empty()) { D = OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc, Vars); D->setAccess(AS_public); } return D; }
//--------------------------------------------------------- VarDecl* isFortranLoop(ForStmt* Node, const char*& errMsg) { // cond must be of form "x >/</!=/ expr": BinaryOperator* condCmp = dyn_cast_or_null<BinaryOperator>(Node->getCond()); if (condCmp == 0 || ((!condCmp->isRelationalOp()) && condCmp->getOpcode() != BO_NE)) { errMsg = "for-cond not fortran-like (must be x rel expr)"; return 0; } DeclRefExpr* condVar = dyn_cast<DeclRefExpr>(stripParenCasts(condCmp->getLHS())); if (condVar == 0 || !condVar->getType()->isIntegerType()) { errMsg = "no integer for-init variable"; return 0; } VarDecl* VD = dyn_cast<VarDecl>(condVar->getDecl()); if (VD == 0) { errMsg = "strange unrecognized lhs in for-condition"; return 0; } // inc must be of form "++x/x++": UnaryOperator* incStmt = dyn_cast_or_null<UnaryOperator>(Node->getInc()); if (incStmt == 0 || (!incStmt->isIncrementOp())) { errMsg = "for-inc not fortran-like (must be ++x/x++)"; return 0; } DeclRefExpr* incVar = dyn_cast<DeclRefExpr>(incStmt->getSubExpr()); if (incVar == 0 || incVar->getDecl() != VD) { errMsg = "for-inc doesn't refer to for-cond variable"; return 0; } return VD; }
ValueDecl *valueDeclFromIncExpr(Expr *incExpr) { UnaryOperator *unaryOperator = dyn_cast_or_null<UnaryOperator>(incExpr); if (unaryOperator) { Expr *unaryOpSubExpr = unaryOperator->getSubExpr(); if (unaryOpSubExpr && isa<DeclRefExpr>(unaryOpSubExpr)) { DeclRefExpr *declRefExpr = dyn_cast<DeclRefExpr>(unaryOpSubExpr); return declRefExpr->getDecl(); } } return nullptr; }
//--------------------------------------------------------- FunctionDecl* findFunctionDecl(CallExpr* expr) { if (CXXMemberCallExpr* CMC = dyn_cast<CXXMemberCallExpr>(expr)) { return CMC->getMethodDecl(); } CastExpr* castExpr; Expr* calleeExpr = expr->getCallee(); while ((castExpr = dyn_cast<CastExpr>(calleeExpr)) != NULL) { calleeExpr = castExpr->getSubExpr(); } DeclRefExpr* fnRef = dyn_cast<DeclRefExpr>(calleeExpr); return fnRef ? dyn_cast<FunctionDecl>(fnRef->getDecl()) : NULL; }
static bool isArgOfFunc(T expr, FunctionDecl *fDecl, const VarDecl *varDecl, bool byRefOrPtrOnly) { unsigned int param = -1; for (auto arg : expr->arguments()) { ++param; DeclRefExpr *refExpr = dyn_cast<DeclRefExpr>(arg); if (!refExpr) { if (clazy_std::hasChildren(arg)) { Stmt* firstChild = *(arg->child_begin()); // Can be null (bug #362236) refExpr = firstChild ? dyn_cast<DeclRefExpr>(firstChild) : nullptr; if (!refExpr) continue; } else { continue; } } if (refExpr->getDecl() != varDecl) // It's our variable ? continue; if (!byRefOrPtrOnly) { // We found it return true; } // It is, lets see if the callee takes our variable by const-ref if (param >= fDecl->param_size()) continue; ParmVarDecl *paramDecl = fDecl->getParamDecl(param); if (!paramDecl) continue; QualType qt = paramDecl->getType(); const Type *t = qt.getTypePtrOrNull(); if (!t) continue; if ((t->isReferenceType() || t->isPointerType()) && !t->getPointeeType().isConstQualified()) return true; // function receives non-const ref, so our foreach variable cant be const-ref } return false; }
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { // Kill the iteration variable. DeclRefExpr *DR = nullptr; const VarDecl *VD = nullptr; Stmt *element = OS->getElement(); if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) { VD = cast<VarDecl>(DS->getSingleDecl()); } else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) { VD = cast<VarDecl>(DR->getDecl()); } if (VD) { val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); if (observer && DR) observer->observerKill(DR); } }
string NetworkDriverRewriteVisitor::GetSharedStructStr(CallExpr *callExpr) { string shared_struct_str = ""; Expr *callee = callExpr->getCallee(); if (!isa<ImplicitCastExpr>(callee)) return shared_struct_str; ImplicitCastExpr *calleeImplExpr = cast<ImplicitCastExpr>(callee); if (!isa<DeclRefExpr>(calleeImplExpr->getSubExpr())) return shared_struct_str; DeclRefExpr *calleeDeclExpr = cast<DeclRefExpr>(calleeImplExpr->getSubExpr()); Stmt *body = callExpr->getCalleeDecl()->getBody(); if (calleeDeclExpr->getNameInfo().getAsString() != "alloc_etherdev") shared_struct_str = GetSharedStructStrInFunctionBody(body, false); if (calleeDeclExpr->getNameInfo().getAsString() != "alloc_etherdev") return shared_struct_str; for (auto i = callExpr->arg_begin(), e = callExpr->arg_end(); i != e; ++i) { if (!isa<ImplicitCastExpr>(*i)) continue; ImplicitCastExpr *argImplExpr = cast<ImplicitCastExpr>(*i); if (!isa<UnaryExprOrTypeTraitExpr>(argImplExpr->getSubExpr())) continue; UnaryExprOrTypeTraitExpr *argExpr = cast<UnaryExprOrTypeTraitExpr>(argImplExpr->getSubExpr()); ParenExpr *parenExpr = cast<ParenExpr>(argExpr->getArgumentExpr()); UnaryOperator *uop = cast<UnaryOperator>(parenExpr->getSubExpr()); ImplicitCastExpr *implExpr = cast<ImplicitCastExpr>(uop->getSubExpr()); DeclRefExpr *declExpr = cast<DeclRefExpr>(implExpr->getSubExpr()); ValueDecl *valueDecl = cast<ValueDecl>(declExpr->getDecl()); shared_struct_str = valueDecl->getType().getAsString(Context->getPrintingPolicy()); break; } return shared_struct_str; }
void VarCollector::HandlePointerInit(VarDecl *VDLHS, string TLHS, SourceLocation StmtLoc) { CompilerInstance &CI = FullDirectives->GetCI(StmtLoc); // Get Dominant RHS DeclRef and its expr DeclRefExpr * RDominantRef = NULL; Expr * RDominantExpr = NULL; VarTraverser rvt(VDLHS->getInit(), RDominantRef, RDominantExpr, CI); rvt.TraverseStmt(VDLHS->getInit()); // If there isn't a dominant variable now being pointed to, just return if (!RDominantRef) { return; } // DEBUG: // Print out the dominant LHS and RHS /*llvm::errs() << "Found init of a pointer:\n"; llvm::errs() << "RHS Ref " << RDominantRef->getDecl()->getName() << " -> " << GetStmtString(RDominantExpr) << " (" << RDominantExpr->getType().getAsString() << ")\n";*/ VarDecl * VDRHS = dyn_cast<VarDecl>(RDominantRef->getDecl()); string TRHS = GetType(RDominantExpr); const Type * T = RDominantExpr->getType()->getUnqualifiedDesugaredType(); maybeContaminated(VDLHS, TLHS, VDRHS, TRHS, T, StmtLoc); }
/* this helper function is called when the traversal reaches a node of type Stmt */ void StmtHelper(Stmt *x){ //variable used for <cond> </cond> //bool condition = false; bool isElse = false; if(x != NULL){ string output = ""; //find current level and next level int intLevel = getLevelStmt(x); int intNextLevel = intLevel+1; //convert them both to strings to use for output string level; string nextLevel; stringstream ss; ss << intLevel; level = ss.str(); stringstream ss2; ss2 << intNextLevel; nextLevel = ss2.str(); const Stmt* parent = getStmtParent(x, Context); //PROBLEM if(x->getStmtClassName() != std::string("ForStmt") && isFlowControl(x, Context)){ //return; } //if the parent is calling any type of funciton then this node should be enclosed in <args> </args> string filename; if(callStackDebug && !callStack.empty()){ cerr << "stmt: call stack top: " << callStack.top()->getStmtClassName() << endl; } while(!callStack.empty() && numClosingArgsNeeded > 0 && !isParentStmt(parent, callStack.top()->getStmtClassName())){ if(debugPrint){ cerr << "adding args" << endl; } numClosingArgsNeeded--; output += "</args,1>\n"; callStack.pop(); if(callStackDebug){ cerr << "popping" << endl; printCallStack(); } } if(isParentStmtInCurFile(x,"CXXConstructExpr") && isParentStmt(x, "CXXConstructExpr")){ if(debugPrint){ cerr << "setting previousConstructorCall to true" << endl; } }else if(isParentStmtInCurFile(x,"CXXTemporaryObjectExpr") && isParentStmt(x, "CXXTemporaryObjectExpr")){ if(debugPrint){ cerr << "setting previousTempConstructorCallArg" << endl; } }else if(isParentStmt(x, "CallExpr")){ if(debugPrint){ cerr << "setting previousCallArgs to true" << endl; } }else if(isParentStmt(x, "CXXMemberCallExpr")){ if(debugPrint){ cerr << "setting previousMemberCallArgs to true" << endl; } } //if the parent is a variable declaration then this node should be encolsed in <decl> </decl> if(isParentStmt(x, "Var")){ previousRhsDecl = true; if(debugPrint){ cout << "setting prev var to true" << endl; } }else if(previousRhsDecl && numClosingVarsNeeded > 0){ //if the current node is not a child of a variable declaration //but the previous node was a child of a variable declation //then we know to print a </decl> output +="</variableDecl,1>\n"; numClosingVarsNeeded--; previousRhsDecl = false; } if(parent != NULL && strcmp(parent->getStmtClassName(), "IfStmt") == 0){ if(debugPrint){ cerr << "possibly an if statement" << endl; } //find the first child of the if statemt const Stmt* firstChild = NULL; auto children = parent->children(); for(const Stmt* child : children){ if(child != NULL){ firstChild = child; break; } } //if the first child is the current node, then we know it is part of the condition if(firstChild != NULL && x->getLocStart() == firstChild->getLocStart()){ if(debugPrint){ cerr << "part of the condition" << endl; } prevCondition = true; }else if(prevCondition){ output +="</cond,1>\n"; prevCondition = false; } //find if else const IfStmt* ifstmt = (IfStmt*) parent; const Stmt* elseStmt = ifstmt->getElse(); if(elseStmt != NULL){ if(debugPrint){ cout << "checking if " << x->getLocStart().printToString(Context->getSourceManager()); cout << " == " << elseStmt->getLocStart().printToString(Context->getSourceManager()); cout << " : " << (x->getLocStart() == elseStmt->getLocStart()) << endl; } if(x->getLocStart() == elseStmt->getLocStart()){ isElse = true; } } } string node = x->getStmtClassName(); if(node == "ReturnStmt"){ output += "<return"; }else if(node == "ForStmt"){ output += "<forLoop"; }else if(node == "WhileStmt"){ output += "<whileLoop"; }else if(node == "DoStmt"){ output += "<do"; }else if(node == "IfStmt"){ if(parent->getStmtClassName() != std::string("IfStmt")){ stringstream ssminus; ssminus << (intLevel-1); output += "<ifBlock," + ssminus.str() + ">\n"; intLevel += 1; stringstream ssif; ssif << intLevel; level = ssif.str(); } output += "<ifStatement"; }else if(node == "SwitchStmt"){ output += "<switch"; }else if(node == "CaseStmt"){ output += "<case"; }else if(node == "CXXMemberCallExpr"){ CXXMemberCallExpr* ce = (CXXMemberCallExpr*) x; Expr* obj = ce->getImplicitObjectArgument(); CallExpr* expr = (CallExpr*) x; output += "<object: "; QualType qt = obj->getType(); output += qt.getBaseTypeIdentifier()->getName().str(); output += "; calling func: "; output += expr->getDirectCallee()->getNameInfo().getAsString(); output += ", " + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } }else if(node == "CallExpr"){ CallExpr* expr = (CallExpr*) x; output += "<calling func: "; output += expr->getDirectCallee()->getNameInfo().getAsString(); output += ", " + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } }else if(node == "CXXConstructExpr"){ CXXConstructExpr* ce = (CXXConstructExpr*) x; //Decl* CD = ce->getConstructor(); string filename; //if(isInCurFile(Context, CD, filename)){ CXXMethodDecl* MD = ce->getConstructor(); output += "<calling func: "; output += MD->getNameInfo().getAsString(); output += "," + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } //} }else if(node == "BinaryOperator"){ BinaryOperator* binaryOp = (BinaryOperator*) x; if(binaryOp->isAssignmentOp()){ output += "<assignment"; }else if(binaryOp->isComparisonOp()){ output += "<comparison"; }else{ output += "<binaryOp"; } }else if(node == "UnaryOperator"){ UnaryOperator* uo = (UnaryOperator*) x; string op = uo->getOpcodeStr(uo->getOpcode()).str(); if(op != "-"){ output += "<unaryOp"; } }else if(node == "CompoundAssignOperator"){ output += "<augAssign"; }else if(node == "CompoundStmt"){ if(isElse){ output += "<elseStatement"; }else{ output += "<compoundStmt"; } }else if(node == "CXXThrowExpr"){ output += "<raisingException"; }else if(node == "CXXTryStmt"){ output += "<try"; }else if(node == "CXXCatchStmt"){ output += "<except"; }else if(node == "CXXOperatorCallExpr"){ CXXOperatorCallExpr* ce = (CXXOperatorCallExpr*) x; if(ce->isAssignmentOp()){ output += "<assignment"; } }else if(node == "CXXTemporaryObjectExpr"){ CXXTemporaryObjectExpr* ce = (CXXTemporaryObjectExpr*) x; Decl* CD = ce->getConstructor(); string filename; if(isInCurFile(Context, CD, filename)){ CXXMethodDecl* MD = ce->getConstructor(); output += "<calling func: "; output += MD->getNameInfo().getAsString(); output += "," + level + ">\n"; output += "<args"; numClosingArgsNeeded++; callStack.push(x); if(callStackDebug){ cerr << "pushing" << endl; printCallStack(); } } }else if(node == "DeclRefExpr"){ if(parent != NULL && parent->getStmtClassName() == std::string("ImplicitCastExpr")){ DeclRefExpr* dr = (DeclRefExpr*) x; ValueDecl* d = (ValueDecl*) dr->getDecl(); //cout << d->getQualType().getAsString() << endl; if(d != NULL){ QualType qt = d->getType(); //cout << qt.getAsString() << endl; if(qt.getAsString() == "std::vector<int, class std::allocator<int> >::const_reference (std::vector::size_type) const noexcept"){ //string type = io->getName().str(); //cout << type << endl; //if(type == "vector"){ output += "<expr"; //} } } } }else{ if(allNodes){ output += "<"; output += node; output += ">"; } } if(output.size() != 0 && !endsIn(output, "</cond,1>\n") && !endsIn(output,"</variableDecl,1>\n") && !endsIn(output,"</args,1>\n") && !endsIn(output,">") && !endsIn(output, ">\n")){ output += ", " + level + ">"; cout << output << endl; output = ""; }else if(output.size() != 0){ cout << output << endl; output = ""; if(debugPrint){ cerr << "printing output" << endl; } } } }
void TransferFunctions::VisitBinaryOperator(BinaryOperator *E) { DeclRefExpr *DRE = nullptr; switch (E->getOpcode()) { case BO_PtrMemD: case BO_PtrMemI: default: KS.num_ops++; if (checkImageAccess(E->getLHS(), READ_WRITE) || checkImageAccess(E->getRHS(), READ_WRITE)) { // not supported on image objects KS.Diags.Report(E->getOperatorLoc(), KS.DiagIDUnsupportedBO) << E->getOpcodeStr(); exit(EXIT_FAILURE); } case BO_Mul: case BO_Div: case BO_Rem: case BO_Add: case BO_Sub: case BO_Shl: case BO_Shr: case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: case BO_And: case BO_Xor: case BO_Or: case BO_LAnd: case BO_LOr: KS.num_ops++; if (checkImageAccess(E->getLHS(), READ_ONLY)) { KS.curStmtVectorize = (VectorInfo) (KS.curStmtVectorize|VECTORIZE); } if (checkImageAccess(E->getRHS(), READ_ONLY)) { KS.curStmtVectorize = (VectorInfo) (KS.curStmtVectorize|VECTORIZE); } break; case BO_Assign: KS.num_ops++; if (checkImageAccess(E->getRHS(), READ_ONLY)) { KS.curStmtVectorize = (VectorInfo) (KS.curStmtVectorize|VECTORIZE); } else { if (isa<DeclRefExpr>(E->getRHS()->IgnoreParenImpCasts())) { DRE = dyn_cast<DeclRefExpr>(E->getRHS()->IgnoreParenImpCasts()); if (isa<VarDecl>(DRE->getDecl())) { VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); KS.declsToVector[VD] = (VectorInfo) (KS.curStmtVectorize|KS.declsToVector[VD]); } } } if (!checkImageAccess(E->getLHS(), WRITE_ONLY)) { if (isa<DeclRefExpr>(E->getLHS())) { DRE = dyn_cast<DeclRefExpr>(E->getLHS()); if (isa<VarDecl>(DRE->getDecl())) { VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); KS.declsToVector[VD] = (VectorInfo) (KS.curStmtVectorize|KS.declsToVector[VD]); } } else { #ifdef DEBUG_ANALYSIS llvm::errs() << "==DEBUG==: is not a DRE (LHS):\n"; E->getLHS()->dump(); llvm::errs() << "\n"; #endif } } // reset vectorization status for next statement KS.curStmtVectorize = SCALAR; break; case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: KS.num_ops+=2; if (checkImageAccess(E->getRHS(), READ_ONLY)) { KS.curStmtVectorize = (VectorInfo) (KS.curStmtVectorize|VECTORIZE); } else { if (isa<DeclRefExpr>(E->getRHS()->IgnoreParenImpCasts())) { DRE = dyn_cast<DeclRefExpr>(E->getRHS()->IgnoreParenImpCasts()); if (isa<VarDecl>(DRE->getDecl())) { VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); KS.declsToVector[VD] = (VectorInfo) (KS.curStmtVectorize|KS.declsToVector[VD]); } } } if (!checkImageAccess(E->getLHS(), READ_WRITE)) { if (isa<DeclRefExpr>(E->getLHS())) { DRE = dyn_cast<DeclRefExpr>(E->getLHS()); if (isa<VarDecl>(DRE->getDecl())) { VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); KS.declsToVector[VD] = (VectorInfo) (KS.curStmtVectorize|KS.declsToVector[VD]); } } else { #ifdef DEBUG_ANALYSIS llvm::errs() << "==DEBUG==: is not a DRE (LHS):\n"; E->getLHS()->dump(); llvm::errs() << "\n"; #endif } } // reset vectorization status for next statement KS.curStmtVectorize = SCALAR; break; case BO_Comma: break; } }
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { assert(*I && "NULL expr in OpenMP firstprivate clause."); if (isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_firstprivate_incomplete_type)) { continue; } if (Type->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) << getOpenMPClauseName(OMPC_firstprivate) << Type; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accesible, unambiguous copy constructor for the // class type. Type = Context.getBaseElementType(Type); CXXRecordDecl *RD = getLangOpts().CPlusPlus ? Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; if (RD) { CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0); PartialDiagnostic PD = PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); if (!CD || CheckConstructorAccess(ELoc, CD, InitializedEntity::InitializeTemporary(Type), CD->getAccess(), PD) == AR_inaccessible || CD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_firstprivate) << 1; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, CD); DiagnoseUseOfDecl(CD, ELoc); CXXDestructorDecl *DD = RD->getDestructor(); if (DD) { if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || DD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_firstprivate) << 4; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, DD); DiagnoseUseOfDecl(DD, ELoc); } } // If StartLoc and EndLoc are invalid - this is an implicit firstprivate // variable and it was checked already. if (StartLoc.isValid() && EndLoc.isValid()) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); Type = Type.getNonReferenceType().getCanonicalType(); bool IsConstant = Type.isConstant(Context); Type = Context.getBaseElementType(Type); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more // than one clause on the same directive, except that a variable may be // specified in both firstprivate and lastprivate clauses. // TODO: add processing for lastprivate. if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); continue; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, p.2] // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) << getOpenMPClauseName(DVar.CKind); continue; } // OpenMP [2.9.3.4, Restrictions, p.2] // A list item that is private within a parallel region must not appear // in a firstprivate clause on a worksharing construct if any of the // worksharing regions arising from the worksharing construct ever bind // to any of the parallel regions arising from the parallel construct. // OpenMP [2.9.3.4, Restrictions, p.3] // A list item that appears in a reduction clause of a parallel construct // must not appear in a firstprivate clause on a worksharing or task // construct if any of the worksharing or task regions arising from the // worksharing or task construct ever bind to any of the parallel regions // arising from the parallel construct. // OpenMP [2.9.3.4, Restrictions, p.4] // A list item that appears in a reduction clause in worksharing // construct must not appear in a firstprivate clause in a task construct // encountered during execution of any of the worksharing regions arising // from the worksharing construct. // TODO: } DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { assert(*I && "NULL expr in OpenMP private clause."); if (isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) { continue; } if (Type->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) << getOpenMPClauseName(OMPC_private) << Type; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accesible, unambiguous default constructor for the // class type. while (Type.getNonReferenceType()->isArrayType()) { Type = cast<ArrayType>( Type.getNonReferenceType().getTypePtr())->getElementType(); } CXXRecordDecl *RD = getLangOpts().CPlusPlus ? Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; if (RD) { CXXConstructorDecl *CD = LookupDefaultConstructor(RD); PartialDiagnostic PD = PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); if (!CD || CheckConstructorAccess(ELoc, CD, InitializedEntity::InitializeTemporary(Type), CD->getAccess(), PD) == AR_inaccessible || CD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 0; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, CD); DiagnoseUseOfDecl(CD, ELoc); CXXDestructorDecl *DD = RD->getDestructor(); if (DD) { if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || DD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 4; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, DD); DiagnoseUseOfDecl(DD, ELoc); } } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); if (DVar.RefExpr) { Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); } else { Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) << getOpenMPClauseName(DVar.CKind); } continue; } DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { assert(*I && "NULL expr in OpenMP shared clause."); if (isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.4, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_shared); Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); continue; } DSAStack->addDSA(VD, DE, OMPC_shared); Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }