diff --git a/DiscoPoP/DiscoPoP.hpp b/DiscoPoP/DiscoPoP.hpp index 1d846147e..d79438360 100644 --- a/DiscoPoP/DiscoPoP.hpp +++ b/DiscoPoP/DiscoPoP.hpp @@ -71,14 +71,14 @@ #define DP_DEBUG false #define ClCheckLoopPar true -#define DumpToDot true +#define DumpToDot false #define DP_BRANCH_TRACKING \ true // toggles the creation of instrumentation calls for tracking taken // branches. Required by the graph pruning step of the DiscoPoP // optimizer. #define DP_DEBUG false #define DP_VERBOSE false // prints warning messages -#define DP_hybrid_DEBUG true +#define DP_hybrid_DEBUG false using namespace llvm; using namespace std; @@ -137,10 +137,10 @@ class DiscoPoP : public ModulePass { Type *pointsToStruct(PointerType *PTy); - Value *determineVariableName_dynamic(Instruction *const I); + Value *determineVariableName_dynamic(Instruction *const I, string prefix); string determineVariableName_static(Instruction *I, bool &isGlobalVariable /*=defaultIsGlobalVariableValue*/, - bool disable_MetadataMap); + bool disable_MetadataMap, string prefix); void getTrueVarNamesFromMetadata(Region *TopRegion, Node *root, std::map *trueVarNamesFromMetadataMap); diff --git a/DiscoPoP/instrumentation/low_level/instrumentAlloca.cpp b/DiscoPoP/instrumentation/low_level/instrumentAlloca.cpp index 407160a42..675251782 100644 --- a/DiscoPoP/instrumentation/low_level/instrumentAlloca.cpp +++ b/DiscoPoP/instrumentation/low_level/instrumentAlloca.cpp @@ -24,7 +24,7 @@ void DiscoPoP::instrumentAlloca(AllocaInst *toInstrument) { vector args; args.push_back(ConstantInt::get(Int32, lid)); - args.push_back(determineVariableName_dynamic(toInstrument)); + args.push_back(determineVariableName_dynamic(toInstrument, "")); bool isGlobal; // Value *startAddr = PtrToIntInst::CreatePointerCast(toInstrument, Int64, "", diff --git a/DiscoPoP/instrumentation/low_level/instrumentLoad.cpp b/DiscoPoP/instrumentation/low_level/instrumentLoad.cpp index 511f92d03..2c97b5b5b 100644 --- a/DiscoPoP/instrumentation/low_level/instrumentLoad.cpp +++ b/DiscoPoP/instrumentation/low_level/instrumentLoad.cpp @@ -25,7 +25,7 @@ void DiscoPoP::instrumentLoad(LoadInst *toInstrument) { Value *memAddr = PtrToIntInst::CreatePointerCast(toInstrument->getPointerOperand(), Int64, "", toInstrument); args.push_back(memAddr); - args.push_back(determineVariableName_dynamic(toInstrument)); + args.push_back(determineVariableName_dynamic(toInstrument, "")); #ifdef SKIP_DUP_INSTR Twine name = Twine("L").concat(Twine(uniqueNum)); diff --git a/DiscoPoP/instrumentation/low_level/instrumentStore.cpp b/DiscoPoP/instrumentation/low_level/instrumentStore.cpp index daf3afe74..b09db4326 100644 --- a/DiscoPoP/instrumentation/low_level/instrumentStore.cpp +++ b/DiscoPoP/instrumentation/low_level/instrumentStore.cpp @@ -24,7 +24,7 @@ void DiscoPoP::instrumentStore(StoreInst *toInstrument) { Value *memAddr = PtrToIntInst::CreatePointerCast(toInstrument->getPointerOperand(), Int64, "", toInstrument); args.push_back(memAddr); - args.push_back(determineVariableName_dynamic(toInstrument)); + args.push_back(determineVariableName_dynamic(toInstrument, "")); #ifdef SKIP_DUP_INSTR Twine name = Twine("S").concat(Twine(uniqueNum)); diff --git a/DiscoPoP/llvm_hooks/runOnFunction.cpp b/DiscoPoP/llvm_hooks/runOnFunction.cpp index 97283df47..f85dd0c88 100644 --- a/DiscoPoP/llvm_hooks/runOnFunction.cpp +++ b/DiscoPoP/llvm_hooks/runOnFunction.cpp @@ -283,9 +283,6 @@ bool DiscoPoP::runOnFunction(Function &F) { if(DG.edgeIsINIT(edge)){ string initLine = DG.getInitEdgeInstructionLine(edge); string varIdentifier = DG.getValueNameAndMemRegIDFromEdge(edge, staticValueNameToMemRegIDMap); - std::cout << "Found init: " << DG.edgeToDPDep(edge, staticValueNameToMemRegIDMap) << "\n"; - std::cout << "\t@ " << initLine << "\n"; - std::cout << "\tvar: " << varIdentifier << "\n"; if(lineToInitializedVarsMap.find(initLine) == lineToInitializedVarsMap.end()){ set tmp; @@ -310,52 +307,26 @@ bool DiscoPoP::runOnFunction(Function &F) { if (!conditionalBBDepMap.count(Src->getParent())) { set tmp; conditionalBBDepMap[Src->getParent()] = tmp; - - std::cout<< "Registered set1: \n"; - for(auto s : tmp){ - std::cout << "--> " << s << "\n"; - } } conditionalBBDepMap[Src->getParent()].insert(DG.edgeToDPDep(edge, staticValueNameToMemRegIDMap)); - std::cout << "Inserted1: " << DG.edgeToDPDep(edge, staticValueNameToMemRegIDMap) << "\n"; } else { if (!conditionalBBPairDepMap.count(Dst->getParent())) { map> tmp; conditionalBBPairDepMap[Dst->getParent()] = tmp; - std::cout<< "Registered set2: \n"; - for(auto pair : tmp){ - for(auto s : pair.second){ - std::cout << "--> " << s << "\n"; - } - } } if (!conditionalBBPairDepMap[Dst->getParent()].count(Src->getParent())) { set tmp; conditionalBBPairDepMap[Dst->getParent()][Src->getParent()] = tmp; - std::cout<< "Registered set3: \n"; - for(auto s : tmp){ - std::cout << "--> " << s << "\n"; - } } - std::cout << "First: " << Dst << "\n"; - Dst->print(outs()); - std::cout << "\n"; - std::cout << "Second: " << Src << "\n"; - Src->print(outs()); - std::cout << "\n"; // Prevent reporting of false-positive WAW Dependencies due to alloca movement from e.g. loops to function entry bool insertDep = true; if(Dst == Src){ // check if instruciton are the same - std::cout << "==> Potential for false-positive WAW\n"; - std::cout << "--> same inst\n"; // check if initialization exists in the instruction line if(lineToInitializedVarsMap.find(DG.getInstructionLine(Dst)) != lineToInitializedVarsMap.end()){ - std::cout << "--> same init exists\n"; // check if the accessed variable is initialed here string varIdentifier = DG.getValueNameAndMemRegIDFromEdge(edge, staticValueNameToMemRegIDMap); if(lineToInitializedVarsMap[DG.getInstructionLine(Dst)].find(varIdentifier) != lineToInitializedVarsMap[DG.getInstructionLine(Dst)].end()){ // ignore this access as the initialized variable is accessed - std::cout << "==> initialized var accessed\n"; insertDep = false; } } @@ -364,7 +335,6 @@ bool DiscoPoP::runOnFunction(Function &F) { if(insertDep){ conditionalBBPairDepMap[Dst->getParent()][Src->getParent()].insert( DG.edgeToDPDep(edge, staticValueNameToMemRegIDMap)); - std::cout << "Inserted: " << DG.edgeToDPDep(edge, staticValueNameToMemRegIDMap) << "\n"; } } omittableInstructions.insert(Src); diff --git a/DiscoPoP/static_analysis/createCUs.cpp b/DiscoPoP/static_analysis/createCUs.cpp index 43bbe981b..3f972fc5f 100644 --- a/DiscoPoP/static_analysis/createCUs.cpp +++ b/DiscoPoP/static_analysis/createCUs.cpp @@ -152,7 +152,7 @@ void DiscoPoP::createCUs(Region *TopRegion, set &globalVariablesSet, vec Type *Ty = operand->getType(); unsigned u = DL->getTypeSizeInBits(Ty); cu->writeDataSize += u; - varName = determineVariableName_static(&*instruction, isGlobalVar, false); + varName = determineVariableName_static(&*instruction, isGlobalVar, false, ""); varType = determineVariableType(&*instruction); suspiciousVariables.insert(varName); if (lid > 0) @@ -162,7 +162,7 @@ void DiscoPoP::createCUs(Region *TopRegion, set &globalVariablesSet, vec Type *Ty = instruction->getType(); unsigned u = DL->getTypeSizeInBits(Ty); cu->readDataSize += u; - varName = determineVariableName_static(&*instruction, isGlobalVar, false); + varName = determineVariableName_static(&*instruction, isGlobalVar, false, ""); if (suspiciousVariables.count(varName)) { // VIOLATION OF CAUTIOUS PROPERTY // it is a load instruction which read the value of a global diff --git a/DiscoPoP/static_analysis/fillCUVariables.cpp b/DiscoPoP/static_analysis/fillCUVariables.cpp index 3afa00781..dd128660a 100644 --- a/DiscoPoP/static_analysis/fillCUVariables.cpp +++ b/DiscoPoP/static_analysis/fillCUVariables.cpp @@ -41,7 +41,7 @@ void DiscoPoP::fillCUVariables(Region *TopRegion, set &globalVariablesSe if (lid == 0) continue; // NOTE: changed 'instruction' to '&*instruction', next 2 lines - varName = determineVariableName_static(&*instruction, isGlobalVar, false); + varName = determineVariableName_static(&*instruction, isGlobalVar, false, ""); varType = determineVariableType(&*instruction); int index = isa(&*instruction) ? 1 : 0; diff --git a/DiscoPoP/static_analysis/populateGlobalVariablesSet.cpp b/DiscoPoP/static_analysis/populateGlobalVariablesSet.cpp index 9af29c78e..1dfe9bc44 100644 --- a/DiscoPoP/static_analysis/populateGlobalVariablesSet.cpp +++ b/DiscoPoP/static_analysis/populateGlobalVariablesSet.cpp @@ -23,7 +23,7 @@ void DiscoPoP::populateGlobalVariablesSet(Region *TopRegion, set &global if (isa(instruction) || isa(instruction) || isa(instruction)) { // NOTE: changed 'instruction' to '&*instruction' - string varName = determineVariableName_static(&*instruction, isGlobalVariable, false); + string varName = determineVariableName_static(&*instruction, isGlobalVariable, false, ""); if (isGlobalVariable) // add it if it is a global variable in the // program diff --git a/DiscoPoP/utils/variables/defLine.cpp b/DiscoPoP/utils/variables/defLine.cpp index 308bebc0f..3cebc1c14 100644 --- a/DiscoPoP/utils/variables/defLine.cpp +++ b/DiscoPoP/utils/variables/defLine.cpp @@ -16,7 +16,7 @@ string DiscoPoP::determineVariableDefLine(Instruction *I) { string varDefLine{"LineNotFound"}; bool isGlobal = false; - string varName = determineVariableName_static(&*I, isGlobal, true); + string varName = determineVariableName_static(&*I, isGlobal, true, ""); // varName = refineVarName(varName); varName = (varName.find(".addr") == varName.npos) ? varName : varName.erase(varName.find(".addr"), 5); // varName.erase(varName.find(".addr"), 5); @@ -63,10 +63,10 @@ string DiscoPoP::determineVariableDefLine(Instruction *I) { if (AI) { for (User *U : AI->users()) { if (StoreInst *SI = dyn_cast(U)) { - vn = determineVariableName_static(&*SI, isGlobal, true); + vn = determineVariableName_static(&*SI, isGlobal, true, ""); break; } else if (LoadInst *LI = dyn_cast(U)) { - vn = determineVariableName_static(&*LI, isGlobal, true); + vn = determineVariableName_static(&*LI, isGlobal, true, ""); break; } } diff --git a/DiscoPoP/utils/variables/names.cpp b/DiscoPoP/utils/variables/names.cpp index 0d5886f65..e96ff7e0b 100644 --- a/DiscoPoP/utils/variables/names.cpp +++ b/DiscoPoP/utils/variables/names.cpp @@ -14,6 +14,11 @@ string DiscoPoP::getOrInsertVarName_static(string varName, IRBuilder<> &builder) { Value *valName = NULL; + // remove .addr if added. Replaced by the GEPRESULT_ tag + if (varName.find(".addr") != std::string::npos){ + varName.erase(varName.find(".addr"), 5); + } + std::string vName = varName; map::iterator pair = VarNames.find(varName); if (pair == VarNames.end()) { @@ -28,6 +33,11 @@ string DiscoPoP::getOrInsertVarName_static(string varName, IRBuilder<> &builder) } Value *DiscoPoP::getOrInsertVarName_dynamic(string varName, IRBuilder<> &builder) { + // remove .addr if added. Replaced by the GEPRESULT_ tag + if (varName.find(".addr") != std::string::npos){ + varName.erase(varName.find(".addr"), 5); + } + // 26.08.2022 Lukas // update varName with original varName from Metadata if (trueVarNamesFromMetadataMap.find(varName) == trueVarNamesFromMetadataMap.end()) { @@ -49,7 +59,7 @@ Value *DiscoPoP::getOrInsertVarName_dynamic(string varName, IRBuilder<> &builder } string DiscoPoP::determineVariableName_static(Instruction *I, bool &isGlobalVariable /*=defaultIsGlobalVariableValue*/, - bool disable_MetadataMap) { + bool disable_MetadataMap, string prefix) { assert(I && "Instruction cannot be NULL \n"); int index = isa(I) ? 1 : 0; @@ -120,9 +130,9 @@ string DiscoPoP::determineVariableName_static(Instruction *I, bool &isGlobalVari // we've found an array if (PTy->getPointerElementType()->getTypeID() == Type::ArrayTyID && isa(*ptrOperand)) { - return determineVariableName_static((Instruction *)ptrOperand, isGlobalVariable, false); + return determineVariableName_static((Instruction *)ptrOperand, isGlobalVariable, false, prefix); } - return determineVariableName_static((Instruction *)gep, isGlobalVariable, false); + return determineVariableName_static((Instruction *)gep, isGlobalVariable, false, "GEPRESULT_" + prefix); } string retVal = string(operand->getName().data()); if (trueVarNamesFromMetadataMap.find(retVal) == trueVarNamesFromMetadataMap.end() || disable_MetadataMap) { @@ -134,13 +144,13 @@ string DiscoPoP::determineVariableName_static(Instruction *I, bool &isGlobalVari } if (isa(*operand) || isa(*operand)) { - return determineVariableName_static((Instruction *)(operand), isGlobalVariable, false); + return determineVariableName_static((Instruction *)(operand), isGlobalVariable, false, prefix); } // if we cannot determine the name, then return * return ""; // getOrInsertVarName("*", builder); } -Value *DiscoPoP::determineVariableName_dynamic(Instruction *const I) { +Value *DiscoPoP::determineVariableName_dynamic(Instruction *const I, string prefix) { assert(I && "Instruction cannot be NULL \n"); int index = isa(I) ? 1 : 0; Value *operand = I->getOperand(index); @@ -156,7 +166,7 @@ Value *DiscoPoP::determineVariableName_dynamic(Instruction *const I) { if (isa(*operand)) { DIGlobalVariable *gv = findDbgGlobalDeclare(cast(operand)); if (gv != NULL) { - return getOrInsertVarName_dynamic(string(gv->getDisplayName().data()), builder); + return getOrInsertVarName_dynamic(prefix + string(gv->getDisplayName().data()), builder); } } if (isa(*operand)) { @@ -187,21 +197,21 @@ Value *DiscoPoP::determineVariableName_dynamic(Instruction *const I) { // we've found an array if (PTy->getPointerElementType()->getTypeID() == Type::ArrayTyID && isa(*ptrOperand)) { - return determineVariableName_dynamic((Instruction *)ptrOperand); + return determineVariableName_dynamic((Instruction *)ptrOperand, prefix); } - return determineVariableName_dynamic((Instruction *)gep); + return determineVariableName_dynamic((Instruction *)gep, "GEPRESULT_"+prefix); } - return getOrInsertVarName_dynamic(string(operand->getName().data()), builder); + return getOrInsertVarName_dynamic(prefix + string(operand->getName().data()), builder); } if (isa(*operand) || isa(*operand)) { - return determineVariableName_dynamic((Instruction *)(operand)); + return determineVariableName_dynamic((Instruction *)(operand), prefix); } if (isa(I)) { - return getOrInsertVarName_dynamic(I->getName().str(), builder); + return getOrInsertVarName_dynamic(prefix + I->getName().str(), builder); } // if we cannot determine the name, then return * - return getOrInsertVarName_dynamic("*", builder); + return getOrInsertVarName_dynamic(prefix + "*", builder); } void DiscoPoP::getTrueVarNamesFromMetadata(Region *TopRegion, Node *root, diff --git a/discopop_explorer/PEGraphX.py b/discopop_explorer/PEGraphX.py index 2b0bcfec3..d7840b6b2 100644 --- a/discopop_explorer/PEGraphX.py +++ b/discopop_explorer/PEGraphX.py @@ -738,6 +738,8 @@ def map_static_and_dynamic_dependencies(self) -> None: if d1.memory_region != d2.memory_region: if d1.memory_region is None or d2.memory_region is None: continue + if d1.memory_region.startswith("GEPRESULT_") or d2.memory_region.startswith("GEPRESULT_"): + continue if d1.memory_region not in mem_reg_mappings: mem_reg_mappings[d1.memory_region] = set() if d2.memory_region not in mem_reg_mappings: diff --git a/discopop_explorer/parser.py b/discopop_explorer/parser.py index 22d46c6e8..9b8b4ff26 100644 --- a/discopop_explorer/parser.py +++ b/discopop_explorer/parser.py @@ -33,6 +33,7 @@ class DependenceItem(object): type: Any var_name: Any memory_region: Any + is_gep_result_dependency: bool metadata: Any # TODO improve typing @@ -198,13 +199,24 @@ def __parse_dep_file(dep_fd: TextIOWrapper, output_path: str) -> Tuple[List[Depe key_tuple = sink, source_fields[0], type, var_name, aa_var_name if key_tuple in dependency_metadata: metadata = dependency_metadata[key_tuple] + + # check if the dependency originates from the result of a GEP instruction + is_gep_result_dependency = False + if var_name.startswith("GEPRESULT_"): + var_name = var_name.replace("GEPRESULT_", "") + is_gep_result_dependency = True + # register dependencies if len(metadata) == 0: - dependencies_list.append(DependenceItem(sink, source_fields[0], type, var_name, aa_var_name, "")) + dependencies_list.append( + DependenceItem(sink, source_fields[0], type, var_name, aa_var_name, is_gep_result_dependency, "") + ) else: for md_set in metadata: dependencies_list.append( - DependenceItem(sink, source_fields[0], type, var_name, aa_var_name, md_set) + DependenceItem( + sink, source_fields[0], type, var_name, aa_var_name, is_gep_result_dependency, md_set + ) ) return dependencies_list, loop_data_list diff --git a/discopop_explorer/pattern_detectors/reduction_detector.py b/discopop_explorer/pattern_detectors/reduction_detector.py index 3b4be08c9..12706cd5d 100644 --- a/discopop_explorer/pattern_detectors/reduction_detector.py +++ b/discopop_explorer/pattern_detectors/reduction_detector.py @@ -145,6 +145,7 @@ def __detect_reduction(pet: PEGraphX, root: LoopNode) -> bool: # and "**" not in v.type --> replaced by check for array reduction ] reduction_var_names = cast(List[str], [v.name for v in reduction_vars]) + fp, p, lp, s, r = classify_loop_variables(pet, root) # get parents of loop diff --git a/discopop_explorer/utils.py b/discopop_explorer/utils.py index 146aab72f..02e8ca60b 100644 --- a/discopop_explorer/utils.py +++ b/discopop_explorer/utils.py @@ -685,51 +685,100 @@ def classify_loop_variables( ) # vars = list(pet.get_variables(sub)) + metadata_safe_index_accesses: List[Variable] = [] for var in vars: - if is_loop_index2(pet, loop, var.name): - if is_read_in_subtree(vars[var], rev_raw, rst): - last_private.append(var) - else: - private.append(var) - elif loop.reduction and pet.is_reduction_var(loop.start_position(), var.name): - var.operation = pet.get_reduction_sign(loop.start_position(), var.name) - reduction.append(var) - elif is_written_in_subtree(vars[var], raw, waw, lst) or is_func_arg(pet, var.name, loop) and is_scalar_val(var): - if is_readonly(vars[var], war, waw, rev_raw): - if is_global(var.name, sub): - shared.append(var) - else: - first_private.append(var) - elif is_read_in_subtree(vars[var], rev_raw, rst): - if is_scalar_val(var): + if loop.start_position() == "1:281" and (var.name == "d" or var.name == "d2"): + pass + # separate pointer and pointee dependencies for separated clasification + # classifications will be merged before returning + non_gep_mem_regs = set([mr for mr in vars[var] if not mr.startswith("GEPRESULT_")]) + gep_mem_regs = set([mr for mr in vars[var] if mr.startswith("GEPRESULT_")]) + + for subset_idx, mem_reg_subset in enumerate([non_gep_mem_regs, gep_mem_regs]): + if subset_idx > 0 and len(mem_reg_subset) == 0: + continue + if is_loop_index2(pet, loop, var.name): + if is_read_in_subtree(mem_reg_subset, rev_raw, rst): last_private.append(var) else: - shared.append(var) - else: - if not is_scalar_val(var): - # array type variable is written - shared.append(var) - else: - if is_first_written(vars[var], raw, waw, sub): - private.append(var) + private.append(var) + elif loop.reduction and pet.is_reduction_var(loop.start_position(), var.name): + var.operation = pet.get_reduction_sign(loop.start_position(), var.name) + reduction.append(var) + elif ( + is_written_in_subtree(mem_reg_subset, raw, waw, lst) + or is_func_arg(pet, var.name, loop) + and is_scalar_val(var) + ): + if is_readonly(mem_reg_subset, war, waw, rev_raw): + if is_global(var.name, sub): + shared.append(var) else: first_private.append(var) - - elif is_first_written(vars[var], raw, war, sub): - if len(vars[var].intersection(initialized_memory_regions)) > 0: - # variable is initialized in loop. No data sharing clauses required. - pass - else: - if is_read_in_subtree(vars[var], rev_raw, rst): + elif is_read_in_subtree(mem_reg_subset, rev_raw, rst): if is_scalar_val(var): last_private.append(var) else: shared.append(var) else: - if is_scalar_val(var): + if not is_scalar_val(var): + # array type variable is written + shared.append(var) + else: + if is_first_written(mem_reg_subset, raw, waw, sub): + private.append(var) + else: + first_private.append(var) + + elif is_first_written(mem_reg_subset, raw, war, sub): + if len(mem_reg_subset.intersection(initialized_memory_regions)) > 0 and subset_idx < 1: + # subset_idx < 1 to ignore this check for gep memory regions, as they create additional INIT dependencies + # variable is initialized in loop. + + # No data sharing clauses required, if the variable is declared inside the loop. + if var_declared_in_subtree(var, sub): + pass + # Else, the variable requires a private clause + else: private.append(var) + else: + if is_read_in_subtree(mem_reg_subset, rev_raw, rst): + if is_scalar_val(var): + last_private.append(var) + else: + shared.append(var) else: - shared.append(var) + # do not distinguish between scalar and structure types + private.append(var) + # keep old code until above replacement is proven to work + # BEGIN: OLD CODE + # if is_scalar_val(var): + # private.append(var) + # else: + # shared.append(var) + # END: OLD CODE + if subset_idx >= 1 and no_inter_iteration_dependency_exists( + mem_reg_subset, raw, war, sub, cast(LoopNode, loop) + ): + # check if metadata suggests, that index accesses are not problematic wrt. parallelization + metadata_safe_index_accesses.append(var) + + if loop.start_position() == "1:281": + pass + # modify classifications + first_private, private, last_private, shared, reduction = __modify_classifications( + first_private, private, last_private, shared, reduction, metadata_safe_index_accesses + ) + + if loop.start_position() == "1:281": + pass + # merge classifications + first_private, private, last_private, shared, reduction = __merge_classifications( + first_private, private, last_private, shared, reduction + ) + + if loop.start_position() == "1:281": + pass # return first_private, private, last_private, shared, reduction return ( sorted(first_private), @@ -740,6 +789,98 @@ def classify_loop_variables( ) +def var_declared_in_subtree(var: Variable, sub: list[CUNode]) -> bool: + var_file_id = int(var.defLine.split(":")[0]) + var_def_line = int(var.defLine.split(":")[1]) + for node in sub: + if (node.file_id == var_file_id) and (node.start_line <= var_def_line) and (node.end_line >= var_def_line): + return True + return False + + +def no_inter_iteration_dependency_exists( + mem_regs: Set[MemoryRegion], + raw: Set[Tuple[NodeID, NodeID, Dependency]], + war: Set[Tuple[NodeID, NodeID, Dependency]], + sub: List[CUNode], + root_loop: LoopNode, +) -> bool: + + for dep in raw.union(war): + if dep[0] in [s.id for s in sub] and dep[1] in [s.id for s in sub]: + if dep[2].memory_region in mem_regs: + if root_loop.start_position() in dep[2].metadata_inter_iteration_dep: + return False + return True + + +def __modify_classifications( + first_private: list[Variable], + private: list[Variable], + last_private: list[Variable], + shared: list[Variable], + reduction: list[Variable], + metadata_safe_index_accesses: list[Variable], +) -> Tuple[list[Variable], list[Variable], list[Variable], list[Variable], list[Variable]]: + # Rule 1: if structure index accesses suggest, that parallelizing is safe without data sharing clauses, loosen private clauses to shared. + # --> this rule does not affect first_ and last_private clauses, as they require a specific access / dependency pattern + move_to_shared: List[Variable] = [] + for var in metadata_safe_index_accesses: + if var in private: + move_to_shared.append(var) + for var in move_to_shared: + if var in private: + private.remove(var) + if var not in shared: + shared.append(var) + + return first_private, private, last_private, shared, reduction + + +def __merge_classifications( + first_private: list[Variable], + private: list[Variable], + last_private: list[Variable], + shared: list[Variable], + reduction: list[Variable], +) -> Tuple[list[Variable], list[Variable], list[Variable], list[Variable], list[Variable]]: + new_first_private: list[Variable] = [] + new_private: list[Variable] = [] + new_last_private: list[Variable] = [] + new_shared: list[Variable] = [] + new_reduction: list[Variable] = reduction + + remove_from_private: Set[Variable] = set() + remove_from_first_private: Set[Variable] = set() + remove_from_last_private: Set[Variable] = set() + remove_from_shared: Set[Variable] = set() + remove_from_reduction: Set[Variable] = set() + + # Rule 1: firstprivate is more restrictive than private + for var_1 in first_private: + for var_2 in private: + if var_1.name == var_2.name: + remove_from_private.add(var_2) + # Rule 2: lastprivate is more restrictive than private + for var_1 in last_private: + for var_2 in private: + if var_1.name == var_2.name: + remove_from_private.add(var_2) + # Rule 3: shared is less restrictive than any private + for var_1 in first_private + last_private + private: + for var_2 in shared: + if var_1.name == var_2.name: + remove_from_shared.add(var_2) + + new_first_private = [v for v in first_private if v not in remove_from_first_private] + new_last_private = [v for v in last_private if v not in remove_from_last_private] + new_private = [v for v in private if v not in remove_from_private] + new_shared = [v for v in shared if v not in remove_from_shared] + new_reduction = [v for v in reduction if v not in remove_from_reduction] + + return new_first_private, new_private, new_last_private, new_shared, new_reduction + + def classify_task_vars( pet: PEGraphX, task: Node, diff --git a/test/end_to_end/reduction_pattern/negative/case_1/src/code.cpp b/test/end_to_end/reduction_pattern/negative/case_1/src/code.cpp index 35859565c..aef86e8a8 100644 --- a/test/end_to_end/reduction_pattern/negative/case_1/src/code.cpp +++ b/test/end_to_end/reduction_pattern/negative/case_1/src/code.cpp @@ -12,7 +12,7 @@ int g(int i) { return i; } int main() { int N = 100000; - int Arr[N]; + int Arr[100000]; // DOALL for (int i = 0; i < N; i++) { diff --git a/test/wip_end_to_end/sharing_clauses/do_all/private/__init__.py b/test/end_to_end/sharing_clauses/do_all/private/case_2/__init__.py similarity index 100% rename from test/wip_end_to_end/sharing_clauses/do_all/private/__init__.py rename to test/end_to_end/sharing_clauses/do_all/private/case_2/__init__.py diff --git a/test/wip_end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile b/test/end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile similarity index 79% rename from test/wip_end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile rename to test/end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile index 8b1635880..4bc2f0c44 100644 --- a/test/wip_end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile +++ b/test/end_to_end/sharing_clauses/do_all/private/case_2/src/Makefile @@ -4,6 +4,8 @@ prog: code.o $(CXX) -o prog code.o $(CXXFLAGS) code.o: + $(CXX) -c -S -emit-llvm -o code.ll code.cpp $(CXXFLAGS) + rm -r .discopop $(CXX) -c -o code.o code.cpp $(CXXFLAGS) clean: diff --git a/test/wip_end_to_end/sharing_clauses/do_all/private/case_2/src/code.cpp b/test/end_to_end/sharing_clauses/do_all/private/case_2/src/code.cpp similarity index 100% rename from test/wip_end_to_end/sharing_clauses/do_all/private/case_2/src/code.cpp rename to test/end_to_end/sharing_clauses/do_all/private/case_2/src/code.cpp diff --git a/test/wip_end_to_end/sharing_clauses/do_all/private/case_2/test.py b/test/end_to_end/sharing_clauses/do_all/private/case_2/test.py similarity index 100% rename from test/wip_end_to_end/sharing_clauses/do_all/private/case_2/test.py rename to test/end_to_end/sharing_clauses/do_all/private/case_2/test.py diff --git a/test/wip_end_to_end/sharing_clauses/do_all/private/case_2/__init__.py b/test/wip_end_to_end/reduction_pattern/__init__.py similarity index 100% rename from test/wip_end_to_end/sharing_clauses/do_all/private/case_2/__init__.py rename to test/wip_end_to_end/reduction_pattern/__init__.py diff --git a/test/wip_end_to_end/reduction_pattern/negative/__init__.py b/test/wip_end_to_end/reduction_pattern/negative/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test/wip_end_to_end/reduction_pattern/negative/case_2/__init__.py b/test/wip_end_to_end/reduction_pattern/negative/case_2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test/wip_end_to_end/reduction_pattern/negative/case_2/src/Makefile b/test/wip_end_to_end/reduction_pattern/negative/case_2/src/Makefile new file mode 100644 index 000000000..a64882be3 --- /dev/null +++ b/test/wip_end_to_end/reduction_pattern/negative/case_2/src/Makefile @@ -0,0 +1,17 @@ +all: clean prog + +prog: code.o + $(CXX) -o prog code.o $(CXXFLAGS) + +code.o: + $(CXX) -c -S -emit-llvm -o code.ll code.cpp $(CXXFLAGS) + rm -rf .discopop + $(CXX) -c -o code.o code.cpp $(CXXFLAGS) + +clean: + rm -rf .discopop + rm -rf src/.discopop + find . -not -name code.cpp -not -name Makefile -not -path **/FileMapping.txt -delete + +veryclean: clean + rm -f FileMapping.txt diff --git a/test/wip_end_to_end/reduction_pattern/negative/case_2/src/code.cpp b/test/wip_end_to_end/reduction_pattern/negative/case_2/src/code.cpp new file mode 100644 index 000000000..35859565c --- /dev/null +++ b/test/wip_end_to_end/reduction_pattern/negative/case_2/src/code.cpp @@ -0,0 +1,29 @@ +#include + +int f(int i) { + if (i < 100000 / 2) { + return i + 100000 / 2; + } else { + return i; + } +} + +int g(int i) { return i; } + +int main() { + int N = 100000; + int Arr[N]; + + // DOALL + for (int i = 0; i < N; i++) { + Arr[i] = 0; + } + + long w = 0; + + // NO REDUCTION, NO DOALL + for (int i = 0; i < N; i++) { + w += Arr[g(i)]; + Arr[f(i)] = 1; + } +} \ No newline at end of file diff --git a/test/wip_end_to_end/reduction_pattern/negative/case_2/test.py b/test/wip_end_to_end/reduction_pattern/negative/case_2/test.py new file mode 100644 index 000000000..102624dc2 --- /dev/null +++ b/test/wip_end_to_end/reduction_pattern/negative/case_2/test.py @@ -0,0 +1,85 @@ +import copy +import os +import pathlib +import unittest + +import jsonpickle + +from discopop_library.result_classes.DetectionResult import DetectionResult +from test.utils.existence.existence_utils import check_patterns_for_FN, check_patterns_for_FP +from test.utils.subprocess_wrapper.command_execution_wrapper import run_cmd +from test.utils.validator_classes.DoAllInfoForValidation import DoAllInfoForValidation +from discopop_library.ConfigProvider.config_provider import run as run_config_provider +from discopop_library.ConfigProvider.ConfigProviderArguments import ConfigProviderArguments + + +class TestMethods(unittest.TestCase): + @classmethod + def setUpClass(self): + current_dir = pathlib.Path(__file__).parent.resolve() + dp_build_dir = run_config_provider( + ConfigProviderArguments( + return_dp_build_dir=True, + return_dp_source_dir=False, + return_llvm_bin_dir=False, + return_full_config=False, + return_version_string=False, + ) + ) + + env_vars = dict(os.environ) + + src_dir = os.path.join(current_dir, "src") + + # create FileMapping + cmd = os.path.join(dp_build_dir, "scripts", "dp-fmap") + run_cmd(cmd, src_dir, env_vars) + + # build + env_vars["CC"] = os.path.join(dp_build_dir, "scripts", "CC_wrapper.sh") + env_vars["CXX"] = os.path.join(dp_build_dir, "scripts", "CXX_wrapper.sh") + env_vars["DP_PROJECT_ROOT_DIR"] = src_dir + cmd = "make" + run_cmd(cmd, src_dir, env_vars) + # execute instrumented program + cmd = "./prog" + run_cmd(cmd, src_dir, env_vars) + # execute DiscoPoP analysis + cwd = os.path.join(src_dir, ".discopop") + cmd = "discopop_explorer --enable-patterns doall,reduction" + run_cmd(cmd, cwd, env_vars) + + self.src_dir = src_dir + self.env_vars = env_vars + + test_output_file = os.path.join(self.src_dir, ".discopop", "explorer", "detection_result_dump.json") + # load detection results + with open(test_output_file, "r") as f: + tmp_str = f.read() + self.test_output: DetectionResult = jsonpickle.decode(tmp_str) + + @classmethod + def tearDownClass(self): + run_cmd("make veryclean", self.src_dir, self.env_vars) + + def test(self): + for pattern_type in self.test_output.patterns.__dict__: + amount_of_identified_patterns = len(self.test_output.patterns.__dict__[pattern_type]) + if pattern_type == "do_all": + expected_lines = ["1:18"] + with self.subTest("check for FP"): + res, msg = check_patterns_for_FP(self, pattern_type, copy.deepcopy(expected_lines), self.test_output.patterns.__dict__[pattern_type]) + self.assertTrue(res, msg) + with self.subTest("check for FN"): + res, msg = check_patterns_for_FN(self, pattern_type, copy.deepcopy(expected_lines), self.test_output.patterns.__dict__[pattern_type]) + self.assertTrue(res, msg) + elif pattern_type == "reduction": + expected_lines = [] + with self.subTest("check for FP"): + res, msg = check_patterns_for_FP(self, pattern_type, copy.deepcopy(expected_lines), self.test_output.patterns.__dict__[pattern_type]) + self.assertTrue(res, msg) + with self.subTest("check for FN"): + res, msg = check_patterns_for_FN(self, pattern_type, copy.deepcopy(expected_lines), self.test_output.patterns.__dict__[pattern_type]) + self.assertTrue(res, msg) + else: + self.assertEqual(amount_of_identified_patterns, 0)