bool PatmosSPMark::runOnMachineModule(const Module &M) { DEBUG( dbgs() << "[Single-Path] Mark functions reachable from single-path roots\n"); MMI = &getAnalysis<MachineModuleInfo>(); assert(MMI); Worklist W; // initialize the worklist with machine functions that have either // sp-root or sp-reachable function attribute for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-root") || F->hasFnAttribute("sp-reachable")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); PMFI->setSinglePath(); NumSPTotal++; // bump STATISTIC W.push_back(MF); } } // process worklist while (!W.empty()) { MachineFunction *MF = W.front(); W.pop_front(); scanAndRewriteCalls(MF, W); } removeUncalledSPFunctions(M); // We either have rewritten calls or removed superfluous functions. return true; }
static CompilationResult compileImpl( VM& vm, CodeBlock* codeBlock, CodeBlock* profiledDFGCodeBlock, CompilationMode mode, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues, PassRefPtr<DeferredCompilationCallback> callback) { SamplingRegion samplingRegion("DFG Compilation (Driver)"); numCompilations++; ASSERT(codeBlock); ASSERT(codeBlock->alternative()); ASSERT(codeBlock->alternative()->jitType() == JITCode::BaselineJIT); ASSERT(!profiledDFGCodeBlock || profiledDFGCodeBlock->jitType() == JITCode::DFGJIT); if (logCompilationChanges(mode)) dataLog("DFG(Driver) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n"); // Make sure that any stubs that the DFG is going to use are initialized. We want to // make sure that all JIT code generation does finalization on the main thread. vm.getCTIStub(osrExitGenerationThunkGenerator); vm.getCTIStub(throwExceptionFromCallSlowPathGenerator); if (mode == DFGMode) { vm.getCTIStub(linkCallThunkGenerator); vm.getCTIStub(linkConstructThunkGenerator); vm.getCTIStub(linkClosureCallThunkGenerator); vm.getCTIStub(virtualCallThunkGenerator); vm.getCTIStub(virtualConstructThunkGenerator); } else { vm.getCTIStub(linkCallThatPreservesRegsThunkGenerator); vm.getCTIStub(linkConstructThatPreservesRegsThunkGenerator); vm.getCTIStub(linkClosureCallThatPreservesRegsThunkGenerator); vm.getCTIStub(virtualCallThatPreservesRegsThunkGenerator); vm.getCTIStub(virtualConstructThatPreservesRegsThunkGenerator); } if (CallEdgeLog::isEnabled()) vm.ensureCallEdgeLog().processLog(); if (vm.typeProfiler()) vm.typeProfilerLog()->processLogEntries(ASCIILiteral("Preparing for DFG compilation.")); RefPtr<Plan> plan = adoptRef( new Plan(codeBlock, profiledDFGCodeBlock, mode, osrEntryBytecodeIndex, mustHandleValues)); if (Options::enableConcurrentJIT()) { Worklist* worklist = ensureGlobalWorklistFor(mode); plan->callback = callback; if (logCompilationChanges(mode)) dataLog("Deferring DFG compilation of ", *codeBlock, " with queue length ", worklist->queueLength(), ".\n"); worklist->enqueue(plan); return CompilationDeferred; } plan->compileInThread(*vm.dfgState, 0); return plan->finalizeWithoutNotifyingCallback(); }
void PatmosSPMark::scanAndRewriteCalls(MachineFunction *MF, Worklist &W) { for (MachineFunction::iterator MBB = MF->begin(), MBBE = MF->end(); MBB != MBBE; ++MBB) { for( MachineBasicBlock::iterator MI = MBB->begin(), ME = MBB->getFirstTerminator(); MI != ME; ++MI) { if (MI->isCall()) { MachineFunction *MF = getCallTargetMF(MI); if (!MF) { dbgs() << "[Single-Path] WARNING: Cannot rewrite call in " << MBB->getParent()->getFunction()->getName() << " (indirect call?)\n"; continue; }; const Function *Target = getCallTarget(MI); if (Target->getName() == "__udivsi3") { //DEBUG(dbgs() << "[Single-Path] skipping call to " // << Target->getName() << "\n"); //continue; } PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); if (!PMFI->isSinglePath()) { // rewrite call to _sp variant rewriteCall(MI); // set _sp MF to single path in PMFI (MF has changed!) MachineFunction *MF = getCallTargetMF(MI); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); // we possibly have already marked the _sp variant as single-path // in an earlier call if (!PMFI->isSinglePath()) { PMFI->setSinglePath(); // add the new single-path function to the worklist W.push_back(MF); NumSPTotal++; // bump STATISTIC NumSPMaybe++; // bump STATISTIC } } } } } }
void PatmosSPMark::scanAndRewriteCalls(MachineFunction *MF, Worklist &W) { DEBUG(dbgs() << "In function '" << MF->getName() << "':\n"); for (MachineFunction::iterator MBB = MF->begin(), MBBE = MF->end(); MBB != MBBE; ++MBB) { for( MachineBasicBlock::iterator MI = MBB->begin(), ME = MBB->getFirstTerminator(); MI != ME; ++MI) { if (MI->isCall()) { MachineFunction *MF = getCallTargetMF(MI); if (!MF) { dbgs() << "[Single-Path] WARNING: Cannot rewrite call in " << MBB->getParent()->getFunction()->getName() << " (indirect call?)\n"; continue; }; const Function *Target = getCallTarget(MI); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); if (!PMFI->isSinglePath()) { // sp-reachable functions were already marked as single-path. // Hence, we have _potential_ sp-maybe functions left; the call // needs to be rewritten to point to the sp-maybe clone. rewriteCall(MI); // set _sp MF to single path in PMFI (MF has changed!) MachineFunction *MF = getCallTargetMF(MI); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); // we possibly have already marked the _sp variant as single-path // in an earlier call, if not, then set this final decision. if (!PMFI->isSinglePath()) { PMFI->setSinglePath(); // add the new single-path function to the worklist W.push_back(MF); NumSPTotal++; // bump STATISTIC NumSPMaybe++; // bump STATISTIC } } } } } }
// // Computes path_summary_iterative_original // void WFA::path_summary_iterative_original(Worklist<State>& wl, sem_elem_t wt) { // BEGIN DEBUGGING //int numPops = 0; // END DEBUGGING IncomingTransMap_t preds; setupFixpoint(wl, &preds, NULL, wt); while (!wl.empty()) { State* q = wl.get(); sem_elem_t the_delta = q->delta(); q->delta() = the_delta->zero(); { // BEGIN DEBUGGING //numPops++; //q->print(*waliErr << " Popped: ") << std::endl; } // END DEBUGGING // Get a handle on ZERO b/c we use it alot sem_elem_t ZERO = q->weight()->zero(); // Find predecessor set IncomingTransMap_t::iterator incomingTransIt = preds.find(q->name()); // Some states may have no predecessors, like // the initial state if (incomingTransIt == preds.end()) { continue; } // Tell predecessors we have changed std::vector<ITrans*> & incoming = incomingTransIt->second; std::vector<ITrans*>::iterator transit = incoming.begin(); for ( ; transit != incoming.end() ; ++transit) { ITrans* t = *transit; // We are looking at a transition (q', _, q) State* qprime = state_map[t->from()]; sem_elem_t newW = qprime->weight()->zero(); { // BEGIN DEBUGGING //t->print(*waliErr << "\t++ Popped ") << std::endl; } // END DEBUGGING assert(t->to() == q->name()); sem_elem_t extended; if (query == INORDER) { extended = t->weight()->extend(the_delta); } else { extended = the_delta->extend(t->weight()); } newW = newW->combine(extended); // delta => (w+se,w-se) // Use extended->delta b/c we want the diff b/w the new // weight (extended) and what was there before std::pair<sem_elem_t,sem_elem_t> p = newW->delta(qprime->weight()); { // BEGIN DEBUGGING //qprime->weight()->print(*waliErr << " oldW " << key2str(qprime->name())) << std::endl; //newW->print(*waliErr << " newW " << key2str(qprime->name())) << std::endl; //p.first->print(*waliErr << "\t++ p.first ") << std::endl; //p.second->print(*waliErr << "\t++ p.second ") << std::endl; } // END DEBUGGING // Sets qprime's new weight // p.first == (l(t) X the_delta) + W(qprime) qprime->weight() = p.first; // on the worklist? if (qprime->marked()) { qprime->delta() = qprime->delta()->combine(p.second); } else { // not on the worklist means its delta is zero qprime->delta() = p.second; // add to worklist if not zero if (!qprime->delta()->equal(ZERO)) { wl.put(qprime); } } } if (progress.is_valid()) { progress->tick(); } } { // BEGIN DEBUGGING //*waliErr << "\n --- WFA::path_summary_iterative_original needed " << numPops << " pops\n"; //*waliErr << "WFA state labels:\n"; //FOR_EACH_STATE(st) { // *waliErr << "\t" << key2str(st->name()) << ": "; // st->weight()->print(*waliErr) << std::endl; //} } // END DEBUGGING }
bool PatmosSPMark::runOnMachineModule(const Module &M) { DEBUG( dbgs() << "[Single-Path] Mark functions reachable from single-path roots\n"); MMI = &getAnalysis<MachineModuleInfo>(); assert(MMI); Worklist W; // initialize the worklist with machine functions that have either // sp-root or sp-reachable function attribute for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-root") || F->hasFnAttribute("sp-reachable")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); PMFI->setSinglePath(); NumSPTotal++; // bump STATISTIC W.push_back(MF); } } // process worklist while (!W.empty()) { MachineFunction *MF = W.front(); W.pop_front(); scanAndRewriteCalls(MF, W); } // clear all cloned machine functions that are not marked as single-path // by now for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-maybe")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); if (!PMFI->isSinglePath()) { // delete all MBBs while (MF->begin() != MF->end()) { MF->begin()->eraseFromParent(); } // insert a new single MBB with a single return instruction MachineBasicBlock *EmptyMBB = MF->CreateMachineBasicBlock(); MF->push_back(EmptyMBB); DebugLoc DL; AddDefaultPred(BuildMI(*EmptyMBB, EmptyMBB->end(), DL, TM.getInstrInfo()->get(Patmos::RET))); NumSPCleared++; // bump STATISTIC }; } } return true; }