summaryrefslogtreecommitdiff
path: root/compiler/codeGen
diff options
context:
space:
mode:
authorMichal Terepeta <michal.terepeta@gmail.com>2017-10-29 20:49:32 -0400
committerBen Gamari <ben@smart-cactus.org>2017-10-29 21:51:05 -0400
commitcca2d6b78f97bfb79bef4dc3f75d6c4d15b94680 (patch)
tree9be80ec91082ad99ba79d21a6cd0aac68309a236 /compiler/codeGen
parent85aa1f4253163985fe07d172f8da73b784bb7b4b (diff)
downloadhaskell-cca2d6b78f97bfb79bef4dc3f75d6c4d15b94680.tar.gz
Allow packing constructor fields
This is another step for fixing #13825 and is based on D38 by Simon Marlow. The change allows storing multiple constructor fields within the same word. This currently applies only to `Float`s, e.g., ``` data Foo = Foo {-# UNPACK #-} !Float {-# UNPACK #-} !Float ``` on 64-bit arch, will now store both fields within the same constructor word. For `WordX/IntX` we'll need to introduce new primop types. Main changes: - We now use sizes in bytes when we compute the offsets for constructor fields in `StgCmmLayout` and introduce padding if necessary (word-sized fields are still word-aligned) - `ByteCodeGen` had to be updated to correctly construct the data types. This required some new bytecode instructions to allow pushing things that are not full words onto the stack (and updating `Interpreter.c`). Note that we only use the packed stuff when constructing data types (i.e., for `PACK`), in all other cases the behavior should not change. - `RtClosureInspect` was changed to handle the new layout when extracting subterms. This seems to be used by things like `:print`. I've also added a test for this. - I deviated slightly from Simon's approach and use `PrimRep` instead of `ArgRep` for computing the size of fields. This seemed more natural and in the future we'll probably want to introduce new primitive types (e.g., `Int8#`) and `PrimRep` seems like a better place to do that (where we already have `Int64Rep` for example). `ArgRep` on the other hand seems to be more focused on calling functions. Signed-off-by: Michal Terepeta <michal.terepeta@gmail.com> Test Plan: ./validate Reviewers: bgamari, simonmar, austin, hvr, goldfire, erikd Reviewed By: bgamari Subscribers: maoe, rwbarton, thomie GHC Trac Issues: #13825 Differential Revision: https://phabricator.haskell.org/D3809
Diffstat (limited to 'compiler/codeGen')
-rw-r--r--compiler/codeGen/StgCmmBind.hs2
-rw-r--r--compiler/codeGen/StgCmmCon.hs15
-rw-r--r--compiler/codeGen/StgCmmHeap.hs15
-rw-r--r--compiler/codeGen/StgCmmLayout.hs93
4 files changed, 89 insertions, 36 deletions
diff --git a/compiler/codeGen/StgCmmBind.hs b/compiler/codeGen/StgCmmBind.hs
index 8b2e998b5e..13f908e846 100644
--- a/compiler/codeGen/StgCmmBind.hs
+++ b/compiler/codeGen/StgCmmBind.hs
@@ -112,7 +112,7 @@ cgTopRhsClosure dflags rec id ccs _ upd_flag args body =
-- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)
; emitDataLits closure_label closure_rep
- ; let fv_details :: [(NonVoid Id, VirtualHpOffset)]
+ ; let fv_details :: [(NonVoid Id, ByteOff)]
(_, _, fv_details) = mkVirtHeapOffsets dflags (isLFThunk lf_info) []
-- Don't drop the non-void args until the closure info has been made
; forkClosureBody (closureCodeBody True id closure_info ccs
diff --git a/compiler/codeGen/StgCmmCon.hs b/compiler/codeGen/StgCmmCon.hs
index 1540d00715..a38f7bce37 100644
--- a/compiler/codeGen/StgCmmCon.hs
+++ b/compiler/codeGen/StgCmmCon.hs
@@ -79,9 +79,16 @@ cgTopRhsCon dflags id con args =
-- LAY IT OUT
; let
+ is_thunk = False
(tot_wds, -- #ptr_wds + #nonptr_wds
ptr_wds, -- #ptr_wds
- nv_args_w_offsets) = mkVirtConstrOffsets dflags (addArgReps args)
+ nv_args_w_offsets) =
+ mkVirtHeapOffsetsWithPadding dflags is_thunk (addArgReps args)
+
+ mk_payload (Padding len _) = return (CmmInt 0 (widthFromBytes len))
+ mk_payload (FieldOff arg _) = do
+ CmmLit lit <- getArgAmode arg
+ return lit
nonptr_wds = tot_wds - ptr_wds
@@ -90,10 +97,8 @@ cgTopRhsCon dflags id con args =
-- needs to poke around inside it.
info_tbl = mkDataConInfoTable dflags con True ptr_wds nonptr_wds
- get_lit (arg, _offset) = do { CmmLit lit <- getArgAmode arg
- ; return lit }
- ; payload <- mapM get_lit nv_args_w_offsets
+ ; payload <- mapM mk_payload nv_args_w_offsets
-- NB1: nv_args_w_offsets is sorted into ptrs then non-ptrs
-- NB2: all the amodes should be Lits!
-- TODO (osa): Why?
@@ -264,7 +269,7 @@ bindConArgs (DataAlt con) base args
-- The binding below forces the masking out of the tag bits
-- when accessing the constructor field.
- bind_arg :: (NonVoid Id, VirtualHpOffset) -> FCode (Maybe LocalReg)
+ bind_arg :: (NonVoid Id, ByteOff) -> FCode (Maybe LocalReg)
bind_arg (arg@(NonVoid b), offset)
| isDeadBinder b =
-- Do not load unused fields from objects to local variables.
diff --git a/compiler/codeGen/StgCmmHeap.hs b/compiler/codeGen/StgCmmHeap.hs
index 15dcaa2d89..790453619c 100644
--- a/compiler/codeGen/StgCmmHeap.hs
+++ b/compiler/codeGen/StgCmmHeap.hs
@@ -221,24 +221,11 @@ mkStaticClosure :: DynFlags -> CLabel -> CostCentreStack -> [CmmLit]
mkStaticClosure dflags info_lbl ccs payload padding static_link_field saved_info_field
= [CmmLabel info_lbl]
++ staticProfHdr dflags ccs
- ++ concatMap (padLitToWord dflags) payload
+ ++ payload
++ padding
++ static_link_field
++ saved_info_field
--- JD: Simon had elided this padding, but without it the C back end asserts
--- failure. Maybe it's a bad assertion, and this padding is indeed unnecessary?
-padLitToWord :: DynFlags -> CmmLit -> [CmmLit]
-padLitToWord dflags lit = lit : padding pad_length
- where width = typeWidth (cmmLitType dflags lit)
- pad_length = wORD_SIZE dflags - widthInBytes width :: Int
-
- padding n | n <= 0 = []
- | n `rem` 2 /= 0 = CmmInt 0 W8 : padding (n-1)
- | n `rem` 4 /= 0 = CmmInt 0 W16 : padding (n-2)
- | n `rem` 8 /= 0 = CmmInt 0 W32 : padding (n-4)
- | otherwise = CmmInt 0 W64 : padding (n-8)
-
-----------------------------------------------------------
-- Heap overflow checking
-----------------------------------------------------------
diff --git a/compiler/codeGen/StgCmmLayout.hs b/compiler/codeGen/StgCmmLayout.hs
index aeb01242e7..5111b93bc5 100644
--- a/compiler/codeGen/StgCmmLayout.hs
+++ b/compiler/codeGen/StgCmmLayout.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
-----------------------------------------------------------------------------
@@ -17,7 +18,12 @@ module StgCmmLayout (
slowCall, directCall,
- mkVirtHeapOffsets, mkVirtConstrOffsets, mkVirtConstrSizes, getHpRelOffset,
+ FieldOffOrPadding(..),
+ mkVirtHeapOffsets,
+ mkVirtHeapOffsetsWithPadding,
+ mkVirtConstrOffsets,
+ mkVirtConstrSizes,
+ getHpRelOffset,
ArgRep(..), toArgRep, argRepSizeW -- re-exported from StgCmmArgRep
) where
@@ -44,7 +50,7 @@ import CmmInfo
import CLabel
import StgSyn
import Id
-import TyCon ( PrimRep(..) )
+import TyCon ( PrimRep(..), primRepSizeB )
import BasicTypes ( RepArity )
import DynFlags
import Module
@@ -387,26 +393,33 @@ getHpRelOffset virtual_offset
hp_usg <- getHpUsage
return (cmmRegOffW dflags hpReg (hpRel (realHp hp_usg) virtual_offset))
-mkVirtHeapOffsets
+data FieldOffOrPadding a
+ = FieldOff (NonVoid a) -- Something that needs an offset.
+ ByteOff -- Offset in bytes.
+ | Padding ByteOff -- Length of padding in bytes.
+ ByteOff -- Offset in bytes.
+
+mkVirtHeapOffsetsWithPadding
:: DynFlags
-> Bool -- True <=> is a thunk
- -> [NonVoid (PrimRep,a)] -- Things to make offsets for
- -> (WordOff, -- _Total_ number of words allocated
- WordOff, -- Number of words allocated for *pointers*
- [(NonVoid a, ByteOff)])
+ -> [NonVoid (PrimRep, a)] -- Things to make offsets for
+ -> ( WordOff -- Total number of words allocated
+ , WordOff -- Number of words allocated for *pointers*
+ , [FieldOffOrPadding a] -- Either an offset or padding.
+ )
-- Things with their offsets from start of object in order of
-- increasing offset; BUT THIS MAY BE DIFFERENT TO INPUT ORDER
-- First in list gets lowest offset, which is initial offset + 1.
--
--- mkVirtHeapOffsets always returns boxed things with smaller offsets
+-- mkVirtHeapOffsetsWithPadding always returns boxed things with smaller offsets
-- than the unboxed things
-mkVirtHeapOffsets dflags is_thunk things
- = ASSERT(not (any (isVoidRep . fst . fromNonVoid) things))
- ( bytesToWordsRoundUp dflags tot_bytes
+mkVirtHeapOffsetsWithPadding dflags is_thunk things =
+ ASSERT(not (any (isVoidRep . fst . fromNonVoid) things))
+ ( tot_wds
, bytesToWordsRoundUp dflags bytes_of_ptrs
- , ptrs_w_offsets ++ non_ptrs_w_offsets
+ , concat (ptrs_w_offsets ++ non_ptrs_w_offsets) ++ final_pad
)
where
hdr_words | is_thunk = thunkHdrSize dflags
@@ -420,10 +433,58 @@ mkVirtHeapOffsets dflags is_thunk things
(tot_bytes, non_ptrs_w_offsets) =
mapAccumL computeOffset bytes_of_ptrs non_ptrs
- computeOffset bytes_so_far nv_thing
- = (bytes_so_far + wordsToBytes dflags (argRepSizeW dflags (toArgRep rep)),
- (NonVoid thing, hdr_bytes + bytes_so_far))
- where (rep,thing) = fromNonVoid nv_thing
+ tot_wds = bytesToWordsRoundUp dflags tot_bytes
+
+ final_pad_size = tot_wds * word_size - tot_bytes
+ final_pad
+ | final_pad_size > 0 = [(Padding final_pad_size
+ (hdr_bytes + tot_bytes))]
+ | otherwise = []
+
+ word_size = wORD_SIZE dflags
+
+ computeOffset bytes_so_far nv_thing =
+ (new_bytes_so_far, with_padding field_off)
+ where
+ (rep, thing) = fromNonVoid nv_thing
+
+ -- Size of the field in bytes.
+ !sizeB = primRepSizeB dflags rep
+
+ -- Align the start offset (eg, 2-byte value should be 2-byte aligned).
+ -- But not more than to a word.
+ !align = min word_size sizeB
+ !start = roundUpTo bytes_so_far align
+ !padding = start - bytes_so_far
+
+ -- Final offset is:
+ -- size of header + bytes_so_far + padding
+ !final_offset = hdr_bytes + bytes_so_far + padding
+ !new_bytes_so_far = start + sizeB
+ field_off = FieldOff (NonVoid thing) final_offset
+
+ with_padding field_off
+ | padding == 0 = [field_off]
+ | otherwise = [ Padding padding (hdr_bytes + bytes_so_far)
+ , field_off
+ ]
+
+
+mkVirtHeapOffsets
+ :: DynFlags
+ -> Bool -- True <=> is a thunk
+ -> [NonVoid (PrimRep,a)] -- Things to make offsets for
+ -> (WordOff, -- _Total_ number of words allocated
+ WordOff, -- Number of words allocated for *pointers*
+ [(NonVoid a, ByteOff)])
+mkVirtHeapOffsets dflags is_thunk things =
+ ( tot_wds
+ , ptr_wds
+ , [ (field, offset) | (FieldOff field offset) <- things_offsets ]
+ )
+ where
+ (tot_wds, ptr_wds, things_offsets) =
+ mkVirtHeapOffsetsWithPadding dflags is_thunk things
-- | Just like mkVirtHeapOffsets, but for constructors
mkVirtConstrOffsets