Lua Types in LLVM ================= We need to map Lua types to equivalent type definitions in LLVM. In Ravi we do hold all the type definitions in a struct as shown below:: struct LuaLLVMTypes { llvm::Type *C_intptr_t; llvm::Type *C_size_t; llvm::Type *C_ptrdiff_t; llvm::Type *lua_NumberT; llvm::Type *lua_IntegerT; llvm::Type *lua_UnsignedT; llvm::Type *lua_KContextT; llvm::FunctionType *lua_CFunctionT; llvm::PointerType *plua_CFunctionT; llvm::FunctionType *lua_KFunctionT; llvm::PointerType *plua_KFunctionT; llvm::FunctionType *lua_HookT; llvm::PointerType *plua_HookT; llvm::FunctionType *lua_AllocT; llvm::PointerType *plua_AllocT; llvm::Type *l_memT; llvm::Type *lu_memT; llvm::Type *lu_byteT; llvm::Type *L_UmaxalignT; llvm::Type *C_pcharT; llvm::Type *C_intT; llvm::StructType *lua_StateT; llvm::PointerType *plua_StateT; llvm::StructType *global_StateT; llvm::PointerType *pglobal_StateT; llvm::StructType *ravi_StateT; llvm::PointerType *pravi_StateT; llvm::StructType *GCObjectT; llvm::PointerType *pGCObjectT; llvm::StructType *ValueT; llvm::StructType *TValueT; llvm::PointerType *pTValueT; llvm::StructType *TStringT; llvm::PointerType *pTStringT; llvm::PointerType *ppTStringT; llvm::StructType *UdataT; llvm::StructType *TableT; llvm::PointerType *pTableT; llvm::StructType *UpvaldescT; llvm::PointerType *pUpvaldescT; llvm::Type *ravitype_tT; llvm::StructType *LocVarT; llvm::PointerType *pLocVarT; llvm::Type *InstructionT; llvm::PointerType *pInstructionT; llvm::StructType *LClosureT; llvm::PointerType *pLClosureT; llvm::PointerType *ppLClosureT; llvm::PointerType *pppLClosureT; llvm::StructType *RaviJITProtoT; llvm::PointerType *pRaviJITProtoT; llvm::StructType *ProtoT; llvm::PointerType *pProtoT; llvm::PointerType *ppProtoT; llvm::StructType *UpValT; llvm::PointerType *pUpValT; llvm::StructType *CClosureT; llvm::PointerType *pCClosureT; llvm::StructType *TKeyT; llvm::PointerType *pTKeyT; llvm::StructType *NodeT; llvm::PointerType *pNodeT; llvm::StructType *lua_DebugT; llvm::PointerType *plua_DebugT; llvm::StructType *lua_longjumpT; llvm::PointerType *plua_longjumpT; llvm::StructType *MbufferT; llvm::StructType *stringtableT; llvm::PointerType *StkIdT; llvm::StructType *CallInfoT; llvm::StructType *CallInfo_cT; llvm::StructType *CallInfo_lT; llvm::PointerType *pCallInfoT; llvm::FunctionType *jitFunctionT; llvm::FunctionType *luaD_poscallT; }; The actual definition of the types above is shown below:: static_assert(std::is_floating_point::value && sizeof(lua_Number) == sizeof(double), "lua_Number is not a double"); lua_NumberT = llvm::Type::getDoubleTy(context); static_assert(std::is_integral::value, "lua_Integer is not an integer type"); lua_IntegerT = llvm::Type::getIntNTy(context, sizeof(lua_Integer) * 8); static_assert(sizeof(lua_Integer) == sizeof(lua_Unsigned), "lua_Integer and lua_Unsigned are of different size"); lua_UnsignedT = lua_IntegerT; C_intptr_t = llvm::Type::getIntNTy(context, sizeof(intptr_t) * 8); C_size_t = llvm::Type::getIntNTy(context, sizeof(size_t) * 8); C_ptrdiff_t = llvm::Type::getIntNTy(context, sizeof(ptrdiff_t) * 8); C_intT = llvm::Type::getIntNTy(context, sizeof(int) * 8); static_assert(sizeof(size_t) == sizeof(lu_mem), "lu_mem size is not same as size_t"); lu_memT = C_size_t; static_assert(sizeof(ptrdiff_t) == sizeof(l_mem), "l_mem size is not same as ptrdiff_t"); l_memT = C_ptrdiff_t; static_assert(sizeof(L_Umaxalign) == sizeof(double), "L_Umaxalign is not same size as double"); L_UmaxalignT = llvm::Type::getDoubleTy(context); lu_byteT = llvm::Type::getInt8Ty(context); C_pcharT = llvm::Type::getInt8PtrTy(context); InstructionT = C_intT; pInstructionT = llvm::PointerType::get(InstructionT, 0); lua_StateT = llvm::StructType::create(context, "ravi.lua_State"); plua_StateT = llvm::PointerType::get(lua_StateT, 0); lua_KContextT = C_ptrdiff_t; std::vector elements; elements.push_back(plua_StateT); lua_CFunctionT = llvm::FunctionType::get(C_intT, elements, false); plua_CFunctionT = llvm::PointerType::get(lua_CFunctionT, 0); jitFunctionT = lua_CFunctionT; elements.clear(); elements.push_back(plua_StateT); elements.push_back(C_intT); elements.push_back(lua_KContextT); lua_KFunctionT = llvm::FunctionType::get(C_intT, elements, false); plua_KFunctionT = llvm::PointerType::get(lua_KFunctionT, 0); elements.clear(); elements.push_back(llvm::Type::getInt8PtrTy(context)); elements.push_back(llvm::Type::getInt8PtrTy(context)); elements.push_back(C_size_t); elements.push_back(C_size_t); lua_AllocT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), elements, false); plua_AllocT = llvm::PointerType::get(lua_AllocT, 0); lua_DebugT = llvm::StructType::create(context, "ravi.lua_Debug"); plua_DebugT = llvm::PointerType::get(lua_DebugT, 0); elements.clear(); elements.push_back(plua_StateT); elements.push_back(plua_DebugT); lua_HookT = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(context), elements, false); plua_HookT = llvm::PointerType::get(lua_HookT, 0); // struct GCObject { // GCObject *next; // lu_byte tt; // lu_byte marked // }; GCObjectT = llvm::StructType::create(context, "ravi.GCObject"); pGCObjectT = llvm::PointerType::get(GCObjectT, 0); elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); GCObjectT->setBody(elements); static_assert(sizeof(Value) == sizeof(lua_Number), "Value type is larger than lua_Number"); // In LLVM unions should be set to the largest member // So in the case of a Value this is the double type // union Value { // GCObject *gc; /* collectable objects */ // void *p; /* light userdata */ // int b; /* booleans */ // lua_CFunction f; /* light C functions */ // lua_Integer i; /* integer numbers */ // lua_Number n; /* float numbers */ // }; ValueT = llvm::StructType::create(context, "ravi.Value"); elements.clear(); elements.push_back(lua_NumberT); ValueT->setBody(elements); // struct TValue { // union Value value_; // int tt_; // }; TValueT = llvm::StructType::create(context, "ravi.TValue"); elements.clear(); elements.push_back(ValueT); elements.push_back(C_intT); TValueT->setBody(elements); pTValueT = llvm::PointerType::get(TValueT, 0); StkIdT = pTValueT; ///* //** Header for string value; string bytes follow the end of this structure //** (aligned according to 'UTString'; see next). //*/ // typedef struct TString { // GCObject *next; // lu_byte tt; // lu_byte marked // lu_byte extra; /* reserved words for short strings; "has hash" for longs // */ // unsigned int hash; // size_t len; /* number of characters in string */ // struct TString *hnext; /* linked list for hash table */ // } TString; ///* //** Ensures that address after this type is always fully aligned. //*/ // typedef union UTString { // L_Umaxalign dummy; /* ensures maximum alignment for strings */ // TString tsv; //} UTString; TStringT = llvm::StructType::create(context, "ravi.TString"); pTStringT = llvm::PointerType::get(TStringT, 0); ppTStringT = llvm::PointerType::get(pTStringT, 0); elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* extra */ elements.push_back(C_intT); /* hash */ elements.push_back(C_size_t); /* len */ elements.push_back(pTStringT); /* hnext */ TStringT->setBody(elements); // Table TableT = llvm::StructType::create(context, "ravi.Table"); pTableT = llvm::PointerType::get(TableT, 0); ///* //** Header for userdata; memory area follows the end of this structure //** (aligned according to 'UUdata'; see next). //*/ // typedef struct Udata { // GCObject *next; // lu_byte tt; // lu_byte marked // lu_byte ttuv_; /* user value's tag */ // struct Table *metatable; // size_t len; /* number of bytes */ // union Value user_; /* user value */ //} Udata; UdataT = llvm::StructType::create(context, "ravi.Udata"); elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* ttuv_ */ elements.push_back(pTableT); /* metatable */ elements.push_back(C_size_t); /* len */ elements.push_back(ValueT); /* user_ */ UdataT->setBody(elements); ///* //** Description of an upvalue for function prototypes //*/ // typedef struct Upvaldesc { // TString *name; /* upvalue name (for debug information) */ // lu_byte instack; /* whether it is in stack */ // lu_byte idx; /* index of upvalue (in stack or in outer function's list) // */ //}Upvaldesc; UpvaldescT = llvm::StructType::create(context, "ravi.Upvaldesc"); elements.clear(); elements.push_back(pTStringT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); UpvaldescT->setBody(elements); pUpvaldescT = llvm::PointerType::get(UpvaldescT, 0); ///* //** Description of a local variable for function prototypes //** (used for debug information) //*/ // typedef struct LocVar { // TString *varname; // int startpc; /* first point where variable is active */ // int endpc; /* first point where variable is dead */ // ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown // */ //} LocVar; ravitype_tT = llvm::Type::getIntNTy(context, sizeof(ravitype_t) * 8); LocVarT = llvm::StructType::create(context, "ravi.LocVar"); elements.clear(); elements.push_back(pTStringT); /* varname */ elements.push_back(C_intT); /* startpc */ elements.push_back(C_intT); /* endpc */ elements.push_back(ravitype_tT); /* ravi_type */ LocVarT->setBody(elements); pLocVarT = llvm::PointerType::get(LocVarT, 0); LClosureT = llvm::StructType::create(context, "ravi.LClosure"); pLClosureT = llvm::PointerType::get(LClosureT, 0); ppLClosureT = llvm::PointerType::get(pLClosureT, 0); pppLClosureT = llvm::PointerType::get(ppLClosureT, 0); RaviJITProtoT = llvm::StructType::create(context, "ravi.RaviJITProto"); pRaviJITProtoT = llvm::PointerType::get(RaviJITProtoT, 0); ///* //** Function Prototypes //*/ // typedef struct Proto { // CommonHeader; // lu_byte numparams; /* number of fixed parameters */ // lu_byte is_vararg; // lu_byte maxstacksize; /* maximum stack used by this function */ // int sizeupvalues; /* size of 'upvalues' */ // int sizek; /* size of 'k' */ // int sizecode; // int sizelineinfo; // int sizep; /* size of 'p' */ // int sizelocvars; // int linedefined; // int lastlinedefined; // TValue *k; /* constants used by the function */ // Instruction *code; // struct Proto **p; /* functions defined inside the function */ // int *lineinfo; /* map from opcodes to source lines (debug information) */ // LocVar *locvars; /* information about local variables (debug information) // */ // Upvaldesc *upvalues; /* upvalue information */ // struct LClosure *cache; /* last created closure with this prototype */ // TString *source; /* used for debug information */ // GCObject *gclist; // /* RAVI */ // RaviJITProto *ravi_jit; //} Proto; ProtoT = llvm::StructType::create(context, "ravi.Proto"); pProtoT = llvm::PointerType::get(ProtoT, 0); ppProtoT = llvm::PointerType::get(pProtoT, 0); elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* numparams */ elements.push_back(lu_byteT); /* is_vararg */ elements.push_back(lu_byteT); /* maxstacksize */ elements.push_back(C_intT); /* sizeupvalues */ elements.push_back(C_intT); /* sizek */ elements.push_back(C_intT); /* sizecode */ elements.push_back(C_intT); /* sizelineinfo */ elements.push_back(C_intT); /* sizep */ elements.push_back(C_intT); /* sizelocvars */ elements.push_back(C_intT); /* linedefined */ elements.push_back(C_intT); /* lastlinedefined */ elements.push_back(pTValueT); /* k */ elements.push_back(pInstructionT); /* code */ elements.push_back(ppProtoT); /* p */ elements.push_back(llvm::PointerType::get(C_intT, 0)); /* lineinfo */ elements.push_back(pLocVarT); /* locvars */ elements.push_back(pUpvaldescT); /* upvalues */ elements.push_back(pLClosureT); /* cache */ elements.push_back(pTStringT); /* source */ elements.push_back(pGCObjectT); /* gclist */ elements.push_back(pRaviJITProtoT); /* ravi_jit */ ProtoT->setBody(elements); ///* //** Lua Upvalues //*/ // typedef struct UpVal UpVal; UpValT = llvm::StructType::create(context, "ravi.UpVal"); pUpValT = llvm::PointerType::get(UpValT, 0); ///* //** Closures //*/ //#define ClosureHeader \ //CommonHeader; lu_byte nupvalues; GCObject *gclist // typedef struct CClosure { // ClosureHeader; // lua_CFunction f; // TValue upvalue[1]; /* list of upvalues */ //} CClosure; CClosureT = llvm::StructType::create(context, "ravi.CClosure"); elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* nupvalues */ elements.push_back(pGCObjectT); /* gclist */ elements.push_back(plua_CFunctionT); /* f */ elements.push_back(llvm::ArrayType::get(TValueT, 1)); CClosureT->setBody(elements); pCClosureT = llvm::PointerType::get(CClosureT, 0); // typedef struct LClosure { // ClosureHeader; // struct Proto *p; // UpVal *upvals[1]; /* list of upvalues */ //} LClosure; elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* nupvalues */ elements.push_back(pGCObjectT); /* gclist */ elements.push_back(pProtoT); /* p */ elements.push_back(llvm::ArrayType::get(pUpValT, 1)); LClosureT->setBody(elements); ///* //** Tables //*/ // typedef union TKey { // struct { // TValuefields; // int next; /* for chaining (offset for next node) */ // } nk; // TValue tvk; //} TKey; TKeyT = llvm::StructType::create(context, "ravi.TKey"); elements.clear(); elements.push_back(ValueT); elements.push_back(C_intT); elements.push_back(C_intT); /* next */ TKeyT->setBody(elements); pTKeyT = llvm::PointerType::get(TKeyT, 0); // typedef struct Node { // TValue i_val; // TKey i_key; //} Node; NodeT = llvm::StructType::create(context, "ravi.Node"); elements.clear(); elements.push_back(TValueT); /* i_val */ elements.push_back(TKeyT); /* i_key */ NodeT->setBody(elements); pNodeT = llvm::PointerType::get(NodeT, 0); // typedef struct Table { // CommonHeader; // lu_byte flags; /* 1<

setBody(elements); // struct lua_longjmp; /* defined in ldo.c */ lua_longjumpT = llvm::StructType::create(context, "ravi.lua_longjmp"); plua_longjumpT = llvm::PointerType::get(lua_longjumpT, 0); // lzio.h // typedef struct Mbuffer { // char *buffer; // size_t n; // size_t buffsize; //} Mbuffer; MbufferT = llvm::StructType::create(context, "ravi.Mbuffer"); elements.clear(); elements.push_back(llvm::Type::getInt8PtrTy(context)); /* buffer */ elements.push_back(C_size_t); /* n */ elements.push_back(C_size_t); /* buffsize */ MbufferT->setBody(elements); // typedef struct stringtable { // TString **hash; // int nuse; /* number of elements */ // int size; //} stringtable; stringtableT = llvm::StructType::create(context, "ravi.stringtable"); elements.clear(); elements.push_back(ppTStringT); /* hash */ elements.push_back(C_intT); /* nuse */ elements.push_back(C_intT); /* size */ stringtableT->setBody(elements); ///* //** Information about a call. //** When a thread yields, 'func' is adjusted to pretend that the //** top function has only the yielded values in its stack; in that //** case, the actual 'func' value is saved in field 'extra'. //** When a function calls another with a continuation, 'extra' keeps //** the function index so that, in case of errors, the continuation //** function can be called with the correct top. //*/ // typedef struct CallInfo { // StkId func; /* function index in the stack */ // StkId top; /* top for this function */ // struct CallInfo *previous, *next; /* dynamic call link */ // union { // struct { /* only for Lua functions */ // StkId base; /* base for this function */ // const Instruction *savedpc; // } l; // struct { /* only for C functions */ // lua_KFunction k; /* continuation in case of yields */ // ptrdiff_t old_errfunc; // lua_KContext ctx; /* context info. in case of yields */ // } c; // } u; // ptrdiff_t extra; // short nresults; /* expected number of results from this function */ // lu_byte callstatus; //} CallInfo; elements.clear(); elements.push_back(StkIdT); /* base */ elements.push_back(pInstructionT); /* savedpc */ elements.push_back( C_ptrdiff_t); /* dummy to make this same size as the other member */ CallInfo_lT = llvm::StructType::create(elements); elements.clear(); elements.push_back(plua_KFunctionT); /* k */ elements.push_back(C_ptrdiff_t); /* old_errfunc */ elements.push_back(lua_KContextT); /* ctx */ CallInfo_cT = llvm::StructType::create(elements); CallInfoT = llvm::StructType::create(context, "ravi.CallInfo"); pCallInfoT = llvm::PointerType::get(CallInfoT, 0); elements.clear(); elements.push_back(StkIdT); /* func */ elements.push_back(StkIdT); /* top */ elements.push_back(pCallInfoT); /* previous */ elements.push_back(pCallInfoT); /* next */ elements.push_back( CallInfo_lT); /* u.l - as we will typically access the lua call details */ elements.push_back(C_ptrdiff_t); /* extra */ elements.push_back(llvm::Type::getInt16Ty(context)); /* nresults */ elements.push_back(lu_byteT); /* callstatus */ CallInfoT->setBody(elements); // typedef struct ravi_State ravi_State; ravi_StateT = llvm::StructType::create(context, "ravi.ravi_State"); pravi_StateT = llvm::PointerType::get(ravi_StateT, 0); ///* //** 'global state', shared by all threads of this state //*/ // typedef struct global_State { // lua_Alloc frealloc; /* function to reallocate memory */ // void *ud; /* auxiliary data to 'frealloc' */ // lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ // l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ // lu_mem GCmemtrav; /* memory traversed by the GC */ // lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ // stringtable strt; /* hash table for strings */ // TValue l_registry; // unsigned int seed; /* randomized seed for hashes */ // lu_byte currentwhite; // lu_byte gcstate; /* state of garbage collector */ // lu_byte gckind; /* kind of GC running */ // lu_byte gcrunning; /* true if GC is running */ // GCObject *allgc; /* list of all collectable objects */ // GCObject **sweepgc; /* current position of sweep in list */ // GCObject *finobj; /* list of collectable objects with finalizers */ // GCObject *gray; /* list of gray objects */ // GCObject *grayagain; /* list of objects to be traversed atomically */ // GCObject *weak; /* list of tables with weak values */ // GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ // GCObject *allweak; /* list of all-weak tables */ // GCObject *tobefnz; /* list of userdata to be GC */ // GCObject *fixedgc; /* list of objects not to be collected */ // struct lua_State *twups; /* list of threads with open upvalues */ // Mbuffer buff; /* temporary buffer for string concatenation */ // unsigned int gcfinnum; /* number of finalizers to call in each GC step */ // int gcpause; /* size of pause between successive GCs */ // int gcstepmul; /* GC 'granularity' */ // lua_CFunction panic; /* to be called in unprotected errors */ // struct lua_State *mainthread; // const lua_Number *version; /* pointer to version number */ // TString *memerrmsg; /* memory-error message */ // TString *tmname[TM_N]; /* array with tag-method names */ // struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ // /* RAVI */ // ravi_State *ravi_state; //} global_State; global_StateT = llvm::StructType::create(context, "ravi.global_State"); pglobal_StateT = llvm::PointerType::get(global_StateT, 0); ///* //** 'per thread' state //*/ // struct lua_State { // CommonHeader; // lu_byte status; // StkId top; /* first free slot in the stack */ // global_State *l_G; // CallInfo *ci; /* call info for current function */ // const Instruction *oldpc; /* last pc traced */ // StkId stack_last; /* last free slot in the stack */ // StkId stack; /* stack base */ // UpVal *openupval; /* list of open upvalues in this stack */ // GCObject *gclist; // struct lua_State *twups; /* list of threads with open upvalues */ // struct lua_longjmp *errorJmp; /* current error recover point */ // CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ // lua_Hook hook; // ptrdiff_t errfunc; /* current error handling function (stack index) */ // int stacksize; // int basehookcount; // int hookcount; // unsigned short nny; /* number of non-yieldable calls in stack */ // unsigned short nCcalls; /* number of nested C calls */ // lu_byte hookmask; // lu_byte allowhook; //}; elements.clear(); elements.push_back(pGCObjectT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); elements.push_back(lu_byteT); /* status */ elements.push_back(StkIdT); /* top */ elements.push_back(pglobal_StateT); /* l_G */ elements.push_back(pCallInfoT); /* ci */ elements.push_back(pInstructionT); /* oldpc */ elements.push_back(StkIdT); /* stack_last */ elements.push_back(StkIdT); /* stack */ elements.push_back(pUpValT); /* openupval */ elements.push_back(pGCObjectT); /* gclist */ elements.push_back(plua_StateT); /* twups */ elements.push_back(plua_longjumpT); /* errorJmp */ elements.push_back(CallInfoT); /* base_ci */ elements.push_back(plua_HookT); /* hook */ elements.push_back(C_ptrdiff_t); /* errfunc */ elements.push_back(C_intT); /* stacksize */ elements.push_back(C_intT); /* basehookcount */ elements.push_back(C_intT); /* hookcount */ elements.push_back(llvm::Type::getInt16Ty(context)); /* nny */ elements.push_back(llvm::Type::getInt16Ty(context)); /* nCcalls */ elements.push_back(lu_byteT); /* hookmask */ elements.push_back(lu_byteT); /* allowhook */ lua_StateT->setBody(elements); // int luaD_poscall (lua_State *L, StkId firstResult) elements.clear(); elements.push_back(plua_StateT); elements.push_back(StkIdT); luaD_poscallT = llvm::FunctionType::get(C_intT, elements, false);