[pypy-commit] pypy arm-backend-2: Implement the hard float (armhf) ABI for ARM. FP arguments to calls are passed
bivab
noreply at buildbot.pypy.org
Sun Jul 22 13:03:13 CEST 2012
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r56387:ecac9a5ff668
Date: 2012-07-22 11:01 +0000
http://bitbucket.org/pypy/pypy/changeset/ecac9a5ff668/
Log: Implement the hard float (armhf) ABI for ARM. FP arguments to calls
are passed using VFP registers d0-d7 instead of using the GPRs.
diff --git a/pypy/jit/backend/arm/opassembler.py b/pypy/jit/backend/arm/opassembler.py
--- a/pypy/jit/backend/arm/opassembler.py
+++ b/pypy/jit/backend/arm/opassembler.py
@@ -2,7 +2,7 @@
from pypy.jit.backend.arm import conditions as c
from pypy.jit.backend.arm import registers as r
from pypy.jit.backend.arm import shift
-from pypy.jit.backend.arm.arch import WORD
+from pypy.jit.backend.arm.arch import WORD, DOUBLE_WORD
from pypy.jit.backend.arm.helper.assembler import (gen_emit_op_by_helper_call,
gen_emit_op_unary_cmp,
@@ -370,31 +370,69 @@
def _emit_call(self, force_index, adr, arglocs, fcond=c.AL,
resloc=None, result_info=(-1,-1)):
+ if self.cpu.use_hf_abi:
+ stack_args, adr = self._setup_call_hf(force_index, adr, arglocs, fcond, resloc, result_info)
+ else:
+ stack_args, adr = self._setup_call_sf(force_index, adr, arglocs, fcond, resloc, result_info)
+
+ #the actual call
+ #self.mc.BKPT()
+ if adr.is_imm():
+ self.mc.BL(adr.value)
+ elif adr.is_stack():
+ self.mov_loc_loc(adr, r.ip)
+ adr = r.ip
+ else:
+ assert adr.is_reg()
+ if adr.is_reg():
+ self.mc.BLX(adr.value)
+ self.mark_gc_roots(force_index)
+ self._restore_sp(stack_args, fcond)
+
+ # ensure the result is wellformed and stored in the correct location
+ if resloc is not None:
+ if resloc.is_vfp_reg() and not self.cpu.use_hf_abi:
+ # move result to the allocated register
+ self.mov_to_vfp_loc(r.r0, r.r1, resloc)
+ elif resloc.is_reg() and result_info != (-1, -1):
+ self._ensure_result_bit_extension(resloc, result_info[0],
+ result_info[1])
+ return fcond
+
+ def _restore_sp(self, stack_args, fcond):
+ # readjust the sp in case we passed some args on the stack
+ if len(stack_args) > 0:
+ n = 0
+ for arg in stack_args:
+ if arg is None or arg.type != FLOAT:
+ n += WORD
+ else:
+ n += DOUBLE_WORD
+ self._adjust_sp(-n, fcond=fcond)
+ assert n % 8 == 0 # sanity check
+
+ def _collect_stack_args_sf(self, arglocs):
n_args = len(arglocs)
reg_args = count_reg_args(arglocs)
# all arguments past the 4th go on the stack
- n = 0 # used to count the number of words pushed on the stack, so we
- #can later modify the SP back to its original value
+ # first we need to prepare the list so it stays aligned
+ stack_args = []
+ count = 0
if n_args > reg_args:
- # first we need to prepare the list so it stays aligned
- stack_args = []
- count = 0
for i in range(reg_args, n_args):
arg = arglocs[i]
if arg.type != FLOAT:
count += 1
- n += WORD
else:
- n += 2 * WORD
if count % 2 != 0:
stack_args.append(None)
- n += WORD
count = 0
stack_args.append(arg)
if count % 2 != 0:
- n += WORD
stack_args.append(None)
+ return stack_args
+ def _push_stack_args(self, stack_args):
#then we push every thing on the stack
for i in range(len(stack_args) - 1, -1, -1):
arg = stack_args[i]
@@ -402,6 +440,13 @@
self.mc.PUSH([r.ip.value])
else:
self.regalloc_push(arg)
+
+ def _setup_call_sf(self, force_index, adr, arglocs, fcond=c.AL,
+ resloc=None, result_info=(-1,-1)):
+ n_args = len(arglocs)
+ reg_args = count_reg_args(arglocs)
+ stack_args = self._collect_stack_args_sf(arglocs)
+ self._push_stack_args(stack_args)
# collect variables that need to go in registers and the registers they
# will be stored in
num = 0
@@ -440,32 +485,55 @@
for loc, reg in float_locs:
self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1])
+ return stack_args, adr
- #the actual call
- if adr.is_imm():
- self.mc.BL(adr.value)
- elif adr.is_stack():
- self.mov_loc_loc(adr, r.ip)
- adr = r.ip
- else:
- assert adr.is_reg()
- if adr.is_reg():
- self.mc.BLX(adr.value)
- self.mark_gc_roots(force_index)
- # readjust the sp in case we passed some args on the stack
- if n > 0:
- self._adjust_sp(-n, fcond=fcond)
- # ensure the result is wellformed and stored in the correct location
- if resloc is not None:
- if resloc.is_vfp_reg():
- # move result to the allocated register
- self.mov_to_vfp_loc(r.r0, r.r1, resloc)
- elif result_info != (-1, -1):
- self._ensure_result_bit_extension(resloc, result_info[0],
- result_info[1])
+ def _setup_call_hf(self, force_index, adr, arglocs, fcond=c.AL,
+ resloc=None, result_info=(-1,-1)):
+ n_reg_args = n_vfp_args = 0
+ non_float_locs = []
+ non_float_regs = []
+ float_locs = []
+ float_regs = []
+ stack_args = []
+ count = 0 # stack alignment counter
+ for arg in arglocs:
+ if arg.type != FLOAT:
+ if len(non_float_regs) < len(r.argument_regs):
+ reg = r.argument_regs[len(non_float_regs)]
+ non_float_locs.append(arg)
+ non_float_regs.append(reg)
+ else: # non-float argument that needs to go on the stack
+ count += 1
+ stack_args.append(arg)
+ else:
+ if len(float_regs) < len(r.vfp_argument_regs):
+ reg = r.vfp_argument_regs[len(float_regs)]
+ float_locs.append(arg)
+ float_regs.append(reg)
+ else: # float argument that needs to go on the stack
+ if count % 2 != 0:
+ stack_args.append(None)
+ count = 0
+ stack_args.append(arg)
+ # align the stack
+ if count % 2 != 0:
+ stack_args.append(None)
+ self._push_stack_args(stack_args)
+ # Check that the address of the function we want to call is not
+ # currently stored in one of the registers used to pass the arguments.
+ # If this happens to be the case we remap the register to r4 and use r4
+ # to call the function
+ if adr in non_float_regs:
+ non_float_locs.append(adr)
+ non_float_regs.append(r.r4)
+ adr = r.r4
+ # remap values stored in core registers
+ remap_frame_layout(self, non_float_locs, non_float_regs, r.ip)
+ # remap values stored in vfp registers
+ remap_frame_layout(self, float_locs, float_regs, r.vfp_ip)
- return fcond
+ return stack_args, adr
def emit_op_same_as(self, op, arglocs, regalloc, fcond):
argloc, resloc = arglocs
diff --git a/pypy/jit/backend/arm/regalloc.py b/pypy/jit/backend/arm/regalloc.py
--- a/pypy/jit/backend/arm/regalloc.py
+++ b/pypy/jit/backend/arm/regalloc.py
@@ -104,8 +104,8 @@
which is in variable v.
"""
self._check_type(v)
- r = self.force_allocate_reg(v)
- return r
+ reg = self.force_allocate_reg(v, selected_reg=r.d0)
+ return reg
def ensure_value_is_boxed(self, thing, forbidden_vars=[]):
loc = None
@@ -309,6 +309,12 @@
# The first inputargs are passed in registers r0-r3
# we relly on the soft-float calling convention so we need to move
# float params to the coprocessor.
+ if self.cpu.use_hf_abi:
+ self._set_initial_bindings_hf(inputargs)
+ else:
+ self._set_initial_bindings_sf(inputargs)
+
+ def _set_initial_bindings_sf(self, inputargs):
arg_index = 0
count = 0
@@ -328,7 +334,7 @@
vfpreg = self.try_allocate_reg(box)
# move soft-float argument to vfp
self.assembler.mov_to_vfp_loc(loc, loc2, vfpreg)
- arg_index += 2 # this argument used to argument registers
+ arg_index += 2 # this argument used two argument registers
else:
loc = r.argument_regs[arg_index]
self.try_allocate_reg(box, selected_reg=loc)
@@ -346,6 +352,38 @@
loc = self.frame_manager.frame_pos(cur_frame_pos, box.type)
self.frame_manager.set_binding(box, loc)
+ def _set_initial_bindings_hf(self, inputargs):
+
+ arg_index = vfp_arg_index = 0
+ count = 0
+ n_reg_args = len(r.argument_regs)
+ n_vfp_reg_args = len(r.vfp_argument_regs)
+ cur_frame_pos = - (self.assembler.STACK_FIXED_AREA / WORD) + 1
+ cur_frame_pos = 1 - (self.assembler.STACK_FIXED_AREA // WORD)
+ for box in inputargs:
+ assert isinstance(box, Box)
+ # handle inputargs in argument registers
+ if box.type != FLOAT and arg_index < n_reg_args:
+ reg = r.argument_regs[arg_index]
+ self.try_allocate_reg(box, selected_reg=reg)
+ arg_index += 1
+ elif box.type == FLOAT and vfp_arg_index < n_vfp_reg_args:
+ reg = r.vfp_argument_regs[vfp_arg_index]
+ self.try_allocate_reg(box, selected_reg=reg)
+ vfp_arg_index += 1
+ else:
+ # treat stack args as stack locations with a negative offset
+ if box.type == FLOAT:
+ cur_frame_pos -= 2
+ if count % 2 != 0: # Stack argument alignment
+ cur_frame_pos -= 1
+ count = 0
+ else:
+ cur_frame_pos -= 1
+ count += 1
+ loc = self.frame_manager.frame_pos(cur_frame_pos, box.type)
+ self.frame_manager.set_binding(box, loc)
+
def _update_bindings(self, locs, inputargs):
used = {}
i = 0
diff --git a/pypy/jit/backend/arm/registers.py b/pypy/jit/backend/arm/registers.py
--- a/pypy/jit/backend/arm/registers.py
+++ b/pypy/jit/backend/arm/registers.py
@@ -26,7 +26,7 @@
callee_saved_registers = callee_resp + [lr]
callee_restored_registers = callee_resp + [pc]
-caller_vfp_resp = [d0, d1, d2, d3, d4, d5, d6, d7]
+vfp_argument_regs = caller_vfp_resp = [d0, d1, d2, d3, d4, d5, d6, d7]
callee_vfp_resp = [d8, d9, d10, d11, d12, d13, d14, d15]
callee_saved_vfp_registers = callee_vfp_resp
diff --git a/pypy/jit/backend/arm/runner.py b/pypy/jit/backend/arm/runner.py
--- a/pypy/jit/backend/arm/runner.py
+++ b/pypy/jit/backend/arm/runner.py
@@ -150,3 +150,4 @@
class CPU_ARMHF(AbstractARMCPU):
"""ARM v7 uses hardfp ABI, requires vfp"""
use_hf_abi = True
+ supports_floats = False
diff --git a/pypy/jit/backend/detect_cpu.py b/pypy/jit/backend/detect_cpu.py
--- a/pypy/jit/backend/detect_cpu.py
+++ b/pypy/jit/backend/detect_cpu.py
@@ -63,7 +63,6 @@
from pypy.jit.backend.arm.detect import detect_hardfloat, detect_float
if detect_hardfloat():
model = 'armhf'
- raise AssertionError, 'disabled for now (ABI switching issues with libffi)'
assert detect_float(), 'the JIT-compiler requires a vfp unit'
return model
More information about the pypy-commit
mailing list