[pypy-commit] pypy portable-threadlocal: Implement this thread-local variant in the JIT.
arigo
noreply at buildbot.pypy.org
Tue Nov 25 23:28:04 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: portable-threadlocal
Changeset: r74718:d739638f9b7f
Date: 2014-11-25 22:48 +0100
http://bitbucket.org/pypy/pypy/changeset/d739638f9b7f/
Log: Implement this thread-local variant in the JIT.
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -1274,8 +1274,10 @@
regalloc.rm.possibly_free_var(dstaddr_box)
return fcond
- def emit_opx_threadlocalref_addr(self, op, arglocs, regalloc, fcond):
- res, = arglocs
+ def emit_opx_threadlocalref_get(self, op, arglocs, regalloc, fcond):
+ ofs0, res = arglocs
+ assert ofs0.is_imm()
ofs = self.saved_threadlocal_addr
self.load_reg(self.mc, res, r.sp, ofs)
+ self.load_reg(self.mc, res, res, ofs0.value)
return fcond
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -559,8 +559,8 @@
args = self._prepare_op_math_sqrt(op, fcond)
self.perform_extra(op, args, fcond)
return
- elif oopspecindex == EffectInfo.OS_THREADLOCALREF_ADDR:
- args = self._prepare_threadlocalref_addr(op, fcond)
+ elif oopspecindex == EffectInfo.OS_THREADLOCALREF_GET:
+ args = self._prepare_threadlocalref_get(op, fcond)
self.perform_extra(op, args, fcond)
return
#elif oopspecindex == EffectInfo.OS_MATH_READ_TIMESTAMP:
@@ -619,9 +619,10 @@
res = self.force_allocate_reg(op.result)
return [loc0, res]
- def _prepare_threadlocalref_addr(self, op, fcond):
+ def _prepare_threadlocalref_get(self, op, fcond):
+ ofs0 = imm(op.getarg(1).getint())
res = self.force_allocate_reg(op.result)
- return [res]
+ return [ofs0, res]
def _prepare_guard(self, op, args=None):
if args is None:
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -220,8 +220,8 @@
# The JIT backend must generate functions with the following
# signature: it takes the jitframe and the threadlocal_addr
# as arguments, and it returns the (possibly reallocated) jitframe.
- # The backend can optimize OS_THREADLOCALREF_ADDR calls to return
- # this threadlocal_addr, but only if 'translate_support_code':
+ # The backend can optimize OS_THREADLOCALREF_GET calls to return a
+ # field of this threadlocal_addr, but only if 'translate_support_code':
# in untranslated tests, threadlocal_addr is a dummy NULL.
FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF, llmemory.Address],
llmemory.GCREF))
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -2322,38 +2322,16 @@
assert isinstance(reg, RegLoc)
self.mc.MOV_rr(reg.value, ebp.value)
- def threadlocalref_addr(self, resloc):
- # This simply loads the stack location THREADLOCAL_OFS into a
- # register. It is only supported if 'translate_support_code' is
+ def threadlocalref_get(self, offset, resloc):
+ # This loads the stack location THREADLOCAL_OFS into a
+ # register, and then read the word at the given offset.
+ # It is only supported if 'translate_support_code' is
# true; otherwise, the original call to the piece of assembler
# was done with a dummy NULL value.
assert self.cpu.translate_support_code
assert isinstance(resloc, RegLoc)
self.mc.MOV_rs(resloc.value, THREADLOCAL_OFS)
-
- def get_set_errno(self, op, loc, issue_a_write):
- # this function is only called on Linux
- from rpython.jit.backend.x86 import stmtlocal
- addr = stmtlocal.get_errno_tl()
- assert rx86.fits_in_32bits(addr)
- mc = self.mc
- mc.writechar(stmtlocal.SEGMENT_TL) # prefix: %fs or %gs
- # !!important: the *next* instruction must be the one using 'addr'!!
- if issue_a_write:
- if isinstance(loc, RegLoc):
- mc.MOV32_jr(addr, loc.value) # memory write from reg
- else:
- assert isinstance(loc, ImmedLoc)
- newvalue = loc.value
- newvalue = rffi.cast(rffi.INT, newvalue)
- newvalue = rffi.cast(lltype.Signed, newvalue)
- mc.MOV32_ji(addr, newvalue) # memory write immediate
- else:
- assert isinstance(loc, RegLoc)
- if IS_X86_32:
- mc.MOV_rj(loc.value, addr) # memory read
- elif IS_X86_64:
- mc.MOVSX32_rj(loc.value, addr) # memory read, sign-extend
+ self.mc.MOV_rm(resloc.value, (resloc.value, offset))
def genop_discard_zero_array(self, op, arglocs):
(base_loc, startindex_loc, bytes_loc,
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -693,10 +693,11 @@
loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(1))
self.perform_math(op, [loc0], loc0)
- def _consider_threadlocalref_addr(self, op):
+ def _consider_threadlocalref_get(self, op):
if self.translate_support_code:
+ offset = op.getarg(1).getint() # getarg(0) == 'threadlocalref_get'
resloc = self.force_allocate_reg(op.result)
- self.assembler.threadlocalref_addr(resloc)
+ self.assembler.threadlocalref_get(offset, resloc)
else:
self._consider_call(op)
@@ -777,8 +778,8 @@
return
if oopspecindex == EffectInfo.OS_MATH_SQRT:
return self._consider_math_sqrt(op)
- if oopspecindex == EffectInfo.OS_THREADLOCALREF_ADDR:
- return self._consider_threadlocalref_addr(op)
+ if oopspecindex == EffectInfo.OS_THREADLOCALREF_GET:
+ return self._consider_threadlocalref_get(op)
if oopspecindex == EffectInfo.OS_MATH_READ_TIMESTAMP:
return self._consider_math_read_timestamp(op)
self._consider_call(op)
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -22,7 +22,7 @@
OS_STR2UNICODE = 2 # "str.str2unicode"
OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array
OS_DICT_LOOKUP = 4 # ll_dict_lookup
- OS_THREADLOCALREF_ADDR = 5 # llop.threadlocalref_addr
+ OS_THREADLOCALREF_GET = 5 # llop.threadlocalref_get
OS_NOT_IN_TRACE = 8 # for calls not recorded in the jit trace
#
OS_STR_CONCAT = 22 # "stroruni.concat"
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1999,11 +1999,16 @@
None)
return [op0, op1]
- def rewrite_op_threadlocalref_addr(self, op):
- op1 = self.prepare_builtin_call(op, 'threadlocalref_addr', [])
+ def rewrite_op_threadlocalref_get(self, op):
+ # only supports RESTYPE being exactly one word.
+ RESTYPE = op.result.concretetype
+ assert (RESTYPE in (lltype.Signed, lltype.Unsigned, llmemory.Address)
+ or isinstance(RESTYPE, lltype.Ptr))
+ c_offset, = op.args
+ op1 = self.prepare_builtin_call(op, 'threadlocalref_get', [c_offset])
return self.handle_residual_call(op1,
- oopspecindex=EffectInfo.OS_THREADLOCALREF_ADDR,
- extraeffect=EffectInfo.EF_CANNOT_RAISE)
+ oopspecindex=EffectInfo.OS_THREADLOCALREF_GET,
+ extraeffect=EffectInfo.EF_LOOPINVARIANT)
# ____________________________________________________________
diff --git a/rpython/jit/codewriter/support.py b/rpython/jit/codewriter/support.py
--- a/rpython/jit/codewriter/support.py
+++ b/rpython/jit/codewriter/support.py
@@ -702,8 +702,9 @@
build_ll_1_raw_free_no_track_allocation = (
build_raw_free_builder(track_allocation=False))
- def _ll_0_threadlocalref_addr():
- return llop.threadlocalref_addr(llmemory.Address)
+ def _ll_1_threadlocalref_get(TP, offset):
+ return llop.threadlocalref_get(TP, offset)
+ _ll_1_threadlocalref_get.need_result_type = 'exact' # don't deref
def _ll_1_weakref_create(obj):
return llop.weakref_create(llmemory.WeakRefPtr, obj)
@@ -816,8 +817,18 @@
s_result = lltype_to_annotation(ll_res)
impl = setup_extra_builtin(rtyper, oopspec_name, len(args_s), extra)
if getattr(impl, 'need_result_type', False):
- bk = rtyper.annotator.bookkeeper
- args_s.insert(0, annmodel.SomePBC([bk.getdesc(deref(ll_res))]))
+ if hasattr(rtyper, 'annotator'):
+ bk = rtyper.annotator.bookkeeper
+ ll_restype = ll_res
+ if impl.need_result_type != 'exact':
+ ll_restype = deref(ll_restype)
+ desc = bk.getdesc(ll_restype)
+ else:
+ class TestingDesc(object):
+ knowntype = int
+ pyobj = None
+ desc = TestingDesc()
+ args_s.insert(0, annmodel.SomePBC([desc]))
#
if hasattr(rtyper, 'annotator'): # regular case
mixlevelann = MixLevelHelperAnnotator(rtyper)
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -148,7 +148,7 @@
EI.OS_UNIEQ_LENGTHOK: ([PUNICODE, PUNICODE], INT),
EI.OS_RAW_MALLOC_VARSIZE_CHAR: ([INT], ARRAYPTR),
EI.OS_RAW_FREE: ([ARRAYPTR], lltype.Void),
- EI.OS_THREADLOCALREF_ADDR: ([], llmemory.Address),
+ EI.OS_THREADLOCALREF_GET: ([INT], INT), # for example
}
argtypes = argtypes[oopspecindex]
assert argtypes[0] == [v.concretetype for v in op.args[1:]]
@@ -157,9 +157,10 @@
assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE_CHAR:
assert extraeffect == EI.EF_CAN_RAISE
- elif oopspecindex in (EI.OS_RAW_FREE,
- EI.OS_THREADLOCALREF_ADDR):
+ elif oopspecindex == EI.OS_RAW_FREE:
assert extraeffect == EI.EF_CANNOT_RAISE
+ elif oopspecindex == EI.OS_THREADLOCALREF_GET:
+ assert extraeffect == EI.EF_LOOPINVARIANT
else:
assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
return 'calldescr-%d' % oopspecindex
@@ -1341,16 +1342,20 @@
assert op1.result is None
assert op2 is None
-def test_threadlocalref_addr():
- OS_THREADLOCALREF_ADDR = effectinfo.EffectInfo.OS_THREADLOCALREF_ADDR
- v = varoftype(llmemory.Address)
- op = SpaceOperation('threadlocalref_addr', [], v)
+def test_threadlocalref_get():
+ from rpython.rlib.rthread import ThreadLocalField
+ tlfield = ThreadLocalField(lltype.Signed, 'foobar_test_')
+ OS_THREADLOCALREF_GET = effectinfo.EffectInfo.OS_THREADLOCALREF_GET
+ c = const(tlfield.offset)
+ v = varoftype(lltype.Signed)
+ op = SpaceOperation('threadlocalref_get', [c], v)
tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
op0 = tr.rewrite_operation(op)
- assert op0.opname == 'residual_call_r_i'
- assert op0.args[0].value == 'threadlocalref_addr' # pseudo-function as str
- assert op0.args[1] == ListOfKind("ref", [])
- assert op0.args[2] == 'calldescr-%d' % OS_THREADLOCALREF_ADDR
+ assert op0.opname == 'residual_call_ir_i'
+ assert op0.args[0].value == 'threadlocalref_get' # pseudo-function as str
+ assert op0.args[1] == ListOfKind("int", [c])
+ assert op0.args[2] == ListOfKind("ref", [])
+ assert op0.args[3] == 'calldescr-%d' % OS_THREADLOCALREF_GET
assert op0.result == v
def test_unknown_operation():
diff --git a/rpython/jit/metainterp/test/test_threadlocal.py b/rpython/jit/metainterp/test/test_threadlocal.py
--- a/rpython/jit/metainterp/test/test_threadlocal.py
+++ b/rpython/jit/metainterp/test/test_threadlocal.py
@@ -1,19 +1,20 @@
import py
+from rpython.rlib import rthread
from rpython.jit.metainterp.test.support import LLJitMixin
-from rpython.rtyper.lltypesystem import llmemory
+from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.lltypesystem.lloperation import llop
class ThreadLocalTest(object):
def test_threadlocalref_get(self):
+ tlfield = rthread.ThreadLocalField(lltype.Signed, 'foobar_test_')
+
def f():
- addr1 = llop.threadlocalref_addr(llmemory.Address)
- # a "does not crash" test only
- return 1
+ return tlfield.getraw()
res = self.interp_operations(f, [])
- assert res == 1
+ assert res == 0x544c # magic value returned by llinterp
class TestLLtype(ThreadLocalTest, LLJitMixin):
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -921,14 +921,12 @@
def op_threadlocalref_addr(self):
raise NotImplementedError("threadlocalref_addr")
- ## class FakeThreadLocalAddr(object):
- ## is_fake_thread_local_addr = True
- ## _TYPE = llmemory.Address
- ## def _cast_to_int(self, symbolic=None):
- ## return FakeThreadLocalAddrAsInt()
- ## class FakeThreadLocalAddrAsInt(object):
- ## _TYPE = lltype.Signed
- ## return FakeThreadLocalAddr()
+
+ def op_threadlocalref_get(self, offset):
+ if (type(offset) is CDefinedIntSymbolic and
+ offset.expr == 'RPY_TLOFS_foobar_test_'): # used in tests
+ return 0x544c
+ raise NotImplementedError("threadlocalref_get")
# __________________________________________________________
# operations on addresses
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -902,15 +902,20 @@
return None # use the default
def OP_THREADLOCALREF_GET(self, op):
- assert isinstance(op.args[0], Constant)
- assert isinstance(op.args[0].value, CDefinedIntSymbolic)
- fieldname = op.args[0].value.expr
- assert fieldname.startswith('RPY_TLOFS_')
- fieldname = fieldname[10:]
typename = self.db.gettype(op.result.concretetype)
- return '%s = (%s)RPY_THREADLOCALREF_GET(%s);' % (
- self.expr(op.result),
- cdecl(typename, ''),
- fieldname)
+ if isinstance(op.args[0], Constant):
+ assert isinstance(op.args[0].value, CDefinedIntSymbolic)
+ fieldname = op.args[0].value.expr
+ assert fieldname.startswith('RPY_TLOFS_')
+ fieldname = fieldname[10:]
+ return '%s = (%s)RPY_THREADLOCALREF_GET(%s);' % (
+ self.expr(op.result),
+ cdecl(typename, ''),
+ fieldname)
+ else:
+ return 'OP_THREADLOCALREF_GET_NONCONST(%s, %s, %s);' % (
+ cdecl(typename, ''),
+ self.expr(op.args[0]),
+ self.expr(op.result))
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
diff --git a/rpython/translator/c/src/threadlocal.h b/rpython/translator/c/src/threadlocal.h
--- a/rpython/translator/c/src/threadlocal.h
+++ b/rpython/translator/c/src/threadlocal.h
@@ -86,4 +86,13 @@
/* ------------------------------------------------------------ */
+/* only for the fall-back path in the JIT */
+#define OP_THREADLOCALREF_GET_NONCONST(RESTYPE, offset, r) \
+ do { \
+ char *a; \
+ OP_THREADLOCALREF_ADDR(a); \
+ r = *(RESTYPE *)(a + offset); \
+ } while (0)
+
+
#endif /* _SRC_THREADLOCAL_H */
More information about the pypy-commit
mailing list