def visit_lowcreate(self, lc): #print "IN LOWC (v = %x, d = %x, lc = %x)" % (id(self), id(self.__dict__), id(lc)) cr = self.cur_scope.creates[lc.label] # compute the calling convention c = regmagic.mapcall(cr.args, funcname = "create", loc = cr.loc) newbl = Block(loc = cr.loc) lbl = cr.label # generate allocate + test for alternative fidvar = cr.cvar_fid usefvar = CVarUse(decl = fidvar) if lc.target_next is None: if cr.extras.get_attr('exclusive', None) is None: warn("this create may fail and no alternative is available", cr) forcesuspend = '|8' else: forcesuspend = '' newbl += (flatten(cr.loc, '__asm__ __volatile__("allocate %%1, %%0\\t# MT: CREATE %s"' ' : "=r"(' % lbl) + usefvar + ') : "rI"(' + CVarUse(decl = cr.cvar_place) + '%s));' % forcesuspend) if lc.target_next is not None: newbl += (flatten(cr.loc, ' if (!__builtin_expect(!!(') + usefvar + '), 1)) ' + CGoto(target = lc.target_next)) + ';' # generate the function pointer if cr.funtype == cr.FUN_ID: if lc.lowfun is not None: funvar = lc.lowfun else: # not yet split funvar = Opaque(cr.fun) else: assert cr.funtype == cr.FUN_VAR n = 'C$mtF$%s' % lbl t = 'C$mtF$%s' % lbl thetype = CTypeDecl(loc = cr.loc, name = t, ctype = CType(items = Opaque(text = "void (*") + CTypeHead() + ')(void)')) self.cur_scope.decls += thetype funvar = CVarDecl(loc = cr.loc, name = n, ctype = CTypeUse(tdecl = thetype)) self.cur_scope.decls += funvar if lc.lowfun is not None: thefun = lc.lowfun else: # not yet split thefun = CVarUse(decl = cr.fun) newbl += CVarSet(loc = cr.loc, decl = funvar, rhs = CCast(ctype = CTypeUse(tdecl = thetype), expr = thefun)) + ';' funvar = CVarUse(decl = funvar) # prepare memory structure for memory-passed arguments ### FIXME: move stuff to cur_scope if c['gl_mem_offset'] is not None: maname = "C$mtM$%s" % lbl mat = 'C$mtM$%s' % lbl thestruct = Opaque('struct {') for d in c['memlayout']: thestruct = thestruct + (Opaque(loc = d['loc']) + d['ctype'] + ' ' + d['name'] + ';') thestruct = thestruct + '}' thetype = CTypeDecl(loc = cr.loc, name = mat, ctype = thestruct) self.cur_scope.decls += thetype mavar = CVarDecl(loc = cr.loc, name = maname, ctype = CTypeUse(tdecl = thetype)) self.cur_scope.decls += mavar mavar = CVarUse(decl = mavar) lc.mavar = mavar # generate create start = CVarUse(decl = cr.cvar_start) limit = CVarUse(decl = cr.cvar_limit) step = CVarUse(decl = cr.cvar_step) block = CVarUse(decl = cr.cvar_block) newbl += (flatten(cr.loc, '__asm__ ("setstart %%0, %%2\\t# MT: CREATE %s"' ' : "=r"(' % lbl) + usefvar + ') : "0"(' + usefvar + '), "rI"(' + start + ')); ' + '__asm__ ("setlimit %%0, %%2\\t# MT: CREATE %s"' % lbl + ' : "=r"(' + usefvar + ') : "0"(' + usefvar + '), "rI"(' + limit + ')); ' + '__asm__ ("setstep %%0, %%2\\t# MT: CREATE %s"' % lbl + ' : "=r"(' + usefvar + ') : "0"(' + usefvar + '), "rI"(' + step + ')); ' + '__asm__ ("setblock %%0, %%2\\t# MT: CREATE %s"' % lbl + ' : "=r"(' + usefvar + ') : "0"(' + usefvar + '), "rI"(' + block + ')); ' + '__asm__ __volatile__("wmb; crei %%0, 0(%%2)\\t# MT: CREATE %s"' % lbl + ' : "=r"(' + usefvar + ') : "0"(' + usefvar + '),' + ' "r"(' + funvar + ') : "memory");') lc.callconv = c['nargs'] lc.fidvar = usefvar newbl += lc.body.accept(self) # done with body, now handle sync # first of all, if there weresome memory-passed arguments, # we need to push the argument register to the child family. if c['gl_mem_offset'] is not None: newbl += (flatten(cr.loc_end, ' __asm__ ("wmb; putg %%2, %%0, %d\\t#MT: set offset for memargs"' % c['gl_mem_offset']) + ' : "=r"(' + usefvar + ') : "0"(' + usefvar + '),' + ' "r"(&' + mavar + '));') # now, on to the sync. if cr.sync_type == 'normal': # normal, synchronized create # first wait for child family to terminate. newbl += (flatten(cr.loc_end, '__asm__ __volatile__("sync %%0, %%1; ' ' mov %%1, $31\\t# MT: SYNC %s"' % lbl) + ' : "=r"(' + usefvar + '), "=r"(' + CVarUse(decl = cr.cvar_exitcode) + ') : "0"(' + usefvar + ') : "memory");') # then pull shared arguments back. for name, arg in c['nargs'].iteritems(): crarg = cr.arg_dic[name] if not crarg.seen_get: # geta() is not used, so no need to retrieve continue if arg['mode'] == 'reg' and arg['cat'] == 'sh': if arg['species'] == 'f': insn1 = 'fgets' insn2 = 'fmov' rspec = 'f' else: insn1 = 'gets' insn2 = 'mov' rspec = 'r' regnr = arg['regnr'] argvar = crarg.cvar # FIXME: perform "mov" after all "get" have been issued! newbl += (flatten(cr.loc_end, ' __asm__ (' '"%(insn1)s %%0, %(regnr)d, %%1; ' ' %(insn2)s %%1, %%1' '\\t# MT: get shared %(name)s"' % locals()) + ' : "=r"(' + usefvar + '), "=%(rspec)s"(' % locals() + CVarUse(decl = argvar) + ') : "0"(' + usefvar + '));') # in call cases (sync and detach), release resources. newbl += (flatten(cr.loc_end, ' __asm__ __volatile__("release %%0\\t#MT: SYNC %s"' % lbl) + ' : : "r"(' + usefvar + '));') return newbl
def visit_fundef(self, fundef): newitems = [] # first compute the call convention c = regmagic.mapcall(fundef.parms, funcname = "function '%s'" % fundef.name, loc = fundef.loc) # generate the function header regdir = regmagic.get_dot_registers(c['nrargregs']['gli'], c['nrargregs']['shi'], c['nrargregs']['glf'], c['nrargregs']['shf']) idxreg = regmagic.vname_to_legacy("idx_init") newitems.append(flatten(fundef.loc, ' extern void %(name)s(void); ' 'void __slf_%(name)s(void) {' ' register long __slI_ __asm__("%(idxreg)s");' ' __asm__("# MT: index in %%0 (must be %(idxreg)s)"' ' : "=r"(__slI_));' ' register const long __slI = __slI_;' ' __asm__ __volatile__("%(regdir)s");' % { 'name': fundef.name, 'regdir' : regdir, 'idxreg' : idxreg })) # analyze the parameter list self.gllist = [] self.shlist = [] self.gllist_mem = [] self.gllist_mutable = [] if c['gl_mem_offset'] is not None: # some parameters are passed using memory. newitems.append(flatten(fundef.loc, "register const struct {")) for d in c['memlayout']: # keep them for getp/setp self.gllist_mem.append(d['name']) # also issue a field in the data structure newitems.append(flatten(d['loc'], ' ') + d['ctype'] + ' %s' % d['name'] + ';') memescape_reg = regmagic.vname_to_legacy('g%d' % c['gl_mem_offset']) newitems.append(flatten(fundef.loc, '} * __restrict__ const __slPgm __asm__("%s");' % memescape_reg)) for species, d1 in c['args'].items(): for cat, d2 in d1.items(): for a in d2: name = a['name'] ctype = a['ctype'] if a['mode'] == 'mem': assert cat == 'gl' self.gllist_mem.append(name) else: # mode: reg regnr = a['regnr'] if cat == "sh": self.shlist.append(name) if species == "f": dreg = "df%d" % regnr sreg = "sf%d" % regnr else: dreg = "d%d" % regnr sreg = "s%d" % regnr dreg = regmagic.vname_to_legacy(dreg) sreg = regmagic.vname_to_legacy(sreg) newitems.append(flatten(a['loc'], 'register ') + ctype + ' __slPsin_%(name)s __asm__("%(dreg)s"); ' 'register ' % locals() + ctype + ' __slPsout_%(name)s __asm__("%(sreg)s"); ' % locals()) else: # cat: gl self.gllist.append(name) if species == "f": reg = "gf%d" % regnr else: reg = "g%d" % regnr reg = regmagic.vname_to_legacy(reg) newitems.append(flatten(a['loc'], 'register ') + ctype + ' const __slPg_%(name)s __asm__("%(reg)s"); ' % locals()) # For every global parameter which is also declared # mutable, we have to create a "regular" variable for it # and trace it in gllist_mutable for getp. for p in fundef.parms: if p.type.endswith('_mutable'): self.gllist_mutable.append(p.name) if p.name in self.gllist_mem: orig = "__slPgm->%s" % p.name else: orig = "__slPg_%s" % p.name newitems.append(flatten(p.loc,'') + p.ctype + " __slPwg_%s = %s;" % (p.name, orig)) # consume the body fundef.lbl_end = CLabel(loc = fundef.loc_end, name = "mtend") self.cur_fun = fundef newitems.append(fundef.body.accept(self)) # close the body definition with a target label for sl_end_thread newitems.append(CGoto(loc = fundef.loc_end, target = fundef.lbl_end) + ';' + fundef.lbl_end + ' __asm__ __volatile__("# MT: end follows"); }') return newitems