diff --git a/hpvm/projects/hetero-c++/include/HCCVerifier.h b/hpvm/projects/hetero-c++/include/HCCVerifier.h index 899a1623b8e19bd7d876a0122e2acf7a90678294..92a7baf41ac511d4d408cf0a4b10f6ddd2d02b97 100644 --- a/hpvm/projects/hetero-c++/include/HCCVerifier.h +++ b/hpvm/projects/hetero-c++/include/HCCVerifier.h @@ -95,7 +95,9 @@ private: void verifyNesting(); bool verifyUses(RegionTree& region, std::set<Value*> inputs, std::set<Value*>* outerInputs); + bool isLoopCondition(RegionTree const& region, Instruction* instr); + bool allUsesLoopCondition(RegionTree const& region, Instruction* instr); }; } diff --git a/hpvm/projects/hetero-c++/lib/HCCVerifier.cpp b/hpvm/projects/hetero-c++/lib/HCCVerifier.cpp index 12c761d587e3754ee603afce736aa5f41e0b9a91..0e4cd756b3853e43f26c82bcb474c6b37a36f89b 100644 --- a/hpvm/projects/hetero-c++/lib/HCCVerifier.cpp +++ b/hpvm/projects/hetero-c++/lib/HCCVerifier.cpp @@ -477,6 +477,24 @@ bool HCCVerifier::isLoopCondition(RegionTree const& region, Instruction* instr) return false; } +bool HCCVerifier::allUsesLoopCondition(RegionTree const& region, Instruction* instr) { + // Don't handle phi's since they can lead to infinite recursion of this + // analysis (since they can depend on themselves or otherwise have circular + // dependences + if (dyn_cast<PHINode>(instr)) return false; + + bool hasUse = false; // Handles branches which don't have uses + for (User* user : instr->users()) { + hasUse = true; + Instruction* useInst = dyn_cast<Instruction>(user); + if (!useInst) return false; + if (!isLoopCondition(region, useInst) + && !allUsesLoopCondition(region, useInst)) + return false; + } + return hasUse; +} + // Verifies that a well-nested region does not use any values it is not allowed // to access (so does not use arguments not included in the region) and // identifies uses of values calculated outside of the region and verifies that @@ -521,7 +539,8 @@ bool HCCVerifier::verifyUses(RegionTree& region, std::set<Value*> inputs, // Instructions that control loop execution iterations are allowed to // access values that are accessible to the outer region bool isLoopCond = region.type == RegionTree::Loop - && isLoopCondition(region, current); + && (isLoopCondition(region, current) + || allUsesLoopCondition(region, current)); // Valid operands are in the list of inputs, instructions dominated by // the start of the region, a Constant, or a BasicBlock @@ -533,7 +552,8 @@ bool HCCVerifier::verifyUses(RegionTree& region, std::set<Value*> inputs, BasicBlock* block = dyn_cast<BasicBlock>(op); MetadataAsValue* meta = dyn_cast<MetadataAsValue>(op); - if (const_ || (inst && DTCache.dominates(region.start, inst)) + if (const_ || (inst && (inst == region.start + || DTCache.dominates(region.start, inst))) || block || meta) { continue; } else if (inst && !inst->mayHaveSideEffects() @@ -673,7 +693,15 @@ bool HCCVerifier::verifyUses(RegionTree& region, std::set<Value*> inputs, } bool extraInstructions = false; + std::set<BasicBlock*> reached; + std::set<BasicBlock*> toSearch; while (current != end) { + reached.insert(current->getParent()); + auto f = toSearch.find(current->getParent()); + if (f != toSearch.end()) { + toSearch.erase(f); + } + if (current == region.marker) { current = current->getNextNonDebugInstruction(); } else { @@ -689,7 +717,36 @@ bool HCCVerifier::verifyUses(RegionTree& region, std::set<Value*> inputs, current); extraInstructions = true; } - current = next; + if (next) { + current = next; + } else { + BranchInst* branch = dyn_cast<BranchInst>(current); + if (!branch) { + errors = true; + reportErrorOnInst("Encountered non-branch terminator in " + "marked region", current); + extraInstructions = true; + } else { + // Add the basic blocks we can reach from this branch to the + // list to explore (if we haven't already). We also don't add + // back-edges since they should already have been processed + // (and if not, only because we skipped over the body because + // it was a parallel loop) + for (BasicBlock* succ : branch->successors()) { + if (reached.find(succ) == reached.end() + && (succ != branch->getParent() + && !DTCache.dominates(succ, branch->getParent()))) { + toSearch.insert(succ); + } + } + // And then pick some unprocessed basic block to process + assert(!toSearch.empty() + && "Cannot explore further but have not located region end"); + BasicBlock* bb = *(toSearch.begin()); + toSearch.erase(toSearch.begin()); + current = getFirstNonDebug(bb); + } + } } } } @@ -737,14 +794,18 @@ void HCCVerifier::verifyNesting() { for (auto it : loops) { Loop* loop = std::get<0>(it); BasicBlock* preheader = loop->getLoopPreheader(); - BasicBlock* pred = preheader->getSinglePredecessor(); - if (!pred) { - errors = true; - reportErrorOnInst("Parallel loop is only allowed one predecessor", - std::get<2>(it)); - continue; + + // Beginning of this region is the first instruction in the pre-header + // that isn' the marker for some other HeteroC++ region + Instruction* begins = preheader->getFirstNonPHIOrDbg(); + while (!begins->isTerminator()) { + CallInst* call = dyn_cast<CallInst>(begins); + if (!call) break; + if (markerFunctions.find(call->getCalledFunction()) + != markerFunctions.end()) { + begins = begins->getNextNonDebugInstruction(); + } } - Instruction* begins = pred->getTerminator(); if (!loop->getExitingBlock() || !std::get<1>(it)->getExitingBlock()) { errors = true; @@ -753,12 +814,7 @@ void HCCVerifier::verifyNesting() { continue; } - Instruction* ends = getFirstNonDebug(loop->getExitBlock()); - BranchInst* branch; - while ((branch = dyn_cast<BranchInst>(ends)) - && branch->isUnconditional()) { - ends = getFirstNonDebug(branch->getSuccessor(0)); - } + Instruction* ends = loop->getExitingBlock()->getTerminator(); allRegions.push_back(std::make_tuple(begins, ends, std::get<2>(it))); } diff --git a/hpvm/projects/hetero-c++/lib/HPVMExtractTask.cpp b/hpvm/projects/hetero-c++/lib/HPVMExtractTask.cpp index 11d4a1a8caf58a53feceda5c29261e1db6eaf9f0..b0640c0036b40b6c4036578a8e47facc0aec2683 100644 --- a/hpvm/projects/hetero-c++/lib/HPVMExtractTask.cpp +++ b/hpvm/projects/hetero-c++/lib/HPVMExtractTask.cpp @@ -3591,6 +3591,10 @@ void HPVMProgram::removeParallelLoopGuard(BasicBlock* Preheader, BasicBlock* Dir if(GuardBB){ BranchInst* Br = dyn_cast<BranchInst>(GuardBB->getTerminator()); + if(Br->isUnconditional()){ + return; + } + BasicBlock* LeftSucc = Br->getSuccessor(0); BasicBlock* RightSucc = Br->getSuccessor(1); diff --git a/hpvm/projects/hetero-c++/test/integration/src/all_const.cc b/hpvm/projects/hetero-c++/test/integration/src/all_const.cc new file mode 100644 index 0000000000000000000000000000000000000000..34f6cc1d83f7055ecfa751e031788f40d7416dc8 --- /dev/null +++ b/hpvm/projects/hetero-c++/test/integration/src/all_const.cc @@ -0,0 +1,35 @@ +#include "heterocc.h" + +void root(int* A, size_t sizeA, int* B, size_t sizeB) { + auto s = __hetero_section_begin(); + + for (int i = 0; i < 10; i++) { + __hetero_parallel_loop(1, 1, A, sizeA, 1, A, sizeA); + A[i] = i * i; + } + + for (int i = 0; i < 15; i++) { + __hetero_parallel_loop(1, 2, A, sizeA, B, sizeB, 1, B, sizeB); + B[i] = i + A[i]; + } + + __hetero_section_end(s); +} + +int main() { + int* A = new int[15]; + for (int i = 0; i < 15; i++) A[i] = i; + + int* B = new int[15]; + + size_t sizeA = sizeof(int) * 15; + size_t sizeB = sizeof(int) * 15; + + auto l = __hetero_launch((void*)root, 2, A, sizeA, B, sizeB, 2, A, sizeA, B, sizeB); + __hetero_wait(l); + + delete [] A; + delete [] B; + + return 0; +} diff --git a/hpvm/projects/hetero-c++/test/integration/src/mixed_const.cc b/hpvm/projects/hetero-c++/test/integration/src/mixed_const.cc new file mode 100644 index 0000000000000000000000000000000000000000..9457bc2cd6d8066427b840aee5d748e472537cb8 --- /dev/null +++ b/hpvm/projects/hetero-c++/test/integration/src/mixed_const.cc @@ -0,0 +1,37 @@ +#include "heterocc.h" + +void root(int* A, size_t sizeA, int n, int* B, size_t sizeB) { + auto s = __hetero_section_begin(); + + for (int i = 0; i < n; i++) { + __hetero_parallel_loop(1, 1, A, sizeA, 1, A, sizeA); + A[i] = i * i; + } + + for (int i = 0; i < 15; i++) { + __hetero_parallel_loop(1, 2, A, sizeA, B, sizeB, 1, B, sizeB); + B[i] = i + A[i]; + } + + __hetero_section_end(s); +} + +int main() { + int* A = new int[15]; + for (int i = 0; i < 15; i++) A[i] = i; + + int* B = new int[15]; + + size_t sizeA = sizeof(int) * 15; + size_t sizeB = sizeof(int) * 15; + + int n = 15; + + auto l = __hetero_launch((void*)root, 3, A, sizeA, n, B, sizeB, 2, A, sizeA, B, sizeB); + __hetero_wait(l); + + delete [] A; + delete [] B; + + return 0; +} diff --git a/hpvm/projects/hetero-c++/test/integration/src/simple_const.cc b/hpvm/projects/hetero-c++/test/integration/src/simple_const.cc new file mode 100644 index 0000000000000000000000000000000000000000..5d4750c431075832c4d08dcba17932a5ff08f9c2 --- /dev/null +++ b/hpvm/projects/hetero-c++/test/integration/src/simple_const.cc @@ -0,0 +1,32 @@ +#include "heterocc.h" + +void root(int* A, size_t sizeA, int n, int* B, size_t sizeB) { + auto s = __hetero_section_begin(); + + for (int i = 0; i < 15; i++) { + __hetero_parallel_loop(1, 2, A, sizeA, B, sizeB, 1, B, sizeB); + B[i] = i + A[i]; + } + + __hetero_section_end(s); +} + +int main() { + int* A = new int[15]; + for (int i = 0; i < 15; i++) A[i] = i; + + int* B = new int[15]; + + size_t sizeA = sizeof(int) * 15; + size_t sizeB = sizeof(int) * 15; + + int n = 15; + + auto l = __hetero_launch((void*)root, 3, A, sizeA, n, B, sizeB, 2, A, sizeA, B, sizeB); + __hetero_wait(l); + + delete [] A; + delete [] B; + + return 0; +}