def add_page(self): mbr = c.Var('memory_buffer') mar = c.Var('memory_address') self.define_objective('memory_buffer', None) self.define_objective('memory_address', None) def pair_name(fn, pair): return 'memory/%s_%d_%d' % (fn, pair.min, pair.max) def create_function(pair, force=False): getter = [] setter = [] def gen_fn(fn, p): return c.ExecuteChain() \ .cond('if') \ .score_range(mar, c.ScoreRange(p.min, p.max)) \ .run(c.Function(pair_name(fn, p))) def gen_assign(n, g=True): slot = c.Var('memory_slot_%d' % n) self.define_objective('memory_slot_%d' % n, None) return c.ExecuteChain() \ .cond('if') \ .score_range(mar, c.ScoreRange(n, n)) \ .run(c.OpAssign(mbr if g else slot, slot if g else mbr)) if pair.left and pair.left.left: getter.append(gen_fn('mem_get', pair.left)) setter.append(gen_fn('mem_set', pair.left)) if pair.right and pair.right.right: getter.append(gen_fn('mem_get', pair.right)) setter.append(gen_fn('mem_set', pair.right)) if not pair.left and not pair.right and not force: # Don't do anything here, it's done in the next level up return if pair.left and not pair.left.left or force: getter.append(gen_assign(pair.min)) setter.append(gen_assign(pair.min, False)) if pair.right and not pair.right.right: getter.append(gen_assign(pair.max)) setter.append(gen_assign(pair.max, False)) name_get = pair_name('mem_get', pair) name_set = pair_name('mem_set', pair) self.scope.add_function_names((name_get, name_set)) self.add_function(name_get, getter) self.add_function(name_set, setter) entry_point = self.generate_bin_tree(self.page_size, create_function) if not entry_point.left and not entry_point.right: create_function(entry_point, force=True) # Redirect mem_get and mem_set to the actual entry point getter = [c.Function(pair_name('mem_get', entry_point))] setter = [c.Function(pair_name('mem_set', entry_point))] self.scope.add_function_names(('mem_get', 'mem_set')) self.add_function('mem_get', getter) self.add_function('mem_set', setter)
def gen_assign(n, g=True): slot = c.Var('memory_slot_%d' % n) self.define_objective('memory_slot_%d' % n, None) return c.ExecuteChain() \ .cond('if') \ .score_range(mar, c.ScoreRange(n, n)) \ .run(c.OpAssign(mbr if g else slot, slot if g else mbr))
def read_shared_object(file): dp = zipfile.ZipFile(file, 'r') with dp.open('__mcc__.json', 'r') as f: meta = json.load(f) dp.close() top = TopLevel() table = meta['symbol_table'] for name, props in table['functions'].items(): params = [(vt(p['t']), p['p']) for p in props['params']] returns = [vt(r) for r in props['returns']] flags = props['flags'] pure = flags.get('pure', False) func = DynLinkFunction(c.NSName(props['_name']), params, returns, pure) top.store(name, func) for name, vardesc in table['variables'].items(): var = ExternVariable(vt(vardesc['type'])) ns = vardesc['namespace'] top.store(name, var) if 'nbt' in vardesc: proxy = GlobalNbtVariable(var.type, ns, vardesc['nbt']) elif 'score' in vardesc: proxy = GlobalScoreVariable(var.type, c.Var(vardesc['score'], ns)) else: assert False var.set_proxy(proxy) top.end() funcs = set(map(c.NSName, meta['reserved_funcs'])) return SharedObject(top, funcs)
def __init__(self): super(ExtendedAssembler, self).__init__() self.instructions.update({ 'MOVIND': self.handle_mov_ind, 'MOVINDD': self.handle_mov_ind_d, 'MOVINDS': self.handle_mov_ind_s }) self.use_mem = False self.mem_get = self.top.generate_name('mem_get', FunctionRef('mem_get')) self.mem_set = self.top.generate_name('mem_set', FunctionRef('mem_set')) self.mem_addr = self.top.create_global('mem_addr', VarType.i32) self.mem_buf = self.top.create_global('mem_buf', VarType.i32) self.mem_addr.set_proxy(GlobalScoreVariable(VarType.i32, c.Var('memory_address'))) self.mem_buf.set_proxy(GlobalScoreVariable(VarType.i32, c.Var('memory_buffer')))
def __enter__(self): self.ref = self.var._direct_ref() if self.ref is None: self.using_temp = self.out.allocate_temp() self.ref = c.Var(self.using_temp) if self.read: self.var._write_to_reference(self.ref, self.out) return self.ref
def scale_down(self, ref, out): if self.type.scale != 1: # TODO extract to constant reference tmp = out.allocate_temp() scaleparam = c.Var(tmp) out.write(c.SetConst(scaleparam, self.type.scale)) out.write(c.OpDiv(ref, scaleparam)) out.free_temp(tmp)
def scale_other_to_this(self, other, otherref, out): factor = self.type.scale / other.type.scale op = c.OpMul if factor < 1: factor = 1 / factor op = c.OpDiv factor = int(factor) if factor == 1: return otherref newvar = out.allocate_temp() scaled = c.Var(newvar) out.write(c.OpAssign(scaled, otherref)) # TODO extract to constant reference tmp = out.allocate_temp() scaleparam = c.Var(tmp) out.write(c.SetConst(scaleparam, factor)) out.write(op(scaled, scaleparam)) out.free_temp(tmp) return newvar
def _branch_apply(out, if_true, if_false, apply): inverted = not if_true if inverted: if_true, if_false = if_false, if_true have_false = if_false is not None if have_false: # Workaround: execute store doesn't set success to 0 if failed # See MC-125058 # Can't use execute store anyway because it locks the success # tracker. See MC-125145 out.write(c.SetConst(c.Var('success_tracker'), 0)) true_fn = c.Function(if_true.global_name) out.write( apply(c.ExecuteChain().cond('unless' if inverted else 'if')).run( true_fn)) if have_false: false_fn = c.Function(if_false.global_name) out.write(c.ExecuteChain().cond('if').score_range( c.Var('success_tracker'), c.ScoreRange(0, 0)).run(false_fn))
def apply(self, out, func): # Possible optimisation where scope exit ("put back" value) is applied # directly to operation i.e. store result ... scoreboard add ... with self.dest.open_for_write(out, read=True) as ref: if isinstance(self.src, Variable): with self.src.open_for_read(out) as srcref: scaled = self.dest.scale_other_to_this( self.src, srcref, out) if scaled != srcref: # TODO this is a hack because a temp is allocated srcref = c.Var(scaled) out.write(self.with_ref(ref, srcref)) if scaled != srcref: out.free_temp(scaled) else: self.apply_const_src(ref, self.dest.to_int(self.src), out) if not self.is_additive: self.dest.scale_down(ref, out)
def extended_setup(self, up, down): for i in range(self.page_size): slot = c.Var('memory_slot_%d' % i) up.append(c.SetConst(slot, 0).resolve(self.scope))
def allocate_temp(self): return c.Var('dummy')
def apply_const_src(self, ref, val, out): tmp = out.allocate_temp() srcref = c.Var(tmp) out.write(c.SetConst(srcref, val)) out.write(self.with_ref(ref, srcref)) out.free_temp(tmp)