Skip to content

Commit

Permalink
implement OP_TEST and OP_TESTSET
Browse files Browse the repository at this point in the history
  • Loading branch information
Dibyendu Majumdar committed Mar 12, 2015
1 parent 49883c9 commit 476375d
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 3 deletions.
14 changes: 14 additions & 0 deletions include/ravi_llvmcodegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,9 @@ class RaviCodeGenerator {
// emit code to load the lua_Integer value from register
llvm::Instruction *emit_load_reg_i(RaviFunctionDef *def, llvm::Value *rb);

// emit code to load the boolean value from register
llvm::Instruction *emit_load_reg_b(RaviFunctionDef *def, llvm::Value *ra);

// emit code to store lua_Number value into register
void emit_store_reg_n(RaviFunctionDef *def, llvm::Value *value,
llvm::Value *dest_ptr);
Expand All @@ -495,6 +498,10 @@ class RaviCodeGenerator {
// emit code to load the type from a register
llvm::Instruction *emit_load_type(RaviFunctionDef *def, llvm::Value *value);

void emit_assign(RaviFunctionDef *def, llvm::Value *ra, llvm::Value *rb);

llvm::Value *emit_boolean_testfalse(RaviFunctionDef *def, llvm::Value *reg, bool not);

// Look for Lua bytecodes that are jump targets and allocate
// a BasicBlock for each such target in def->jump_targets.
// The BasicBlocks are not inserted into the function until later
Expand Down Expand Up @@ -642,6 +649,13 @@ class RaviCodeGenerator {
void emit_EQ(RaviFunctionDef *def, llvm::Value *L_ci, llvm::Value *proto,
int A, int B, int C, int j, int jA, llvm::Constant *callee);

void emit_TEST(RaviFunctionDef *def, llvm::Value *L_ci, llvm::Value *proto,
int A, int B, int C, int j, int jA);

void emit_TESTSET(RaviFunctionDef *def, llvm::Value *L_ci, llvm::Value *proto,
int A, int B, int C, int j, int jA);


private:
RaviJITStateImpl *jitState_;
char temp_[31]; // for name
Expand Down
50 changes: 50 additions & 0 deletions ravi-tests/ravi_tests1.ravi
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,54 @@ assert(ravi.compile(tabtest))
assert(tabtest({}) == 5)
print("test 18 OK")

-- test 19
function optest()
local a,b,c = 1, 5
c = a and b
return c
end
-- ravi.dumplua(optest)
assert(ravi.compile(optest))
-- ravi.dumpllvm(optest)
assert(optest() == 5)
print("test 19 OK")

-- test 20
function optest()
local a,b,c = 1, 5
c = a or b
return c
end
-- ravi.dumplua(optest)
assert(ravi.compile(optest))
-- ravi.dumpllvm(optest)
assert(optest() == 1)
print("test 20 OK")

-- test 21
function optest()
local a,b = 1, 5
if a and b then
return b
end
return a
end
-- ravi.dumplua(optest)
assert(ravi.compile(optest))
-- ravi.dumpllvm(optest)
assert(optest() == 5)
print("test 21 OK")

-- test 22
function optest()
local a,b = nil, 5
if a or b then
return b
end
return a
end
-- ravi.dumplua(optest)
assert(ravi.compile(optest))
-- ravi.dumpllvm(optest)
assert(optest() == 5)
print("test 22 OK")
4 changes: 2 additions & 2 deletions readthedocs/ravi-jit-status.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ Note that if a Lua functions contains a bytecode that cannot be be JITed then th
+-------------------------+----------+--------------------------------------------------+
| OP_LE | YES | if ((RK(B) <= RK(C)) ~= A) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_TEST | NO | if not (R(A) <=> C) then pc++ |
| OP_TEST | YES | if not (R(A) <=> C) then pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_TESTSET | NO | if (R(B) <=> C) then R(A) := R(B) else pc++ |
| OP_TESTSET | YES | if (R(B) <=> C) then R(A) := R(B) else pc++ |
+-------------------------+----------+--------------------------------------------------+
| OP_CALL | YES | R(A), .. ,R(A+C-2) := R(A)(R(A+1), .. ,R(A+B-1)) |
+-------------------------+----------+--------------------------------------------------+
Expand Down
43 changes: 43 additions & 0 deletions src/ravi_llvmcodegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ void RaviCodeGenerator::emit_JMP(RaviFunctionDef *def, int j) {
def->builder->SetInsertPoint(jmp_block);
}
def->builder->CreateBr(def->jmp_targets[j].jmp1);
llvm::BasicBlock *block =
llvm::BasicBlock::Create(def->jitState->context(), "postjump", def->f);
def->builder->SetInsertPoint(block);
}

llvm::Instruction *RaviCodeGenerator::emit_load_base(RaviFunctionDef *def) {
Expand Down Expand Up @@ -127,6 +130,15 @@ llvm::Instruction *RaviCodeGenerator::emit_load_reg_i(RaviFunctionDef *def,
return lhs;
}

llvm::Instruction *RaviCodeGenerator::emit_load_reg_b(RaviFunctionDef *def,
llvm::Value *rb) {
llvm::Value *rb_n =
def->builder->CreateBitCast(rb, def->types->C_pintT);
llvm::Instruction *lhs = def->builder->CreateLoad(rb_n);
lhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT);
return lhs;
}

void RaviCodeGenerator::emit_store_reg_n(RaviFunctionDef *def,
llvm::Value *result,
llvm::Value *dest_ptr) {
Expand Down Expand Up @@ -222,6 +234,8 @@ bool RaviCodeGenerator::canCompile(Proto *p) {
case OP_EQ:
case OP_LT:
case OP_LE:
case OP_TEST:
case OP_TESTSET:
case OP_FORPREP:
case OP_FORLOOP:
case OP_MOVE:
Expand Down Expand Up @@ -528,6 +542,35 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
int j = sbx + pc + 1;
emit_EQ(&def, L_ci, proto, A, B, C, j, GETARG_A(i), comparison_function);
} break;
case OP_TEST: {
int B = GETARG_B(i);
int C = GETARG_C(i);
// OP_TEST is followed by OP_JMP - we process this
// along with OP_EQ
pc++;
i = code[pc];
op = GET_OPCODE(i);
lua_assert(op == OP_JMP);
int sbx = GETARG_sBx(i);
// j below is the jump target
int j = sbx + pc + 1;
emit_TEST(&def, L_ci, proto, A, B, C, j, GETARG_A(i));
} break;
case OP_TESTSET: {
int B = GETARG_B(i);
int C = GETARG_C(i);
// OP_TESTSET is followed by OP_JMP - we process this
// along with OP_EQ
pc++;
i = code[pc];
op = GET_OPCODE(i);
lua_assert(op == OP_JMP);
int sbx = GETARG_sBx(i);
// j below is the jump target
int j = sbx + pc + 1;
emit_TESTSET(&def, L_ci, proto, A, B, C, j, GETARG_A(i));
} break;

case OP_JMP: {
int sbx = GETARG_sBx(i);
int j = sbx + pc + 1;
Expand Down
173 changes: 173 additions & 0 deletions src/ravi_llvmcomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,177 @@ void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, llvm::Value *L_ci,
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
}

llvm::Value *RaviCodeGenerator::emit_boolean_testfalse(RaviFunctionDef *def,
llvm::Value *reg,
bool not) {
// (isnil() || isbool() && b == 0)

llvm::IRBuilder<> TmpB(def->entry, def->entry->begin());
llvm::Value *var = TmpB.CreateAlloca(
llvm::Type::getInt1Ty(def->jitState->context()), nullptr, "b");

llvm::Value *type = emit_load_type(def, reg);

// Test if type == LUA_TNIL (0)
llvm::Value *isnil = def->builder->CreateICmpEQ(type, def->types->kInt[0]);
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.nil", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "not.nil");
llvm::BasicBlock *end_block =
llvm::BasicBlock::Create(def->jitState->context(), "end");
def->builder->CreateCondBr(isnil, then_block, else_block);
def->builder->SetInsertPoint(then_block);

auto ins = def->builder->CreateStore(isnil, var);
ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_intT);
def->builder->CreateBr(end_block);

def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
// value is not nil
// so check if bool and b == 0

// Test if type == LUA_TBOOLEAN
llvm::Value *isbool = def->builder->CreateICmpEQ(type, def->types->kInt[1]);
// Test if bool value == 0
llvm::Value *bool_value = emit_load_reg_b(def, reg);
llvm::Value *boolzero =
def->builder->CreateICmpEQ(bool_value, def->types->kInt[0]);
// Test type == LUA_TBOOLEAN && bool value == 0
llvm::Value *andvalue = def->builder->CreateAnd(isbool, boolzero);

auto ins2 = def->builder->CreateStore(andvalue, var);
ins2->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_intT);
def->builder->CreateBr(end_block);

def->f->getBasicBlockList().push_back(end_block);
def->builder->SetInsertPoint(end_block);

llvm::Value *result = nullptr;
if (not) {
auto ins = def->builder->CreateLoad(var);
ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_intT);
result = def->builder->CreateNot(ins);
}
else {
auto ins = def->builder->CreateLoad(var);
ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_intT);
result = ins;
}

return result;
}

void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, llvm::Value *L_ci,
llvm::Value *proto, int A, int B, int C,
int j, int jA) {

// case OP_TEST: {
// if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra))
// ci->u.l.savedpc++;
// else
// donextjump(ci);
// } break;

// Load pointer to base
llvm::Instruction *base_ptr = def->builder->CreateLoad(def->Ci_base);
base_ptr->setMetadata(llvm::LLVMContext::MD_tbaa,
def->types->tbaa_luaState_ci_baseT);

// Get pointer to register A
llvm::Value *ra = emit_gep_ra(def, base_ptr, A);
// v = C ? is_false(ra) : !is_false(ra)
llvm::Value *v = C ? emit_boolean_testfalse(def, ra, false)
: emit_boolean_testfalse(def, ra, true);

// Test NOT v
llvm::Value *result = def->builder->CreateNot(v);
// If !v then we need to execute the next statement which is a jump
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.else");
def->builder->CreateCondBr(result, then_block, else_block);
def->builder->SetInsertPoint(then_block);

// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (jA > 0) {
// jA is the A operand of the Jump instruction

// base + a - 1
llvm::Value *val =
jA == 1 ? base_ptr : emit_array_get(def, base_ptr, jA - 1);

// Call luaF_close
def->builder->CreateCall2(def->luaF_closeF, def->L, val);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);

// Add the else block and make it current so that the next instruction flows
// here
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
}

void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, llvm::Value *L_ci,
llvm::Value *proto, int A, int B, int C,
int j, int jA) {

// case OP_TESTSET: {
// TValue *rb = RB(i);
// if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb))
// ci->u.l.savedpc++;
// else {
// setobjs2s(L, ra, rb);
// donextjump(ci);
// }
// } break;

// Load pointer to base
llvm::Instruction *base_ptr = def->builder->CreateLoad(def->Ci_base);
base_ptr->setMetadata(llvm::LLVMContext::MD_tbaa,
def->types->tbaa_luaState_ci_baseT);

// Get pointer to register B
llvm::Value *rb = emit_gep_ra(def, base_ptr, B);
// v = C ? is_false(ra) : !is_false(ra)
llvm::Value *v = C ? emit_boolean_testfalse(def, rb, false)
: emit_boolean_testfalse(def, rb, true);

// Test NOT v
llvm::Value *result = def->builder->CreateNot(v);
// If !v then we need to execute the next statement which is a jump
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.then", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.else");
def->builder->CreateCondBr(result, then_block, else_block);
def->builder->SetInsertPoint(then_block);

// Get pointer to register A
llvm::Value *ra = emit_gep_ra(def, base_ptr, A);
emit_assign(def, ra, rb);

// if (a > 0) luaF_close(L, ci->u.l.base + a - 1);
if (jA > 0) {
// jA is the A operand of the Jump instruction

// base + a - 1
llvm::Value *val =
jA == 1 ? base_ptr : emit_array_get(def, base_ptr, jA - 1);

// Call luaF_close
def->builder->CreateCall2(def->luaF_closeF, def->L, val);
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);

// Add the else block and make it current so that the next instruction flows
// here
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
}
}
21 changes: 21 additions & 0 deletions src/ravi_llvmload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,25 @@ void RaviCodeGenerator::emit_LOADK(RaviFunctionDef *def, llvm::Value *L_ci,
store = def->builder->CreateStore(load, desttype);
store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
}

void RaviCodeGenerator::emit_assign(RaviFunctionDef *def, llvm::Value *dest, llvm::Value *src) {
// Below is more efficient that memcpy()
// destvalue->value->i = srcvalue->value->i;
// destvalue->value->i = srcvalue->value->i;
llvm::Value *srcvalue = emit_gep(def, "srcvalue", src, 0, 0, 0);
llvm::Value *destvalue = emit_gep(def, "destvalue", dest, 0, 0, 0);
llvm::Instruction *load = def->builder->CreateLoad(srcvalue);
load->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT);
llvm::Instruction *store = def->builder->CreateStore(load, destvalue);
store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_nT);

// destvalue->type = srcvalue->type
llvm::Value *srctype = emit_gep(def, "srctype", src, 0, 1);
llvm::Value *desttype = emit_gep(def, "desttype", dest, 0, 1);
load = def->builder->CreateLoad(srctype);
load->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
store = def->builder->CreateStore(load, desttype);
store->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_TValue_ttT);
}

}
2 changes: 1 addition & 1 deletion tests/README.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The tests in ths folder are run via the CMake CTest capability.
The tests in this folder are run via the CMake CTest capability.

On UNIX systems, just execute::

Expand Down

0 comments on commit 476375d

Please sign in to comment.