CmmCallConv.hs 6.63 KB
Newer Older
1
2
3
4
module CmmCallConv (
  ParamLocation(..),
  ArgumentFormat,
  assignArguments,
5
  assignArgumentsPos,
6
  argumentsSize,
7
8
9
10
11
12
) where

#include "HsVersions.h"

import Cmm
import SMRep
13
import ZipCfgCmmRep (Convention(..))
14
15
16

import Constants
import StaticFlags (opt_Unregisterised)
17
import Outputable
18
19
import Panic

20
21
22
-- Calculate the 'GlobalReg' or stack locations for function call
-- parameters as used by the Cmm calling convention.

23
data ParamLocation a
24
  = RegisterParam GlobalReg
25
  | StackParam a
26

27
28
29
30
instance (Outputable a) => Outputable (ParamLocation a) where
  ppr (RegisterParam g) = ppr g
  ppr (StackParam p)    = ppr p

31
type ArgumentFormat a b = [(a, ParamLocation b)]
32

33
34
-- Stack parameters are returned as word offsets.
assignArguments :: (a -> CmmType) -> [a] -> ArgumentFormat a WordOff
35
assignArguments f reps = assignments
36
    where
37
      availRegs = getRegs False
38
      (sizes, assignments) = unzip $ assignArguments' reps (negate (sum sizes)) availRegs
Ian Lynagh's avatar
Ian Lynagh committed
39
      assignArguments' [] _ _ = []
40
      assignArguments' (r:rs) offset availRegs =
41
          (size,(r,assignment)):assignArguments' rs new_offset remaining
42
          where 
43
            (assignment, new_offset, size, remaining) =
44
                assign_reg assign_slot_neg (f r) offset availRegs
45
46
47
48
49

-- | JD: For the new stack story, I want arguments passed on the stack to manifest as
-- positive offsets in a CallArea, not negative offsets from the stack pointer.
-- Also, I want byte offsets, not word offsets.
-- The first argument tells us whether we are assigning positions for call arguments
50
51
52
53
54
55
-- or return results. The distinction matters because some conventions use different
-- global registers in each case. In particular, the native calling convention
-- uses the `node' register to pass the closure environment.
assignArgumentsPos :: (Outputable a) => Convention -> Bool -> (a -> CmmType) -> [a] ->
                      ArgumentFormat a ByteOff
assignArgumentsPos conv isCall arg_ty reps = map cvt assignments
56
    where
57
58
59
60
61
62
      regs = case conv of Native -> getRegs isCall
                          GC     -> getRegs False
                          PrimOp -> noStack
                          Slow   -> noRegs
                          _      -> panic "unrecognized calling convention"
      (sizes, assignments) = unzip $ assignArguments' reps (sum sizes) regs
63
64
      assignArguments' [] _ _ = []
      assignArguments' (r:rs) offset avails =
65
          (size, (r,assignment)):assignArguments' rs new_offset remaining
66
67
          where 
            (assignment, new_offset, size, remaining) =
68
                assign_reg assign_slot_pos (arg_ty r) offset avails
69
70
      cvt (l, RegisterParam r) = (l, RegisterParam r)
      cvt (l, StackParam off)  = (l, StackParam $ off * wORD_SIZE)
71

72
argumentsSize :: (a -> CmmType) -> [a] -> WordOff
73
74
75
argumentsSize f reps = maximum (0 : map arg_top args)
    where
      args = assignArguments f reps
Ian Lynagh's avatar
Ian Lynagh committed
76
      arg_top (_, StackParam offset) = -offset
77
78
79
80
      arg_top (_, RegisterParam _) = 0

-----------------------------------------------------------------------------
-- Local information about the registers available
81

82
type AvailRegs = ( [VGcPtr -> GlobalReg]   -- available vanilla regs.
83
84
85
86
87
88
89
90
91
92
93
		 , [GlobalReg]   -- floats
		 , [GlobalReg]   -- doubles
		 , [GlobalReg]   -- longs (int64 and word64)
		 )

-- Vanilla registers can contain pointers, Ints, Chars.
-- Floats and doubles have separate register supplies.
--
-- We take these register supplies from the *real* registers, i.e. those
-- that are guaranteed to map to machine registers.

Ian Lynagh's avatar
Ian Lynagh committed
94
useVanillaRegs, useFloatRegs, useDoubleRegs, useLongRegs :: Int
95
96
97
98
99
100
101
102
103
useVanillaRegs | opt_Unregisterised = 0
	       | otherwise          = mAX_Real_Vanilla_REG
useFloatRegs   | opt_Unregisterised = 0
	       | otherwise          = mAX_Real_Float_REG
useDoubleRegs  | opt_Unregisterised = 0
	       | otherwise          = mAX_Real_Double_REG
useLongRegs    | opt_Unregisterised = 0
	       | otherwise          = mAX_Real_Long_REG

Ian Lynagh's avatar
Ian Lynagh committed
104
getRegs :: Bool -> AvailRegs
105
106
107
108
109
getRegs reserveNode =
  (if reserveNode then filter (\r -> r VGcPtr /= node) intRegs else intRegs,
   regList FloatReg  useFloatRegs,
   regList DoubleReg useDoubleRegs,
   regList LongReg   useLongRegs)
110
111
    where
      regList f max = map f [1 .. max]
112
113
      intRegs = regList VanillaReg useVanillaRegs

Ian Lynagh's avatar
Ian Lynagh committed
114
noStack :: AvailRegs
115
116
noStack = (map VanillaReg any, map FloatReg any, map DoubleReg any, map LongReg any)
  where any = [1 .. ]
Ian Lynagh's avatar
Ian Lynagh committed
117
118

noRegs :: AvailRegs
119
noRegs    = ([], [], [], [])
120

121
-- Round the size of a local register up to the nearest word.
Ian Lynagh's avatar
Ian Lynagh committed
122
123
124
{-
UNUSED 2008-12-29

125
slot_size :: LocalReg -> Int
126
slot_size reg = slot_size' (typeWidth (localRegType reg))
Ian Lynagh's avatar
Ian Lynagh committed
127
-}
128
129
130
131
132
133
134

slot_size' :: Width -> Int
slot_size' reg = ((widthInBytes reg - 1) `div` wORD_SIZE) + 1

type Assignment = (ParamLocation WordOff, WordOff, WordOff, AvailRegs)
type SlotAssigner = Width -> Int -> AvailRegs -> Assignment

135
136
137
138
assign_reg :: SlotAssigner -> CmmType -> WordOff -> AvailRegs -> Assignment
assign_reg slot ty off avails
  | isFloatType ty = assign_float_reg slot width off avails
  | otherwise      = assign_bits_reg  slot width off gcp avails
139
140
141
142
143
  where
    width = typeWidth ty
    gcp | isGcPtrType ty = VGcPtr
	| otherwise  	 = VNonGcPtr

144
-- Assigning a slot using negative offsets from the stack pointer.
145
146
-- JD: I don't know why this convention stops using all the registers
--     after running out of one class of registers.
147
assign_slot_neg :: SlotAssigner
Ian Lynagh's avatar
Ian Lynagh committed
148
assign_slot_neg width off _regs =
149
150
  (StackParam $ off, off + size, size, ([], [], [], [])) where size = slot_size' width

151
152
-- Assigning a slot using positive offsets into a CallArea.
assign_slot_pos :: SlotAssigner
Ian Lynagh's avatar
Ian Lynagh committed
153
assign_slot_pos width off _regs =
154
  (StackParam $ off, off - size, size, ([], [], [], []))
155
156
  where size = slot_size' width

157
158
-- On calls in the native convention, `node` is used to hold the environment
-- for the closure, so we can't pass arguments in that register.
Ian Lynagh's avatar
Ian Lynagh committed
159
160
assign_bits_reg :: SlotAssigner -> Width -> WordOff -> VGcPtr -> AvailRegs
                -> Assignment
161
162
163
assign_bits_reg _ W128 _ _ _ = panic "W128 is not a supported register type"
assign_bits_reg assign_slot w off gcp regs@(v:vs, fs, ds, ls) =
  if widthInBits w <= widthInBits wordWidth then
164
165
    (RegisterParam (v gcp), off, 0, (vs, fs, ds, ls))
  else assign_slot w off regs
Ian Lynagh's avatar
Ian Lynagh committed
166
assign_bits_reg assign_slot w off _ regs@([], _, _, _) =
167
  assign_slot w off regs
168

Ian Lynagh's avatar
Ian Lynagh committed
169
assign_float_reg :: SlotAssigner -> Width -> WordOff -> AvailRegs -> Assignment
170
171
assign_float_reg _ W32 off (vs, f:fs, ds, ls) = (RegisterParam $ f, off, 0, (vs, fs, ds, ls))
assign_float_reg _ W64 off (vs, fs, d:ds, ls) = (RegisterParam $ d, off, 0, (vs, fs, ds, ls))
Ian Lynagh's avatar
Ian Lynagh committed
172
assign_float_reg _ W80 _   _                  = panic "F80 is not a supported register type"
173
assign_float_reg assign_slot width off r = assign_slot width off r