Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
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;
}
Example #5
0
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);
}
Example #6
0
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;
}
Example #7
0
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());
}
Example #8
0
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
	}
}
Example #9
0
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);
}