You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/src/ravi_llvmforloop.cpp

454 lines
17 KiB

/******************************************************************************
* Copyright (C) 2015-2020 Dibyendu Majumdar
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include "ravi_llvmcodegen.h"
namespace ravi {
void RaviCodeGenerator::emit_FORLOOP2(RaviFunctionDef *def, int A, int pc,
RaviBranchDef &b, int pc1) {
// 7[1] FORLOOP 1 - 2; to 6
// if (ttisinteger(ra)) { /* integer loop? */
// lua_Integer step = ivalue(ra + 2);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
// lua_Integer limit = ivalue(ra + 1);
// if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setivalue(ra, idx); /* update internal index... */
// setivalue(ra + 3, idx); /* ...and external index */
// }
//}
// else { /* floating loop */
// lua_Number step = fltvalue(ra + 2);
// lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
// lua_Number limit = fltvalue(ra + 1);
// if (luai_numlt(0, step) ? luai_numle(idx, limit)
// : luai_numle(limit, idx)) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setfltvalue(ra, idx); /* update internal index... */
// setfltvalue(ra + 3, idx); /* ...and external index */
// }
//}
emit_debug_trace(def, OP_FORLOOP, pc1);
// We are in b.jmp1 as this is already the current block
lua_assert(def->builder->GetInsertBlock() == b.jmp1);
// Obtain pointers to the value.i field
llvm::Value *step_int_ptr = b.istep;
llvm::Value *idx_int_ptr = b.iidx;
llvm::Value *limit_int_ptr = b.ilimit;
// Obtain pointers to the value.n field
llvm::Value *step_double_ptr = b.fstep;
llvm::Value *idx_double_ptr = b.fidx;
llvm::Value *limit_double_ptr = b.flimit;
// Create the done block
llvm::BasicBlock *exit_block =
llvm::BasicBlock::Create(def->jitState->context(), "exit_iforloop");
// INTEGER CASE
// lua_Integer step = ivalue(ra + 2);
llvm::Instruction *step_int_value = emit_load_local_n(def, step_int_ptr);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
llvm::Instruction *idx_int_value = emit_load_local_n(def, idx_int_ptr);
llvm::Value *new_idx = def->builder->CreateAdd(step_int_value, idx_int_value,
"next.idx", false, true);
emit_store_local_n(def, new_idx, idx_int_ptr);
// lua_Integer limit = ivalue(ra + 1);
llvm::Instruction *limit_int_value = emit_load_local_n(def, limit_int_ptr);
// idx > limit?
llvm::Value *new_idx_gt_limit =
def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit");
// If idx > limit we are done
llvm::BasicBlock *update_block =
llvm::BasicBlock::Create(def->jitState->context(), "updatei");
def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block);
// NOW INTEGER step < 0
def->f->getBasicBlockList().push_back(b.jmp2);
def->builder->SetInsertPoint(b.jmp2);
step_int_value = emit_load_local_n(def, step_int_ptr);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
idx_int_value = emit_load_local_n(def, idx_int_ptr);
new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, "next.idx",
false, true);
emit_store_local_n(def, new_idx, idx_int_ptr);
// lua_Integer limit = ivalue(ra + 1);
limit_int_value = emit_load_local_n(def, limit_int_ptr);
// limit > idx?
llvm::Value *limit_gt_idx =
def->builder->CreateICmpSGT(limit_int_value, new_idx, "limit.gt.idx");
// If limit > idx we are done
def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block);
// Merge into update block
def->f->getBasicBlockList().push_back(update_block);
def->builder->SetInsertPoint(update_block);
emit_load_base(def);
llvm::Value *rvar = emit_gep_register(def, A + 3);
// setivalue(ra + 3, idx); /* ...and external index */
idx_int_value = emit_load_local_n(def, idx_int_ptr);
emit_store_reg_i_withtype(def, idx_int_value, rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
def->builder->CreateBr(def->jmp_targets[pc].jmp1);
// FLOATING CASE
def->f->getBasicBlockList().push_back(b.jmp3);
def->builder->SetInsertPoint(b.jmp3);
// lua_Number step = fltvalue(ra + 2);
llvm::Instruction *step_double_value =
emit_load_local_n(def, step_double_ptr);
// lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
llvm::Instruction *idx_double_value = emit_load_local_n(def, idx_double_ptr);
new_idx =
def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx");
emit_store_local_n(def, new_idx, idx_double_ptr);
// lua_Number limit = fltvalue(ra + 1);
llvm::Instruction *limit_double_value =
emit_load_local_n(def, limit_double_ptr);
// step > 0?
// idx > limit?
new_idx_gt_limit =
def->builder->CreateFCmpOGT(new_idx, limit_double_value, "idx.gt.limit");
// If idx > limit we are done
update_block = llvm::BasicBlock::Create(def->jitState->context(), "updatef");
def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block);
def->f->getBasicBlockList().push_back(b.jmp4);
def->builder->SetInsertPoint(b.jmp4);
// lua_Number step = fltvalue(ra + 2);
step_double_value = emit_load_local_n(def, step_double_ptr);
// lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
idx_double_value = emit_load_local_n(def, idx_double_ptr);
new_idx =
def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx");
emit_store_local_n(def, new_idx, idx_double_ptr);
// lua_Number limit = fltvalue(ra + 1);
limit_double_value = emit_load_local_n(def, limit_double_ptr);
// limit > idx?
limit_gt_idx =
def->builder->CreateFCmpOGT(limit_double_value, new_idx, "limit.gt.idx");
// If limit > idx we are done
def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block);
// Merge into update block
def->f->getBasicBlockList().push_back(update_block);
def->builder->SetInsertPoint(update_block);
emit_load_base(def);
rvar = emit_gep_register(def, A + 3);
// setfltvalue(ra + 3, idx); /* ...and external index */
idx_double_value = emit_load_local_n(def, idx_double_ptr);
emit_store_reg_n_withtype(def, idx_double_value, rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
def->builder->CreateBr(def->jmp_targets[pc].jmp1);
def->f->getBasicBlockList().push_back(exit_block);
def->builder->SetInsertPoint(exit_block);
}
void RaviCodeGenerator::emit_FORLOOP(RaviFunctionDef *def, int A, int pc,
int pc1) {
// 7[1] FORLOOP 1 - 2; to 6
// if (ttisinteger(ra)) { /* integer loop? */
// lua_Integer step = ivalue(ra + 2);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
// lua_Integer limit = ivalue(ra + 1);
// if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setivalue(ra, idx); /* update internal index... */
// setivalue(ra + 3, idx); /* ...and external index */
// }
//}
// else { /* floating loop */
// lua_Number step = fltvalue(ra + 2);
// lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
// lua_Number limit = fltvalue(ra + 1);
// if (luai_numlt(0, step) ? luai_numle(idx, limit)
// : luai_numle(limit, idx)) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setfltvalue(ra, idx); /* update internal index... */
// setfltvalue(ra + 3, idx); /* ...and external index */
// }
//}
emit_debug_trace(def, OP_FORLOOP, pc1);
// Load pointer to base
emit_load_base(def);
// TValue *rinit = ra;
// TValue *rlimit = ra + 1;
// TValue *rstep = ra + 2;
// TValue *rvar = ra + 3
llvm::Value *rinit = emit_gep_register(def, A);
llvm::Value *rlimit = emit_gep_register(def, A + 1);
llvm::Value *rstep = emit_gep_register(def, A + 2);
llvm::Value *rvar = emit_gep_register(def, A + 3);
// Create the done block
llvm::BasicBlock *exit_block =
llvm::BasicBlock::Create(def->jitState->context(), "exit_forloop");
// Is index an integer?
llvm::Instruction *rinit_tt = emit_load_type(def, rinit);
llvm::Value *cmp1 =
emit_is_value_of_type(def, rinit_tt, LUA__TNUMINT, "init.is.integer");
// Setup if then else branch for integer
llvm::BasicBlock *if_integer =
llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f);
llvm::BasicBlock *else_integer =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer");
def->builder->CreateCondBr(cmp1, if_integer, else_integer);
def->builder->SetInsertPoint(if_integer);
// INTEGER CASE
// lua_Integer step = ivalue(ra + 2);
llvm::Instruction *step_int_value = emit_load_reg_i(def, rstep);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
llvm::Instruction *idx_int_value = emit_load_reg_i(def, rinit);
llvm::Value *new_idx = def->builder->CreateAdd(step_int_value, idx_int_value,
"next.idx", false, true);
// lua_Integer limit = ivalue(ra + 1);
llvm::Instruction *limit_int_value = emit_load_reg_i(def, rlimit);
// step > 0?
llvm::Value *step_gt_zero = def->builder->CreateICmpSGT(
step_int_value, def->types->kluaInteger[0], "step.gt.zero");
llvm::BasicBlock *step_gt_zero_true = llvm::BasicBlock::Create(
def->jitState->context(), "step.gt.zero.true", def->f);
llvm::BasicBlock *step_gt_zero_false =
llvm::BasicBlock::Create(def->jitState->context(), "step.gt.zero.false");
def->builder->CreateCondBr(step_gt_zero, step_gt_zero_true,
step_gt_zero_false);
def->builder->SetInsertPoint(step_gt_zero_true);
// idx > limit?
llvm::Value *new_idx_gt_limit =
def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit");
// If idx > limit we are done
llvm::BasicBlock *update_block =
llvm::BasicBlock::Create(def->jitState->context(), "update");
def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block);
def->f->getBasicBlockList().push_back(step_gt_zero_false);
def->builder->SetInsertPoint(step_gt_zero_false);
// limit > idx?
llvm::Value *limit_gt_idx =
def->builder->CreateICmpSGT(limit_int_value, new_idx, "limit.gt.idx");
// If limit > idx we are done
def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block);
// Merge into update block
def->f->getBasicBlockList().push_back(update_block);
def->builder->SetInsertPoint(update_block);
// setivalue(ra, idx); /* update internal index... */
emit_store_reg_i(def, new_idx, rinit);
// setivalue(ra + 3, idx); /* ...and external index */
emit_store_reg_i_withtype(def, new_idx, rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
def->builder->CreateBr(def->jmp_targets[pc].jmp1);
// FLOATING CASE
def->f->getBasicBlockList().push_back(else_integer);
def->builder->SetInsertPoint(else_integer);
// lua_Number step = fltvalue(ra + 2);
llvm::Instruction *step_double_value = emit_load_reg_n(def, rstep);
// lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */
llvm::Instruction *idx_double_value = emit_load_reg_n(def, rinit);
new_idx =
def->builder->CreateFAdd(step_double_value, idx_double_value, "next.idx");
// lua_Number limit = fltvalue(ra + 1);
llvm::Instruction *limit_double_value = emit_load_reg_n(def, rlimit);
// step > 0?
step_gt_zero = def->builder->CreateFCmpOGT(
step_double_value, llvm::ConstantFP::get(def->types->lua_NumberT, 0.0),
"step.gt.zero");
step_gt_zero_true = llvm::BasicBlock::Create(def->jitState->context(),
"step.gt.zero.true", def->f);
step_gt_zero_false =
llvm::BasicBlock::Create(def->jitState->context(), "step.gt.zero.false");
def->builder->CreateCondBr(step_gt_zero, step_gt_zero_true,
step_gt_zero_false);
def->builder->SetInsertPoint(step_gt_zero_true);
// idx > limit?
new_idx_gt_limit =
def->builder->CreateFCmpOGT(new_idx, limit_double_value, "idx.gt.limit");
// If idx > limit we are done
update_block = llvm::BasicBlock::Create(def->jitState->context(), "update");
def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block);
def->f->getBasicBlockList().push_back(step_gt_zero_false);
def->builder->SetInsertPoint(step_gt_zero_false);
// limit > idx?
limit_gt_idx =
def->builder->CreateFCmpOGT(limit_double_value, new_idx, "limit.gt.idx");
// If limit > idx we are done
def->builder->CreateCondBr(limit_gt_idx, exit_block, update_block);
// Merge into update block
def->f->getBasicBlockList().push_back(update_block);
def->builder->SetInsertPoint(update_block);
// setfltvalue(ra, idx); /* update internal index... */
emit_store_reg_n(def, new_idx, rinit);
// setfltvalue(ra + 3, idx); /* ...and external index */
emit_store_reg_n_withtype(def, new_idx, rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
def->builder->CreateBr(def->jmp_targets[pc].jmp1);
def->f->getBasicBlockList().push_back(exit_block);
def->builder->SetInsertPoint(exit_block);
}
void RaviCodeGenerator::emit_iFORLOOP(RaviFunctionDef *def, int A, int pc,
RaviBranchDef &b, int step_one, int pc1) {
// lua_Integer step = ivalue(ra + 2);
// lua_Integer idx = ivalue(ra) + step; /* increment index */
// lua_Integer limit = ivalue(ra + 1);
// if (idx <= limit) {
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
// setivalue(ra, idx); /* update internal index... */
// setivalue(ra + 3, idx); /* ...and external index */
// }
emit_debug_trace(def, step_one ? OP_RAVI_FORLOOP_I1 : OP_RAVI_FORLOOP_IP,
pc1);
// We are in b.jmp1 as this is already the current block
lua_assert(def->builder->GetInsertBlock() == b.jmp1);
// Obtain pointers to the value.i field
llvm::Value *idx_int_ptr = b.iidx;
llvm::Value *limit_int_ptr = b.ilimit;
// Create the done block
llvm::BasicBlock *exit_block =
llvm::BasicBlock::Create(def->jitState->context(), "exit_iforloop");
// lua_Integer idx = ivalue(ra) + step; /* increment index */
llvm::Instruction *idx_int_value = emit_load_local_n(def, idx_int_ptr);
llvm::Value *new_idx;
if (!step_one) {
// lua_Integer step = ivalue(ra + 2);
llvm::Value *step_int_ptr = b.istep;
llvm::Instruction *step_int_value = emit_load_local_n(def, step_int_ptr);
new_idx = def->builder->CreateAdd(step_int_value, idx_int_value, "next.idx",
false, true);
} else
new_idx = def->builder->CreateAdd(def->types->kluaInteger[1], idx_int_value,
"next.idx", false, true);
// save new index
emit_store_local_n(def, new_idx, idx_int_ptr);
// lua_Integer limit = ivalue(ra + 1);
llvm::Instruction *limit_int_value = emit_load_local_n(def, limit_int_ptr);
// idx > limit?
llvm::Value *new_idx_gt_limit =
def->builder->CreateICmpSGT(new_idx, limit_int_value, "idx.gt.limit");
// If idx > limit we are done
llvm::BasicBlock *update_block =
llvm::BasicBlock::Create(def->jitState->context(), "updatei");
def->builder->CreateCondBr(new_idx_gt_limit, exit_block, update_block);
// Merge into update block
def->f->getBasicBlockList().push_back(update_block);
def->builder->SetInsertPoint(update_block);
// Load pointer to base
emit_load_base(def);
llvm::Value *rvar = emit_gep_register(def, A + 3);
// setivalue(ra + 3, idx); /* ...and external index */
idx_int_value = emit_load_local_n(def, idx_int_ptr);
emit_store_reg_i_withtype(def, idx_int_value, rvar);
// ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
def->builder->CreateBr(def->jmp_targets[pc].jmp1);
def->f->getBasicBlockList().push_back(exit_block);
def->builder->SetInsertPoint(exit_block);
}
}