def add_case(self, gv_case): targetbuilder = self.builder._fork() self.cases.append('%s,label %%%s' % (gv_case.operand(), targetbuilder.nextlabel)) log('%s FlexSwitch.add_case %s => %s' % ( self.builder.block.label, gv_case.operand(), targetbuilder.nextlabel)) targetbuilder.start_writing() return targetbuilder
def genop_malloc_varsize(self, varsizealloctoken, gv_size): log('%s Builder.genop_malloc_varsize %s,%s' % ( self.block.label, varsizealloctoken, gv_size.operand())) length_offset, items_offset, item_size, item_type = varsizealloctoken gv_gc_malloc_fnaddr = Var('%s (%s)*' % (pi8, i32)) #or use addGlobalFunctionMapping in libllvmjit.restart() self.asm.append(' %s=%s %s %d to %s ;gc_malloc_fnaddr (varsize)' % ( gv_gc_malloc_fnaddr.operand2(), inttoptr, i32, gc_malloc_fnaddr(), gv_gc_malloc_fnaddr.type)) op_size = self._itemaddr(varsizealloctoken, gv_size) gv_result = Var(pi8) self.asm.append(' %s=call %s(%s)' % ( gv_result.operand2(), gv_gc_malloc_fnaddr.operand(), op_size.operand())) gv_p = Var(gv_result.type) self.asm.append(' %s=getelementptr %s,%s %s' % ( gv_p.operand2(), gv_result.operand(), i32, length_offset)) gv_p2 = self._cast_to(gv_p, pi32) #warning: length field hardcoded as int here self.asm.append(' store %s, %s' % (gv_size.operand(), gv_p2.operand())) return gv_result
def pause_writing(self, args_gv): log('%s Builder.pause_writing' % self.block.label) assert self.asm is not None self.nextlabel = count.newlabel() # for the next block self.asm.append(' br label %%%s' % (self.nextlabel,)) self.asm = None return self
def genop_call(self, sigtoken, gv_fnptr, args_gv): log('%s Builder.genop_call %s,%s,%s' % ( self.block.label, sigtoken, gv_fnptr, [v.operand() for v in args_gv])) argtypes, restype = sigtoken if isinstance(gv_fnptr, AddrConst): gv_fn = Var(self._funcsig_type(args_gv, restype) + '*') self.asm.append(' %s=%s %s %s to %s' % ( gv_fn.operand2(), inttoptr, i32, gv_fnptr.operand2(), gv_fn.type)) funcsig = gv_fn.operand() else: try: funcsig = self.rgenop.funcsig[gv_fnptr.get_integer_value()] except KeyError: funcsig = 'TODO: funcsig here' py.test.skip('call an address directly not supported yet') args_gv2 = [] for v in args_gv: if v.is_const and v.type[-1] == '*': #or use some kind of 'inline' cast (see LangRef) t = Var(v.type) self.asm.append(' %s=%s %s %s to %s' % ( t.operand2(), inttoptr, i32, v.operand2(), v.type)) v = t args_gv2.append(v) gv_returnvar = Var(restype) self.asm.append(' %s=call %s(%s)' % ( gv_returnvar.operand2(), funcsig, ','.join([v.operand() for v in args_gv2]))) return gv_returnvar
def _add_default(self): targetbuilder = self.builder._fork() self.default_label = targetbuilder.nextlabel log('%s FlexSwitch.add_default => %s' % ( self.builder.block.label, targetbuilder.nextlabel)) targetbuilder.start_writing() return targetbuilder
def jump_if_true(self, gv_condition, args_for_jump_gv): log('%s Builder.jump_if_true %s' % (self.block.label, gv_condition.operand())) targetbuilder = self._fork() self.nextlabel = count.newlabel() self.asm.append(' br %s,label %%%s,label %%%s' % ( gv_condition.operand(), targetbuilder.nextlabel, self.nextlabel)) self.start_writing() return targetbuilder
def _rgenop1_generic(self, llvm_opcode, gv_x, restype=None): log('%s Builder._rgenop1_generic %s %s' % ( self.block.label, llvm_opcode, gv_x.operand())) restype = restype or gv_x.type gv_result = Var(restype) self.asm.append(' %s=%s %s' % ( gv_result.operand2(), llvm_opcode, gv_x.operand())) return gv_resulgv_comp.operand(), t
def _rgenop2_generic(self, llvm_opcode, gv_arg1, gv_arg2, restype=None): log('%s Builder._rgenop2_generic %s %s,%s' % ( self.block.label, llvm_opcode, gv_arg1.operand(), gv_arg2.operand2())) restype = restype or gv_arg1.type gv_result = Var(restype) self.asm.append(' %s=%s %s,%s' % ( gv_result.operand2(), llvm_opcode, gv_arg1.operand(), gv_arg2.operand2())) return gv_result
def finish_and_goto(self, outputargs_gv, target): # 'target' is a label, which for the llvm backend is a Block log('%s Builder.finish_and_goto' % self.block.label) gv = [v.operand() for v in outputargs_gv] log('%s Builder.finish_and_goto %s,%s' % ( self.block.label, gv, target.label)) self.asm.append(' br label %%%s' % (target.label,)) target.add_incoming_link(self.block, outputargs_gv) self._close()
def genop_getsubstruct(self, fieldtoken, gv_ptr): offset, fieldtype = fieldtoken log('%s Builder.genop_getsubstruct (%d,%s) %s' % ( self.block.label, offset, fieldtype, gv_ptr.operand())) gv_ptr_var = self._as_var(gv_ptr) gv_sub = Var(gv_ptr.type) self.asm.append(' %s=getelementptr %s,%s %d' % ( gv_sub.operand2(), gv_ptr_var.operand(), i32, offset)) return gv_sub
def _is_true(self, gv_x, nullstr='0'): log('%s Builder._is_true %s' % (self.block.label, gv_x.operand())) gv_result = Var(i1) if nullstr == 'null' or nullstr == '0': cmp = icmp else: cmp = fcmp self.asm.append(' %s=%sne %s,%s' % ( gv_result.operand2(), cmp, gv_x.operand(), nullstr)) return gv_result
def start_writing(self): log('%s Builder.start_writing' % self.nextlabel) assert self.nextlabel is not None coming_from = self.block # prepare the next block nextblock = BasicBlock(self.rgenop, self.nextlabel, []) self.block = nextblock self.asm = nextblock.asm self.nextlabel = None nextblock.add_incoming_link(coming_from, [])
def __init__(self, rgenop, builder, gv_exitswitch): log('%s FlexSwitch.__init__ %s' % (builder.block.label, gv_exitswitch.operand())) self.rgenop = rgenop self.builder = builder self.gv_exitswitch = gv_exitswitch self.default_label = None self.cases = [] self.rgenop.blocklist.append(self)
def genop_setfield(self, fieldtoken, gv_ptr, gv_value): offset, fieldtype = fieldtoken log('%s Builder.genop_setfield (%d,%s) %s=%s' % ( self.block.label, offset, fieldtype, gv_ptr.operand(), gv_value.operand())) gv_ptr_var = self._as_var(gv_ptr) gv_p = Var(gv_ptr.type) self.asm.append(' %s=getelementptr %s,%s %s' % ( gv_p.operand2(), gv_ptr_var.operand(), i32, offset)) gv_p2 = self._cast_to(gv_p, fieldtype + '*') self.asm.append(' store %s,%s' % ( gv_value.operand(), gv_p2.operand()))
def genop_malloc_fixedsize(self, size): log('%s Builder.genop_malloc_fixedsize %s' % ( self.block.label, str(size))) gv_gc_malloc_fnaddr = Var('%s (%s)*' % (pi8, i32)) gv_result = Var(pi8) #or use addGlobalFunctionMapping in libllvmjit.restart() self.asm.append(' %s=%s %s %d to %s ;gc_malloc_fnaddr' % ( gv_gc_malloc_fnaddr.operand2(), inttoptr, i32, gc_malloc_fnaddr(), gv_gc_malloc_fnaddr.type)) self.asm.append(' %s=call %s(%s %d)' % ( gv_result.operand2(), gv_gc_malloc_fnaddr.operand(), i32, size)) return gv_result
def genop_getfield(self, fieldtoken, gv_ptr): offset, fieldtype = fieldtoken log('%s Builder.genop_getfield (%d,%s) %s' % ( self.block.label, offset, fieldtype, gv_ptr.operand())) gv_ptr_var = self._as_var(gv_ptr) gv_p = Var(gv_ptr.type) self.asm.append(' %s=getelementptr %s,%s %s' % ( gv_p.operand2(), gv_ptr_var.operand(), i32, offset)) gv_p2 = self._cast_to(gv_p, fieldtype + '*') gv_result = Var(fieldtype) self.asm.append(' %s=load %s' % ( gv_result.operand2(), gv_p2.operand())) return gv_result
def genop_getarraysize(self, arraytoken, gv_ptr): log('%s Builder.genop_getarraysize %s,%s' % ( self.block.label, arraytoken, gv_ptr.operand())) array_length_offset, array_items_offset, item_size, item_type = arraytoken gv_ptr_var = self._as_var(gv_ptr) gv_p = Var(gv_ptr_var.type) self.asm.append(' %s=getelementptr %s,%s %s' % ( gv_p.operand2(), gv_ptr_var.operand(), i32, array_length_offset)) gv_p2 = self._cast_to(gv_p, pi32) gv_result = Var(i32) self.asm.append(' %s=load %s' % ( gv_result.operand2(), gv_p2.operand())) return gv_result
def genop_setarrayitem(self, arraytoken, gv_ptr, gv_index, gv_value): array_length_offset, array_items_offset, item_size, item_type = arraytoken log('%s Builder.genop_setarrayitem %s,%s[%s]=%s' % ( self.block.label, arraytoken, gv_ptr.operand(), gv_index.operand(), gv_value.operand())) gv_ptr_var = self._as_var(gv_ptr) gv_p = Var(gv_ptr_var.type) self.asm.append(' %s=getelementptr %s,%s %s' % ( gv_p.operand2(), gv_ptr_var.operand(), i32, array_items_offset)) gv_p2 = self._cast_to(gv_p, item_type + '*') gv_p3 = Var(gv_p2.type) self.asm.append(' %s=getelementptr %s,%s' % ( gv_p3.operand2(), gv_p2.operand(), gv_index.operand())) self.asm.append(' store %s,%s' % ( gv_value.operand(), gv_p3.operand()))
def newgraph(self, sigtoken, name): if name in self.funcused: self.funcused[name] += 1 name = '%s_%d' % (name, self.funcused[name]) else: self.funcused[name] = 0 log(' RLLVMGenOp.newgraph %s,%s' % (sigtoken, name)) prologueblock = PrologueBlock(sigtoken, name) self.blocklist = [prologueblock] builder = Builder(self, coming_from=prologueblock) prologueblock.startblocklabel = builder.nextlabel argtypes, restype = sigtoken n = len(self.funcsig) * 2 + 1 #+1 so we recognize these pre compilation 'pointers' self.name = name self.funcsig[n] = '%s %s%s' % (restype, globalprefix, name) self.gv_entrypoint = IntConst(n) #note: updated by Builder.end() (i.e after compilation) args = list(prologueblock.inputargs) return builder, self.gv_entrypoint, args
def enter_next_block(self, kinds, args_gv): assert self.nextlabel is None coming_from = self.block newlabel = count.newlabel() # we still need to properly terminate the current block # (with a br to go to the next block) # see: http://llvm.org/docs/LangRef.html#terminators self.asm.append(' br label %%%s' % (newlabel,)) # prepare the next block nextblock = BasicBlock(self.rgenop, newlabel, kinds) log('%s Builder enter block %s' % ( nextblock.label, [v.operand() for v in nextblock.inputargs])) self.block = nextblock self.asm = nextblock.asm # link the two blocks together and update args_gv nextblock.add_incoming_link(coming_from, args_gv) for i in range(len(args_gv)): args_gv[i] = nextblock.inputargs[i] return self.block
def genop_getarraysubstruct(self, arraytoken, gv_ptr, gv_index): ''' self.mc.MOV(edx, gv_ptr.operand(self)) op = self.itemaddr(edx, arraytoken, gv_index) self.mc.LEA(eax, op) return self.returnvar(eax) ''' #XXX WIP log('%s Builder.genop_getarraysubstruct %s,%s,%s' % ( self.block.label, arraytoken, gv_ptr.operand(), gv_index.operand())) array_length_offset, array_items_offset, item_size, item_type = arraytoken op_size = self._itemaddr(arraytoken, gv_index) gv_ptr_var = self._as_var(gv_ptr) gv_result = Var(pi8) self.asm.append(' %s=getelementptr %s,%s' % ( gv_result.operand2(), gv_ptr_var.operand(), op_size.operand())) return gv_result
def end(self): log(' RLLVMGenOp.end') self.blocklist.append(EpilogueBlock()) asmlines = [] for block in self.blocklist: block.writecode(asmlines) if LINENO: asmlines = ['%s ;%d' % (asmlines[i], i+1) for i in range(len(asmlines))] asm_string = '\n'.join(asmlines) self.blocklist = None if PRINT_SOURCE: print asm_string logger.dump(asm_string) parse_ok = llvmjit.parse(asm_string) if not parse_ok: raise ParseException() llvmjit.transform(3) #optimize module (should be on functions actually) function = llvmjit.getNamedFunction(self.name) entrypoint = llvmjit.getPointerToFunctionAsInt(function) # XXX or directly cast the ctypes ptr to int with: # ctypes.cast(ptr, c_void_p).value self.funcsig[entrypoint] = self.funcsig[self.gv_entrypoint.value] self.gv_entrypoint.value = entrypoint
def flexswitch(self, gv_exitswitch, args_gv): log('%s Builder.flexswitch %s' % (self.block.label, gv_exitswitch.operand())) flexswitch = FlexSwitch(self.rgenop, self, gv_exitswitch) return flexswitch, flexswitch._add_default()
def _fork(self): targetbuilder = Builder(self.rgenop, coming_from=self.block) log('%s Builder._fork => %s' % (self.block.label, targetbuilder.nextlabel)) return targetbuilder
def finish_and_return(self, sigtoken, gv_returnvar): log('%s Builder.finish_and_return %s,%s' % ( self.block.label, sigtoken, gv_returnvar.operand())) self.asm.append(' ret ' + gv_returnvar.operand()) self._close()
def genop1(self, opname, gv_arg): log('%s Builder.genop1 %s %s' % ( self.block.label, opname, gv_arg.operand())) genmethod = getattr(self, 'op_' + opname) return genmethod(gv_arg)
def genop2(self, opname, gv_arg1, gv_arg2): log('%s Builder.genop2 %s %s,%s' % ( self.block.label, opname, gv_arg1.operand(), gv_arg2.operand())) genmethod = getattr(self, 'op_' + opname) return genmethod(gv_arg1, gv_arg2)