Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
d57f01a4
by Matthew Pickering at 2026-03-11T15:08:40-04:00
-
23d111ce
by Matthew Pickering at 2026-03-11T15:08:41-04:00
6 changed files:
- libraries/ghc-internal/cbits/Stack.cmm
- libraries/ghc-internal/src/GHC/Internal/Stack/Decode.hs
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum.hs
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum.stdout
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum_cmm.cmm
- testsuite/tests/ffi/should_run/all.T
Changes:
| ... | ... | @@ -8,9 +8,11 @@ |
| 8 | 8 | // developed.
|
| 9 | 9 | #if defined(StgStack_marking)
|
| 10 | 10 | |
| 11 | -// Returns the next stackframe's StgStack* and offset in it. And, an indicator
|
|
| 12 | -// if this frame is the last one (`hasNext` bit.)
|
|
| 13 | -// (StgStack*, StgWord, StgWord) advanceStackFrameLocationzh(StgStack* stack, StgWord offsetWords)
|
|
| 11 | +// Returns the next stackframe location as
|
|
| 12 | +// (# (# #) | (# StgStack*, StgWord #) #)
|
|
| 13 | +// flattened to its runtime representation:
|
|
| 14 | +// (tag, StgStack*, StgWord)
|
|
| 15 | +// where tag 1 means no next frame and tag 2 means the payload is present.
|
|
| 14 | 16 | advanceStackFrameLocationzh (P_ stack, W_ offsetWords) {
|
| 15 | 17 | W_ frameSize;
|
| 16 | 18 | (frameSize) = ccall stackFrameSize(stack, offsetWords);
|
| ... | ... | @@ -27,27 +29,30 @@ advanceStackFrameLocationzh (P_ stack, W_ offsetWords) { |
| 27 | 29 | stackSizeInBytes = WDS(stackSize);
|
| 28 | 30 | stackBottom = stackSizeInBytes + stackArrayPtr;
|
| 29 | 31 | |
| 32 | + W_ tag, newOffsetWords;
|
|
| 30 | 33 | P_ newStack;
|
| 31 | - W_ newOffsetWords, hasNext;
|
|
| 32 | 34 | if(nextClosurePtr < stackBottom) (likely: True) {
|
| 35 | + tag = 2;
|
|
| 33 | 36 | newStack = stack;
|
| 34 | 37 | newOffsetWords = offsetWords + frameSize;
|
| 35 | - hasNext = 1;
|
|
| 36 | 38 | } else {
|
| 37 | 39 | P_ underflowFrameStack;
|
| 38 | 40 | (underflowFrameStack) = ccall getUnderflowFrameStack(stack, offsetWords);
|
| 39 | 41 | if (underflowFrameStack == NULL) (likely: True) {
|
| 40 | - newStack = NULL;
|
|
| 41 | - newOffsetWords = NULL;
|
|
| 42 | - hasNext = NULL;
|
|
| 42 | + // The empty alternative still has dead payload slots in the flattened
|
|
| 43 | + // sum representation, so the pointer field must contain a valid closure
|
|
| 44 | + // pointer rather than NULL.
|
|
| 45 | + tag = 1;
|
|
| 46 | + newStack = stack;
|
|
| 47 | + newOffsetWords = 0;
|
|
| 43 | 48 | } else {
|
| 49 | + tag = 2;
|
|
| 44 | 50 | newStack = underflowFrameStack;
|
| 45 | - newOffsetWords = NULL;
|
|
| 46 | - hasNext = 1;
|
|
| 51 | + newOffsetWords = 0;
|
|
| 47 | 52 | }
|
| 48 | 53 | }
|
| 49 | 54 | |
| 50 | - return (newStack, newOffsetWords, hasNext);
|
|
| 55 | + return (tag, newStack, newOffsetWords);
|
|
| 51 | 56 | }
|
| 52 | 57 | |
| 53 | 58 | // (StgWord, StgWord) getSmallBitmapzh(StgStack* stack, StgWord offsetWords)
|
| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | {-# LANGUAGE TypeFamilies #-}
|
| 12 | 12 | {-# LANGUAGE TypeInType #-}
|
| 13 | 13 | {-# LANGUAGE UnboxedTuples #-}
|
| 14 | +{-# LANGUAGE UnboxedSums #-}
|
|
| 14 | 15 | {-# LANGUAGE UnliftedFFITypes #-}
|
| 15 | 16 | |
| 16 | 17 | module GHC.Internal.Stack.Decode (
|
| ... | ... | @@ -214,21 +215,19 @@ getStackFields stackSnapshot# = |
| 214 | 215 | stackHead :: StackSnapshot# -> StackFrameLocation
|
| 215 | 216 | stackHead s# = (StackSnapshot s#, 0) -- GHC stacks are never empty
|
| 216 | 217 | |
| 217 | --- | Advance to the next stack frame (if any)
|
|
| 218 | ---
|
|
| 219 | --- The last `Int#` in the result tuple is meant to be treated as bool
|
|
| 220 | --- (has_next).
|
|
| 218 | +-- | Advance to the next stack frame (if any).
|
|
| 221 | 219 | foreign import prim "advanceStackFrameLocationzh"
|
| 222 | 220 | advanceStackFrameLocation# ::
|
| 223 | - StackSnapshot# -> Word# -> (# StackSnapshot#, Word#, Int# #)
|
|
| 221 | + StackSnapshot# -> Word# -> (# (# #) | (# StackSnapshot#, Word# #) #)
|
|
| 224 | 222 | |
| 225 | 223 | -- | Advance to the next stack frame (if any)
|
| 226 | 224 | advanceStackFrameLocation :: StackFrameLocation -> Maybe StackFrameLocation
|
| 227 | 225 | advanceStackFrameLocation ((StackSnapshot stackSnapshot#), index) =
|
| 228 | - let !(# s', i', hasNext #) = advanceStackFrameLocation# stackSnapshot# (wordOffsetToWord# index)
|
|
| 229 | - in if I# hasNext > 0
|
|
| 230 | - then Just (StackSnapshot s', primWordToWordOffset i')
|
|
| 231 | - else Nothing
|
|
| 226 | + case advanceStackFrameLocation# stackSnapshot# (wordOffsetToWord# index) of
|
|
| 227 | + (# (# #) | #) ->
|
|
| 228 | + Nothing
|
|
| 229 | + (# | (# s', i' #) #) ->
|
|
| 230 | + Just (StackSnapshot s', primWordToWordOffset i')
|
|
| 232 | 231 | where
|
| 233 | 232 | primWordToWordOffset :: Word# -> WordOffset
|
| 234 | 233 | primWordToWordOffset w# = fromIntegral (W# w#)
|
| 1 | +{-# LANGUAGE GHCForeignImportPrim #-}
|
|
| 2 | +{-# LANGUAGE MagicHash #-}
|
|
| 3 | +{-# LANGUAGE UnboxedTuples #-}
|
|
| 4 | +{-# LANGUAGE UnboxedSums #-}
|
|
| 5 | +{-# LANGUAGE UnliftedFFITypes #-}
|
|
| 6 | + |
|
| 7 | +module Main where
|
|
| 8 | + |
|
| 9 | +import GHC.Exts
|
|
| 10 | +import GHC.Word
|
|
| 11 | + |
|
| 12 | +foreign import prim "sumWord"
|
|
| 13 | + sumWord# :: Word# -> (# (# #) | Word# #)
|
|
| 14 | + |
|
| 15 | +render :: Word# -> String
|
|
| 16 | +render w# =
|
|
| 17 | + case sumWord# w# of
|
|
| 18 | + (# (# #) | #) -> "none"
|
|
| 19 | + (# | r# #) -> "some " ++ show (W# r#)
|
|
| 20 | + |
|
| 21 | +main :: IO ()
|
|
| 22 | +main = do
|
|
| 23 | + putStrLn (render 0##)
|
|
| 24 | + putStrLn (render 5##) |
| 1 | +none
|
|
| 2 | +some 6 |
| 1 | +#include "Cmm.h"
|
|
| 2 | + |
|
| 3 | +sumWord(W_ w) {
|
|
| 4 | + if (w == 0) {
|
|
| 5 | + return (1, 0);
|
|
| 6 | + } else {
|
|
| 7 | + return (2, w + 1);
|
|
| 8 | + }
|
|
| 9 | +} |
| ... | ... | @@ -225,6 +225,8 @@ test('PrimFFIInt32', [req_c], compile_and_run, ['PrimFFIInt32_c.c']) |
| 225 | 225 | |
| 226 | 226 | test('PrimFFIWord32', [req_c], compile_and_run, ['PrimFFIWord32_c.c'])
|
| 227 | 227 | |
| 228 | +test('PrimFFIUnboxedSum', req_cmm, compile_and_run, ['PrimFFIUnboxedSum_cmm.cmm'])
|
|
| 229 | + |
|
| 228 | 230 | test('T493', [ req_c], compile_and_run, ['T493_c.c'])
|
| 229 | 231 | |
| 230 | 232 | test('UnliftedNewtypesByteArrayOffset', [req_c], compile_and_run, ['UnliftedNewtypesByteArrayOffset_c.c'])
|