void Compiler::CompileNot() { auto entry = cs_.blocks_[cs_.curr_]; auto checkbool = cs_.CreateSubBlock("checkbool", entry); auto assign_by_bool = cs_.CreateSubBlock("assignbool", checkbool); auto assign_by_tag = cs_.CreateSubBlock("assignbytag", assign_by_bool); auto exit = cs_.blocks_[cs_.curr_ + 1]; cs_.B_.SetInsertPoint(entry); auto& ra = stack_.GetR(GETARG_A(cs_.instr_)); auto& rb = stack_.GetR(GETARG_B(cs_.instr_)); auto btag = rb.GetTag(); auto b_is_nil = cs_.B_.CreateICmpEQ(btag, cs_.MakeInt(LUA_TNIL)); cs_.B_.CreateCondBr(b_is_nil, assign_by_tag, checkbool); cs_.B_.SetInsertPoint(checkbool); auto b_is_bool = cs_.B_.CreateICmpEQ(btag, cs_.MakeInt(LUA_TBOOLEAN)); cs_.B_.CreateCondBr(b_is_bool, assign_by_bool, assign_by_tag); cs_.B_.SetInsertPoint(assign_by_tag); auto intt = cs_.rt_.MakeIntT(); auto val = cs_.B_.CreatePHI(intt, 2); val->addIncoming(cs_.MakeInt(1), entry); val->addIncoming(cs_.MakeInt(0), checkbool); ra.SetBoolean(val); cs_.B_.CreateBr(exit); cs_.B_.SetInsertPoint(assign_by_bool); auto b_bool = rb.GetBoolean(); auto not_b = cs_.B_.CreateICmpEQ(b_bool, cs_.MakeInt(0)); auto not_b_int = cs_.B_.CreateIntCast(not_b, intt, false); ra.SetBoolean(not_b_int); cs_.B_.CreateBr(exit); }
void Compiler::CompileUnm() { auto entry = cs_.blocks_[cs_.curr_]; auto checkfloat = cs_.CreateSubBlock("isfloat", entry); auto convert = cs_.CreateSubBlock("convert", checkfloat); auto intop = cs_.CreateSubBlock("intop", convert); auto floatop = cs_.CreateSubBlock("floatop", intop); auto tmop = cs_.CreateSubBlock("tmop", floatop); auto exit = cs_.blocks_[cs_.curr_ + 1]; cs_.B_.SetInsertPoint(entry); auto& ra = stack_.GetR(GETARG_A(cs_.instr_)); auto& rb = stack_.GetR(GETARG_B(cs_.instr_)); auto tag = rb.GetTag(); auto isint = cs_.B_.CreateICmpEQ(tag, cs_.MakeInt(LUA_TNUMINT)); cs_.B_.CreateCondBr(isint, intop, checkfloat); cs_.B_.SetInsertPoint(checkfloat); auto floatval = rb.GetFloat(); auto isfloat = cs_.B_.CreateICmpEQ(tag, cs_.MakeInt(LUA_TNUMFLT)); cs_.B_.CreateCondBr(isfloat, floatop, convert); cs_.B_.SetInsertPoint(convert); auto args = {rb.GetTValue(), cs_.values_.xnumber}; auto tonumberret = cs_.CreateCall("luaV_tonumber_", args); auto convertedval = cs_.B_.CreateLoad(cs_.values_.xnumber); auto convok = cs_.ToBool(tonumberret); cs_.B_.CreateCondBr(convok, floatop, tmop); cs_.B_.SetInsertPoint(intop); auto intresult = cs_.B_.CreateNeg(rb.GetInteger(), "intresult"); ra.SetInteger(intresult); cs_.B_.CreateBr(exit); cs_.B_.SetInsertPoint(floatop); auto floatt = cs_.rt_.GetType("lua_Number"); auto floatphi = cs_.B_.CreatePHI(floatt, 2, "floatphi"); floatphi->addIncoming(floatval, checkfloat); floatphi->addIncoming(convertedval, convert); auto floatresult = cs_.B_.CreateFNeg(floatphi, "floatresult"); ra.SetFloat(floatresult); cs_.B_.CreateBr(exit); cs_.B_.SetInsertPoint(tmop); auto tm_args = { cs_.values_.state, rb.GetTValue(), rb.GetTValue(), ra.GetTValue(), cs_.MakeInt(TM_UNM) }; cs_.CreateCall("luaT_trybinTM", tm_args); stack_.Update(); cs_.B_.CreateBr(exit); }
ComplexValueTy CodeGenFunction::EmitComplexDivSmiths(ComplexValueTy LHS, ComplexValueTy RHS) { auto ElemTy = RHS.Re->getType(); // if(abs(d) <= abs(c)) then auto FabsIntrinsic = GetIntrinsicFunction(llvm::Intrinsic::fabs, ElemTy); auto Predicate = Builder.CreateFCmpOLE(Builder.CreateCall(FabsIntrinsic, RHS.Im), Builder.CreateCall(FabsIntrinsic, RHS.Re)); auto ThenBlock = createBasicBlock("compdiv-then"); auto ElseBlock = createBasicBlock("compdiv-else"); auto MergeBlock = createBasicBlock("compdiv-done"); Builder.CreateCondBr(Predicate, ThenBlock, ElseBlock); llvm::Value *R, *Den, *E, *F; auto ResultRe = llvm::PHINode::Create(ElemTy, 2, "compdiv-re"); auto ResultIm = llvm::PHINode::Create(ElemTy, 2, "compdiv-im"); // r = d / c // den = c + d * r // e = (a + b * r) / den // f = (b - a * r) / den EmitBlock(ThenBlock); R = Builder.CreateFDiv(RHS.Im, RHS.Re); Den = Builder.CreateFAdd(RHS.Re, Builder.CreateFMul(RHS.Im, R)); E = Builder.CreateFDiv(Builder.CreateFAdd(LHS.Re, Builder.CreateFMul(LHS.Im, R)), Den); F = Builder.CreateFDiv(Builder.CreateFSub(LHS.Im, Builder.CreateFMul(LHS.Re, R)), Den); ResultRe->addIncoming(E, ThenBlock); ResultIm->addIncoming(F, ThenBlock); EmitBranch(MergeBlock); // r = c / d // den = c * r + d // e = (a * r + b) / den // f = (b * r - a) / den EmitBlock(ElseBlock); R = Builder.CreateFDiv(RHS.Re, RHS.Im); Den = Builder.CreateFAdd(Builder.CreateFMul(RHS.Re, R), RHS.Im); E = Builder.CreateFDiv(Builder.CreateFAdd( Builder.CreateFMul(LHS.Re, R), LHS.Im), Den); F = Builder.CreateFDiv(Builder.CreateFSub( Builder.CreateFMul(LHS.Im, R), LHS.Re), Den); ResultRe->addIncoming(E, ElseBlock); ResultIm->addIncoming(F, ElseBlock); EmitBranch(MergeBlock); EmitBlock(MergeBlock); Builder.Insert(ResultRe); Builder.Insert(ResultIm); return ComplexValueTy(ResultRe, ResultIm); }
llvm::Function* Array::createArrayPushFunc() { llvm::Type* argTypes[] = {m_array->getType(), Type::Word}; auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule()); func->setDoesNotThrow(); func->setDoesNotCapture(1); auto arrayPtr = &func->getArgumentList().front(); arrayPtr->setName("arrayPtr"); auto value = arrayPtr->getNextNode(); value->setName("value"); InsertPointGuard guard{m_builder}; auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func); auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); m_builder.SetInsertPoint(entryBB); auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto cap = m_builder.CreateLoad(capPtr, "cap"); auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq"); m_builder.CreateCondBr(reallocReq, reallocBB, pushBB); m_builder.SetInsertPoint(reallocBB); auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap"); auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32 auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes"); auto newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes"); auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData"); m_builder.CreateStore(newData, dataPtr); m_builder.CreateStore(newCap, capPtr); m_builder.CreateBr(pushBB); m_builder.SetInsertPoint(pushBB); auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi"); dataPhi->addIncoming(data, entryBB); dataPhi->addIncoming(newData, reallocBB); auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr"); m_builder.CreateStore(value, newElemPtr); auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize"); m_builder.CreateStore(newSize, sizePtr); m_builder.CreateRetVoid(); return func; }
void Compiler::CompileBNot() { auto entry = cs_.blocks_[cs_.curr_]; auto convert = cs_.CreateSubBlock("convert", entry); auto intop = cs_.CreateSubBlock("intop", convert); auto tmop = cs_.CreateSubBlock("tmtop", intop); auto exit = cs_.blocks_[cs_.curr_ + 1]; cs_.B_.SetInsertPoint(entry); auto& ra = stack_.GetR(GETARG_A(cs_.instr_)); auto& rb = stack_.GetR(GETARG_B(cs_.instr_)); auto b_int = rb.GetInteger(); auto b_is_int = rb.HasTag(LUA_TNUMINT); cs_.B_.CreateCondBr(b_is_int, intop, convert); cs_.B_.SetInsertPoint(convert); auto args = { rb.GetTValue(), cs_.values_.meminteger, cs_.MakeInt(LUA_FLOORN2I) }; auto convresult = cs_.CreateCall("luaV_tointeger", args); auto b_conv = cs_.B_.CreateLoad(cs_.values_.meminteger); auto b_is_conv = cs_.ToBool(convresult); cs_.B_.CreateCondBr(b_is_conv, intop, tmop); cs_.B_.SetInsertPoint(intop); auto tluainteger = cs_.rt_.GetType("lua_Integer"); auto b_val = cs_.B_.CreatePHI(tluainteger, 2); b_val->addIncoming(b_int, entry); b_val->addIncoming(b_conv, convert); auto a_val = cs_.B_.CreateNot(b_val); ra.SetInteger(a_val); cs_.B_.CreateBr(exit); cs_.B_.SetInsertPoint(tmop); auto tm_args = { cs_.values_.state, rb.GetTValue(), rb.GetTValue(), ra.GetTValue(), cs_.MakeInt(TM_BNOT) }; cs_.CreateCall("luaT_trybinTM", tm_args); stack_.Update(); cs_.B_.CreateBr(exit); }
llvm::Value *ConditionalNode::generate(GenerateState &state, llvm::Value *read, llvm::Value *header, llvm::Value *error_fn, llvm::Value *error_ctx) { /* Create three blocks: one for the “then”, one for the “else” and one for the * final. */ auto function = state->GetInsertBlock()->getParent(); auto then_block = llvm::BasicBlock::Create(state.module()->getContext(), "then", function); auto else_block = llvm::BasicBlock::Create(state.module()->getContext(), "else", function); auto merge_block = llvm::BasicBlock::Create(state.module()->getContext(), "merge", function); /* Compute the conditional argument and then decide to which block to jump. */ this->condition->writeDebug(state); auto conditional_result = condition->generate(state, read, header, error_fn, error_ctx); state->CreateCondBr(conditional_result, then_block, else_block); /* Generate the “then” block. */ state->SetInsertPoint(then_block); this->then_part->writeDebug(state); auto then_result = then_part->generate(state, read, header, error_fn, error_ctx); /* Jump to the final block. */ state->CreateBr(merge_block); then_block = state->GetInsertBlock(); /* Generate the “else” block. */ state->SetInsertPoint(else_block); this->else_part->writeDebug(state); auto else_result = else_part->generate(state, read, header, error_fn, error_ctx); /* Jump to the final block. */ state->CreateBr(merge_block); else_block = state->GetInsertBlock(); /* Get the two results and select the correct one using a PHI node. */ state->SetInsertPoint(merge_block); auto phi = state->CreatePHI(llvm::Type::getInt1Ty(state.module()->getContext()), 2); phi->addIncoming(then_result, then_block); phi->addIncoming(else_result, else_block); return phi; }
llvm::Value *ConditionalNode::generateIndex(GenerateState &state, llvm::Value *tid, llvm::Value *header, llvm::Value *error_fn, llvm::Value *error_ctx) { if (condition->usesIndex()) { /* * The logic in this function is twisty, so here is the explanation. Given * we have `C ? T : E`, consider the following cases during index building: * * 1. C is true. If C is true, we don't know if it will necessarily always * return true to this chromosome in the query, so we might execute T or E. * Therefore, whether this is true is `T | E`. * * 2. C is false. If C is false, T will never be executed. E might be * executed, so we should return E. */ /* Create three blocks: one for the “then”, one for the “else” and one for * the final. */ auto function = state->GetInsertBlock()->getParent(); auto then_block = llvm::BasicBlock::Create(state.module()->getContext(), "then", function); auto else_block = llvm::BasicBlock::Create(state.module()->getContext(), "else", function); auto merge_block = llvm::BasicBlock::Create(state.module()->getContext(), "merge", function); /* Compute the conditional argument and then decide to which block to jump. * If true, try to make a decision based on the “then” block, otherwise, * only make a decision based on the “else” block. */ this->condition->writeDebug(state); auto conditional_result = condition->generateIndex(state, tid, header, error_fn, error_ctx); state->CreateCondBr(conditional_result, then_block, else_block); /* Generate the “then” block. */ state->SetInsertPoint(then_block); this->then_part->writeDebug(state); auto then_result = then_part->generateIndex(state, tid, header, error_fn, error_ctx); /* If we fail, the “else” block might still be interested. */ state->CreateCondBr(then_result, merge_block, else_block); then_block = state->GetInsertBlock(); /* Generate the “else” block. */ state->SetInsertPoint(else_block); this->else_part->writeDebug(state); auto else_result = else_part->generateIndex(state, tid, header, error_fn, error_ctx); /* Jump to the final block. */ state->CreateBr(merge_block); else_block = state->GetInsertBlock(); /* Get the two results and select the correct one using a PHI node. */ state->SetInsertPoint(merge_block); auto phi = state->CreatePHI( llvm::Type::getInt1Ty(state.module()->getContext()), 2); phi->addIncoming(then_result, then_block); phi->addIncoming(else_result, else_block); return phi; } if (then_part->usesIndex() && else_part->usesIndex()) { auto function = state->GetInsertBlock()->getParent(); auto else_block = llvm::BasicBlock::Create(state.module()->getContext(), "else", function); auto merge_block = llvm::BasicBlock::Create(state.module()->getContext(), "merge", function); auto then_result = then_part->generateIndex(state, tid, header, error_fn, error_ctx); state->CreateCondBr(then_result, merge_block, else_block); auto original_block = state->GetInsertBlock(); state->SetInsertPoint(else_block); this->else_part->writeDebug(state); auto else_result = else_part->generateIndex(state, tid, header, error_fn, error_ctx); state->CreateBr(merge_block); else_block = state->GetInsertBlock(); state->SetInsertPoint(merge_block); auto phi = state->CreatePHI( llvm::Type::getInt1Ty(state.module()->getContext()), 2); phi->addIncoming(then_result, original_block); phi->addIncoming(else_result, else_block); return phi; } return llvm::ConstantInt::getTrue(state.module()->getContext()); }
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 } }
void RaviCodeGenerator::emit_FORPREP(RaviFunctionDef *def, int A, int pc, int pc1) { // case OP_FORPREP: { // if (ttisinteger(init) && ttisinteger(pstep) && // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { // /* all values are integer */ // lua_Integer initv = (stopnow ? 0 : ivalue(init)); // setivalue(plimit, ilimit); // setivalue(init, initv - ivalue(pstep)); // } // else { /* try making all values floats */ // if (!tonumber(plimit, &nlimit)) // luaG_runerror(L, "'for' limit must be a number"); // setfltvalue(plimit, nlimit); // if (!tonumber(pstep, &nstep)) // luaG_runerror(L, "'for' step must be a number"); // setfltvalue(pstep, nstep); // if (!tonumber(init, &ninit)) // luaG_runerror(L, "'for' initial value must be a number"); // setfltvalue(init, luai_numsub(L, ninit, nstep)); // } // ci->u.l.savedpc += GETARG_sBx(i); //} break; emit_debug_trace(def, OP_FORPREP, pc1); // Load pointer to base emit_load_base(def); // lua_Integer ilimit; // int stopnow; // lua_Number ninit; lua_Number nlimit; lua_Number nstep; llvm::IRBuilder<> TmpB(def->entry, def->entry->begin()); llvm::Value *ilimit = TmpB.CreateAlloca(def->types->lua_IntegerT, nullptr, "ilimit"); llvm::Value *stopnow = TmpB.CreateAlloca(def->types->C_intT, nullptr, "stopnow"); llvm::Value *nlimit = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nlimit"); llvm::Value *ninit = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "ninit"); llvm::Value *nstep = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nstep"); // TValue *init = ra; // TValue *plimit = ra + 1; // TValue *pstep = ra + 2; llvm::Value *init = emit_gep_register(def, A); llvm::Value *plimit = emit_gep_register(def, A + 1); llvm::Value *pstep = emit_gep_register(def, A + 2); // if (ttisinteger(init) && ttisinteger(pstep) && // forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { // Get init->tt_ llvm::Instruction *pinit_tt = emit_load_type(def, init); // Compare init->tt_ == LUA_TNUMINT llvm::Value *cmp1 = emit_is_value_of_type(def, pinit_tt, LUA__TNUMINT, "init.is.integer"); // Get pstep->tt_ llvm::Instruction *pstep_tt = emit_load_type(def, pstep); // Compare pstep->tt_ == LUA_TNUMINT llvm::Value *icmp2 = emit_is_value_of_type(def, pstep_tt, LUA__TNUMINT, "step.is.integer"); // Get ivalue(pstep) llvm::Instruction *pstep_ivalue = emit_load_reg_i(def, pstep); // Call forlimit() llvm::Value *forlimit_ret = CreateCall4( def->builder, def->luaV_forlimitF, plimit, ilimit, pstep_ivalue, stopnow); // init->tt_ == LUA_TNUMINT && pstep->tt_ == LUA_TNUMINT llvm::Value *and1 = def->builder->CreateAnd(cmp1, icmp2, "init.and.step.are.integers"); // Convert result from forlimit() to bool llvm::Value *tobool = def->builder->CreateICmpNE(forlimit_ret, def->types->kInt[0]); // init->tt_ == LUA_TNUMINT && pstep->tt_ == LUA_TNUMINT && forlimit() llvm::Value *and2 = def->builder->CreateAnd(and1, tobool, "all.integers"); // Create if then else branch llvm::BasicBlock *then1 = llvm::BasicBlock::Create(def->jitState->context(), "if.all.integers", def->f); llvm::BasicBlock *else1 = llvm::BasicBlock::Create(def->jitState->context(), "if.not.all.integers"); def->builder->CreateCondBr(and2, then1, else1); def->builder->SetInsertPoint(then1); // all values are integers // lua_Integer initv = (stopnow ? 0 : ivalue(init)); // Get stopnow llvm::Instruction *stopnow_val = emit_load_local_int(def, stopnow); // Test if stopnow is 0 llvm::Value *stopnow_is_zero = def->builder->CreateICmpEQ( stopnow_val, def->types->kInt[0], "stopnow.is.zero"); // Setup if then else branch for stopnow llvm::BasicBlock *then1_iffalse = llvm::BasicBlock::Create( def->jitState->context(), "if.stopnow.iszero", def->f); llvm::BasicBlock *then1_iftrue = llvm::BasicBlock::Create(def->jitState->context(), "if.stopnow.notzero"); def->builder->CreateCondBr(stopnow_is_zero, then1_iffalse, then1_iftrue); def->builder->SetInsertPoint(then1_iffalse); // stopnow is 0 // Get init->i llvm::Instruction *init_ivalue = emit_load_reg_i(def, init); // Join after the branch def->builder->CreateBr(then1_iftrue); def->f->getBasicBlockList().push_back(then1_iftrue); def->builder->SetInsertPoint(then1_iftrue); // Set initv to 0 if !stopnow else init->i auto phi1 = def->builder->CreatePHI(def->types->lua_IntegerT, 2, "initv"); phi1->addIncoming(init_ivalue, then1_iffalse); phi1->addIncoming(def->types->kluaInteger[0], then1); // setivalue(plimit, ilimit); llvm::Instruction *ilimit_val = emit_load_local_n(def, ilimit); emit_store_reg_i_withtype(def, ilimit_val, plimit); // setivalue(init, initv - ivalue(pstep)); // we aleady know init is LUA_TNUMINT pstep_ivalue = emit_load_reg_i(def, pstep); llvm::Value *sub = def->builder->CreateSub(phi1, pstep_ivalue, "initv-pstep.i", false, true); emit_store_reg_i(def, sub, init); // We are done so jump to forloop lua_assert(def->jmp_targets[pc].jmp1); def->builder->CreateBr(def->jmp_targets[pc].jmp1); // NOW the non-integer case def->f->getBasicBlockList().push_back(else1); def->builder->SetInsertPoint(else1); // ************ PLIMIT - Convert plimit to float llvm::Instruction *plimit_tt = emit_load_type(def, plimit); // Test if already a float cmp1 = emit_is_value_of_type(def, plimit_tt, LUA__TNUMFLT, "limit.is.float"); llvm::BasicBlock *else1_plimit_ifnum = llvm::BasicBlock::Create( def->jitState->context(), "if.limit.isfloat", def->f); llvm::BasicBlock *else1_plimit_elsenum = llvm::BasicBlock::Create(def->jitState->context(), "if.limit.notfloat"); def->builder->CreateCondBr(cmp1, else1_plimit_ifnum, else1_plimit_elsenum); def->builder->SetInsertPoint(else1_plimit_ifnum); // Already a float - copy to nlimit llvm::Instruction *plimit_nvalue_load = emit_load_reg_n(def, plimit); emit_store_local_n(def, plimit_nvalue_load, nlimit); // Go to the PSTEP section llvm::BasicBlock *else1_pstep = llvm::BasicBlock::Create(def->jitState->context(), "if.else.step"); def->builder->CreateBr(else1_pstep); // If plimit was not already a float we need to convert def->f->getBasicBlockList().push_back(else1_plimit_elsenum); def->builder->SetInsertPoint(else1_plimit_elsenum); // Call luaV_tonumber_() llvm::Value *plimit_isnum = CreateCall2(def->builder, def->luaV_tonumberF, plimit, nlimit); llvm::Value *plimit_isnum_bool = def->builder->CreateICmpEQ( plimit_isnum, def->types->kInt[0], "limit.float.ok"); // Did conversion fail? llvm::BasicBlock *else1_plimit_tonum_elsenum = llvm::BasicBlock::Create( def->jitState->context(), "if.limit.float.failed", def->f); def->builder->CreateCondBr(plimit_isnum_bool, else1_plimit_tonum_elsenum, else1_pstep); // Conversion failed, so raise error def->builder->SetInsertPoint(else1_plimit_tonum_elsenum); emit_raise_lua_error(def, "'for' limit must be a number"); def->builder->CreateBr(else1_pstep); // Conversion OK // Update plimit def->f->getBasicBlockList().push_back(else1_pstep); def->builder->SetInsertPoint(else1_pstep); llvm::Instruction *nlimit_load = emit_load_local_n(def, nlimit); emit_store_reg_n_withtype(def, nlimit_load, plimit); // *********** PSTEP - convert pstep to float // Test if already a float pstep_tt = emit_load_type(def, pstep); cmp1 = emit_is_value_of_type(def, pstep_tt, LUA__TNUMFLT, "step.is.float"); llvm::BasicBlock *else1_pstep_ifnum = llvm::BasicBlock::Create( def->jitState->context(), "if.step.isfloat", def->f); llvm::BasicBlock *else1_pstep_elsenum = llvm::BasicBlock::Create(def->jitState->context(), "if.step.notfloat"); def->builder->CreateCondBr(cmp1, else1_pstep_ifnum, else1_pstep_elsenum); def->builder->SetInsertPoint(else1_pstep_ifnum); // We float then copy to nstep llvm::Instruction *pstep_nvalue_load = emit_load_reg_n(def, pstep); emit_store_local_n(def, pstep_nvalue_load, nstep); // Now go to handle initial value llvm::BasicBlock *else1_pinit = llvm::BasicBlock::Create(def->jitState->context(), "if.else.init"); def->builder->CreateBr(else1_pinit); // If pstep was not already a float then we need to convert def->f->getBasicBlockList().push_back(else1_pstep_elsenum); def->builder->SetInsertPoint(else1_pstep_elsenum); // call luaV_tonumber_() llvm::Value *pstep_isnum = CreateCall2(def->builder, def->luaV_tonumberF, pstep, nstep); llvm::Value *pstep_isnum_bool = def->builder->CreateICmpEQ( pstep_isnum, def->types->kInt[0], "step.float.ok"); llvm::BasicBlock *else1_pstep_tonum_elsenum = llvm::BasicBlock::Create( def->jitState->context(), "if.step.float.failed", def->f); def->builder->CreateCondBr(pstep_isnum_bool, else1_pstep_tonum_elsenum, else1_pinit); // If conversion failed raise error def->builder->SetInsertPoint(else1_pstep_tonum_elsenum); emit_raise_lua_error(def, "'for' step must be a number"); def->builder->CreateBr(else1_pinit); // Conversion okay so update pstep def->f->getBasicBlockList().push_back(else1_pinit); def->builder->SetInsertPoint(else1_pinit); llvm::Instruction *nstep_load = emit_load_local_n(def, nstep); emit_store_reg_n_withtype(def, nstep_load, pstep); // *********** PINIT finally handle initial value // Check if it is already a float pinit_tt = emit_load_type(def, init); cmp1 = emit_is_value_of_type(def, pinit_tt, LUA__TNUMFLT, "init.is.float"); llvm::BasicBlock *else1_pinit_ifnum = llvm::BasicBlock::Create( def->jitState->context(), "if.init.is.float", def->f); llvm::BasicBlock *else1_pinit_elsenum = llvm::BasicBlock::Create(def->jitState->context(), "if.init.not.float"); def->builder->CreateCondBr(cmp1, else1_pinit_ifnum, else1_pinit_elsenum); def->builder->SetInsertPoint(else1_pinit_ifnum); // Already float so copy to ninit llvm::Instruction *pinit_nvalue_load = emit_load_reg_n(def, init); emit_store_local_n(def, pinit_nvalue_load, ninit); // Go to final section llvm::BasicBlock *else1_pdone = llvm::BasicBlock::Create(def->jitState->context(), "if.else.done"); def->builder->CreateBr(else1_pdone); // Not a float so we need to convert def->f->getBasicBlockList().push_back(else1_pinit_elsenum); def->builder->SetInsertPoint(else1_pinit_elsenum); // Call luaV_tonumber_() llvm::Value *pinit_isnum = CreateCall2(def->builder, def->luaV_tonumberF, init, ninit); llvm::Value *pinit_isnum_bool = def->builder->CreateICmpEQ( pinit_isnum, def->types->kInt[0], "init.float.ok"); llvm::BasicBlock *else1_pinit_tonum_elsenum = llvm::BasicBlock::Create( def->jitState->context(), "if.init.float.failed", def->f); def->builder->CreateCondBr(pinit_isnum_bool, else1_pinit_tonum_elsenum, else1_pdone); // Conversion failed so raise error def->builder->SetInsertPoint(else1_pinit_tonum_elsenum); emit_raise_lua_error(def, "'for' initial value must be a number"); def->builder->CreateBr(else1_pdone); // Conversion OK so we are nearly done def->f->getBasicBlockList().push_back(else1_pdone); def->builder->SetInsertPoint(else1_pdone); llvm::Instruction *ninit_load = emit_load_local_n(def, ninit); nstep_load = emit_load_local_n(def, nstep); // setfltvalue(init, luai_numsub(L, ninit, nstep)); llvm::Value *init_n = def->builder->CreateFSub(ninit_load, nstep_load, "ninit-nstep"); emit_store_reg_n_withtype(def, init_n, init); // Done so jump to forloop def->builder->CreateBr(def->jmp_targets[pc].jmp1); }