|
|
|
@ -36,6 +36,9 @@ RaviCodeGenerator::RaviCodeGenerator(RaviJITStateImpl *jitState)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *RaviCodeGenerator::unique_function_name() {
|
|
|
|
|
// Create unique name for the compiled function
|
|
|
|
|
// Lua functions are nameless so a compiled function has no name
|
|
|
|
|
// as far as Lua is concerned
|
|
|
|
|
snprintf(temp_, sizeof temp_, "ravif%d", id_++);
|
|
|
|
|
return temp_;
|
|
|
|
|
}
|
|
|
|
@ -115,42 +118,62 @@ llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
|
|
|
|
|
llvm::Value *ptr, llvm::Value *offset,
|
|
|
|
|
int arg1, int arg2) {
|
|
|
|
|
llvm::SmallVector<llvm::Value *, 3> values;
|
|
|
|
|
llvm::Value *ptr, llvm::Value *offset,
|
|
|
|
|
int arg1) {
|
|
|
|
|
llvm::SmallVector<llvm::Value *, 2> values;
|
|
|
|
|
values.push_back(offset);
|
|
|
|
|
values.push_back(def->types->kInt[arg1]);
|
|
|
|
|
values.push_back(def->types->kInt[arg2]);
|
|
|
|
|
return def->builder->CreateInBoundsGEP(ptr, values, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
|
|
|
|
|
llvm::Value *ptr, llvm::Value *offset,
|
|
|
|
|
int arg1) {
|
|
|
|
|
llvm::SmallVector<llvm::Value *, 2> values;
|
|
|
|
|
int arg1, int arg2) {
|
|
|
|
|
llvm::SmallVector<llvm::Value *, 3> values;
|
|
|
|
|
values.push_back(offset);
|
|
|
|
|
values.push_back(def->types->kInt[arg1]);
|
|
|
|
|
values.push_back(def->types->kInt[arg2]);
|
|
|
|
|
return def->builder->CreateInBoundsGEP(ptr, values, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Value *
|
|
|
|
|
llvm::Value *RaviCodeGenerator::emit_array_get(RaviFunctionDef *def,
|
|
|
|
|
llvm::Value *ptr, int offset) {
|
|
|
|
|
// emit code for &ptr[offset]
|
|
|
|
|
return def->builder->CreateInBoundsGEP(
|
|
|
|
|
ptr, llvm::ConstantInt::get(def->types->C_intT, offset));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Instruction *
|
|
|
|
|
RaviCodeGenerator::emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def) {
|
|
|
|
|
// emit code for (LClosure *)ci->func->value_.gc
|
|
|
|
|
// fortunately as func is at the beginning of the ci
|
|
|
|
|
// structure we can just cast ci to LClosure*
|
|
|
|
|
// emit code for
|
|
|
|
|
// LClosure *cl = clLvalue(ci->func);
|
|
|
|
|
// clLvalue() is a macros that expands to (LClosure *)ci->func->value_.gc
|
|
|
|
|
// via a complex series of macros and unions
|
|
|
|
|
// fortunately as func is at the beginning of the CallInfo
|
|
|
|
|
// structure we can just cast ci to LClosure***
|
|
|
|
|
// This insight is based on code generated by Clang
|
|
|
|
|
llvm::Value *pppLuaClosure =
|
|
|
|
|
def->builder->CreateBitCast(def->ci_val, def->types->pppLClosureT);
|
|
|
|
|
|
|
|
|
|
// Load pointer to LClosure**
|
|
|
|
|
llvm::Instruction *ppLuaClosure = def->builder->CreateLoad(pppLuaClosure);
|
|
|
|
|
ppLuaClosure->setMetadata(llvm::LLVMContext::MD_tbaa,
|
|
|
|
|
def->types->tbaa_CallInfo_funcT);
|
|
|
|
|
return ppLuaClosure;
|
|
|
|
|
|
|
|
|
|
// Load pointer to LClosure*
|
|
|
|
|
llvm::Instruction *cl_ptr = def->builder->CreateLoad(ppLuaClosure);
|
|
|
|
|
cl_ptr->setMetadata(llvm::LLVMContext::MD_tbaa,
|
|
|
|
|
def->types->tbaa_CallInfo_func_LClosureT);
|
|
|
|
|
|
|
|
|
|
return cl_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Retrieve the proto->sizep
|
|
|
|
|
// sizep is a count of the number of closures defined
|
|
|
|
|
// in the function
|
|
|
|
|
llvm::Instruction *
|
|
|
|
|
RaviCodeGenerator::emit_load_proto_sizep(RaviFunctionDef *def) {
|
|
|
|
|
llvm::Value *psize_ptr = emit_gep(def, "sizep", def->proto_ptr, 0, 10);
|
|
|
|
|
// Load sizep
|
|
|
|
|
llvm::Instruction *psize = def->builder->CreateLoad(psize_ptr);
|
|
|
|
|
psize->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Proto_sizepT);
|
|
|
|
|
return psize;
|
|
|
|
@ -173,7 +196,7 @@ void RaviCodeGenerator::emit_update_savedpc(RaviFunctionDef *def, int pc) {
|
|
|
|
|
llvm::Instruction *code_ptr = def->builder->CreateLoad(proto_code_ptr);
|
|
|
|
|
code_ptr->setMetadata(llvm::LLVMContext::MD_tbaa,
|
|
|
|
|
def->types->tbaa_Proto_codeT);
|
|
|
|
|
// Need to set savedpc to the next instruction rather than current as that is
|
|
|
|
|
// Need to set savedpc to the next instruction (pc+1) rather than current as that is
|
|
|
|
|
// what the VM does in interpreted mode
|
|
|
|
|
llvm::Value *code_offset_ptr = emit_array_get(def, code_ptr, pc + 1);
|
|
|
|
|
llvm::Value *savedpc_ptr = emit_gep(def, "savedpc", def->ci_val, 0, 4, 1);
|
|
|
|
@ -183,13 +206,10 @@ void RaviCodeGenerator::emit_update_savedpc(RaviFunctionDef *def, int pc) {
|
|
|
|
|
def->types->tbaa_CallInfo_savedpcT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Value *RaviCodeGenerator::emit_array_get(RaviFunctionDef *def,
|
|
|
|
|
llvm::Value *ptr, int offset) {
|
|
|
|
|
// emit code for &ptr[offset]
|
|
|
|
|
return def->builder->CreateInBoundsGEP(
|
|
|
|
|
ptr, llvm::ConstantInt::get(def->types->C_intT, offset));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate code to reload the function's stack 'base'
|
|
|
|
|
// pointer - the VM needs to do this after any bytecode that
|
|
|
|
|
// may invoke a Lua function and thereby resize the stack; which
|
|
|
|
|
// would invalidate the current 'base' pointer
|
|
|
|
|
void RaviCodeGenerator::emit_load_base(RaviFunctionDef *def) {
|
|
|
|
|
// Load pointer to base
|
|
|
|
|
llvm::Instruction *base_ptr = def->builder->CreateLoad(def->Ci_base);
|
|
|
|
@ -211,6 +231,7 @@ llvm::Value *RaviCodeGenerator::emit_gep_register(RaviFunctionDef *def, int A) {
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit code to obtain address of a constant
|
|
|
|
|
llvm::Value *RaviCodeGenerator::emit_gep_constant(RaviFunctionDef *def,
|
|
|
|
|
int Bx) {
|
|
|
|
|
// Load pointer to k
|
|
|
|
@ -226,7 +247,8 @@ llvm::Value *RaviCodeGenerator::emit_gep_constant(RaviFunctionDef *def,
|
|
|
|
|
return src;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads the value at register B - if the value is an integer constant
|
|
|
|
|
// Loads the value at register or constant at location B -
|
|
|
|
|
// if the value is an integer constant
|
|
|
|
|
// then returns a constant literal
|
|
|
|
|
llvm::Value *
|
|
|
|
|
RaviCodeGenerator::emit_load_register_or_constant_i(RaviFunctionDef *def,
|
|
|
|
@ -1186,7 +1208,7 @@ void RaviCodeGenerator::link_block(RaviFunctionDef *def, int pc) {
|
|
|
|
|
idb->addDestination(def->jmp_targets[pc].jmp3);
|
|
|
|
|
idb->addDestination(def->jmp_targets[pc].jmp4);
|
|
|
|
|
// As we have terminated the block the code below will not
|
|
|
|
|
// add the branch insruction, but we still need to create the new
|
|
|
|
|
// add the branch instruction, but we still need to create the new
|
|
|
|
|
// block which is handled below.
|
|
|
|
|
}
|
|
|
|
|
// If the current bytecode offset pc is on a jump target
|
|
|
|
@ -1247,8 +1269,6 @@ RaviCodeGenerator::emit_gep_upval_value(RaviFunctionDef *def,
|
|
|
|
|
|
|
|
|
|
void RaviCodeGenerator::compile(lua_State *L, Proto *p,
|
|
|
|
|
ravi_compile_options_t *options) {
|
|
|
|
|
TValue *k = p->k;
|
|
|
|
|
|
|
|
|
|
bool doDump = options ? options->dump_level != 0 : 0;
|
|
|
|
|
bool doVerify = options ? options->verification_level != 0 : 0;
|
|
|
|
|
bool omitArrayGetRangeCheck =
|
|
|
|
@ -1260,12 +1280,21 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
|
|
|
|
|
llvm::LLVMContext &context = jitState_->context();
|
|
|
|
|
llvm::IRBuilder<> builder(context);
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<RaviFunctionDef> definition =
|
|
|
|
|
std::unique_ptr<RaviFunctionDef>(new RaviFunctionDef());
|
|
|
|
|
RaviFunctionDef *def = definition.get();
|
|
|
|
|
// RaviFunctionDef definition = {0};
|
|
|
|
|
// RaviFunctionDef *def = &definition;
|
|
|
|
|
|
|
|
|
|
// std::unique_ptr<RaviFunctionDef> definition =
|
|
|
|
|
// std::unique_ptr<RaviFunctionDef>(new RaviFunctionDef());
|
|
|
|
|
// RaviFunctionDef *def = definition.get();
|
|
|
|
|
RaviFunctionDef definition = {0};
|
|
|
|
|
RaviFunctionDef *def = &definition;
|
|
|
|
|
|
|
|
|
|
// The Lua GC doesn't know about memory allocated by the JIT
|
|
|
|
|
// compiler; this means that if lots of functions are being compiled
|
|
|
|
|
// such as in the test cases, then memory usage can grow very large
|
|
|
|
|
// as the GC is blissfully unaware of the actual memory in use
|
|
|
|
|
// To workaround this issue we provide an option that can be used to
|
|
|
|
|
// force a GC after every n compilations where n is supplied
|
|
|
|
|
// by the gcstep parameter; this is not ideal as it kills performance
|
|
|
|
|
// but appears to work for the test cases
|
|
|
|
|
// A better solution is needed
|
|
|
|
|
int gcstep = this->jitState_->get_gcstep();
|
|
|
|
|
if (gcstep > 0 && (id_ % gcstep) == 0) {
|
|
|
|
|
lua_unlock(L);
|
|
|
|
@ -1273,12 +1302,15 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
|
|
|
|
|
lua_lock(L);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printf("compiling function\n");
|
|
|
|
|
auto f = create_function(builder, def);
|
|
|
|
|
if (!f) {
|
|
|
|
|
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; // can't compile
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The functions constants
|
|
|
|
|
TValue *k = p->k;
|
|
|
|
|
|
|
|
|
|
// Add extern declarations for Lua functions we need to call
|
|
|
|
|
emit_extern_declarations(def);
|
|
|
|
|
def->p = p;
|
|
|
|
@ -1290,29 +1322,24 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p,
|
|
|
|
|
def->L_ci = emit_gep(def, "L_ci", def->L, 0, 6);
|
|
|
|
|
|
|
|
|
|
// Load L->ci
|
|
|
|
|
// This is the function's activation record / stack frame
|
|
|
|
|
def->ci_val = builder.CreateLoad(def->L_ci);
|
|
|
|
|
def->ci_val->setMetadata(llvm::LLVMContext::MD_tbaa,
|
|
|
|
|
def->types->tbaa_CallInfoT);
|
|
|
|
|
|
|
|
|
|
// Get pointer to base
|
|
|
|
|
// Get pointer to function's 'base' stack location
|
|
|
|
|
// 'base' is the address relative to which all the
|
|
|
|
|
// function registers are located
|
|
|
|
|
def->Ci_base = emit_gep(def, "base", def->ci_val, 0, 4, 0);
|
|
|
|
|
|
|
|
|
|
// We need to get hold of the constants table
|
|
|
|
|
// which is located in ci->func->value_.gc
|
|
|
|
|
// and is a value of type LClosure*
|
|
|
|
|
// fortunately as func is at the beginning of the ci
|
|
|
|
|
// structure we can just cast ci to LClosure*
|
|
|
|
|
llvm::Value *L_cl = emit_gep_ci_func_value_gc_asLClosure(def);
|
|
|
|
|
|
|
|
|
|
// Load pointer to LClosure
|
|
|
|
|
llvm::Instruction *cl_ptr = builder.CreateLoad(L_cl);
|
|
|
|
|
cl_ptr->setMetadata(llvm::LLVMContext::MD_tbaa,
|
|
|
|
|
def->types->tbaa_CallInfo_func_LClosureT);
|
|
|
|
|
|
|
|
|
|
def->p_LClosure = cl_ptr;
|
|
|
|
|
// which is located in the function definition
|
|
|
|
|
// This is the line in lvm.c that says:
|
|
|
|
|
// LClosure *cl = clLvalue(ci->func)
|
|
|
|
|
def->p_LClosure = emit_gep_ci_func_value_gc_asLClosure(def);
|
|
|
|
|
|
|
|
|
|
// Get pointer to the Proto* which is cl->p
|
|
|
|
|
def->proto = emit_gep(def, "Proto", cl_ptr, 0, 5);
|
|
|
|
|
def->proto = emit_gep(def, "Proto", def->p_LClosure, 0, 5);
|
|
|
|
|
|
|
|
|
|
// Load pointer to proto
|
|
|
|
|
def->proto_ptr = builder.CreateLoad(def->proto);
|
|
|
|
|