void QDeleteAll::VisitStmt(clang::Stmt *stmt) { // Find a call to QMap/QSet/QHash::values CXXMemberCallExpr *valuesCall = dyn_cast<CXXMemberCallExpr>(stmt); if (valuesCall && valuesCall->getDirectCallee() && valuesCall->getDirectCallee()->getNameAsString() == "values") { const std::string valuesClassName = valuesCall->getMethodDecl()->getParent()->getNameAsString(); if (valuesClassName == "QMap" || valuesClassName == "QSet" || valuesClassName == "QHash") { // QMultiHash and QMultiMap automatically supported // Once found see if the first parent call is qDeleteAll int i = 1; Stmt *p = Utils::parent(m_parentMap, stmt, i); while (p) { CallExpr *pc = dyn_cast<CallExpr>(p); if (pc) { if (pc->getDirectCallee() && pc->getDirectCallee()->getNameAsString() == "qDeleteAll") { emitWarning(p->getLocStart(), "Calling qDeleteAll with " + valuesClassName + "::values, call qDeleteAll on the container itself"); } break; } ++i; p = Utils::parent(m_parentMap, stmt, i); } } } }
// Catches cases like: int i = s.mid(1, 1).toInt() bool StringRefCandidates::processCase1(CXXMemberCallExpr *memberCall) { if (!memberCall) return false; // In the AST secondMethod() is parent of firstMethod() call, and will be visited first (because at runtime firstMethod() is resolved first(). // So check for interesting second method first CXXMethodDecl *method = memberCall->getMethodDecl(); if (!isInterestingSecondMethod(method)) return false; vector<CallExpr *> callExprs = Utils::callListForChain(memberCall); if (callExprs.size() < 2) return false; // The list now contains {secondMethod(), firstMethod() } CXXMemberCallExpr *firstMemberCall = dyn_cast<CXXMemberCallExpr>(callExprs.at(1)); if (!firstMemberCall || !isInterestingFirstMethod(firstMemberCall->getMethodDecl())) return false; const string firstMethodName = firstMemberCall->getMethodDecl()->getNameAsString(); std::vector<FixItHint> fixits; if (isFixitEnabled(FixitUseQStringRef)) { fixits = fixit(firstMemberCall); } emitWarning(firstMemberCall->getLocEnd(), "Use " + firstMethodName + "Ref() instead", fixits); return true; }
void QGetEnv::VisitStmt(clang::Stmt *stmt) { // Lets check only in function calls. Otherwise there are too many false positives, it's common // to implicit cast to bool when checking pointers for validity, like if (ptr) CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stmt); if (!memberCall) return; CXXMethodDecl *method = memberCall->getMethodDecl(); if (!method) return; CXXRecordDecl *record = method->getParent(); if (!record || record->getNameAsString() != "QByteArray") { return; } std::vector<CallExpr *> calls = Utils::callListForChain(memberCall); if (calls.size() != 2) return; CallExpr *qgetEnvCall = calls.back(); FunctionDecl *func = qgetEnvCall->getDirectCallee(); if (!func || func->getNameAsString() != "qgetenv") return; string methodname = method->getNameAsString(); string errorMsg; std::string replacement; if (methodname == "isEmpty") { errorMsg = "qgetenv().isEmpty() allocates."; replacement = "qEnvironmentVariableIsEmpty"; } else if (methodname == "isNull") { errorMsg = "qgetenv().isNull() allocates."; replacement = "qEnvironmentVariableIsSet"; } else if (methodname == "toInt") { errorMsg = "qgetenv().toInt() is slow."; replacement = "qEnvironmentVariableIntValue"; } if (!errorMsg.empty()) { std::vector<FixItHint> fixits; if (isFixitEnabled(FixitAll)) { const bool success = FixItUtils::transformTwoCallsIntoOne(m_ci, qgetEnvCall, memberCall, replacement, fixits); if (!success) { queueManualFixitWarning(memberCall->getLocStart(), FixitAll); } } errorMsg += " Use " + replacement + "() instead"; emitWarning(memberCall->getLocStart(), errorMsg.c_str(), fixits); } }
void Qt4_QStringFromArray::VisitStmt(clang::Stmt *stm) { CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(stm); CXXOperatorCallExpr *operatorCall = dyn_cast<CXXOperatorCallExpr>(stm); CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stm); if (!ctorExpr && !operatorCall && !memberCall) return; vector<FixItHint> fixits; bool is_char_array = false; bool is_byte_array = false; string methodName; string message; if (ctorExpr) { CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor(); if (!isInterestingCtorCall(ctorDecl, is_char_array, is_byte_array)) return; fixits = fixCtorCall(ctorExpr); if (is_char_array) { message = "QString(const char *) ctor being called"; } else { message = "QString(QByteArray) ctor being called"; } } else if (operatorCall) { if (!isInterestingOperatorCall(operatorCall, /*by-ref*/methodName, is_char_array, is_byte_array)) return; fixits = fixOperatorCall(operatorCall); } else if (memberCall) { if (!isInterestingMethodCall(memberCall->getMethodDecl(), /*by-ref*/methodName, is_char_array, is_byte_array)) return; fixits = fixMethodCallCall(memberCall); } else { return; } if (operatorCall || memberCall) { if (is_char_array) { message = "QString::" + methodName + "(const char *) being called"; } else { message = "QString::" + methodName + "(QByteArray) being called"; } } emitWarning(stm->getLocStart(), message, fixits); }
void IsEmptyVSCount::VisitStmt(clang::Stmt *stmt) { ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(stmt); if (!cast || cast->getCastKind() != clang::CK_IntegralToBoolean) return; CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(*(cast->child_begin())); CXXMethodDecl *method = memberCall ? memberCall->getMethodDecl() : nullptr; if (!StringUtils::functionIsOneOf(method, {"size", "count", "length"})) return; if (!StringUtils::classIsOneOf(method->getParent(), QtUtils::qtContainers())) return; emitWarning(stmt->getLocStart(), "use isEmpty() instead"); }
// Catches cases like: s.append(s2.mid(1, 1)); bool StringRefCandidates::processCase2(CallExpr *call) { CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(call); CXXOperatorCallExpr *operatorCall = dyn_cast<CXXOperatorCallExpr>(call); CXXMethodDecl *method = nullptr; if (memberCall) { method = memberCall->getMethodDecl(); } else if (operatorCall && operatorCall->getCalleeDecl()) { Decl *decl = operatorCall->getCalleeDecl(); method = dyn_cast<CXXMethodDecl>(decl); } if (!isMethodReceivingQStringRef(method)) return false; Expr *firstArgument = call->getNumArgs() > 0 ? call->getArg(0) : nullptr; MaterializeTemporaryExpr *temp = firstArgument ? dyn_cast<MaterializeTemporaryExpr>(firstArgument) : nullptr; if (!temp) { Expr *secondArgument = call->getNumArgs() > 1 ? call->getArg(1) : nullptr; temp = secondArgument ? dyn_cast<MaterializeTemporaryExpr>(secondArgument) : nullptr; if (!temp) // For the CXXOperatorCallExpr it's in the second argument return false; } CallExpr *innerCall = HierarchyUtils::getFirstChildOfType2<CallExpr>(temp); CXXMemberCallExpr *innerMemberCall = innerCall ? dyn_cast<CXXMemberCallExpr>(innerCall) : nullptr; if (!innerMemberCall) return false; CXXMethodDecl *innerMethod = innerMemberCall->getMethodDecl(); if (!isInterestingFirstMethod(innerMethod)) return false; std::vector<FixItHint> fixits; if (isFixitEnabled(FixitUseQStringRef)) { fixits = fixit(innerMemberCall); } emitWarning(call->getLocStart(), "Use " + innerMethod->getNameAsString() + "Ref() instead", fixits); return true; }
void TransferFunctions::Visit(Stmt *S) { if (observer) observer->observeStmt(S, currentBlock, val); StmtVisitor<TransferFunctions>::Visit(S); if (isa<Expr>(S)) { val.liveStmts = LV.SSetFact.remove(val.liveStmts, S); } // Mark all children expressions live. switch (S->getStmtClass()) { default: break; case Stmt::StmtExprClass: { // For statement expressions, look through the compound statement. S = cast<StmtExpr>(S)->getSubStmt(); break; } case Stmt::CXXMemberCallExprClass: { // Include the implicit "this" pointer as being live. CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S); if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) { AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj); } break; } case Stmt::ObjCMessageExprClass: { // In calls to super, include the implicit "self" pointer as being live. ObjCMessageExpr *CE = cast<ObjCMessageExpr>(S); if (CE->getReceiverKind() == ObjCMessageExpr::SuperInstance) val.liveDecls = LV.DSetFact.add(val.liveDecls, LV.analysisContext.getSelfDecl()); break; } case Stmt::DeclStmtClass: { const DeclStmt *DS = cast<DeclStmt>(S); if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) { for (const VariableArrayType* VA = FindVA(VD->getType()); VA != nullptr; VA = FindVA(VA->getElementType())) { AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr()); } } break; } case Stmt::PseudoObjectExprClass: { // A pseudo-object operation only directly consumes its result // expression. Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr(); if (!child) return; if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child)) child = OV->getSourceExpr(); child = child->IgnoreParens(); val.liveStmts = LV.SSetFact.add(val.liveStmts, child); return; } // FIXME: These cases eventually shouldn't be needed. case Stmt::ExprWithCleanupsClass: { S = cast<ExprWithCleanups>(S)->getSubExpr(); break; } case Stmt::CXXBindTemporaryExprClass: { S = cast<CXXBindTemporaryExpr>(S)->getSubExpr(); break; } case Stmt::UnaryExprOrTypeTraitExprClass: { // No need to unconditionally visit subexpressions. return; } } for (Stmt *Child : S->children()) { if (Child) AddLiveStmt(val.liveStmts, LV.SSetFact, Child); } }
/* 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; } } } }
bool TransferFunctions::checkImageAccess(Expr *E, MemoryAccess curMemAcc) { // discard implicit casts and paren expressions E = E->IgnoreParenImpCasts(); // match Image(), Accessor(), Mask(), and Domain() calls if (isa<CXXOperatorCallExpr>(E)) { CXXOperatorCallExpr *COCE = dyn_cast<CXXOperatorCallExpr>(E); if (isa<MemberExpr>(COCE->getArg(0))) { MemberExpr *ME = dyn_cast<MemberExpr>(COCE->getArg(0)); if (isa<FieldDecl>(ME->getMemberDecl())) { FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); MemoryAccess memAcc = KS.imagesToAccess[FD]; MemoryAccessDetail memAccDetail = KS.imagesToAccessDetail[FD]; memAcc = (MemoryAccess) (memAcc|curMemAcc); KS.imagesToAccess[FD] = memAcc; // access to Image if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(), KS.compilerClasses.Image)) { KS.Diags.Report(E->getLocStart(), KS.DiagIDImageAccess) << FD->getNameAsString(); exit(EXIT_FAILURE); } // access to Accessor if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(), KS.compilerClasses.Accessor)) { if (curMemAcc & READ_ONLY) KS.num_img_loads++; if (curMemAcc & WRITE_ONLY) KS.num_img_stores++; switch (COCE->getNumArgs()) { default: break; case 1: memAccDetail = (MemoryAccessDetail) (memAccDetail|NO_STRIDE); if (KS.kernelType < PointOperator) KS.kernelType = PointOperator; break; case 2: // TODO: check for Mask or Domain as parameter and check if we // need only STRIDE_X or STRIDE_Y memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY); if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator; break; case 3: memAccDetail = (MemoryAccessDetail) (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2))); if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) { KS.kernelType = LocalOperator; } break; } KS.imagesToAccessDetail[FD] = memAccDetail; return true; } // access to Mask if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(), KS.compilerClasses.Mask)) { if (curMemAcc & READ_ONLY) KS.num_mask_loads++; if (curMemAcc & WRITE_ONLY) KS.num_mask_stores++; if (KS.inLambdaFunction) { // TODO: check for Mask as parameter and check if we need only // STRIDE_X or STRIDE_Y memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY); if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator; } else { assert(COCE->getNumArgs()==3 && "Mask access requires x and y parameters!"); memAccDetail = (MemoryAccessDetail) (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2))); if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) { KS.kernelType = LocalOperator; } } KS.imagesToAccessDetail[FD] = memAccDetail; return false; } // access to Domain if (KS.compilerClasses.isTypeOfClass(FD->getType(), KS.compilerClasses.Domain)) { if (curMemAcc & READ_ONLY) KS.num_mask_loads++; if (curMemAcc & WRITE_ONLY) KS.num_mask_stores++; if (KS.inLambdaFunction) { // TODO: check for Domain as parameter and check if we need only // STRIDE_X or STRIDE_Y memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY); if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator; } else { assert(COCE->getNumArgs()==3 && "Domain access requires x and y parameters!"); memAccDetail = (MemoryAccessDetail) (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2))); if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) { KS.kernelType = LocalOperator; } } KS.imagesToAccessDetail[FD] = memAccDetail; return false; } } } } // match Image->getPixel(), output(), and outputAtPixel() calls if (isa<CXXMemberCallExpr>(E)) { CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(E); if (isa<MemberExpr>(CMCE->getCallee())) { MemberExpr *ME = dyn_cast<MemberExpr>(CMCE->getCallee()); if (isa<MemberExpr>(ME->getBase())) { MemberExpr *MEAcc = dyn_cast<MemberExpr>(ME->getBase()); if (isa<FieldDecl>(MEAcc->getMemberDecl())) { FieldDecl *FD = dyn_cast<FieldDecl>(MEAcc->getMemberDecl()); // Image if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(), KS.compilerClasses.Image)) { KS.Diags.Report(E->getLocStart(), KS.DiagIDImageAccess) << FD->getNameAsString(); exit(EXIT_FAILURE); } // Accessor if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(), KS.compilerClasses.Accessor)) { // Accessor->getPixel() if (ME->getMemberNameInfo().getAsString()=="getPixel") { MemoryAccess memAcc = KS.imagesToAccess[FD]; MemoryAccessDetail memAccDetail = KS.imagesToAccessDetail[FD]; memAcc = (MemoryAccess) (memAcc|curMemAcc); KS.imagesToAccess[FD] = memAcc; memAccDetail = (MemoryAccessDetail) (memAccDetail|USER_XY); KS.imagesToAccessDetail[FD] = memAccDetail; KS.kernelType = UserOperator; if (curMemAcc & READ_ONLY) KS.num_img_loads++; if (curMemAcc & WRITE_ONLY) KS.num_img_stores++; return true; } } } } // output() if (ME->getMemberNameInfo().getAsString()=="output") { if (curMemAcc & READ_ONLY) KS.num_img_loads++; if (curMemAcc & WRITE_ONLY) KS.num_img_stores++; MemoryAccessDetail cur = KS.outputAccessDetail; KS.outputAccessDetail = (MemoryAccessDetail)(cur|NO_STRIDE); if (KS.kernelType < PointOperator) KS.kernelType = PointOperator; return true; } // outputAtPixel() if (ME->getMemberNameInfo().getAsString()=="outputAtPixel") { if (curMemAcc & READ_ONLY) KS.num_img_loads++; if (curMemAcc & WRITE_ONLY) KS.num_img_stores++; MemoryAccessDetail cur = KS.outputAccessDetail; KS.outputAccessDetail = (MemoryAccessDetail)(cur|USER_XY); KS.kernelType = UserOperator; return true; } } } return false; }