summaryrefslogtreecommitdiff
path: root/utils/genprimopcode
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2020-10-29 14:11:35 -0400
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-10-31 02:55:10 -0400
commitb4278a41a18132a981b25c59b296cdf3ba970024 (patch)
tree7b6f2cafc38a009634145371240fa5090ff56f55 /utils/genprimopcode
parentd5a53c1aa6a417a466deb5951c0cc4cd94be97c0 (diff)
downloadhaskell-b4278a41a18132a981b25c59b296cdf3ba970024.tar.gz
primops: Generate ByteArray# index/read/write primops
Previously these were mostly undocumented and was ripe for potential inconsistencies.
Diffstat (limited to 'utils/genprimopcode')
-rw-r--r--utils/genprimopcode/gen_bytearray_ops.py144
1 files changed, 144 insertions, 0 deletions
diff --git a/utils/genprimopcode/gen_bytearray_ops.py b/utils/genprimopcode/gen_bytearray_ops.py
new file mode 100644
index 0000000000..760ad150c9
--- /dev/null
+++ b/utils/genprimopcode/gen_bytearray_ops.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from typing import Optional, NamedTuple
+import textwrap
+
+class ElementType(NamedTuple):
+ name: str
+ rep_ty: str
+ desc: str
+ width: Optional[int]
+
+MACH_WORD = None
+
+element_types = [
+ # (name, representation type, human description, width)
+ #
+ # width in bytes.
+ # width == None denotes machine word
+
+ ElementType("Char", "Char#", "8-bit character", 1),
+ ElementType("WideChar", "Char#", "32-bit character", 4),
+ ElementType("Int", "Int#", "word-sized integer", MACH_WORD),
+ ElementType("Word", "Word#", "word-sized unsigned integer", MACH_WORD),
+ ElementType("Addr", "Addr#", "machine address", MACH_WORD),
+ ElementType("Float", "Float#", "single-precision floating-point value", 4),
+ ElementType("Double", "Double#", "double-precision floating-point value", 8),
+ ElementType("StablePtr", "StablePtr# a", "{\\tt StablePtr#} value", MACH_WORD),
+]
+
+# TODO: Eventually when the sized integer primops use proper unboxed types we
+# should rather do:
+#
+#for n in [8,16,32,64]:
+# element_types += [ ElementType(f"Int{n}", f"Int{n}#", f"{n}-bit signed integer", n // 8) ]
+#
+#for n in [8,16,32,64]:
+# element_types += [ ElementType(f"Word{n}", f"Word{n}#", f"{n}-bit unsigned integer", n // 8) ]
+
+element_types += [
+ ElementType("Int8", "Int#", "8-bit signed integer", 1),
+ ElementType("Int16", "Int#", "16-bit signed integer", 2),
+ ElementType("Int32", "INT32", "32-bit signed integer", 4),
+ ElementType("Int64", "INT64", "64-bit signed integer", 8),
+
+ ElementType("Word8", "Word#", "8-bit unsigned integer", 1),
+ ElementType("Word16", "Word#", "16-bit unsigned integer", 2),
+ ElementType("Word32", "WORD32", "32-bit unsigned integer", 4),
+ ElementType("Word64", "WORD64", "64-bit unsigned integer", 8),
+]
+
+def pretty_offset(n: Optional[int]) -> str:
+ if n == MACH_WORD:
+ return 'machine words'
+ elif n == 1:
+ return 'bytes'
+ else:
+ return f'{n}-byte words'
+
+def print_block(template: str, **kwargs) -> None:
+ print(textwrap.dedent(template.format(**kwargs)).lstrip())
+
+def header(s: str):
+ print('')
+ print_block('''
+ ------------------------------------
+ -- {s}
+ ------------------------------------
+ ''', s=s)
+
+
+header("ByteArray# operations")
+
+print('''
+-- Do not edit. This file is generated by utils/genprimopcode/gen_bytearray_ops.py.
+-- To regenerate run,
+--
+-- python3 utils/genprimops/gen_bytearray_ops.py > compiler/GHC/Builtin/bytearray-ops.txt.pp
+''')
+
+header('aligned index operations')
+for t in element_types:
+ offset = pretty_offset(t.width)
+ print_block('''
+ primop IndexByteArrayOp_{name} "index{name}Array#" GenPrimOp
+ ByteArray# -> Int# -> {rep_ty}
+ {{Read a {desc}; offset in {offset}.}}
+ with can_fail = True
+ ''', offset = offset, **t._asdict())
+
+header('unaligned index operations')
+for t in element_types:
+ if t.name in ['Int8', 'Word8']: continue
+ print_block('''
+ primop IndexByteArrayOp_Word8As{name} "indexWord8ArrayAs{name}#" GenPrimOp
+ ByteArray# -> Int# -> {rep_ty}
+ {{Read a {desc}; offset in bytes.}}
+ with can_fail = True
+ ''', **t._asdict())
+
+header('aligned read operations')
+for t in element_types:
+ offset = pretty_offset(t.width)
+ print_block('''
+ primop ReadByteArrayOp_{name} "read{name}Array#" GenPrimOp
+ MutableByteArray# s -> Int# -> State# s -> (# State# s, {rep_ty} #)
+ {{Read a {desc}; offset in {offset}.}}
+ with has_side_effects = True
+ can_fail = True
+ ''', offset = offset, **t._asdict())
+
+header('unaligned read operations')
+for t in element_types:
+ if t.name in ['Int8', 'Word8']: continue
+ print_block('''
+ primop ReadByteArrayOp_Word8As{name} "readWord8ArrayAs{name}#" GenPrimOp
+ MutableByteArray# s -> Int# -> State# s -> (# State# s, {rep_ty} #)
+ {{Read a {desc}; offset in bytes.}}
+ with has_side_effects = True
+ can_fail = True
+ ''', **t._asdict())
+
+header('aligned write operations')
+for t in element_types:
+ offset = pretty_offset(t.width)
+ print_block('''
+ primop WriteByteArrayOp_{name} "write{name}Array#" GenPrimOp
+ MutableByteArray# s -> Int# -> {rep_ty} -> State# s -> State# s
+ {{Write a {desc}; offset in {offset}.}}
+ with has_side_effects = True
+ can_fail = True
+ ''', offset = offset, **t._asdict())
+
+header('unaligned write operations')
+for t in element_types:
+ if t.name in ['Int8', 'Word8']: continue
+ print_block('''
+ primop WriteByteArrayOp_Word8As{name} "writeWord8ArrayAs{name}#" GenPrimOp
+ MutableByteArray# s -> Int# -> {rep_ty} -> State# s -> State# s
+ {{Write a {desc}; offset in bytes.}}
+ with has_side_effects = True
+ can_fail = True
+ ''', **t._asdict())
+