diff options
author | Alexis King <lexi.lambda@gmail.com> | 2023-03-04 00:55:01 -0600 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2023-03-08 08:59:53 -0500 |
commit | bed3a292df532935426987e1f0c5eaa4f605407e (patch) | |
tree | 06449c39b4e1712293d72884d99d191b46597225 | |
parent | 1e0d8fdb55a38ece34fa6cf214e1d2d46f5f5bf2 (diff) | |
download | haskell-bed3a292df532935426987e1f0c5eaa4f605407e.tar.gz |
bytecode: Fix bitmaps for BCOs used to tag tuples and prim call args
fixes #23068
-rw-r--r-- | compiler/GHC/ByteCode/Instr.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/StgToByteCode.hs | 91 | ||||
-rw-r--r-- | testsuite/tests/bytecode/T23068.hs | 9 | ||||
-rw-r--r-- | testsuite/tests/bytecode/T23068.script | 1 | ||||
-rw-r--r-- | testsuite/tests/bytecode/T23068.stdout | 71 | ||||
-rw-r--r-- | testsuite/tests/bytecode/all.T | 3 |
6 files changed, 145 insertions, 36 deletions
diff --git a/compiler/GHC/ByteCode/Instr.hs b/compiler/GHC/ByteCode/Instr.hs index 4f9fd75fc4..4fbfaa76a6 100644 --- a/compiler/GHC/ByteCode/Instr.hs +++ b/compiler/GHC/ByteCode/Instr.hs @@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# OPTIONS_GHC -funbox-strict-fields #-} -- -- (c) The University of Glasgow 2002-2006 @@ -354,7 +355,10 @@ instance Outputable BCInstr where ppr RETURN = text "RETURN" ppr (RETURN_UNLIFTED pk) = text "RETURN_UNLIFTED " <+> ppr pk ppr (RETURN_TUPLE) = text "RETURN_TUPLE" - ppr (BRK_FUN index uniq _cc) = text "BRK_FUN" <+> ppr index <+> ppr uniq <+> text "<cc>" + ppr (BRK_FUN index uniq _cc) = text "BRK_FUN" <+> ppr index <+> mb_uniq <+> text "<cc>" + where mb_uniq = sdocOption sdocSuppressUniques $ \case + True -> text "<uniq>" + False -> ppr uniq diff --git a/compiler/GHC/StgToByteCode.hs b/compiler/GHC/StgToByteCode.hs index 8c54a04d4f..da3c055411 100644 --- a/compiler/GHC/StgToByteCode.hs +++ b/compiler/GHC/StgToByteCode.hs @@ -486,8 +486,7 @@ returnUnliftedReps d s szb reps = do -- otherwise use RETURN_TUPLE with a tuple descriptor nv_reps -> do let (call_info, args_offsets) = layoutNativeCall profile NativeTupleReturn 0 (primRepCmmType platform) nv_reps - args_ptrs = map (\(rep, off) -> (isFollowableArg (toArgRep platform rep), off)) args_offsets - tuple_bco <- emitBc (tupleBCO platform call_info args_ptrs) + tuple_bco <- emitBc (tupleBCO platform call_info args_offsets) return $ PUSH_UBX (mkNativeCallInfoLit platform call_info) 1 `consOL` PUSH_BCO tuple_bco `consOL` unitOL RETURN_TUPLE @@ -1050,13 +1049,9 @@ doCase d s p scrut bndr alts p scrut alt_bco' <- emitBc alt_bco if ubx_tuple_frame - then do - let args_ptrs = - map (\(rep, off) -> (isFollowableArg (toArgRep platform rep), off)) - args_offsets - tuple_bco <- emitBc (tupleBCO platform call_info args_ptrs) - return (PUSH_ALTS_TUPLE alt_bco' call_info tuple_bco - `consOL` scrut_code) + then do tuple_bco <- emitBc (tupleBCO platform call_info args_offsets) + return (PUSH_ALTS_TUPLE alt_bco' call_info tuple_bco + `consOL` scrut_code) else let push_alts | not ubx_frame = PUSH_ALTS alt_bco' @@ -1244,11 +1239,10 @@ usePlainReturn t -} -tupleBCO :: Platform -> NativeCallInfo -> [(Bool, ByteOff)] -> [FFIInfo] -> ProtoBCO Name -tupleBCO platform info pointers = +tupleBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name +tupleBCO platform args_info args = mkProtoBCO platform invented_name body_code (Left []) 0{-no arity-} bitmap_size bitmap False{-is alts-} - where {- The tuple BCO is never referred to by name, so we can get away @@ -1260,18 +1254,16 @@ tupleBCO platform info pointers = -- the first word in the frame is the call_info word, -- which is not a pointer - bitmap_size = trunc16W $ 1 + nativeCallSize info - bitmap = intsToReverseBitmap platform (fromIntegral bitmap_size) $ - map ((+1) . fromIntegral . bytesToWords platform . snd) - (filter fst pointers) + nptrs_prefix = 1 + (bitmap_size, bitmap) = mkStackBitmap platform nptrs_prefix args_info args + body_code = mkSlideW 0 1 -- pop frame header `snocOL` RETURN_TUPLE -- and add it again -primCallBCO :: Platform -> NativeCallInfo -> [(Bool, ByteOff)] -> [FFIInfo] -> ProtoBCO Name -primCallBCO platform args_info pointers = +primCallBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name +primCallBCO platform args_info args = mkProtoBCO platform invented_name body_code (Left []) 0{-no arity-} bitmap_size bitmap False{-is alts-} - where {- The primcall BCO is never referred to by name, so we can get away @@ -1281,20 +1273,52 @@ primCallBCO platform args_info pointers = -} invented_name = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "primcall") - -- the first three words in the frame are the BCO describing the - -- pointers in the frame, the call_info word and the pointer - -- to the Cmm function being called. None of these is a pointer that - -- should be followed by the garbage collector - bitmap_size = trunc16W $ 2 + nativeCallSize args_info - bitmap = intsToReverseBitmap platform (fromIntegral bitmap_size) $ - map ((+2) . fromIntegral . bytesToWords platform . snd) - (filter fst pointers) + -- The first two words in the frame (after the BCO) are the call_info word + -- and the pointer to the Cmm function being called. Neither of these is a + -- pointer that should be followed by the garbage collector. + nptrs_prefix = 2 + (bitmap_size, bitmap) = mkStackBitmap platform nptrs_prefix args_info args + -- if the primcall BCO is ever run it's a bug, since the BCO should only -- be pushed immediately before running the PRIMCALL bytecode instruction, -- which immediately leaves the interpreter to jump to the stg_primcall_info -- Cmm function body_code = unitOL CASEFAIL +-- | Builds a bitmap for a stack layout with a nonpointer prefix followed by +-- some number of arguments. +mkStackBitmap + :: Platform + -> WordOff + -- ^ The number of nonpointer words that prefix the arguments. + -> NativeCallInfo + -> [(PrimRep, ByteOff)] + -- ^ The stack layout of the arguments, where each offset is relative to the + -- /bottom/ of the stack space they occupy. Their offsets must be word-aligned, + -- and the list must be sorted in order of ascending offset (i.e. bottom to top). + -> (Word16, [StgWord]) +mkStackBitmap platform nptrs_prefix args_info args + = (bitmap_size, bitmap) + where + bitmap_size = trunc16W $ nptrs_prefix + arg_bottom + bitmap = intsToReverseBitmap platform (fromIntegral bitmap_size) ptr_offsets + + arg_bottom = nativeCallSize args_info + ptr_offsets = reverse $ map (fromIntegral . convert_arg_offset) + $ mapMaybe get_ptr_offset args + + get_ptr_offset :: (PrimRep, ByteOff) -> Maybe ByteOff + get_ptr_offset (rep, byte_offset) + | isFollowableArg (toArgRep platform rep) = Just byte_offset + | otherwise = Nothing + + convert_arg_offset :: ByteOff -> WordOff + convert_arg_offset arg_offset = + -- The argument offsets are relative to `arg_bottom`, but + -- `intsToReverseBitmap` expects offsets from the top, so we need to flip + -- them around. + nptrs_prefix + (arg_bottom - bytesToWords platform arg_offset) + -- ----------------------------------------------------------------------------- -- Deal with a primitive call to native code. @@ -1322,15 +1346,12 @@ generatePrimCall d s p target _mb_unit _result_ty args (args_info, args_offsets) = layoutNativeCall profile NativePrimCall - d + 0 (primRepCmmType platform . argPrimRep) nv_args - args_ptrs :: [(Bool, ByteOff)] - args_ptrs = - map (\(r, off) -> - (isFollowableArg (toArgRep platform . argPrimRep $ r), off)) - args_offsets + prim_args_offsets = mapFst argPrimRep args_offsets + shifted_args_offsets = mapSnd (+ d) args_offsets push_target = PUSH_UBX (LitLabel target Nothing IsFunction) 1 push_info = PUSH_UBX (mkNativeCallInfoLit platform args_info) 1 @@ -1347,8 +1368,8 @@ generatePrimCall d s p target _mb_unit _result_ty args go !dd pushes ((a, off):cs) = do (push, szb) <- pushAtom dd p a massert (off == dd + szb) go (dd + szb) (push:pushes) cs - push_args <- go d [] args_offsets - args_bco <- emitBc (primCallBCO platform args_info args_ptrs) + push_args <- go d [] shifted_args_offsets + args_bco <- emitBc (primCallBCO platform args_info prim_args_offsets) return $ mconcat push_args `appOL` (push_target `consOL` push_info `consOL` diff --git a/testsuite/tests/bytecode/T23068.hs b/testsuite/tests/bytecode/T23068.hs new file mode 100644 index 0000000000..638327c361 --- /dev/null +++ b/testsuite/tests/bytecode/T23068.hs @@ -0,0 +1,9 @@ +{-# LANGUAGE MagicHash, UnboxedTuples #-} +module T23068 where +import GHC.Exts + +f :: () -> (# Int, Int #) +f () = (# 0, 0 #) + +g :: () -> (# Int#, Int#, Int #) +g () = (# 0#, 0#, 0 #) diff --git a/testsuite/tests/bytecode/T23068.script b/testsuite/tests/bytecode/T23068.script new file mode 100644 index 0000000000..e89cf5e053 --- /dev/null +++ b/testsuite/tests/bytecode/T23068.script @@ -0,0 +1 @@ +:l T23068 diff --git a/testsuite/tests/bytecode/T23068.stdout b/testsuite/tests/bytecode/T23068.stdout new file mode 100644 index 0000000000..86d2c9ddfc --- /dev/null +++ b/testsuite/tests/bytecode/T23068.stdout @@ -0,0 +1,71 @@ + +==================== Proto-BCOs ==================== +ProtoBCO T23068.g#1 []: + \r [ds] case of wild + bitmap: 1 [0] + PUSH_ALTS P + ProtoBCO wild#0 []: + { () -> let bcprep = ... in ... + bitmap: 1 [0] + ALLOC_PAP 1 0 + PUSH_BCO + ProtoBCO bcprep#1 []: + \r [void] break<0>() let sat = ... in ... + bitmap: 0 [] + BRK_FUN 0 <uniq> <cc> + PUSH_UBX (1) 0# + PACK GHC.Types.I# 1 + PUSH_L 0 + PUSH_UBX (1) 0# + PUSH_UBX (1) 0# + SLIDE 3 1 + PUSH_UBX (1) 7## + PUSH_BCO + ProtoBCO tuple#0 []: + bitmap: 4 [7] + SLIDE 0 1 + RETURN_TUPLE + RETURN_TUPLE + MKPAP 0 words, 1 stkoff + PUSH_APPLY_V + PUSH_L 1 + SLIDE 2 5 + ENTER + PUSH_L 2 + ENTER + +ProtoBCO T23068.f#1 []: + \r [ds] case of wild + bitmap: 1 [0] + PUSH_ALTS P + ProtoBCO wild#0 []: + { () -> let bcprep = ... in ... + bitmap: 1 [0] + ALLOC_PAP 1 0 + PUSH_BCO + ProtoBCO bcprep#1 []: + \r [void] break<1>() let sat = ... in ... + bitmap: 0 [] + BRK_FUN 1 <uniq> <cc> + PUSH_UBX (1) 0# + PACK GHC.Types.I# 1 + PUSH_UBX (1) 0# + PACK GHC.Types.I# 1 + PUSH_LL 1 0 + SLIDE 2 2 + PUSH_UBX (1) 3## + PUSH_BCO + ProtoBCO tuple#0 []: + bitmap: 3 [1] + SLIDE 0 1 + RETURN_TUPLE + RETURN_TUPLE + MKPAP 0 words, 1 stkoff + PUSH_APPLY_V + PUSH_L 1 + SLIDE 2 5 + ENTER + PUSH_L 2 + ENTER + + diff --git a/testsuite/tests/bytecode/all.T b/testsuite/tests/bytecode/all.T new file mode 100644 index 0000000000..63ed3c19ce --- /dev/null +++ b/testsuite/tests/bytecode/all.T @@ -0,0 +1,3 @@ +ghci_dump_bcos = [only_ways(['ghci']), extra_run_opts('-dno-typeable-binds -dsuppress-uniques -ddump-bcos')] + +test('T23068', ghci_dump_bcos + [filter_stdout_lines(r'.*bitmap: .*')], ghci_script, ['T23068.script']) |