`foreign import prim` is not as expressive as out_of_line primops
Motivation
This is the future work left by !1330 (closed), and described in Note [When do out-of-line primops go in primops.txt.pp]
. In short, it would be nice to make external only primops just foreign calls to C--, since they don't need special compiler support.
Proposal
There are for axes on which foreign import prim
needs to be made more flexible.
- No polymorphism in type. Should be no restriction beyond normal Haskell I think. It is up to the C-- to do things correctly.
-
can_fail = False
. Needs to sometimes be true. -
has_side_effects = True
. Needs to sometimes be false. -
strictness = <default>
this is the hardest to fix, as we can not just allow arbitrary code likegenprimop
does. But we can defunctionalize the functions we need in practice at least (far fewer than number offoreign import prim
s). @simonpj mentions using wired-in IDs for this in !1330 (comment 211428).
Some syntax similar to genprimop
foreign import prim "symbol" Type where
identifier = identifier
where the LHS is the properties, and the right hand side is True
or false False
, except for strictness where it is the wired-in strictness function.
Primop Census
Here's a census of primops that could in principle be turned into foreign import prim. First I collected all primops whose data constructors are not used inside the compiler:
for x in $(cat primops); do [ (git grep -l $x compiler | wc -l) = 1 ] && echo "$x"; done
This yields a list of primops which don't need bespoke compiler support.
Next I marked any current restrictions for
Primop | Strictness | Type Signature | Can fail | Side effect free |
---|---|---|---|---|
DoubleDecode_2IntOp | X | |||
DoubleDecode_Int64Op | X | |||
FloatDecode_IntOp | X | |||
UnsafeThawArrayOp | X | |||
CasArrayOp | X | |||
UnsafeThawSmallArrayOp | X | |||
CasSmallArrayOp | X | |||
NewPinnedByteArrayOp_Char | X | |||
NewAlignedPinnedByteArrayOp_Char | X | |||
MutableByteArrayIsPinnedOp | X | X | ||
ByteArrayIsPinnedOp | X | |||
ShrinkMutableByteArrayOp_Char | X | |||
ResizeMutableByteArrayOp_Char | X | |||
NewArrayArrayOp | X | |||
NewMutVarOp | X | |||
AtomicModifyMutVar2Op | X | X | ||
AtomicModifyMutVar_Op | X | X | ||
CasMutVarOp | X | X | ||
CatchOp | X | X | ||
RaiseOp | X | X | ||
RaiseIOOp | X | X | ||
MaskAsyncExceptionsOp | X | X | ||
MaskUninterruptibleOp | X | X | ||
UnmaskAsyncExceptionsOp | X | X | ||
MaskStatus | X | |||
AtomicallyOp | X | X | ||
RetryOp | X | X | ||
CatchRetryOp | X | X | ||
CatchSTMOp | X | X | ||
NewTVarOp | X | |||
ReadTVarOp | X | |||
ReadTVarIOOp | X | |||
WriteTVarOp | X | |||
NewMVarOp | X | |||
TakeMVarOp | X | |||
TryTakeMVarOp | X | |||
PutMVarOp | X | |||
TryPutMVarOp | X | |||
ReadMVarOp | X | |||
TryReadMVarOp | X | |||
IsEmptyMVarOp | X | |||
DelayOp | X | |||
WaitReadOp | X | |||
WaitWriteOp | X | |||
ForkOp | X | |||
ForkOnOp | X | |||
KillThreadOp | X | |||
YieldOp | X | |||
LabelThreadOp | X | |||
IsCurrentThreadBoundOp | ||||
NoDuplicateOp | X | |||
ThreadStatusOp | ||||
MkWeakOp | X | |||
MkWeakNoFinalizerOp | X | |||
AddCFinalizerToWeakOp | ||||
DeRefWeakOp | X | |||
FinalizeWeakOp | X | |||
MakeStablePtrOp | X | |||
DeRefStablePtrOp | X | |||
MakeStableNameOp | X | |||
CompactNewOp | ||||
CompactResizeOp | X | |||
CompactContainsOp | ||||
CompactContainsAnyOp | ||||
CompactGetFirstBlockOp | ||||
CompactGetNextBlockOp | ||||
CompactAllocateBlockOp | ||||
CompactFixupPointersOp | ||||
CompactAdd | X | |||
CompactAddWithSharing | X | |||
CompactSize | ||||
GetSparkOp | X | |||
NumSparks | ||||
MkApUpd0_Op | X | |||
NewBCOOp | X | |||
UnpackClosureOp | X | |||
ClosureSizeOp | X | |||
GetApStackValOp | X | |||
ClearCCSOp | X | |||
TraceEventOp | X | |||
TraceEventBinaryOp | X | |||
TraceMarkerOp | X | |||
GetThreadAllocationCounter | ||||
SetThreadAllocationCounter | X |
That's 84 out of 579 primops.