GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : CompilerHelper(_builder), m_runtimeManager(_runtimeManager) { llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr}; m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule()); m_gasCheckFunc->setDoesNotThrow(); m_gasCheckFunc->setDoesNotCapture(1); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto gasPtr = &m_gasCheckFunc->getArgumentList().front(); gasPtr->setName("gasPtr"); auto cost = gasPtr->getNextNode(); cost->setName("cost"); auto jmpBuf = cost->getNextNode(); jmpBuf->setName("jmpBuf"); InsertPointGuard guard(m_builder); m_builder.SetInsertPoint(checkBB); auto gas = m_builder.CreateLoad(gasPtr, "gas"); auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue); m_builder.SetInsertPoint(updateBB); m_builder.CreateStore(gasUpdated, gasPtr); m_builder.CreateRetVoid(); m_builder.SetInsertPoint(outOfGasBB); m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); }
void ASTInfo::code_gen(llvm::Module *M, llvm::IRBuilder<> &B) { llvm::LLVMContext &context = M->getContext(); if (!__brain_index_ptr) { // Create global variable |brain.index| llvm::Type *Ty = llvm::Type::getInt32Ty(context); const llvm::APInt Zero = llvm::APInt(32, 0); // int32 0 llvm::Constant *InitV = llvm::Constant::getIntegerValue(Ty, Zero); ASTInfo::__brain_index_ptr = new llvm::GlobalVariable(*M, Ty, false, // Keep one copy when linking (weak) llvm::GlobalValue::WeakAnyLinkage, InitV, "brain.index"); } if (!__brain_cells_ptr) { // Create |brain.cells| auto *ArrTy = llvm::ArrayType::get(llvm::Type::getInt32Ty(context), ArgsOptions::instance()->get_cells_size()); // Create a vector of _k_cells_size items equal to 0 std::vector<llvm::Constant *> constants(ArgsOptions::instance()->get_cells_size(), B.getInt32(0)); llvm::ArrayRef<llvm::Constant *> Constants = llvm::ArrayRef<llvm::Constant *>(constants); llvm::Constant *InitPtr = llvm::ConstantArray::get(ArrTy, Constants); ASTInfo::__brain_cells_ptr = new llvm::GlobalVariable(*M, ArrTy, false, // Keep one copy when linking (weak) llvm::GlobalValue::WeakAnyLinkage, InitPtr, "brain.cells"); } }
void RestartOperation::EmitCompiledCode(llvm::IRBuilder<>& irb, llvm::Value * statePointer, llvm::Module * module) { std::vector<llvm::Value*> argVector; argVector.push_back(statePointer); llvm::ArrayRef<llvm::Value*> argArrayRef(argVector); llvm::Function* callee = module->getFunction(metadata_.GetFunctionName()); irb.CreateCall(callee, argArrayRef); }
void LLVMIRGen::setCurrentDebugLocation(llvm::IRBuilder<> &builder, glow::Instruction *I) { if (!emitDebugInfo) return; auto instrNum = instrNumbering_->getInstrNumber(I); auto DILoc = llvm::DILocation::get( ctx_, dbgInfo_.mainFileFirstInstrLineNo_ + instrNum, 0, dbgInfo_.mainF_); llvm::DebugLoc loc(DILoc); builder.SetCurrentDebugLocation(loc); }
void WordOperandOperation::EmitCompiledCode(llvm::IRBuilder<>& irb, llvm::Value * statePointer, llvm::Module * module) { llvm::ConstantInt* operandArgument = llvm::ConstantInt::get(module->getContext(), llvm::APInt(16, operand_)); std::vector<llvm::Value*> argVector; argVector.push_back(statePointer); argVector.push_back(operandArgument); llvm::ArrayRef<llvm::Value*> argArrayRef(argVector); llvm::Function* callee = module->getFunction(metadata_.GetFunctionName()); irb.CreateCall(callee, argArrayRef); }
std::string SwitchExpression::HandleExpressionCase(ExpressionCaseDefinition* expr, std::map<llvm::BasicBlock*, llvm::Value*>& values, std::map<std::string, llvm::BasicBlock*>& association, WasmFunction* fct, llvm::IRBuilder<>& builder) { // Create a CaseExpression and generate the code like that. // First step: find an unused name. std::string name = "anonymous_case"; int idx = 0; std::string final_name; while (1) { std::ostringstream oss; oss << name << "_" << idx; final_name = oss.str(); if (association.find(final_name) == association.end()) { break; } idx++; } // Create and generate the CaseExpression. std::list<Expression*> list; list.push_back(expr->GetExpression()); CaseExpression case_expr(final_name.c_str(), &list); llvm::Value* value = case_expr.Codegen(nullptr, this, fct, builder, true); // Register it. llvm::BasicBlock* bb = builder.GetInsertBlock(); std::string res = bb->getName(); association[res] = bb; // And the value. values[bb] = value; return res; }
llvm::Value* Load(llvm::Value* val) { if(val && isa<llvm::AllocaInst>(val)) return builder.CreateLoad(val); return val; }
void Simulator::Simulate() { llvm::SMDiagnostic error; //std::unique_ptr<llvm::Module> M = llvm::ParseIRFile("Behavior.bc", error, context); //MyModule = M.get(); MyModule = llvm::ParseIRFile("Behavior.bc", error, context); string err_str; /* OwningPtr<MemoryBuffer> result; MemoryBuffer *mb; llvm::error_code ec = MemoryBuffer::getFile("Behavior.bc", result); mb = result.take(); err_str = ec.message(); if (!mb) { error() <<"Cannot open \"" <<bitcode_file() <<"\": " <<err_str <<endl; exit(1); } MyModule = llvm::ParseBitcodeFile(mb,context,&err_str); if (!MyModule) { error() <<"Failed to load module from bitcode file: " <<err_str <<endl; exit(1); } delete mb; */ /* for (llvm::Module::iterator f = MyModule->begin(), ef = MyModule->end(); f!=ef; ++f) { f->addFnAttr(Attributes::AlwaysInline); } */ for (int32_t i = 0; i < (int32_t)OPCODE::INVALID; i++) { OPCODE op = (OPCODE) i; llvm::Function *func = MyModule->getFunction(GetFuncName(op)); func->addFnAttr(llvm::Attribute::AlwaysInline); OpFunctionMap[op] = func; } test_type = MyModule->getFunction("test")->getFunctionType(); std::string ErrStr; passManager = new llvm::PassManager(); passManager->add(llvm::createAlwaysInlinerPass()); fPassManager = new llvm::FunctionPassManager(MyModule); //fPassManager->add(new DataLayout(*EE->getDataLayout())); //fPassManager->add(new DataLayout(*EE->getDataLayout())); fPassManager->add(llvm::createGVNPass()); fPassManager->add(llvm::createInstructionCombiningPass()); fPassManager->add(llvm::createCFGSimplificationPass()); fPassManager->add(llvm::createDeadStoreEliminationPass()); /* llvm::EngineBuilder builder(MyModule); builder.setErrorStr(&ErrStr); builder.setEngineKind(llvm::EngineKind::JIT); builder.setOptLevel(llvm::CodeGenOpt::Default); // None/Less/Default/Aggressive //llvm::TargetOptions options; //options.JITExceptionHandling = 1; //builder.setTargetOptions(options); EE = builder.create(); */ //StringRef MCPU = llvm::sys::getHostCPUName() EE = llvm::EngineBuilder(MyModule).create(); /* EE = llvm::EngineBuilder(std::move(M)) .setErrorStr(&ErrStr) .setMCJITMemoryManager(llvm::make_unique<llvm::SectionMemoryManager>()) .create(); */ /* EE = llvm::EngineBuilder(M) .setErrorStr(&ErrStr) .setMCJITMemoryManager(llvm::SectionMemoryManager()) .create(); EE = llvm::EngineBuilder(std::move(M)).setErrorStr(&ErrStr).create(); */ if (!EE) { fprintf(stderr, "Could not create ExecutionEngine: %s\n", ErrStr.c_str()); exit(1); } EE->DisableLazyCompilation(true); /* //atexit(llvm_shutdown); // Call llvm_shutdown() on exit. //llvm::EngineBuilder builder(MyModule); llvm::EngineBuilder builder(std::move(M)); //llvm::EngineBuilder builder(MyModule); builder.setErrorStr(&err_str); builder.setEngineKind(llvm::EngineKind::JIT); builder.setOptLevel(llvm::CodeGenOpt::Default); // None/Less/Default/Aggressive //TargetOptions options; //options.JITExceptionHandling = 1; //builder.setTargetOptions(options); EE = builder.create(); if (!EE) { std::cout <<"failed to create execution engine: " <<err_str <<"\n"; exit(1); } */ /* //MyModule->dump(); EE = llvm::EngineBuilder(std::move(M)).create(); */ //string ErrStr; //EE = llvm::EngineBuilder(std::move(M)).setErrorStr(&ErrStr).setMCPU("i386").create(); //context = llvm::getGlobalContext(); int32_t index = 0; Blocks = new HostBlock[1000]; int32_t block_index = 0; while(index < total_inst) { Blocks[block_index].pc = index; ostringstream f_name; f_name << "func"; f_name << block_index; //string f_name = string("func");// + string(index); /* llvm::Function *func = llvm::cast<llvm::Function>(MyModule->getOrInsertFunction(f_name.str(), llvm::Type::getVoidTy(context), (llvm::Type *)0)); */ // Make the function type: double(double,double) etc. //std::vector<Type*> Doubles(Args.size(), // Type::getDoubleTy(getGlobalContext())); llvm::FunctionType *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), false); llvm::Function *func = llvm::Function::Create(FT, llvm::Function::ExternalLinkage, f_name.str(), MyModule); //Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, M); // Add a basic block to the function. As before, it automatically inserts // because of the last argument. llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, "EntryBlock", func); // Create a basic block builder with default parameters. The builder will // automatically append instructions to the basic block `BB'. IRB.SetInsertPoint(BB); llvm::Function *sim_func; CInst *inst; int b_size = 0; do { inst = &instructions[index]; llvm::Value *dst = IRB.getInt32(inst->dst_reg); llvm::Value *src0 = IRB.getInt32(inst->src0_reg); llvm::Value *src1 = IRB.getInt32(inst->src1_reg); sim_func = OpFunctionMap[inst->opcode]; llvm::Value *oprnds[] = {dst, src0, src1}; llvm::ArrayRef <llvm::Value *> ref(oprnds, 3); IRB.CreateCall(sim_func, ref); index++; b_size++; //cout << "Index " << index << endl; //} while(b_size < 10 || inst->opcode != OPCODE::JMP); } while(b_size < 10 && index < total_inst); IRB.CreateRetVoid(); passManager->run(*MyModule); fPassManager->run(*func); EE->finalizeObject(); //std::vector<llvm::GenericValue> noargs; //std::cout << "calling " << f_name.str() << endl; //EE->runFunction(func, noargs); //Blocks[block_index].func_ptr = reinterpret_cast<HostFunction>(EE->getPointerToFunction(func)); Blocks[block_index].func_ptr = (void *)(EE->getPointerToFunction(func)); //Blocks[block_index].func_ptr = reinterpret_cast<decltype(HostFunction())>(EE->getPointerToNamedFunction(f_name.str())); //(Blocks[block_index].func_ptr)(); block_index++; //cout << "BlockIndex " << block_index << endl; } total_blocks = block_index; MyModule->dump(); /* cout << "calling add32" << endl; void (*add32)(int32_t, int32_t, int32_t) = reinterpret_cast<void (*)(int32_t, int32_t, int32_t)>(EE->getFunctionAddress("add32")); add32(0, 2, 3); */ /* void (*func0)() = reinterpret_cast<void (*)()>(EE->getFunctionAddress("func1")); func0(); */ /* struct timeval tp; gettimeofday(&tp, NULL); long int start = tp.tv_sec * 1000 + tp.tv_usec / 1000; for (int32_t i = 0; i < 100; i++) { for (int32_t j = 0 ; j < total_blocks; j++) { ((HostFunction)(Blocks[j].func_ptr))(); } } gettimeofday(&tp, NULL); long int end = tp.tv_sec * 1000 + tp.tv_usec / 1000; cout << "Time = " << end - start << endl; */ }
void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRBuilder<>& _builder) { struct BBInfo { BasicBlock& bblock; std::vector<BBInfo*> predecessors; size_t inputItems; size_t outputItems; std::vector<llvm::PHINode*> phisToRewrite; BBInfo(BasicBlock& _bblock) : bblock(_bblock), predecessors(), inputItems(0), outputItems(0) { auto& initialStack = bblock.m_initialStack; for (auto it = initialStack.begin(); it != initialStack.end() && *it != nullptr; ++it, ++inputItems); //if (bblock.localStack().m_tosOffset > 0) // outputItems = bblock.localStack().m_tosOffset; auto& exitStack = bblock.m_currentStack; for (auto it = exitStack.rbegin(); it != exitStack.rend() && *it != nullptr; ++it, ++outputItems); } }; std::map<llvm::BasicBlock*, BBInfo> cfg; // Create nodes in cfg for (auto bb : basicBlocks) cfg.emplace(bb->llvm(), *bb); // Create edges in cfg: for each bb info fill the list // of predecessor infos. for (auto& pair : cfg) { auto bb = pair.first; auto& info = pair.second; for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) { auto predInfoEntry = cfg.find(*predIt); if (predInfoEntry != cfg.end()) info.predecessors.push_back(&predInfoEntry->second); } } // Iteratively compute inputs and outputs of each block, until reaching fixpoint. bool valuesChanged = true; while (valuesChanged) { for (auto& pair : cfg) { DLOG(bb) << pair.second.bblock.llvm()->getName().str() << ": in " << pair.second.inputItems << ", out " << pair.second.outputItems << "\n"; } valuesChanged = false; for (auto& pair : cfg) { auto& info = pair.second; if (info.predecessors.empty()) info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false for (auto predInfo : info.predecessors) { if (predInfo->outputItems < info.inputItems) { info.inputItems = predInfo->outputItems; valuesChanged = true; } else if (predInfo->outputItems > info.inputItems) { predInfo->outputItems = info.inputItems; valuesChanged = true; } } } } // Propagate values between blocks. for (auto& entry : cfg) { auto& info = entry.second; auto& bblock = info.bblock; llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); auto phiIter = bblock.m_initialStack.begin(); for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) { assert(llvm::isa<llvm::PHINode>(*phiIter)); auto phi = llvm::cast<llvm::PHINode>(*phiIter); for (auto predIt : info.predecessors) { auto& predExitStack = predIt->bblock.m_currentStack; auto value = *(predExitStack.end() - 1 - index); phi->addIncoming(value, predIt->bblock.llvm()); } // Move phi to the front if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) { phi->removeFromParent(); _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); _builder.Insert(phi); } } // The items pulled directly from predecessors block must be removed // from the list of items that has to be popped from the initial stack. auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor // blocks and thus should not be on the list of items to be pushed onto // to EVM stack for (auto& entry : cfg) { auto& info = entry.second; auto& bblock = info.bblock; auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } }