diff --git a/.gitignore b/.gitignore index 9e92182f..3aae2fa1 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ build/* *.s *.pyc *.o +*.cache *.data *.exe *.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8b627b5..f61536ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(LLVMTDGPass MODULE stream/MemStream.cpp stream/StreamPass.cpp stream/StreamPrefetchPass.cpp + stream/ae/AddressDataGraph.cpp # CCA.cpp # StreamAnalyzeTrace.cpp ) diff --git a/src/LoopUtils.cpp b/src/LoopUtils.cpp index 6351cdeb..47f61815 100644 --- a/src/LoopUtils.cpp +++ b/src/LoopUtils.cpp @@ -106,6 +106,14 @@ std::string LoopUtils::formatLLVMInst(const llvm::Instruction *Inst) { } } +std::string LoopUtils::formatLLVMValue(const llvm::Value *Value) { + if (auto Inst = llvm::dyn_cast(Value)) { + return LoopUtils::formatLLVMInst(Inst); + } else { + return Value->getName(); + } +} + void LoopIterCounter::configure(llvm::Loop *_Loop) { this->Loop = _Loop; this->Iter = -1; diff --git a/src/LoopUtils.h b/src/LoopUtils.h index d556158a..0e92970a 100644 --- a/src/LoopUtils.h +++ b/src/LoopUtils.h @@ -55,6 +55,7 @@ class LoopUtils { * Print an static instruction. */ static std::string formatLLVMInst(const llvm::Instruction *Inst); + static std::string formatLLVMValue(const llvm::Value *Value); static const std::unordered_set SupportedMathFunctions; }; diff --git a/src/Utils.h b/src/Utils.h index 62075507..b09891c6 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -11,6 +11,17 @@ class Utils { return llvm::isa(Inst) || llvm::isa(Inst); } + static const llvm::Value *getMemAddrValue(const llvm::Instruction *Inst) { + assert( + Utils::isMemAccessInst(Inst) && + "This is not a memory access instruction to get memory address value."); + if (llvm::isa(Inst)) { + return Inst->getOperand(1); + } else { + return Inst->getOperand(0); + } + } + static uint64_t getMemAddr(const DynamicInstruction *DynamicInst) { auto StaticInst = DynamicInst->getStaticInstruction(); assert(Utils::isMemAccessInst(StaticInst) && diff --git a/src/stream/CMakeLists.txt b/src/stream/CMakeLists.txt index 1366aa3b..fca0884a 100644 --- a/src/stream/CMakeLists.txt +++ b/src/stream/CMakeLists.txt @@ -9,4 +9,6 @@ add_library(ProtobufStreamMessage OBJECT ) set_target_properties(ProtobufStreamMessage PROPERTIES COMPILE_FLAGS "-std=c++14 -O3 -fPIC -fno-rtti -DGOOGLE_PROTOBUF_NO_RTTI" -) \ No newline at end of file +) + +add_subdirectory(ae) \ No newline at end of file diff --git a/src/stream/InductionVarStream.h b/src/stream/InductionVarStream.h index 9d80d74e..92de18d4 100644 --- a/src/stream/InductionVarStream.h +++ b/src/stream/InductionVarStream.h @@ -8,10 +8,10 @@ class InductionVarStream : public Stream { public: InductionVarStream( const std::string &_Folder, const llvm::PHINode *_PHIInst, - const llvm::Loop *_Loop, size_t _Level, + const llvm::Loop *_Loop, const llvm::Loop *_InnerMostLoop, size_t _Level, std::unordered_set &&_ComputeInsts) - : Stream(TypeT::IV, _Folder, _PHIInst, _Loop, _Level), PHIInst(_PHIInst), - ComputeInsts(std::move(_ComputeInsts)) {} + : Stream(TypeT::IV, _Folder, _PHIInst, _Loop, _InnerMostLoop, _Level), + PHIInst(_PHIInst), ComputeInsts(std::move(_ComputeInsts)) {} InductionVarStream(const InductionVarStream &Other) = delete; InductionVarStream(InductionVarStream &&Other) = delete; @@ -47,7 +47,6 @@ class InductionVarStream : public Stream { const llvm::PHINode *PHINode, const std::unordered_set &ComputeInsts); - std::string format() const { std::stringstream ss; ss << "InductionVarStream " << LoopUtils::formatLLVMInst(this->PHIInst) diff --git a/src/stream/MemStream.cpp b/src/stream/MemStream.cpp index ef64f0aa..1ce38c20 100644 --- a/src/stream/MemStream.cpp +++ b/src/stream/MemStream.cpp @@ -1,7 +1,7 @@ #include "stream/MemStream.h" void MemStream::searchAddressComputeInstructions( - std::function IsInductionVar) { + std::function IsInductionVar) { std::list Queue; @@ -58,4 +58,12 @@ void MemStream::searchAddressComputeInstructions( } } } +} + +void MemStream::formatAdditionalInfoText(std::ostream &OStream) const { + this->AddrDG.format(OStream); +} + +void MemStream::generateComputeFunction(llvm::Module *Module) const { + this->AddrDG.generateComputeFunction(this->AddressFunctionName, Module); } \ No newline at end of file diff --git a/src/stream/MemStream.h b/src/stream/MemStream.h index c121bd2b..6374e4bd 100644 --- a/src/stream/MemStream.h +++ b/src/stream/MemStream.h @@ -3,15 +3,23 @@ #include "MemoryFootprint.h" #include "stream/Stream.h" +#include "stream/ae/AddressDataGraph.h" class MemStream : public Stream { public: MemStream(const std::string &_Folder, const llvm::Instruction *_Inst, - const llvm::Loop *_Loop, size_t _LoopLevel, - std::function IsInductionVar) - : Stream(TypeT::MEM, _Folder, _Inst, _Loop, _LoopLevel) { + const llvm::Loop *_Loop, const llvm::Loop *_InnerMostLoop, + size_t _LoopLevel, + std::function IsInductionVar) + : Stream(TypeT::MEM, _Folder, _Inst, _Loop, _InnerMostLoop, _LoopLevel), + AddrDG(_InnerMostLoop, Utils::getMemAddrValue(_Inst), IsInductionVar) { assert(Utils::isMemAccessInst(this->Inst) && "Should be load/store instruction to build a stream."); + this->AddressFunctionName = + (this->Inst->getFunction()->getName() + "_" + + this->Inst->getParent()->getName() + "_" + this->Inst->getName() + + "_" + this->Inst->getOpcodeName()) + .str(); this->searchAddressComputeInstructions(IsInductionVar); } @@ -61,6 +69,14 @@ class MemStream : public Stream { return false; } + std::string getAddressFunctionName() const { + return this->AddressFunctionName; + } + void generateComputeFunction(llvm::Module *Module) const; + +protected: + void formatAdditionalInfoText(std::ostream &OStream) const override; + private: MemoryFootprint Footprint; std::unordered_set BaseLoads; @@ -68,7 +84,11 @@ class MemStream : public Stream { std::unordered_set AddrInsts; std::unordered_set AliasInsts; + std::string AddressFunctionName; + + AddressDataGraph AddrDG; + void searchAddressComputeInstructions( - std::function IsInductionVar); + std::function IsInductionVar); }; #endif \ No newline at end of file diff --git a/src/stream/Stream.cpp b/src/stream/Stream.cpp index cdb7ad3e..ec62e212 100644 --- a/src/stream/Stream.cpp +++ b/src/stream/Stream.cpp @@ -2,11 +2,11 @@ Stream::Stream(TypeT _Type, const std::string &_Folder, const llvm::Instruction *_Inst, const llvm::Loop *_Loop, - size_t _LoopLevel) + const llvm::Loop *_InnerMostLoop, size_t _LoopLevel) : Type(_Type), Folder(_Folder), Inst(_Inst), Loop(_Loop), - LoopLevel(_LoopLevel), Qualified(false), Chosen(false), TotalIters(0), - TotalAccesses(0), TotalStreams(0), Iters(1), LastAccessIters(0), - StartId(DynamicInstruction::InvalidId), Pattern() { + InnerMostLoop(_InnerMostLoop), LoopLevel(_LoopLevel), Qualified(false), + Chosen(false), TotalIters(0), TotalAccesses(0), TotalStreams(0), Iters(1), + LastAccessIters(0), StartId(DynamicInstruction::InvalidId), Pattern() { this->PatternFullPath = this->Folder + "/" + this->formatName() + ".pattern"; this->PatternTextFullPath = this->PatternFullPath + ".txt"; this->InfoFullPath = this->Folder + "/" + this->formatName() + ".info"; @@ -98,6 +98,10 @@ void Stream::finalize(llvm::DataLayout *DataLayout) { << AllChosenBaseStream->formatName() << '\n'; } InfoTextFStream << "------------------------------\n"; + /** + * Formatting any additional text information for the subclass. + */ + this->formatAdditionalInfoText(InfoTextFStream); InfoTextFStream.close(); // Also serialize with protobuf. diff --git a/src/stream/Stream.h b/src/stream/Stream.h index 6ff9d97a..7dca0dfe 100644 --- a/src/stream/Stream.h +++ b/src/stream/Stream.h @@ -25,7 +25,7 @@ class Stream { const TypeT Type; Stream(TypeT _Type, const std::string &_Folder, const llvm::Instruction *_Inst, const llvm::Loop *_Loop, - size_t _LoopLevel); + const llvm::Loop *_InnerMostLoop, size_t _LoopLevel); bool hasNoBaseStream() const { return this->BaseStreams.empty(); } const std::unordered_set &getBaseStreams() const { @@ -45,6 +45,7 @@ class Stream { void markChosen() { this->Chosen = true; } bool isChosen() const { return this->Chosen; } const llvm::Loop *getLoop() const { return this->Loop; } + const llvm::Loop *getInnerMostLoop() const { return this->InnerMostLoop; } const llvm::Instruction *getInst() const { return this->Inst; } uint64_t getStreamId() const { return reinterpret_cast(this); } const std::string &getPatternPath() const { return this->PatternFullPath; } @@ -140,6 +141,7 @@ class Stream { */ const llvm::Instruction *Inst; const llvm::Loop *Loop; + const llvm::Loop *InnerMostLoop; const size_t LoopLevel; std::unordered_set BaseStreams; @@ -178,6 +180,11 @@ class Stream { StreamPattern Pattern; int getElementSize(llvm::DataLayout *DataLayout) const; + + /** + * Used for subclass to add additionl dumping information. + */ + virtual void formatAdditionalInfoText(std::ostream &OStream) const {} }; #endif \ No newline at end of file diff --git a/src/stream/StreamPass.cpp b/src/stream/StreamPass.cpp index 6566719e..f8f3e5b5 100644 --- a/src/stream/StreamPass.cpp +++ b/src/stream/StreamPass.cpp @@ -1,5 +1,7 @@ #include "stream/StreamPass.h" +#include "llvm/Support/FileSystem.h" + #include #include @@ -271,6 +273,7 @@ void StreamPass::transform() { S->finalize(this->Trace->DataLayout); } } + this->buildAddressDataGraphForChosenStreams(); this->makeStreamTransformPlan(); @@ -327,14 +330,18 @@ void StreamPass::initializeMemStreamIfNecessary(const LoopStackT &LoopStack, } // Initialize the remaining loops. - auto IsInductionVar = [this](llvm::PHINode *PHINode) -> bool { + auto IsInductionVar = [this](const llvm::PHINode *PHINode) -> bool { return this->PHINodeIVStreamMap.count(PHINode) != 0; // return false; }; while (LoopIter != LoopStack.rend()) { auto LoopLevel = Streams.size(); + const llvm::Loop *InnerMostLoop = *LoopIter; + if (LoopLevel > 0) { + InnerMostLoop = Streams.front().getInnerMostLoop(); + } Streams.emplace_back(this->OutputExtraFolderPath, Inst, *LoopIter, - LoopLevel, IsInductionVar); + InnerMostLoop, LoopLevel, IsInductionVar); this->InstStreamMap.at(Inst).emplace_back(&Streams.back()); ++LoopIter; } @@ -372,10 +379,14 @@ void StreamPass::initializeIVStreamIfNecessary(const LoopStackT &LoopStack, auto LoopLevel = Streams.size(); auto Loop = *LoopIter; auto Level = Streams.size(); + const llvm::Loop *InnerMostLoop = *LoopIter; + if (LoopLevel > 0) { + InnerMostLoop = Streams.front().getInnerMostLoop(); + } auto ComputeInsts = InductionVarStream::searchComputeInsts(Inst, Loop); if (InductionVarStream::isInductionVarStream(Inst, ComputeInsts)) { - Streams.emplace_back(this->OutputExtraFolderPath, Inst, Loop, Level, - std::move(ComputeInsts)); + Streams.emplace_back(this->OutputExtraFolderPath, Inst, Loop, + InnerMostLoop, Level, std::move(ComputeInsts)); this->InstStreamMap.at(Inst).emplace_back(&Streams.back()); DEBUG(llvm::errs() << "Initialize IVStream " << Streams.back().formatName() << '\n'); @@ -1032,6 +1043,29 @@ void StreamPass::buildAllChosenStreamDependenceGraph() { } } +std::string StreamPass::getAddressModuleName() const { + return this->OutTraceName + ".address.bc"; +} + +void StreamPass::buildAddressDataGraphForChosenStreams() const { + auto &Context = this->Module->getContext(); + llvm::Module AddressModule(this->getAddressModuleName(), Context); + + for (const auto &InstMemStreamEntry : this->InstMemStreamMap) { + for (const auto &S : InstMemStreamEntry.second) { + if (S.isChosen()) { + S.generateComputeFunction(&AddressModule); + } + } + } + + std::error_code EC; + llvm::raw_fd_ostream ModuleFStream(this->AddressModulePath, EC, + llvm::sys::fs::OpenFlags::F_None); + AddressModule.print(ModuleFStream, nullptr); + ModuleFStream.close(); +} + StreamTransformPlan & StreamPass::getOrCreatePlan(const llvm::Instruction *Inst) { auto UserPlanIter = this->InstPlanMap.find(Inst); @@ -1074,6 +1108,15 @@ void StreamPass::DEBUG_PLAN_FOR_LOOP(const llvm::Loop *Loop) { } } llvm::errs() << ss.str() << '\n'; + + // Also dump to file. + std::string PlanPath = this->OutputExtraFolderPath + "/" + + LoopUtils::getLoopId(Loop) + ".plan.txt"; + std::ofstream PlanFStream(PlanPath); + assert(PlanFStream.is_open() && + "Failed to open dump loop transform plan file."); + PlanFStream << ss.str() << '\n'; + PlanFStream.close(); } void StreamPass::DEBUG_SORTED_STREAMS_FOR_LOOP(const llvm::Loop *Loop) { @@ -1418,9 +1461,12 @@ void StreamPass::transformStream() { while (this->Trace->DynamicInstructionList.size() > 10) { auto DynamicInst = this->Trace->DynamicInstructionList.front(); - if (DynamicInst->getId() > 19923000 && DynamicInst->getId() < 19923700) { - DEBUG(this->DEBUG_TRANSFORMED_STREAM(DynamicInst)); - } + // Debug a certain range of transformed instructions. + // if (DynamicInst->getId() > 19923000 && DynamicInst->getId() < 19923700) + // { + // DEBUG(this->DEBUG_TRANSFORMED_STREAM(DynamicInst)); + // } + this->Serializer->serialize(DynamicInst, this->Trace); this->Trace->commitOneDynamicInst(); } @@ -1472,95 +1518,111 @@ void StreamPass::transformStream() { } auto PlanIter = this->InstPlanMap.find(NewStaticInst); - if (PlanIter == this->InstPlanMap.end()) { - continue; - } + if (PlanIter != this->InstPlanMap.end()) { + const auto &TransformPlan = PlanIter->second; + bool NeedToHandleUseInformation = true; + if (TransformPlan.Plan == StreamTransformPlan::PlanT::DELETE) { + /** + * This is important to make the future instruction not dependent on + * this deleted instruction. + */ + this->Trace->DynamicFrameStack.front() + .updateRegisterDependenceLookUpMap(NewStaticInst, + std::list()); + + auto NewDynamicId = NewDynamicInst->getId(); + this->Trace->commitDynamicInst(NewDynamicId); + this->Trace->DynamicInstructionList.erase(NewInstIter); + NewDynamicInst = nullptr; + /** + * No more handling use information for the deleted instruction. + */ + this->DeletedInstCount++; + NeedToHandleUseInformation = false; + } else if (TransformPlan.Plan == StreamTransformPlan::PlanT::STEP) { + + this->Trace->DynamicFrameStack.front() + .updateRegisterDependenceLookUpMap(NewStaticInst, + std::list()); + + auto NewDynamicId = NewDynamicInst->getId(); + delete NewDynamicInst; + + auto StepInst = + new StreamStepInst(TransformPlan.getParamStream(), NewDynamicId); + *NewInstIter = StepInst; + NewDynamicInst = StepInst; + + /** + * Handle the dependence for the step instruction. + */ + auto StreamInst = TransformPlan.getParamStream()->getInst(); + auto StreamInstIter = ActiveStreamInstMap.find(StreamInst); + if (StreamInstIter == ActiveStreamInstMap.end()) { + ActiveStreamInstMap.emplace(StreamInst, NewDynamicId); + } else { + this->Trace->RegDeps.at(NewDynamicId) + .emplace_back(nullptr, StreamInstIter->second); + StreamInstIter->second = NewDynamicId; + } - const auto &TransformPlan = PlanIter->second; - if (TransformPlan.Plan == StreamTransformPlan::PlanT::DELETE) { - /** - * This is important to make the future instruction not dependent on - * this deleted instruction. - */ - this->Trace->DynamicFrameStack.front().updateRegisterDependenceLookUpMap( - NewStaticInst, std::list()); + this->StepInstCount++; + NeedToHandleUseInformation = false; - auto NewDynamicId = NewDynamicInst->getId(); - this->Trace->commitDynamicInst(NewDynamicId); - this->Trace->DynamicInstructionList.erase(NewInstIter); - /** - * No more handling for the deleted instruction. - */ - this->DeletedInstCount++; - continue; - } else if (TransformPlan.Plan == StreamTransformPlan::PlanT::STEP) { + } else if (TransformPlan.Plan == StreamTransformPlan::PlanT::STORE) { - this->Trace->DynamicFrameStack.front().updateRegisterDependenceLookUpMap( - NewStaticInst, std::list()); + assert(llvm::isa(NewStaticInst) && + "STORE plan for non store instruction."); - auto NewDynamicId = NewDynamicInst->getId(); - delete NewDynamicInst; + this->Trace->DynamicFrameStack.front() + .updateRegisterDependenceLookUpMap(NewStaticInst, + std::list()); - auto StepInst = - new StreamStepInst(TransformPlan.getParamStream(), NewDynamicId); - *NewInstIter = StepInst; - NewDynamicInst = StepInst; + /** + * REPLACE the original store instruction with our special stream store. + */ + auto NewDynamicId = NewDynamicInst->getId(); + delete NewDynamicInst; - /** - * Handle the dependence for the step instruction. - */ - auto StreamInst = TransformPlan.getParamStream()->getInst(); - auto StreamInstIter = ActiveStreamInstMap.find(StreamInst); - if (StreamInstIter == ActiveStreamInstMap.end()) { - ActiveStreamInstMap.emplace(StreamInst, NewDynamicId); - } else { - this->Trace->RegDeps.at(NewDynamicId) - .emplace_back(nullptr, StreamInstIter->second); - StreamInstIter->second = NewDynamicId; + auto StoreInst = + new StreamStoreInst(TransformPlan.getParamStream(), NewDynamicId); + *NewInstIter = StoreInst; + NewDynamicInst = StoreInst; } - this->StepInstCount++; - continue; - - } else if (TransformPlan.Plan == StreamTransformPlan::PlanT::STORE) { - - assert(llvm::isa(NewStaticInst) && - "STORE plan for non store instruction."); - - this->Trace->DynamicFrameStack.front().updateRegisterDependenceLookUpMap( - NewStaticInst, std::list()); - - /** - * REPLACE the original store instruction with our special stream store. - */ - auto NewDynamicId = NewDynamicInst->getId(); - delete NewDynamicInst; - - auto StoreInst = - new StreamStoreInst(TransformPlan.getParamStream(), NewDynamicId); - *NewInstIter = StoreInst; - NewDynamicInst = StoreInst; - } - - /** - * Handle the use information. - */ - auto &RegDeps = this->Trace->RegDeps.at(NewDynamicInst->getId()); - for (auto &UsedStream : TransformPlan.getUsedStreams()) { - // Add the used stream id to the dynamic instruction. - NewDynamicInst->addUsedStreamId(UsedStream->getStreamId()); - auto UsedStreamInst = UsedStream->getInst(); - auto UsedStreamInstIter = ActiveStreamInstMap.find(UsedStreamInst); - if (UsedStreamInstIter != ActiveStreamInstMap.end()) { - RegDeps.emplace_back(nullptr, UsedStreamInstIter->second); + if (NeedToHandleUseInformation) { + /** + * Handle the use information. + */ + auto &RegDeps = this->Trace->RegDeps.at(NewDynamicInst->getId()); + for (auto &UsedStream : TransformPlan.getUsedStreams()) { + // Add the used stream id to the dynamic instruction. + NewDynamicInst->addUsedStreamId(UsedStream->getStreamId()); + auto UsedStreamInst = UsedStream->getInst(); + auto UsedStreamInstIter = ActiveStreamInstMap.find(UsedStreamInst); + if (UsedStreamInstIter != ActiveStreamInstMap.end()) { + RegDeps.emplace_back(nullptr, UsedStreamInstIter->second); + } + for (auto &ChosenBaseStream : UsedStream->getAllChosenBaseStreams()) { + auto Iter = ActiveStreamInstMap.find(ChosenBaseStream->getInst()); + if (Iter != ActiveStreamInstMap.end()) { + RegDeps.emplace_back(nullptr, Iter->second); + } + } + } } - for (auto &ChosenBaseStream : UsedStream->getAllChosenBaseStreams()) { - auto Iter = ActiveStreamInstMap.find(ChosenBaseStream->getInst()); - if (Iter != ActiveStreamInstMap.end()) { - RegDeps.emplace_back(nullptr, Iter->second); + } +// Debug a certain tranformed loop. +#define DEBUG_LOOP_TRANSFORMED "train::bb13" + for (auto &Loop : LoopStack) { + if (LoopUtils::getLoopId(Loop) == DEBUG_LOOP_TRANSFORMED) { + if (NewDynamicInst != nullptr) { + DEBUG(this->DEBUG_TRANSFORMED_STREAM(NewDynamicInst)); } + break; } } +#undef DEBUG_LOOP_TRANSFORMED } DEBUG(llvm::errs() << "Stream: Transform done.\n"); diff --git a/src/stream/StreamPass.h b/src/stream/StreamPass.h index ba9ba05f..0a350482 100644 --- a/src/stream/StreamPass.h +++ b/src/stream/StreamPass.h @@ -138,7 +138,9 @@ class StreamPass : public ReplayTrace { static char ID; StreamPass(char _ID = ID) : ReplayTrace(_ID), DynInstCount(0), DynMemInstCount(0), StepInstCount(0), - ConfigInstCount(0), DeletedInstCount(0) {} + ConfigInstCount(0), DeletedInstCount(0) { + this->AddressModulePath = this->OutputExtraFolderPath + "/stream.addr.ll"; + } protected: bool initialize(llvm::Module &Module) override; @@ -191,6 +193,8 @@ class StreamPass : public ReplayTrace { Stream *S); void buildChosenStreamDependenceGraph(); void buildAllChosenStreamDependenceGraph(); + void buildAddressDataGraphForChosenStreams() const; + std::string getAddressModuleName() const; MemStream *getMemStreamByInstLoop(llvm::Instruction *Inst, const llvm::Loop *Loop); @@ -220,6 +224,8 @@ class StreamPass : public ReplayTrace { void DEBUG_TRANSFORMED_STREAM(DynamicInstruction *DynamicInst); virtual void transformStream(); + std::string AddressModulePath; + std::unordered_map> InstStreamMap; diff --git a/src/stream/ae/AddressDataGraph.cpp b/src/stream/ae/AddressDataGraph.cpp new file mode 100644 index 00000000..fa64256a --- /dev/null +++ b/src/stream/ae/AddressDataGraph.cpp @@ -0,0 +1,267 @@ +#include "stream/ae/AddressDataGraph.h" + +#include "LoopUtils.h" + +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" + +#include +#include + +AddressDataGraph::AddressDataGraph( + const llvm::Loop *_Loop, const llvm::Value *_AddrValue, + std::function IsInductionVar) + : Loop(_Loop), AddrValue(_AddrValue), HasCircle(false) { + this->constructDataGraph(IsInductionVar); + this->HasCircle = this->detectCircle(); +} + +void AddressDataGraph::constructDataGraph( + std::function IsInductionVar) { + std::list Queue; + Queue.emplace_back(this->AddrValue); + + std::unordered_set UnsortedInputs; + + while (!Queue.empty()) { + auto Value = Queue.front(); + Queue.pop_front(); + auto Inst = llvm::dyn_cast(Value); + if (Inst == nullptr) { + // This is not an instruction, should be an input value. + UnsortedInputs.insert(Value); + continue; + } + if (!this->Loop->contains(Inst)) { + // This is an instruction falling out of the loop, should also be an input + // value. + UnsortedInputs.insert(Inst); + continue; + } + + if (auto PHINode = llvm::dyn_cast(Inst)) { + if (IsInductionVar(PHINode)) { + // This is an induction variable stream, should also be an input value. + UnsortedInputs.insert(PHINode); + this->BaseIVs.insert(PHINode); + continue; + } + } + + if (auto LoadInst = llvm::dyn_cast(Inst)) { + // This is a load stream, should also be an input value. + UnsortedInputs.insert(LoadInst); + this->BaseLoads.insert(LoadInst); + continue; + } + + // This is an compute instruction. + bool Inserted = this->ComputeInsts.insert(Inst).second; + if (Inserted) { + // The instruction is inserted, which means that it is an new instruction. + for (unsigned OperandIdx = 0, NumOperand = Inst->getNumOperands(); + OperandIdx != NumOperand; ++OperandIdx) { + Queue.emplace_back(Inst->getOperand(OperandIdx)); + } + } + } + + /** + * Generate the sorted inputs list. + */ + this->Inputs.insert(this->Inputs.end(), UnsortedInputs.begin(), + UnsortedInputs.end()); +} + +void AddressDataGraph::format(std::ostream &OStream) const { + OStream << "AddressDataGraph of Loop " << LoopUtils::getLoopId(this->Loop) + << " Value " << LoopUtils::formatLLVMValue(this->AddrValue) << '\n'; + OStream << "-------------- Input Values ---------------\n"; + for (const auto &Input : this->Inputs) { + OStream << LoopUtils::formatLLVMValue(Input) << '\n'; + } + OStream << "-------------- Compute Insts --------------\n"; + if (auto AddrInst = llvm::dyn_cast(this->AddrValue)) { + if (this->ComputeInsts.count(AddrInst) == 0) { + // This address instruction is somehow loop invariant. + assert(this->ComputeInsts.empty() && + "If the address instruction is not in the loop, there should be " + "no compute instructions."); + } else { + std::unordered_set FormattedInsts; + auto FormatTask = + [&OStream, &FormattedInsts](const llvm::Instruction *Inst) -> void { + if (FormattedInsts.count(Inst) == 0) { + OStream << LoopUtils::formatLLVMInst(Inst); + for (unsigned OperandIdx = 0, NumOperands = Inst->getNumOperands(); + OperandIdx != NumOperands; ++OperandIdx) { + OStream << ' ' + << LoopUtils::formatLLVMValue(Inst->getOperand(OperandIdx)); + } + OStream << '\n'; + FormattedInsts.insert(Inst); + } + }; + if (this->HasCircle) { + OStream << "!!! Circle !!!\n"; + for (const auto &ComputeInst : this->ComputeInsts) { + FormatTask(ComputeInst); + } + } else { + this->dfsOnComputeInsts(AddrInst, FormatTask); + } + } + } else { + assert(this->ComputeInsts.empty() && + "If there is no address instruction, there should be no compute " + "instructions."); + } + OStream << "-------------- AddressDatagraph End -------\n"; +} + +bool AddressDataGraph::detectCircle() const { + if (auto AddrInst = llvm::dyn_cast(this->AddrValue)) { + if (!this->ComputeInsts.empty()) { + std::vector> Stack; + Stack.emplace_back(AddrInst, 0); + while (!Stack.empty()) { + auto &Entry = Stack.back(); + auto &Inst = Entry.first; + if (Entry.second == 0) { + // First time. + Entry.second = 1; + for (unsigned OperandIdx = 0, NumOperand = Inst->getNumOperands(); + OperandIdx != NumOperand; ++OperandIdx) { + if (auto OperandInst = llvm::dyn_cast( + Inst->getOperand(OperandIdx))) { + if (this->ComputeInsts.count(OperandInst) != 0) { + // Check if this instruction is already in the stack. + for (const auto &StackElement : Stack) { + if (StackElement.first == OperandInst && + StackElement.second == 1) { + // There is circle. + return true; + } + } + Stack.emplace_back(OperandInst, 0); + } + } + } + } else { + // Second time. + Stack.pop_back(); + } + } + } + } + return false; +} + +void AddressDataGraph::dfsOnComputeInsts(const llvm::Instruction *Inst, + DFSTaskT Task) const { + assert( + !this->HasCircle && + "Try to do DFS when there is circle in the address compute datagraph."); + assert(this->ComputeInsts.count(Inst) != 0 && + "This instruction is not in the compute instructions."); + + for (unsigned OperandIdx = 0, NumOperand = Inst->getNumOperands(); + OperandIdx != NumOperand; ++OperandIdx) { + if (auto OperandInst = + llvm::dyn_cast(Inst->getOperand(OperandIdx))) { + if (this->ComputeInsts.count(OperandInst) != 0) { + this->dfsOnComputeInsts(OperandInst, Task); + } + } + } + Task(Inst); +} + +llvm::Function * +AddressDataGraph::generateComputeFunction(const std::string &FuncName, + llvm::Module *Module) const { + assert(!this->HasCircle && + "Can not create address function for cyclic address datagaph."); + { + auto TempFunc = Module->getFunction(FuncName); + assert(TempFunc == nullptr && "Function is already inside the module."); + } + + auto FuncType = this->createFunctionType(Module); + auto Function = llvm::Function::Create( + FuncType, llvm::GlobalValue::LinkageTypes::ExternalLinkage, FuncName, + Module); + assert(Function != nullptr && "Failed to insert the function."); + + // Create the first and only basic block. + auto &Context = Module->getContext(); + auto BB = llvm::BasicBlock::Create(Context, "entry", Function); + llvm::IRBuilder<> Builder(BB); + + // Create the map from the original value to the new value. + std::unordered_map ValueMap; + { + auto ArgIter = Function->arg_begin(); + auto ArgEnd = Function->arg_end(); + for (const auto &Input : this->Inputs) { + assert(ArgIter != ArgEnd && + "Mismatch between address daragraph input and function argument."); + ValueMap.emplace(Input, ArgIter); + ++ArgIter; + } + } + + // Start to translate the datagraph into the function body. + if (!this->ComputeInsts.empty()) { + auto Translate = [this, &Builder, + &ValueMap](const llvm::Instruction *Inst) -> void { + this->translate(Builder, ValueMap, Inst); + }; + auto AddrInst = llvm::dyn_cast(this->AddrValue); + assert(AddrInst != nullptr && + "AddrValue is not an instruction when we have a datagraph."); + this->dfsOnComputeInsts(AddrInst, Translate); + } + + // Create the return inst. + { + auto ValueIter = ValueMap.find(this->AddrValue); + assert(ValueIter != ValueMap.end() && + "Failed to find the translated address value."); + Builder.CreateRet(ValueIter->second); + } + + return Function; +} + +llvm::FunctionType * +AddressDataGraph::createFunctionType(llvm::Module *Module) const { + std::vector Args; + for (const auto &Input : this->Inputs) { + Args.emplace_back(Input->getType()); + } + auto ResultType = this->AddrValue->getType(); + return llvm::FunctionType::get(ResultType, Args, false); +} + +void AddressDataGraph::translate( + llvm::IRBuilder<> &Builder, + std::unordered_map &ValueMap, + const llvm::Instruction *Inst) const { + if (ValueMap.count(Inst) != 0) { + // We have already translated this instruction. + return; + } + auto NewInst = Inst->clone(); + // Fix the operand. + for (unsigned OperandIdx = 0, NumOperands = NewInst->getNumOperands(); + OperandIdx != NumOperands; ++OperandIdx) { + auto ValueIter = ValueMap.find(Inst->getOperand(OperandIdx)); + assert(ValueIter != ValueMap.end() && "Failed to find translated operand."); + NewInst->setOperand(OperandIdx, ValueIter->second); + } + // Insert with the same name. + Builder.Insert(NewInst, Inst->getName()); + // Insert into the value map. + ValueMap.emplace(Inst, NewInst); +} \ No newline at end of file diff --git a/src/stream/ae/AddressDataGraph.h b/src/stream/ae/AddressDataGraph.h new file mode 100644 index 00000000..c80541a5 --- /dev/null +++ b/src/stream/ae/AddressDataGraph.h @@ -0,0 +1,55 @@ +#ifndef LLVM_TDG_ADDRESS_DATAGRAPH_H +#define LLVM_TDG_ADDRESS_DATAGRAPH_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" + +#include +#include +#include +#include +#include + +class AddressDataGraph { +public: + AddressDataGraph(const llvm::Loop *_Loop, const llvm::Value *_AddrValue, + std::function IsInductionVar); + + void format(std::ostream &OStream) const; + + bool hasCircle() const { return this->HasCircle; } + + /** + * Generate a function takes the input and returns the value. + * Returns the inserted function. + */ + llvm::Function *generateComputeFunction(const std::string &FuncName, + llvm::Module *Module) const; + +private: + const llvm::Loop *Loop; + const llvm::Value *AddrValue; + std::list Inputs; + std::unordered_set BaseIVs; + std::unordered_set BaseLoads; + std::unordered_set ComputeInsts; + bool HasCircle; + + void + constructDataGraph(std::function IsInductionVar); + + using DFSTaskT = std::function; + void dfsOnComputeInsts(const llvm::Instruction *Inst, DFSTaskT Task) const; + + bool detectCircle() const; + + llvm::FunctionType *createFunctionType(llvm::Module *Module) const; + + void + translate(llvm::IRBuilder<> &Builder, + std::unordered_map &ValueMap, + const llvm::Instruction *Inst) const; +}; + +#endif \ No newline at end of file diff --git a/src/stream/ae/AddressEngine.cpp b/src/stream/ae/AddressEngine.cpp new file mode 100644 index 00000000..e95fe302 --- /dev/null +++ b/src/stream/ae/AddressEngine.cpp @@ -0,0 +1,57 @@ + +#include "llvm/IRReader/IRReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" + +#include "ExecutionEngine/Interpreter/Interpreter.h" + +#include +#include + +namespace { +llvm::cl::opt BitCodeFile(llvm::cl::desc("Input bitcode file."), + llvm::cl::Positional); +} + +std::unique_ptr readBitCodeFile(llvm::LLVMContext &Context, + const std::string &BitCodeFile) { + llvm::SMDiagnostic Err; + return llvm::parseIRFile(BitCodeFile, Err, Context); +} + +void *interpret(llvm::Interpreter &Interpreter, const std::string &FuncName) { + + auto FuncPtr = Interpreter.FindFunctionNamed(FuncName); + assert(FuncPtr != nullptr && "Failed to find the callee."); + + llvm::GenericValue Arr; + llvm::GenericValue Idx; + Arr.PointerVal = reinterpret_cast(0x128); + Idx.IntVal = llvm::APInt(32, 1, true); + + std::vector Args{Arr, Idx}; + auto Result = Interpreter.runFunction(FuncPtr, Args); + + return Result.PointerVal; +} + +int main(int argc, char *argv[]) { + + llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); + llvm::PrettyStackTraceProgram X(argc, argv); + + llvm::cl::ParseCommandLineOptions(argc, argv, + "Start stream address engine.\n"); + + llvm::LLVMContext Context; + auto Module = readBitCodeFile(Context, BitCodeFile.getValue()); + assert(Module != nullptr && "Failed to parse llvm bitcode file.\n"); + + llvm::Interpreter Interpreter(std::move(Module)); + + llvm::errs() << interpret(Interpreter, "addr") << '\n'; + + return 0; +} \ No newline at end of file