Exemple #1
0
  void* Compiler::generate_function(bool indy) {
    if(!mci_) {
      if(!function_) return NULL;

      if(indy) ctx_->llvm_state()->shared().gc_independent(ctx_->llvm_state());
      if(ctx_->llvm_state()->jit_dump_code() & cSimple) {
        llvm::outs() << "[[[ LLVM Simple IR ]]]\n";
        llvm::outs() << *function_ << "\n";
      }

      std::vector<BasicBlock*> to_remove;
      bool Broken = false;
      for(Function::iterator I = function_->begin(),
          E = function_->end();
          I != E;
          ++I)
      {
        if(I->empty()) {
          BasicBlock& bb = *I;
          // No one jumps to it....
          if(llvm::pred_begin(&bb) == llvm::pred_end(&bb)) {
            to_remove.push_back(&bb);
          } else {
            llvm::outs() << "Basic Block is empty and used!\n";
          }
        } else if(!I->back().isTerminator()) {
          llvm::errs() << "Basic Block does not have terminator!\n";
          llvm::errs() << *I << "\n";
          llvm::errs() << "\n";
          Broken = true;
        }
      }

      for(std::vector<BasicBlock*>::iterator i = to_remove.begin();
          i != to_remove.end();
          ++i) {
        (*i)->eraseFromParent();
      }

      if(Broken or llvm::verifyFunction(*function_, PrintMessageAction)) {
        llvm::outs() << "ERROR: complication error detected.\n";
        llvm::outs() << "ERROR: Please report the above message and the\n";
        llvm::outs() << "       code below to http://github.com/rubinius/rubinius/issues\n";
        llvm::outs() << *function_ << "\n";
        function_ = NULL;
        if(indy) ctx_->llvm_state()->shared().gc_dependent(ctx_->llvm_state());
        return NULL;
      }

      ctx_->passes()->run(*function_);

      if(ctx_->llvm_state()->jit_dump_code() & cOptimized) {
        llvm::outs() << "[[[ LLVM Optimized IR: ]]]\n";
        llvm::outs() << *function_ << "\n";
      }

      mci_ = new llvm::MachineCodeInfo();
      ctx_->engine()->runJITOnFunction(function_, mci_);
      ctx_->llvm_state()->add_code_bytes(mci_->size());

      // If we're not in JIT debug mode, delete the body IR, now that we're
      // done with it.
      // This saves us 100M+ of memory in a full spec run.
      if(!ctx_->llvm_state()->debug_p()) {
        function_->dropAllReferences();
      }

      if(indy) ctx_->llvm_state()->shared().gc_dependent(ctx_->llvm_state());

      // Inject the RuntimeData objects used into the original CompiledCode
      // Do this way after we've validated the IR so things are consistent.

      void* native_function = ctx_->native_function();

      ctx_->runtime_data_holder()->set_function(native_function,
                                   mci_->address(), mci_->size());

      // info.method()->set_jit_data(ctx.runtime_data_holder());
      ctx_->llvm_state()->shared().om->add_code_resource(ctx_->runtime_data_holder());
    }

    return mci_->address();
  }
Exemple #2
0
Function* Decompiler::decompileFunction(unsigned Address) {
  // Check that Address is inside the current section.
  // TODO: Find a better way to do this check. What we really care about is
  // avoiding reads to library calls and areas of memory we can't "see".
  const object::SectionRef Sect = Dis->getCurrentSection();
  uint64_t SectStart, SectEnd;
  Sect.getAddress(SectStart);
  Sect.getSize(SectEnd);
  SectEnd += SectStart;
  if (Address < SectStart || Address > SectEnd) {
    errs() << "Address out of bounds for section (is this a library call?): "
           << format("%1" PRIx64, Address) << "\n";
    return NULL;
  }

  MachineFunction *MF = Dis->disassemble(Address);

  // Get Function Name
  // TODO: Determine Function Type
  FunctionType *FType = FunctionType::get(Type::getPrimitiveType(*Context,
      Type::VoidTyID), false);
  Function *F =
    cast<Function>(Mod->getOrInsertFunction(MF->getName(), FType));

  if (!F->empty()) {
    return F;
  }

  // Create a basic block to hold entry point (alloca) information
  BasicBlock *entry = getOrCreateBasicBlock("entry", F);

  // For each basic block
  MachineFunction::iterator BI = MF->begin(), BE = MF->end();
  while (BI != BE) {
    // Add branch from "entry"
    if (BI == MF->begin()) {
      entry->getInstList().push_back(
        BranchInst::Create(getOrCreateBasicBlock(BI->getName(), F)));
    } else {
      getOrCreateBasicBlock(BI->getName(), F);
    }
    ++BI;
  }

  BI = MF->begin();
  while (BI != BE) {
    if (decompileBasicBlock(BI, F) == NULL) {
      printError("Unable to decompile basic block!");
    }
    ++BI;
  }

  // During Decompilation, did any "in-between" basic blocks get created?
  // Nothing ever splits the entry block, so we skip it.
  for (Function::iterator I = ++F->begin(), E = F->end(); I != E; ++I) {
    if (!(I->empty())) {
      continue;
    }
    // Right now, the only way to get the right offset is to parse its name
    // it sucks, but it works.
    StringRef Name = I->getName();
    if (Name == "end" || Name == "entry") continue; // these can be empty

    size_t Off = F->getName().size() + 1;
    size_t Size = Name.size() - Off;
    StringRef BBAddrStr = Name.substr(Off, Size);
    unsigned long long BBAddr;
    getAsUnsignedInteger(BBAddrStr, 10, BBAddr);
    BBAddr += Address;
    DEBUG(errs() << "Split Target: " << Name << "\t Address: "
                 << BBAddr << "\n");
    // split Block at AddrStr
    Function::iterator SB;      // Split basic block
    BasicBlock::iterator SI, SE;    // Split instruction
    // Note the ++, nothing ever splits the entry block.
    for (SB = ++F->begin(); SB != E; ++SB) {
      DEBUG(outs() << "SB: " << SB->getName()
        << "\tRange: " << Dis->getDebugOffset(SB->begin()->getDebugLoc())
        << " " << Dis->getDebugOffset(SB->getTerminator()->getDebugLoc())
        << "\n");
      if (SB->empty() || BBAddr < getBasicBlockAddress(SB)
        || BBAddr > Dis->getDebugOffset(SB->getTerminator()->getDebugLoc())) {
        continue;
      }
      // Reorder instructions based on Debug Location
      sortBasicBlock(SB);
      DEBUG(errs() << "Found Split Block: " << SB->getName() << "\n");
      // Find iterator to split on.
      for (SI = SB->begin(), SE = SB->end(); SI != SE; ++SI) {
        // outs() << "SI: " << SI->getDebugLoc().getLine() << "\n";
        if (Dis->getDebugOffset(SI->getDebugLoc()) == BBAddr) break;
        if (Dis->getDebugOffset(SI->getDebugLoc()) > BBAddr) {
          errs() << "Could not find address inside basic block!\n"
                 << "SI: " << Dis->getDebugOffset(SI->getDebugLoc()) << "\n"
                 << "BBAddr: " << BBAddr << "\n";
          break;
        }
      }
      break;
    }
    if (!SB || SI == SE || SB == E) {
      errs() << "Decompiler: Failed to find instruction offset in function!\n";
      continue;
    }
    // outs() << SB->getName() << " " << SI->getName() << "\n";
    // outs() << "Creating Block...";
    splitBasicBlockIntoBlock(SB, SI, I);
  }

  // Clean up unnecessary stores and loads
  FunctionPassManager FPM(Mod);
  // FPM.add(createPromoteMemoryToRegisterPass()); // See Scalar.h for more.
  FPM.add(createTypeRecoveryPass());
  FPM.run(*F);

  return F;
}
Exemple #3
0
  void LLVMCompiler::compile(LLVMState* ls, VMMethod* vmm, bool is_block) {
    if(ls->config().jit_inline_debug) {
      if(is_block) {
        VMMethod* parent = vmm->parent();
        assert(parent);

        llvm::errs() << "JIT: compiling block in "
                  << ls->symbol_cstr(parent->original->scope()->module()->name())
                  << "#"
                  << ls->symbol_cstr(vmm->original->name())
                  << " near "
                  << ls->symbol_cstr(vmm->original->file()) << ":"
                  << vmm->original->start_line() << "\n";
      } else {
        llvm::errs() << "JIT: compiling "
                  << ls->symbol_cstr(vmm->original->scope()->module()->name())
                  << "#"
                  << ls->symbol_cstr(vmm->original->name()) << "\n";
      }
    }

    JITMethodInfo info(vmm);
    info.is_block = is_block;

    LLVMWorkHorse work(ls, info);

    if(is_block) {
      work.setup_block();
    } else {
      work.setup();
    }

    llvm::Function* func = info.function();

    if(!work.generate_body()) {
      function_ = NULL;
      // This is too noisy to report
      // llvm::outs() << "not supported yet.\n";
      return;
    }

    if(ls->jit_dump_code() & cSimple) {
      llvm::outs() << "[[[ LLVM Simple IR ]]]\n";
      llvm::outs() << *func << "\n";
    }

    std::vector<BasicBlock*> to_remove;
    bool Broken = false;
    for(Function::iterator I = func->begin(), E = func->end(); I != E; ++I) {
      if(I->empty()) {
        BasicBlock& bb = *I;
        // No one jumps to it....
        if(llvm::pred_begin(&bb) == llvm::pred_end(&bb)) {
          to_remove.push_back(&bb);
        } else {
          llvm::outs() << "Basic Block is empty and used!\n";
        }
      } else if(!I->back().isTerminator()) {
        llvm::errs() << "Basic Block does not have terminator!\n";
        llvm::errs() << *I << "\n";
        llvm::errs() << "\n";
        Broken = true;
      }
    }

    for(std::vector<BasicBlock*>::iterator i = to_remove.begin();
        i != to_remove.end();
        i++) {
      (*i)->eraseFromParent();
    }

    if(Broken or llvm::verifyFunction(*func, PrintMessageAction)) {
      llvm::outs() << "ERROR: complication error detected.\n";
      llvm::outs() << "ERROR: Please report the above message and the\n";
      llvm::outs() << "       code below to http://github.com/evanphx/rubinius/issues\n";
      llvm::outs() << *func << "\n";
      function_ = NULL;
      return;
    }

    ls->passes()->run(*func);

    if(ls->jit_dump_code() & cOptimized) {
      llvm::outs() << "[[[ LLVM Optimized IR: "
        << ls->symbol_cstr(vmm->original->name()) << " ]]]\n";
      llvm::outs() << *func << "\n";
    }

    function_ = func;
  }
Exemple #4
0
  void Compiler::compile_builder(jit::Context& ctx, LLVMState* ls, JITMethodInfo& info,
                                     jit::Builder& work)
  {
    llvm::Function* func = info.function();

    if(!work.generate_body()) {
      function_ = NULL;
      // This is too noisy to report
      // llvm::outs() << "not supported yet.\n";
      return;
    }

    // Hook up the return pad and return phi.
    work.generate_hard_return();

    if(ls->jit_dump_code() & cSimple) {
      llvm::outs() << "[[[ LLVM Simple IR ]]]\n";
      llvm::outs() << *func << "\n";
    }

    std::vector<BasicBlock*> to_remove;
    bool Broken = false;
    for(Function::iterator I = func->begin(), E = func->end(); I != E; ++I) {
      if(I->empty()) {
        BasicBlock& bb = *I;
        // No one jumps to it....
        if(llvm::pred_begin(&bb) == llvm::pred_end(&bb)) {
          to_remove.push_back(&bb);
        } else {
          llvm::outs() << "Basic Block is empty and used!\n";
        }
      } else if(!I->back().isTerminator()) {
        llvm::errs() << "Basic Block does not have terminator!\n";
        llvm::errs() << *I << "\n";
        llvm::errs() << "\n";
        Broken = true;
      }
    }

    for(std::vector<BasicBlock*>::iterator i = to_remove.begin();
        i != to_remove.end();
        ++i) {
      (*i)->eraseFromParent();
    }

    if(Broken or llvm::verifyFunction(*func, PrintMessageAction)) {
      llvm::outs() << "ERROR: complication error detected.\n";
      llvm::outs() << "ERROR: Please report the above message and the\n";
      llvm::outs() << "       code below to http://github.com/rubinius/rubinius/issues\n";
      llvm::outs() << *func << "\n";
      function_ = NULL;
      return;
    }

    ls->passes()->run(*func);

    if(ls->jit_dump_code() & cOptimized) {
      llvm::outs() << "[[[ LLVM Optimized IR: "
        << ls->symbol_cstr(info.method()->name()) << " ]]]\n";
      llvm::outs() << *func << "\n";
    }

    function_ = func;

    generate_function(ls);

    // Inject the RuntimeData objects used into the original CompiledMethod
    // Do this way after we've validated the IR so things are consistent.
    ctx.runtime_data_holder()->set_function(func, mci_->address(), mci_->size());

    info.method()->set_jit_data(ctx.runtime_data_holder());
    ls->shared().om->add_code_resource(ctx.runtime_data_holder());

  }