implement OP_ADD, OP_SUB and OP_MUL

pull/81/head
Dibyendu Majumdar 9 years ago
parent 1571cb431e
commit ef74e153c9

@ -70,7 +70,8 @@ set (LUA_CORE_SRCS src/lapi.c src/lcode.c src/lctype.c src/ldebug.c src/ldo.c sr
src/lvm.c src/lzio.c src/ravijit.cpp src/ravi_llvmtypes.cpp
src/ravi_llvmcodegen.cpp src/ravi_llvmforprep.cpp src/ravi_llvmcomp.cpp
src/ravi_llvmreturn.cpp src/ravi_llvmload.cpp src/ravi_llvmforloop.cpp
src/ravi_llvmarith1.cpp src/ravi_llvmcall.cpp src/ravi_llvmtable.cpp)
src/ravi_llvmarith1.cpp src/ravi_llvmcall.cpp src/ravi_llvmtable.cpp
src/ravi_llvmarith2.cpp)
# define the lua lib source files
set (LUA_LIB_SRCS src/lauxlib.c src/lbaselib.c src/lbitlib.c src/lcorolib.c src/ldblib.c src/liolib.c
src/lmathlib.c src/loslib.c src/ltablib.c src/lstrlib.c src/loadlib.c src/linit.c src/lutf8lib.c)

@ -104,6 +104,8 @@ struct LuaLLVMTypes {
llvm::Type *l_memT;
llvm::Type *lu_memT;
llvm::Type *tmsT;
llvm::Type *lu_byteT;
llvm::Type *L_UmaxalignT;
llvm::Type *C_pcharT;
@ -190,6 +192,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *luaD_precallT;
llvm::FunctionType *luaD_callT;
llvm::FunctionType *luaF_closeT;
llvm::FunctionType *luaT_trybinTMT;
llvm::FunctionType *luaG_runerrorT;
llvm::FunctionType *luaV_equalobjT;
llvm::FunctionType *luaV_lessthanT;
@ -203,7 +206,7 @@ struct LuaLLVMTypes {
llvm::FunctionType *luaV_op_loadnilT;
std::array<llvm::Constant *, 21> kInt;
std::array<llvm::Constant *, TM_N> kInt;
std::array<llvm::Constant *, 21> kluaInteger;
llvm::Constant *kFalse;
@ -384,6 +387,7 @@ struct RaviFunctionDef {
llvm::Constant *luaD_callF;
llvm::Constant *luaF_closeF;
llvm::Constant *luaG_runerrorF;
llvm::Constant *luaT_trybinTMF;
llvm::Constant *luaV_equalobjF;
llvm::Constant *luaV_lessthanF;
llvm::Constant *luaV_lessequalF;
@ -501,7 +505,7 @@ public:
// emit code to load the type from a register
llvm::Instruction *emit_load_type(RaviFunctionDef *def, llvm::Value *value);
// TValue assign
// TValue assign
void emit_assign(RaviFunctionDef *def, llvm::Value *ra, llvm::Value *rb);
// isnil(reg) || isboolean(reg) && reg.value == 0
@ -533,6 +537,9 @@ public:
void emit_LOADBOOL(RaviFunctionDef *def, llvm::Value *L_ci,
llvm::Value *proto, int A, int B, int C, int j);
void emit_ARITH(RaviFunctionDef *def, llvm::Value *L_ci, llvm::Value *proto,
int A, int B, int C, OpCode op, TMS tms);
void emit_UNMF(RaviFunctionDef *def, llvm::Value *L_ci, llvm::Value *proto,
int A, int B);

@ -296,3 +296,36 @@ assert(ravi.compile(optest))
-- ravi.dumpllvm(optest)
assert(optest() == 5)
print("test 22 OK")
-- test 23
function testadd(a,b)
return a+b
end
assert(ravi.compile(testadd))
assert(testadd(1,1) == 2)
assert(testadd(1.5,1.6) == 3.1)
assert(testadd("1.5",1.6) == 3.1)
assert(testadd("1.5","1.6") == 3.1)
print("test 23 OK")
-- test 24
function testsub(a,b)
return a-b
end
assert(ravi.compile(testsub))
assert(testsub(1,1) == 0)
assert(math.abs(testsub(1.5,1.6)-(-0.1)) < 1e-12)
assert(math.abs(testsub("1.5",1.6)-(-0.1)) < 1e-12)
assert(math.abs(testsub("1.5","1.6")-(-0.1)) < 1e-12)
print("test 24 OK")
-- test 25
function testmul(a,b)
return a*b
end
assert(ravi.compile(testmul))
assert(testmul(2,2) == 4)
assert(math.abs(testmul(1.5,1.6)-2.4) < 1e-12)
assert(math.abs(testmul("1.5",1.6)-2.4) < 1e-12)
assert(math.abs(testmul("1.5","1.6")-2.4) < 1e-12)
print("test 25 OK")

@ -3,7 +3,7 @@ Ravi JIT Compilation Status
The JIT compilation status of the Lua and Ravi bytecodes are given below.
This information was last updated on 10th March 2015. As new bytecodes are being added to the JIT compiler on a regular basis
This information was last updated on 15th March 2015. As new bytecodes are being added to the JIT compiler on a regular basis
the status information below may be slightly out of date.
Note that if a Lua functions contains a bytecode that cannot be be JITed then the function cannot be JITed.
@ -37,11 +37,11 @@ Note that if a Lua functions contains a bytecode that cannot be be JITed then th
+-------------------------+----------+--------------------------------------------------+
| OP_SELF | NO | R(A+1) := R(B); R(A) := R(B)[RK(C)] |
+-------------------------+----------+--------------------------------------------------+
| OP_ADD | NO | R(A) := RK(B) + RK(C) |
| OP_ADD | YES | R(A) := RK(B) + RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_SUB | NO | R(A) := RK(B) - RK(C) |
| OP_SUB | YES | R(A) := RK(B) - RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_MUL | NO | R(A) := RK(B) * RK(C) |
| OP_MUL | YES | R(A) := RK(B) * RK(C) |
+-------------------------+----------+--------------------------------------------------+
| OP_MOD | NO | R(A) := RK(B) % RK(C) |
+-------------------------+----------+--------------------------------------------------+

@ -0,0 +1,224 @@
/******************************************************************************
* 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"
// This file contains LLVM IR generation for standard Lua arithmetic op codes
namespace ravi {
// OP_ADD, OP_SUB and OP_MUL
void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, llvm::Value *L_ci,
llvm::Value *proto, int A, int B, int C,
OpCode op, TMS tms) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
// if (ttisinteger(rb) && ttisinteger(rc)) {
// lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
// setivalue(ra, intop(+, ib, ic));
//}
// else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
// setfltvalue(ra, luai_numadd(L, nb, nc));
//}
// else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
llvm::IRBuilder<> TmpB(def->entry, def->entry->begin());
llvm::Value *nb = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nb");
llvm::Value *nc = TmpB.CreateAlloca(def->types->lua_NumberT, nullptr, "nc");
llvm::Instruction *base_ptr = emit_load_base(def);
llvm::Value *ra = emit_gep_ra(def, base_ptr, A);
llvm::Value *rb = emit_gep_rkb(def, base_ptr, B);
llvm::Value *rc = emit_gep_rkb(def, base_ptr, C);
llvm::Value *rb_type = emit_load_type(def, rb);
llvm::Value *rc_type = emit_load_type(def, rc);
llvm::Value *cmp1 = def->builder->CreateICmpEQ(
rb_type, def->types->kInt[LUA_TNUMINT], "rb.is.integer");
llvm::Value *cmp2 = def->builder->CreateICmpEQ(
rc_type, def->types->kInt[LUA_TNUMINT], "rc.is.integer");
llvm::Value *andvalue = def->builder->CreateAnd(cmp1, cmp2);
// Check if both RB and RC are integers
llvm::BasicBlock *then_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.integer", def->f);
llvm::BasicBlock *else_block =
llvm::BasicBlock::Create(def->jitState->context(), "if.not.integer");
llvm::BasicBlock *float_op =
llvm::BasicBlock::Create(def->jitState->context(), "float.op");
llvm::BasicBlock *try_meta =
llvm::BasicBlock::Create(def->jitState->context(), "try_meta");
llvm::BasicBlock *done_block =
llvm::BasicBlock::Create(def->jitState->context(), "done");
def->builder->CreateCondBr(andvalue, then_block, else_block);
def->builder->SetInsertPoint(then_block);
// Both are integers
llvm::Instruction *lhs = emit_load_reg_i(def, rb);
llvm::Instruction *rhs = emit_load_reg_i(def, rc);
llvm::Value *result = nullptr;
switch (op) {
case OP_ADD:
result = def->builder->CreateAdd(lhs, rhs, "", false, true);
break;
case OP_SUB:
result = def->builder->CreateSub(lhs, rhs, "", false, true);
break;
case OP_MUL:
result = def->builder->CreateMul(lhs, rhs, "", false, true);
break;
default:
lua_assert(0);
}
emit_store_reg_i(def, result, ra);
emit_store_type(def, ra, LUA_TNUMINT);
def->builder->CreateBr(done_block);
// Not integer
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
// Is RB a float?
cmp1 = def->builder->CreateICmpEQ(rb_type, def->types->kInt[LUA_TNUMFLT],
"rb.is.float");
llvm::BasicBlock *convert_rb =
llvm::BasicBlock::Create(def->jitState->context(), "convert.rb");
llvm::BasicBlock *test_rc =
llvm::BasicBlock::Create(def->jitState->context(), "test.rc");
llvm::BasicBlock *load_rb =
llvm::BasicBlock::Create(def->jitState->context(), "load.rb");
// If RB is floating then load RB, else convert RB
def->builder->CreateCondBr(cmp1, load_rb, convert_rb);
// Convert RB
def->f->getBasicBlockList().push_back(convert_rb);
def->builder->SetInsertPoint(convert_rb);
// Call luaV_tonumber_()
llvm::Value *rb_isnum =
def->builder->CreateCall2(def->luaV_tonumberF, rb, nb);
cmp1 =
def->builder->CreateICmpEQ(rb_isnum, def->types->kInt[1], "rb.float.ok");
// If not number then go to meta block
// Else proceed to test RC
def->builder->CreateCondBr(cmp1, test_rc, try_meta);
def->f->getBasicBlockList().push_back(load_rb);
def->builder->SetInsertPoint(load_rb);
// Copy RB to local nb
auto src = emit_load_reg_n(def, rb);
auto ins = def->builder->CreateStore(src, nb);
ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_longlongT);
def->builder->CreateBr(test_rc);
def->f->getBasicBlockList().push_back(test_rc);
def->builder->SetInsertPoint(test_rc);
// Is RC a float?
cmp1 = def->builder->CreateICmpEQ(rc_type, def->types->kInt[LUA_TNUMFLT],
"rc.is.float");
llvm::BasicBlock *convert_rc =
llvm::BasicBlock::Create(def->jitState->context(), "convert.rc");
llvm::BasicBlock *load_rc =
llvm::BasicBlock::Create(def->jitState->context(), "load.rc");
// If RC is float load RC
// else try to convert RC
def->builder->CreateCondBr(cmp1, load_rc, convert_rc);
def->f->getBasicBlockList().push_back(convert_rc);
def->builder->SetInsertPoint(convert_rc);
// Call luaV_tonumber_()
llvm::Value *rc_isnum =
def->builder->CreateCall2(def->luaV_tonumberF, rc, nc);
cmp1 =
def->builder->CreateICmpEQ(rc_isnum, def->types->kInt[1], "rc.float.ok");
// If not number then go to meta block
// else both RB and RC float so go to op
def->builder->CreateCondBr(cmp1, float_op, try_meta);
def->f->getBasicBlockList().push_back(load_rc);
def->builder->SetInsertPoint(load_rc);
// Copy RC to local;
src = emit_load_reg_n(def, rc);
ins = def->builder->CreateStore(src, nc);
ins->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_longlongT);
def->builder->CreateBr(float_op);
def->f->getBasicBlockList().push_back(float_op);
def->builder->SetInsertPoint(float_op);
lhs = def->builder->CreateLoad(nb);
lhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_longlongT);
rhs = def->builder->CreateLoad(nc);
rhs->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_longlongT);
// Add and set RA
switch (op) {
case OP_ADD:
result = def->builder->CreateFAdd(lhs, rhs);
break;
case OP_SUB:
result = def->builder->CreateFSub(lhs, rhs);
break;
case OP_MUL:
result = def->builder->CreateFMul(lhs, rhs);
break;
default:
lua_assert(0);
}
emit_store_reg_n(def, result, ra);
emit_store_type(def, ra, LUA_TNUMFLT);
def->builder->CreateBr(done_block);
// Neither integer nor float so try meta
def->f->getBasicBlockList().push_back(try_meta);
def->builder->SetInsertPoint(try_meta);
def->builder->CreateCall5(def->luaT_trybinTMF, def->L, rb, rc, ra,
def->types->kInt[tms]);
def->builder->CreateBr(done_block);
def->f->getBasicBlockList().push_back(done_block);
def->builder->SetInsertPoint(done_block);
}
}

@ -238,6 +238,9 @@ bool RaviCodeGenerator::canCompile(Proto *p) {
case OP_FORPREP:
case OP_FORLOOP:
case OP_MOVE:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_SETTABLE:
case OP_GETTABLE:
case OP_RAVI_MOVEI:
@ -312,6 +315,9 @@ RaviCodeGenerator::create_function(llvm::IRBuilder<> &builder,
void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
// Add extern declarations for Lua functions that we need to call
def->luaT_trybinTMF = def->raviF->addExternFunction(
def->types->luaT_trybinTMT, reinterpret_cast<void *>(&luaT_trybinTM),
"luaT_trybinTM");
def->luaD_callF = def->raviF->addExternFunction(
def->types->luaD_callT, reinterpret_cast<void *>(&luaD_call),
"luaD_call");
@ -623,6 +629,11 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
emit_GETTABLE(&def, L_ci, proto, A, B, C);
} break;
case OP_ADD: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(&def, L_ci, proto, A, B, C, OP_ADD, TM_ADD);
} break;
case OP_RAVI_ADDFN: {
int B = GETARG_B(i);
int C = GETARG_C(i);
@ -649,6 +660,11 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
emit_ADDII(&def, L_ci, proto, A, B, C);
} break;
case OP_SUB: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(&def, L_ci, proto, A, B, C, OP_SUB, TM_SUB);
} break;
case OP_RAVI_SUBFF: {
int B = GETARG_B(i);
int C = GETARG_C(i);
@ -690,6 +706,11 @@ void RaviCodeGenerator::compile(lua_State *L, Proto *p) {
emit_SUBNI(&def, L_ci, proto, A, B, C);
} break;
case OP_MUL: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(&def, L_ci, proto, A, B, C, OP_MUL, TM_MUL);
} break;
case OP_RAVI_MULFN: {
int B = GETARG_B(i);
int C = GETARG_C(i);

@ -58,6 +58,8 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
"l_mem size is not same as ptrdiff_t");
l_memT = C_ptrdiff_t;
tmsT = C_intT;
static_assert(sizeof(L_Umaxalign) == sizeof(double),
"L_Umaxalign is not same size as double");
L_UmaxalignT = llvm::Type::getDoubleTy(context);
@ -694,6 +696,14 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
luaV_gettableT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
luaV_settableT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(pTValueT);
elements.push_back(pTValueT);
elements.push_back(pTValueT);
elements.push_back(tmsT);
luaT_trybinTMT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
elements.clear();
elements.push_back(pCallInfoT);
elements.push_back(C_intT);

@ -122,6 +122,7 @@ int main(int argc, const char *argv[])
{
int failures = 0;
//
failures += test_luacompexec1("function z(); local a = 5; a = a + 1; return a; end; ravi.compile(z); return z()", 6);
failures += test_luacompexec1("function z(x); x[1] = 5; return x[1]; end; ravi.compile(z); return z({})", 5);
failures += test_luacompexec1("function z(x,y) return x<y end; ravi.compile(z); return not z(2,1)", 1);
failures += test_luacompexec1("local function x(); local d:number = 5.0; return d+5 == 5+d and d-5 == 5-d and d*5 == 5*d; end; local y = x(); return y", 1);

Loading…
Cancel
Save