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_llvmtable.cpp

670 lines
26 KiB

/******************************************************************************
* Copyright (C) 2015 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 {
// R(A+1) := R(B); R(A) := R(B)[RK(C)]
void RaviCodeGenerator::emit_SELF(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// StkId rb = RB(i);
// setobjs2s(L, ra + 1, rb);
// Protect(luaV_gettable(L, rb, RKC(i), ra));
bool traced = emit_debug_trace(def, OP_SELF, pc);
// Below may invoke metamethod so we set savedpc
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *ra1 = emit_gep_register(def, A + 1);
emit_assign(def, ra1, rb);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
CreateCall4(def->builder, def->luaV_gettableF, def->L, rb, rc, ra);
}
// R(A) := length of R(B)
void RaviCodeGenerator::emit_LEN(RaviFunctionDef *def, int A, int B, int pc) {
// Protect(luaV_objlen(L, ra, RB(i)));
bool traced = emit_debug_trace(def, OP_LEN, pc);
// Below may invoke metamethod so we set savedpc
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
CreateCall3(def->builder, def->luaV_objlenF, def->L, ra, rb);
}
// R(A)[RK(B)] := RK(C)
void RaviCodeGenerator::emit_SETTABLE(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
bool traced = emit_debug_trace(def, OP_SETTABLE, pc);
// Below may invoke metamethod so we set savedpc
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
CreateCall4(def->builder, def->luaV_settableF, def->L, ra, rb, rc);
}
// R(A) := R(B)[RK(C)]
void RaviCodeGenerator::emit_GETTABLE(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// Protect(luaV_gettable(L, RB(i), RKC(i), ra));
bool traced = emit_debug_trace(def, OP_GETTABLE, pc);
// Below may invoke metamethod so we set savedpc
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
CreateCall4(def->builder, def->luaV_gettableF, def->L, rb, rc, ra);
}
// Emit inline code for accessing a table element using a string key
// We try to access the element using the hash part but if the
// key is not in the main position then we fall back on luaH_getstr().
// IMPORTANT - this emitter should only be called when key is known to
// to be short string
void RaviCodeGenerator::emit_GETTABLE_S(RaviFunctionDef *def, int A, int B,
int C, int pc, TString *key) {
// The code we want to generate is this:
// struct Node *n = hashstr(t, key);
// const struct TValue *k = gkey(n);
// if (ttisshrstring(k) && eqshrstr(tsvalue(k), key))
// return gval(n);
// return luaH_getstr(t, key);
// A number of macros are involved above do the
// the generated code is somewhat more complex
// we don't need to refresh base here as the lua_State is not being touched
emit_debug_trace(def, OP_RAVI_GETTABLE_S, pc);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
// Fortunately as we are dealing with a string constant we already
// know the hash code of the key
//unsigned int hash = key->hash;
// Get the hash table
llvm::Instruction *t = emit_load_reg_h(def, rb);
// Obtain the lsizenode of the hash table
//llvm::Value *lsizenode_ptr = emit_gep(def, "lsizenode", t, 0, 4);
//llvm::Instruction *lsizenode = def->builder->CreateLoad(lsizenode_ptr);
//lsizenode->setMetadata(llvm::LLVMContext::MD_tbaa,
// def->types->tbaa_Table_lsizenode);
//// convert to integer (lsizenode is a byte)
//llvm::Value *intsize =
// def->builder->CreateZExt(lsizenode, def->types->C_intT);
//// #define twoto(x) (1<<(x))
//// #define sizenode(t) (twoto((t)->lsizenode))
//llvm::Value *size = def->builder->CreateShl(def->types->kInt[1], intsize);
// #define lmod(s,size) (cast(int, (s) & ((size)-1)))
//llvm::Value *sizeminusone =
// def->builder->CreateNSWSub(size, def->types->kInt[1]);
//llvm::Value *offset = def->builder->CreateAnd(
// llvm::ConstantInt::get(def->types->C_intT, hash), sizeminusone);
llvm::Value *offset = emit_table_get_hashstr(def, t, key);
// Get access to the node array
//llvm::Value *node_ptr = emit_gep(def, "node", t, 0, 7);
//llvm::Instruction *node = def->builder->CreateLoad(node_ptr);
//node->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_node);
llvm::Value *node = emit_table_get_nodearray(def, t);
// Now we need to get to the right element in the node array
// and retrieve the type information which is held there
//llvm::Value *ktype_ptr = emit_gep(def, "keytype", node, offset, 1, 1);
//llvm::Instruction *ktype = def->builder->CreateLoad(ktype_ptr);
//ktype->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
llvm::Value *ktype = emit_table_get_keytype(def, node, offset);
// We need to check that the key type is also short string
llvm::Value *is_shortstring =
emit_is_value_of_type(def, ktype, LUA__TSHRSTR, "is_shortstring");
llvm::BasicBlock *testkey =
llvm::BasicBlock::Create(def->jitState->context(), "testkey");
llvm::BasicBlock *testok =
llvm::BasicBlock::Create(def->jitState->context(), "testok");
llvm::BasicBlock *testfail =
llvm::BasicBlock::Create(def->jitState->context(), "testfail");
llvm::BasicBlock *testend =
llvm::BasicBlock::Create(def->jitState->context(), "testend");
def->builder->CreateCondBr(is_shortstring, testkey, testfail);
// Now we need to compare the keys
def->f->getBasicBlockList().push_back(testkey);
def->builder->SetInsertPoint(testkey);
// Get the key from the node
//llvm::Value *value_ptr = emit_gep(def, "keyvalue", node, offset, 1, 0);
//llvm::Value *sptr =
// def->builder->CreateBitCast(value_ptr, def->types->ppTStringT);
//llvm::Instruction *keyvalue = def->builder->CreateLoad(sptr);
//keyvalue->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_ppointerT);
llvm::Value *keyvalue = emit_table_get_strkey(def, node, offset);
// Cast the pointer to a intptr so we can compare
llvm::Value *intptr =
def->builder->CreatePtrToInt(keyvalue, def->types->C_intptr_t);
llvm::Value *ourptr =
llvm::ConstantInt::get(def->types->C_intptr_t, (intptr_t)key);
// Compare the two pointers
// If they match then we found the element
llvm::Value *same = def->builder->CreateICmpEQ(intptr, ourptr);
def->builder->CreateCondBr(same, testok, testfail);
// If key found return the value
def->f->getBasicBlockList().push_back(testok);
def->builder->SetInsertPoint(testok);
//llvm::Value *value1 = emit_gep(def, "nodeval", node, offset, 0);
llvm::Value *value1 = emit_table_get_value(def, node, offset);
def->builder->CreateBr(testend);
// Not found so call luaH_getstr
def->f->getBasicBlockList().push_back(testfail);
def->builder->SetInsertPoint(testfail);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Value *value2 =
CreateCall2(def->builder, def->luaH_getstrF, t, emit_load_reg_s(def, rc));
def->builder->CreateBr(testend);
// merge
def->f->getBasicBlockList().push_back(testend);
def->builder->SetInsertPoint(testend);
llvm::PHINode *phi = def->builder->CreatePHI(def->types->pTValueT, 2);
phi->addIncoming(value1, testok);
phi->addIncoming(value2, testfail);
emit_assign(def, ra, phi);
}
void RaviCodeGenerator::emit_GETTABLE_AF(RaviFunctionDef *def, int A, int B,
int C, bool omitArrayGetRangeCheck,
int pc) {
//#define raviH_get_float_inline(L, t, key, v)
//{ unsigned ukey = (unsigned)((key));
// lua_Number *data = (lua_Number *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// setfltvalue(v, data[ukey]);
// }else
// luaG_runerror(L, "array out of bounds");
//}
// TValue *rb = RB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rc);
// Table *t = hvalue(rb);
// raviH_get_float_inline(L, t, idx, ra);
emit_debug_trace(def, OP_RAVI_GETTABLE_AF, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *key = emit_load_reg_i(def, rc);
llvm::Instruction *t = emit_load_reg_h(def, rb);
llvm::Instruction *data = emit_load_reg_h_floatarray(def, t);
llvm::BasicBlock *then_block = nullptr;
llvm::BasicBlock *else_block = nullptr;
llvm::BasicBlock *end_block = nullptr;
if (!omitArrayGetRangeCheck) {
llvm::Instruction *len = emit_load_ravi_arraylength(def, t);
llvm::Value *ulen =
def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen");
llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen);
then_block = llvm::BasicBlock::Create(def->jitState->context(),
"if.in.range", def->f);
else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
end_block = llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(cmp, then_block, else_block);
def->builder->SetInsertPoint(then_block);
}
llvm::Value *ptr = def->builder->CreateGEP(data, key);
llvm::Instruction *value = def->builder->CreateLoad(ptr);
value->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pdoubleT);
emit_store_reg_n_withtype(def, value, ra);
if (!omitArrayGetRangeCheck) {
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
emit_raise_lua_error(def, "array out of bounds");
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
}
}
void RaviCodeGenerator::emit_GETTABLE_AI(RaviFunctionDef *def, int A, int B,
int C, bool omitArrayGetRangeCheck,
int pc) {
//#define raviH_get_int_inline(L, t, key, v)
//{ unsigned ukey = (unsigned)((key));
// lua_Integer *data = (lua_Integer *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// setivalue(v, data[ukey]);
// } else
// luaG_runerror(L, "array out of bounds");
//}
// TValue *rb = RB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rc);
// Table *t = hvalue(rb);
// raviH_get_int_inline(L, t, idx, ra);
emit_debug_trace(def, OP_RAVI_GETTABLE_AI, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *key = emit_load_reg_i(def, rc);
llvm::Instruction *t = emit_load_reg_h(def, rb);
llvm::Instruction *data = emit_load_reg_h_intarray(def, t);
llvm::BasicBlock *then_block = nullptr;
llvm::BasicBlock *else_block = nullptr;
llvm::BasicBlock *end_block = nullptr;
if (!omitArrayGetRangeCheck) {
llvm::Instruction *len = emit_load_ravi_arraylength(def, t);
llvm::Value *ulen =
def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen");
llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen);
then_block = llvm::BasicBlock::Create(def->jitState->context(),
"if.in.range", def->f);
else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
end_block = llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(cmp, then_block, else_block);
def->builder->SetInsertPoint(then_block);
}
llvm::Value *ptr = def->builder->CreateGEP(data, key);
llvm::Instruction *value = def->builder->CreateLoad(ptr);
value->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_plonglongT);
emit_store_reg_i_withtype(def, value, ra);
if (!omitArrayGetRangeCheck) {
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
emit_raise_lua_error(def, "array out of bounds");
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
}
}
void RaviCodeGenerator::emit_SETTABLE_AI(RaviFunctionDef *def, int A, int B,
int C, bool known_int, int pc) {
//#define raviH_set_int_inline(L, t, key, value)
//{ unsigned ukey = (unsigned)((key));
// lua_Integer *data = (lua_Integer *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// data[ukey] = value;
// } else
// raviH_set_int(L, t, ukey, value);
//}
// Table *t = hvalue(ra);
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rb);
// lua_Integer value = ivalue(rc);
// raviH_set_int_inline(L, t, idx, value);
emit_debug_trace(def, known_int ? OP_RAVI_SETTABLE_AII : OP_RAVI_SETTABLE_AI,
pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *key = emit_load_reg_i(def, rb);
llvm::Instruction *value =
known_int ? emit_load_reg_i(def, rc) : emit_tointeger(def, rc);
llvm::Instruction *t = emit_load_reg_h(def, ra);
llvm::Instruction *data = emit_load_reg_h_intarray(def, t);
llvm::Instruction *len = emit_load_ravi_arraylength(def, t);
llvm::Value *ulen =
def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen");
llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen);
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
llvm::BasicBlock *end_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(cmp, then_block, else_block);
def->builder->SetInsertPoint(then_block);
llvm::Value *ptr = def->builder->CreateGEP(data, key);
llvm::Instruction *storeinst = def->builder->CreateStore(value, ptr);
storeinst->setMetadata(llvm::LLVMContext::MD_tbaa,
def->types->tbaa_plonglongT);
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
CreateCall4(def->builder, def->raviH_set_intF, def->L, t, key, value);
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
}
void RaviCodeGenerator::emit_SETTABLE_AF(RaviFunctionDef *def, int A, int B,
int C, bool known_float, int pc) {
//#define raviH_set_float_inline(L, t, key, value)
//{ unsigned ukey = (unsigned)((key));
// lua_Number *data = (lua_Number *)t->ravi_array.data;
// if (ukey < t->ravi_array.len) {
// data[ukey] = value;
// } else
// raviH_set_float(L, t, ukey, value);
// }
// Table *t = hvalue(ra);
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Integer idx = ivalue(rb);
// if (ttisfloat(rc)) {
// raviH_set_float_inline(L, t, idx, fltvalue(rc));
//}
// else {
// raviH_set_float_inline(L, t, idx, ((lua_Number)ivalue(rc)));
//}
emit_debug_trace(
def, known_float ? OP_RAVI_SETTABLE_AFF : OP_RAVI_SETTABLE_AF, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Instruction *key = emit_load_reg_i(def, rb);
llvm::Instruction *value =
known_float ? emit_load_reg_n(def, rc) : emit_tofloat(def, rc);
llvm::Instruction *t = emit_load_reg_h(def, ra);
llvm::Instruction *data = emit_load_reg_h_floatarray(def, t);
llvm::Instruction *len = emit_load_ravi_arraylength(def, t);
llvm::Value *ulen =
def->builder->CreateZExt(len, def->types->lua_UnsignedT, "ulen");
llvm::Value *cmp = def->builder->CreateICmpULT(key, ulen);
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.in.range", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.in.range");
llvm::BasicBlock *end_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(cmp, then_block, else_block);
def->builder->SetInsertPoint(then_block);
llvm::Value *ptr = def->builder->CreateGEP(data, key);
llvm::Instruction *storeinst = def->builder->CreateStore(value, ptr);
storeinst->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_pdoubleT);
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
CreateCall4(def->builder, def->raviH_set_floatF, def->L, t, key, value);
def->builder->CreateBr(end_block);
def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);
}
// R(A) := UpValue[B]
void RaviCodeGenerator::emit_GETUPVAL(RaviFunctionDef *def, int A, int B,
int pc) {
// int b = GETARG_B(i);
// setobj2s(L, ra, cl->upvals[b]->v);
emit_debug_trace(def, OP_GETUPVAL, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *upval_ptr = emit_gep_upvals(def, B);
llvm::Instruction *upval = emit_load_pupval(def, upval_ptr);
llvm::Value *v = emit_load_upval_v(def, upval);
emit_assign(def, ra, v);
}
// UpValue[B] := R(A)
void RaviCodeGenerator::emit_SETUPVAL(RaviFunctionDef *def, int A, int B,
int pc) {
// UpVal *uv = cl->upvals[GETARG_B(i)];
// setobj(L, uv->v, ra);
// luaC_upvalbarrier(L, uv);
emit_debug_trace(def, OP_SETUPVAL, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *upval_ptr = emit_gep_upvals(def, B);
llvm::Instruction *upval = emit_load_pupval(def, upval_ptr);
llvm::Value *v = emit_load_upval_v(def, upval);
emit_assign(def, v, ra);
llvm::Value *type = emit_load_type(def, v);
llvm::Value *is_collectible =
def->builder->CreateAnd(type, def->types->kInt[BIT_ISCOLLECTABLE]);
llvm::Value *value = emit_gep_upval_value(def, upval);
llvm::Value *cmp = def->builder->CreateICmpNE(v, value, "v.ne.value");
llvm::Value *tobool = def->builder->CreateICmpEQ(
is_collectible, def->types->kInt[0], "not.collectible");
llvm::Value *orcond =
def->builder->CreateOr(cmp, tobool, "v.ne.value.or.not.collectible");
llvm::BasicBlock *then =
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock *end =
llvm::BasicBlock::Create(def->jitState->context(), "if.end");
def->builder->CreateCondBr(orcond, end, then);
def->builder->SetInsertPoint(then);
CreateCall2(def->builder, def->luaC_upvalbarrierF, def->L, upval);
def->builder->CreateBr(end);
def->f->getBasicBlockList().push_back(end);
def->builder->SetInsertPoint(end);
}
// R(A) := UpValue[B][RK(C)]
void RaviCodeGenerator::emit_GETTABUP(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// int b = GETARG_B(i);
// Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
bool traced = emit_debug_trace(def, OP_GETTABUP, pc);
// Below may invoke metamethod so we set savedpc
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Value *upval_ptr = emit_gep_upvals(def, B);
llvm::Instruction *upval = emit_load_pupval(def, upval_ptr);
llvm::Value *v = emit_load_upval_v(def, upval);
CreateCall4(def->builder, def->luaV_gettableF, def->L, v, rc, ra);
}
// UpValue[A][RK(B)] := RK(C)
void RaviCodeGenerator::emit_SETTABUP(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// int a = GETARG_A(i);
// Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
bool traced = emit_debug_trace(def, OP_SETTABUP, pc);
if (!traced)
emit_update_savedpc(def, pc);
emit_load_base(def);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Value *upval_ptr = emit_gep_upvals(def, A);
llvm::Instruction *upval = emit_load_pupval(def, upval_ptr);
llvm::Value *v = emit_load_upval_v(def, upval);
CreateCall4(def->builder, def->luaV_settableF, def->L, v, rb, rc);
}
void RaviCodeGenerator::emit_NEWARRAYINT(RaviFunctionDef *def, int A, int pc) {
emit_debug_trace(def, OP_RAVI_NEWARRAYI, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall3(def->builder, def->raviV_op_newarrayintF, def->L, def->ci_val,
ra);
}
void RaviCodeGenerator::emit_NEWARRAYFLOAT(RaviFunctionDef *def, int A,
int pc) {
emit_debug_trace(def, OP_RAVI_NEWARRAYF, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall3(def->builder, def->raviV_op_newarrayfloatF, def->L, def->ci_val,
ra);
}
void RaviCodeGenerator::emit_NEWTABLE(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// case OP_NEWTABLE: {
// int b = GETARG_B(i);
// int c = GETARG_C(i);
// Table *t = luaH_new(L);
// sethvalue(L, ra, t);
// if (b != 0 || c != 0)
// luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
// checkGC(L, ra + 1);
// } break;
emit_debug_trace(def, OP_NEWTABLE, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall5(def->builder, def->raviV_op_newtableF, def->L, def->ci_val, ra,
def->types->kInt[B], def->types->kInt[C]);
}
void RaviCodeGenerator::emit_SETLIST(RaviFunctionDef *def, int A, int B, int C,
int pc) {
emit_debug_trace(def, OP_SETLIST, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall5(def->builder, def->raviV_op_setlistF, def->L, def->ci_val, ra,
def->types->kInt[B], def->types->kInt[C]);
}
void RaviCodeGenerator::emit_TOARRAY(RaviFunctionDef *def, int A,
int array_type_expected,
const char *errmsg, int pc) {
// if (!ttistable(ra) || hvalue(ra)->ravi_array.type != RAVI_TARRAYINT)
// luaG_runerror(L, "integer[] expected");
emit_debug_trace(def,
array_type_expected == RAVI_TARRAYINT ? OP_RAVI_TOARRAYI
: OP_RAVI_TOARRAYF,
pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Instruction *type = emit_load_type(def, ra);
// type != LUA_TTABLE ?
llvm::Value *cmp1 =
emit_is_not_value_of_type(def, type, LUA__TTABLE, "is.not.table");
llvm::BasicBlock *raise_error = llvm::BasicBlock::Create(
def->jitState->context(), "if.not.table", def->f);
llvm::BasicBlock *else1 =
llvm::BasicBlock::Create(def->jitState->context(), "test.if.array");
llvm::BasicBlock *done =
llvm::BasicBlock::Create(def->jitState->context(), "done");
def->builder->CreateCondBr(cmp1, raise_error, else1);
def->builder->SetInsertPoint(raise_error);
// Conversion failed, so raise error
emit_raise_lua_error(def, errmsg);
def->builder->CreateBr(done);
def->f->getBasicBlockList().push_back(else1);
def->builder->SetInsertPoint(else1);
// Get table
llvm::Instruction *h = emit_load_reg_h(def, ra);
// Get array type
llvm::Instruction *ravi_array_type = emit_load_ravi_arraytype(def, h);
// array_type == RAVI_TARRAYXXX?
llvm::Value *cmp2 = def->builder->CreateICmpEQ(
ravi_array_type, def->types->kByte[array_type_expected], "is.array.type");
// If array then fine else raise error
def->builder->CreateCondBr(cmp2, done, raise_error);
def->f->getBasicBlockList().push_back(done);
def->builder->SetInsertPoint(done);
}
void RaviCodeGenerator::emit_MOVEAI(RaviFunctionDef *def, int A, int B,
int pc) {
emit_debug_trace(def, OP_RAVI_MOVEAI, pc);
emit_TOARRAY(def, B, RAVI_TARRAYINT, "integer[] expected", pc);
llvm::Value *src = emit_gep_register(def, B);
llvm::Value *dest = emit_gep_register(def, A);
emit_assign(def, dest, src);
}
void RaviCodeGenerator::emit_MOVEAF(RaviFunctionDef *def, int A, int B,
int pc) {
emit_debug_trace(def, OP_RAVI_MOVEAF, pc);
emit_TOARRAY(def, B, RAVI_TARRAYFLT, "number[] expected", pc);
llvm::Value *src = emit_gep_register(def, B);
llvm::Value *dest = emit_gep_register(def, A);
emit_assign(def, dest, src);
}
}