ABC.icl 23.7 KB
Newer Older
Camil Staps's avatar
Camil Staps committed
1
implementation module Builtin.ABC
Camil Staps's avatar
Camil Staps committed
2

3 4
import _SystemArray
import StdList
Camil Staps's avatar
Camil Staps committed
5 6
import StdMisc

Camil Staps's avatar
Camil Staps committed
7
import Data.Either
8 9
import Text

Camil Staps's avatar
Camil Staps committed
10 11
import Cloogle.API
import Cloogle.DB
Camil Staps's avatar
Camil Staps committed
12

Camil Staps's avatar
Camil Staps committed
13
builtin_abc_instructions :: [Either String ABCInstructionEntry]
Camil Staps's avatar
Camil Staps committed
14
builtin_abc_instructions =
Camil Staps's avatar
Camil Staps committed
15 16 17 18 19 20 21 22
	withTitle "Arithmetic" arith_instructions ++
	withTitle "Stack manipulation" stack_operations ++
	withTitle "Branching" branches ++
	withTitle "Miscellaneous" miscellaneous ++
	withTitle "Directives" directives ++
	withTitle "Undocumented instructions" [{zero & aie_instruction=i} \\ i <- other_instructions]
where
	withTitle title instrs = [Left title:map Right instrs]
Camil Staps's avatar
Camil Staps committed
23 24 25 26

instance zero ABCInstructionEntry
where
	zero =
Camil Staps's avatar
Camil Staps committed
27
		{ aie_instruction = ""
Camil Staps's avatar
Camil Staps committed
28 29 30 31
		, aie_arguments   = []
		, aie_description = "There is no documentation for this ABC instruction yet."
		}

32 33 34 35
LABEL    :== ABCArgument ABCTypeLabel        False
LABEL_   :== ABCArgument ABCTypeLabel        True
A_OFFSET :== ABCArgument ABCTypeAStackOffset False
B_OFFSET :== ABCArgument ABCTypeBStackOffset False
36 37
A_SIZE   :== ABCArgument ABCTypeAStackSize   False
B_SIZE   :== ABCArgument ABCTypeBStackSize   False
38 39 40 41 42 43 44 45 46 47
STRING   :== ABCArgument ABCTypeString       False
STRING_  :== ABCArgument ABCTypeString       True
BOOL     :== ABCArgument ABCTypeBool         False
BOOL_    :== ABCArgument ABCTypeBool         True
CHAR     :== ABCArgument ABCTypeChar         False
CHAR_    :== ABCArgument ABCTypeChar         True
INT      :== ABCArgument ABCTypeInt          False
INT_     :== ABCArgument ABCTypeInt          True
REAL     :== ABCArgument ABCTypeReal         False
REAL_    :== ABCArgument ABCTypeReal         True
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
arith_instructions :: [ABCInstructionEntry]
arith_instructions =
	[ arith1 "absR"    "Real" "absolute value"
	, arith1 "acosR"   "Real" "arccosine"
	, arith1 "asinR"   "Real" "arcsine"
	, arith1 "atanR"   "Real" "arctangent"
	, arith1 "cosR"    "Real" "cosine"
	, arith1 "entierR" "Real" "(Int) entier (floor)"
	, arith1 "expR"    "Real" "exponential function (e^r)"
	, arith1 "lnR"     "Real" "natural logarithm"
	, arith1 "log10R"  "Real" "base-10 logarithm"
	, arith1 "notB"    "Bool" "logical negation"
	, arith1 "sinR"    "Real" "sine"
	, arith1 "sqrtR"   "Real" "square root"
	, arith1 "tanR"    "Real" "tangent"

	, op1 "decI" "Int"  "Decrements"
	, op1 "incI" "Int"  "Increments"
	, op1 "negI" "Int"  "Negates"
	, op1 "negR" "Real" "Negates"
	, op1 "not%" "Int"  "Bitwise negates"

	, op2 "addI"    "Int"  "Sums"
	, op2 "addR"    "Real" "Sums"
	, op2 "andB"    "Bool" "Logically conjuncts"
	, op2 "and%"    "Int"  "Bitwise conjuncts"
	, op2 "divI"    "Int"  "Divides"
	, op2 "divR"    "Real" "Divides"
	, op2 "eqB"     "Bool" "Checks equality on"
	, op2 "eqC"     "Char" "Checks equality on"
	, op2 "eqI"     "Int"  "Checks equality on"
	, op2 "eqR"     "Real" "Checks equality on"
Camil Staps's avatar
Camil Staps committed
81
	, i_eqAC_a
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	, op2 "gtC"     "Char" "Checks greater-than on"
	, op2 "gtI"     "Int"  "Checks greater-than on"
	, op2 "gtR"     "Real" "Checks greater-than on"
	, op2 "ltC"     "Char" "Checks less-than on"
	, op2 "ltI"     "Int"  "Checks less-than on"
	, op2 "ltR"     "Real" "Checks less-than on"
	, op2 "mulI"    "Int"  "Multiplies"
	, op2 "mulR"    "Real" "Multiplies"
	, op2 "orB"     "Bool" "Logically disjuncts"
	, op2 "or%"     "Int"  "Bitwise disjuncts"
	, op2 "powR"    "Real" "Raises to the power on"
	, op2 "remI"    "Int"  "Computes the remainder after division of"
	, op2 "rotl%"   "Int"  "Bitwise left-rotate on"
	, op2 "rotr%"   "Int"  "Bitwise right-rotate on"
	, op2 "shiftl%" "Int"  "Bitwise left-shift on"
	, op2 "shiftr%" "Int"  "Bitwise right-shift on"
	, op2 "subI"    "Int"  "Subtracts"
	, op2 "subR"    "Real" "Subtracts"
	, op2 "xor%"    "Int"  "Bitwise XOR on"

102 103 104 105 106 107 108 109 110
	, eq_arg "Bool" BOOL 'A'
	, eq_arg "Bool" BOOL 'B'
	, eq_arg "Char" CHAR 'A'
	, eq_arg "Char" CHAR 'B'
	, eq_arg "Int"  INT  'A'
	, eq_arg "Int"  INT  'B'
	, eq_arg "Real" REAL 'A'
	, eq_arg "Real" REAL 'B'

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	, convert "CtoI"  "Char" "Int"
	, convert "CtoAC" "Char" "String"
	, convert "ItoC"  "Int"  "Char"
	, convert "ItoR"  "Int"  "Real"
	, convert "RtoI"  "Real" "Int"
	]
where
	arith1 :: !String !String !String -> ABCInstructionEntry
	arith1 instr type description =
		{ zero
		& aie_instruction = instr
		, aie_description = "Computes the " + description + " of the " + type + " on top of the B-stack."
		}

	op1 :: !String !String !String -> ABCInstructionEntry
	op1 instr type description =
		{ zero
		& aie_instruction = instr
		, aie_description = description + " the " + type + " on top of the B-stack."
		}

	op2 :: !String !String !String -> ABCInstructionEntry
	op2 instr type description =
		{ zero
		& aie_instruction = instr
		, aie_description = description + " the two " + type + "s on top of the B-stack."
		}

139 140 141 142
	eq_arg :: !String !ABCArgument !Char -> ABCInstructionEntry
	eq_arg type arg stack =
		{ zero
		& aie_instruction = {'e','q',type.[0],'_',toLower stack}
143 144
		, aie_arguments   = [arg, if (stack == 'A') A_OFFSET B_OFFSET]
		, aie_description = "Checks equality between the first argument and the " + {stack} + "-stack element."
145 146
		}

147 148 149 150 151 152 153
	convert :: !String !String !String -> ABCInstructionEntry
	convert instr fr to =
		{ zero
		& aie_instruction = instr
		, aie_description = "Converts the " + fr + " on top of the B-stack to " + to + "."
		}

Camil Staps's avatar
Camil Staps committed
154 155 156 157 158 159 160
	i_eqAC_a =
		{ zero
		& aie_instruction = "eqAC_a"
		, aie_arguments   = [STRING]
		, aie_description = "Checks that the string on top of the A-stack equals the argument string."
		}

Camil Staps's avatar
Camil Staps committed
161 162
stack_operations :: [ABCInstructionEntry]
stack_operations =
163 164 165 166 167 168 169 170
	[ push    "Bool" BOOL
	, push    "Char" CHAR
	, push    "Int"  INT
	, push    "Real" REAL
	, push_a  "Bool"
	, push_a  "Char"
	, push_a  "Int"
	, push_a  "Real"
171 172 173 174 175
	, i_pop_a
	, i_pop_b
	, i_push_a
	, i_push_b
	, i_push_a_b
176 177 178 179 180 181 182 183
	, build   "Bool" BOOL
	, build   "Char" CHAR
	, build   "Int"  INT
	, build   "Real" REAL
	, build_b "Bool"
	, build_b "Char"
	, build_b "Int"
	, build_b "Real"
184 185 186
	, i_build_r
	, i_build_u
	, i_buildAC
Camil Staps's avatar
Camil Staps committed
187
	, i_create
Camil Staps's avatar
Camil Staps committed
188 189
	, i_create_array
	, i_create_array_
190 191 192 193 194 195 196 197 198
	, fill    "Bool" BOOL
	, fill    "Char" CHAR
	, fill    "Int"  INT
	, fill    "Real" REAL
	, fill_b  "Bool"
	, fill_b  "Char"
	, fill_b  "Int"
	, fill_b  "Real"
	, i_fill
Camil Staps's avatar
Camil Staps committed
199 200 201
	, i_eq_desc
	, i_eq_desc_b
	, i_eq_nulldesc
202 203
	]
where
204 205
	push :: !String !ABCArgument -> ABCInstructionEntry
	push type arg =
206
		{ zero
207
		& aie_instruction = "push" + {type.[0]}
208
		, aie_arguments   = [arg]
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
		, aie_description = "Pushes the " + type + " argument to the B-stack."
		}

	push_a :: !String -> ABCInstructionEntry
	push_a type =
		{ zero
		& aie_instruction = "push" + {type.[0]} + "_a"
		, aie_arguments   = [INT]
		, aie_description = "Pushes the " + type + " from the nth position on the A-stack to the B-stack."
		}

	build :: !String !ABCArgument -> ABCInstructionEntry
	build type arg =
		{ zero
		& aie_instruction = "build" + {type.[0]}
		, aie_arguments   = [arg]
		, aie_description = "Builds a " + type + "-node with the argument as value on the A-stack."
		}

	build_b :: !String -> ABCInstructionEntry
	build_b type =
		{ zero
		& aie_instruction = "build" + {type.[0]} + "_b"
		, aie_arguments   = [INT]
		, aie_description = "Builds a " + type + "-node with the value on the nth position of the B-stack on the A-stack."
234 235
		}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	fill :: !String !ABCArgument -> ABCInstructionEntry
	fill type arg =
		{ zero
		& aie_instruction = "fill" + {type.[0]}
		, aie_arguments   = [arg, A_OFFSET]
		, aie_description = "Fills the referenced A-stack node with a boxed " + type + " argument."
		}

	fill_b :: !String -> ABCInstructionEntry
	fill_b type =
		{ zero
		& aie_instruction = "fill" + {type.[0]} + "_b"
		, aie_arguments   = [B_OFFSET, A_OFFSET]
		, aie_description = "Fills the referenced A-stack node with a boxed " + type + " argument from the referenced B-stack element."
		}

	i_build_r =
		{ zero
		& aie_instruction = "build_r"
		, aie_arguments   = [LABEL, A_SIZE, B_SIZE, A_OFFSET, B_OFFSET]
		, aie_description = "Builds a record with the specified number of arguments starting from the referenced offsets."
		}

	i_build_u =
		{ zero
		& aie_instruction = "build_u"
		, aie_arguments   = [LABEL, A_SIZE, B_SIZE, LABEL]
		, aie_description = join " "
			[ "Builds a thunk with unboxed arguments with the specified number of arguments starting from the tops of the A and B stacks."
			, "The first label is for the descriptor and is typically ignored; the second label is the code address."
			]
		}

Camil Staps's avatar
Camil Staps committed
269 270 271 272 273 274 275
	i_buildAC =
		{ zero
		& aie_instruction = "buildAC"
		, aie_arguments   = [STRING]
		, aie_description = "Pushes the argument string to the A-stack."
		}

Camil Staps's avatar
Camil Staps committed
276 277 278 279 280 281
	i_create =
		{ zero
		& aie_instruction = "create"
		, aie_description = "Creates a new empty node and pushes its address to the A-stack."
		}

Camil Staps's avatar
Camil Staps committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	i_create_array =
		{ zero
		& aie_instruction = "create_array"
		, aie_arguments   = [LABEL, A_OFFSET, B_OFFSET]
		, aie_description = join " "
			[ "Creates an array on the A-stack."
			, "The elements have type `label` (which can be `_` for any A-stack type)."
			, "The last two arguments indicate the stack sizes of the elements."
			, "The size and initial value are popped from the B and A stacks."
			]
		}
	i_create_array_ =
		{ zero
		& aie_instruction = "create_array_"
		, aie_arguments   = [LABEL, A_OFFSET, B_OFFSET]
		, aie_description = join " "
			[ "Creates an array on the A-stack."
			, "The elements have type `label` (which can be `_` for any A-stack type)."
			, "The last two arguments indicate the stack sizes of the elements."
			, "The size is popped from the B-stack; the elements are initialised as `_Nil` regardless of the type."
			]
		}

	i_eq_desc =
		{ zero
		& aie_instruction = "eq_desc"
		, aie_arguments   = [LABEL, INT, A_OFFSET]
		, aie_description = join " "
			[ "Checks that the indicated node on the A-stack matches the descriptor given by the label."
			, "The `int` argument is the arity of the descriptor."
			]
		}
	i_eq_desc_b =
		{ zero
		& aie_instruction = "eq_desc_b"
		, aie_arguments   = [LABEL, A_OFFSET]
		, aie_description = join " "
			[ "The indicated node on the A-stack is assumed to be an array."
			, "The instruction checks that the array is of the type indicated by `label`."
			]
		}
	i_eq_nulldesc =
		{ zero
		& aie_instruction = "eq_nulldesc"
		, aie_arguments   = [LABEL, A_OFFSET]
		, aie_description = "Checks that the indicated node on the A-stack matches the descriptor given by the label, ignoring arity."
		}

Camil Staps's avatar
Camil Staps committed
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
	i_pop_a =
		{ zero
		& aie_instruction = "pop_a"
		, aie_arguments   = [A_OFFSET]
		, aie_description = "Pops elements off the A-stack until the referenced element."
		}
	i_pop_b =
		{ zero
		& aie_instruction = "pop_b"
		, aie_arguments   = [B_OFFSET]
		, aie_description = "Pops elements off the B-stack until the referenced element."
		}
	i_push_a =
		{ zero
		& aie_instruction = "push_a"
		, aie_arguments   = [A_OFFSET]
		, aie_description = "Pushes the referenced A-stack element on the A-stack."
		}
	i_push_b =
		{ zero
		& aie_instruction = "push_b"
		, aie_arguments   = [B_OFFSET]
		, aie_description = "Pushes the referenced B-stack element on the B-stack."
		}
354 355 356 357 358 359
	i_push_a_b =
		{ zero
		& aie_instruction = "push_a_b"
		, aie_arguments   = [A_OFFSET, B_OFFSET]
		, aie_description = "Pushes the A-stack element as an integer (i.e., a pointer to the heap) on the B-stack."
		}
Camil Staps's avatar
Camil Staps committed
360

361 362 363 364 365 366 367 368 369 370 371
	i_fill =
		{ zero
		& aie_instruction = "fill"
		, aie_arguments   = [LABEL, A_SIZE, LABEL, A_OFFSET]
		, aie_description = join " "
			[ "Fills the referenced A-stack node as a thunk with the specified code address and a number of elements from the top of the A-stack."
			, "The arguments are popped from the A-stack."
			, "The first label is the descriptor, which is typically ignored; the second is the code address."
			]
		}

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
branches :: [ABCInstructionEntry]
branches =
	[ i_jmp
	, i_jmp_false
	, i_jmp_true
	, i_jsr
	, i_jsr_eval
	, i_rtn
	]
where
	i_jmp =
		{ zero
		& aie_instruction = "jmp"
		, aie_arguments   = [LABEL]
		, aie_description = "Unconditional jump to a label."
		}
	i_jmp_false =
		{ zero
		& aie_instruction = "jmp_false"
		, aie_arguments   = [LABEL]
		, aie_description = "Jump to a label if the Bool on top of the B-stack is false."
		}
	i_jmp_true =
		{ zero
		& aie_instruction = "jmp_true"
		, aie_arguments   = [LABEL]
		, aie_description = "Jump to a label if the Bool on top of the B-stack is true."
		}
	i_jsr =
		{ zero
		& aie_instruction = "jsr"
		, aie_arguments   = [LABEL]
		, aie_description = "Subroutine jump to a label. {{`rtn`}} returns to the instruction after this `jsr`."
		}
	i_jsr_eval =
		{ zero
		& aie_instruction = "jsr_eval"
		, aie_arguments   = [A_OFFSET, LABEL]
		, aie_description = "Subroutine jump to evaluate the indicated A-stack element. {{`rtn`}} returns to the instruction after this `jsr_eval`."
		}
	i_rtn =
		{ zero
		& aie_instruction = "rtn"
		, aie_description = "Returns from a subroutine call (e.g. {{`jsr`}})."
		}

miscellaneous :: [ABCInstructionEntry]
miscellaneous =
	[ i_ccall
	, i_centry
Camil Staps's avatar
Camil Staps committed
422
	, i_get_node_arity
423 424 425 426 427 428 429
	, i_halt
	, i_instruction
	, i_load_i
	, i_load_si16
	, i_load_si32
	, i_load_ui8
	, i_no_op
430 431 432
	, i_push_r_arg_t
	, i_push_t_r_a
	, i_push_t_r_args
433 434 435 436 437 438 439 440
	]
where
	i_ccall =
		{ zero
		& aie_instruction = "ccall"
		, aie_arguments   = [LABEL, STRING]
		, aie_description = join "\n"
			[ "Calls a C function."
Camil Staps's avatar
Camil Staps committed
441
			, "Some of this is documented in https://svn.cs.ru.nl/repos/clean-tools/trunk/htoclean/CallingCFromClean.html."
442 443 444
			, "The first argument is the name of the function, the second is the signature."
			, "\n"
			, "The signature has to be of the form `flags?input?sep output(sep state)?`, where"
Camil Staps's avatar
Camil Staps committed
445 446 447 448 449
			, "  - `sep`    can be either `-` or `:`."
			, "  - `flags`  can be `G` and/or `P`. `G` saves the state in global variables and is needed when the called C function will call Clean functions. `P` lets the callee pop arguments (necessary on 32-bit Windows)."
			, "  - `input`  is a number of input argument types (allowed: `IpRrSsAOF`; see below)."
			, "  - `output` is a number of output argument types (allowed: `VIpRrSsAOF`; see below)."
			, "  - `state`  is a carried state that is not passed to the C function, for example used to thread {{`World`}} in ccalls (allowed: `IpRSA`)."
450 451
			, "\n"
			, "Input, output and state argument types can be:"
452 453 454
			, "  - `I`    for integers"
			, "  - `p`    for pointers (e.g. from {{`System.Pointer`}}; on most systems this is identical to `I`)"
			, "  - [`Rr`] for reals"
Camil Staps's avatar
Camil Staps committed
455
			, "  - `S`    for Clean Strings (`{#Char}`). If used as input type this passes a pointer to the string's length (number of characters). The actual array is at offset 4/8 (32/64 bit). If this is used as output type, the C function has to return a pointer to the string's length, followed by the actual string. A copy of the string will be created in the Clean heap, and this copy will be used by Clean. If the string was allocated in C, for example using malloc, it should be deallocated in C when it is no longer used."
456
			, "  - `s`    for the characters of a Clean String (handy to use in conjuction with {{`packString`}}, as the string is not null-terminated). The length (number of characters) is at offset -4/-8. (32/64 bit)."
Camil Staps's avatar
Camil Staps committed
457
			, "  - `A`    for A-stack elements. A pointer to the third block of the node is passed. For arrays, this is a pointer to the elements. One word higher is the element type. The size of the array is two words higher."
458 459
			, "  - [`OF`] for function pointers"
			, "  - `V`    for `void`, packs the following argument types in a tuple (e.g. `VIR` means `(Int, Real)`)"
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
			]
		}
	i_centry =
		{ zero
		& aie_instruction = "centry"
		, aie_arguments   = [LABEL, LABEL, STRING]
		, aie_description = join "\n"
			[ "Adds code to call a Clean function from C."
			, "Usually it is not needed to write this instruction yourself."
			, "It is generated with the `foreign export` construct.\n"
			, "The first label is the name of the C function to generate."
			, "The second label is the Clean function to link it to.\n"
			, "The string argument indicates the type."
			, "For more information, see {{`ccall`}}."
			]
		}

Camil Staps's avatar
Camil Staps committed
477 478 479 480 481 482 483
	i_get_node_arity =
		{ zero
		& aie_instruction = "get_node_arity"
		, aie_arguments   = [A_OFFSET]
		, aie_description = "Pushes the arity of the descriptor of the referenced A-stack element to the B-stack."
		}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	i_halt =
		{ zero
		& aie_instruction = "halt"
		, aie_description = "Terminates the program immediately."
		}

	i_instruction =
		{ zero
		& aie_instruction = "instruction"
		, aie_arguments   = [INT]
		, aie_description = "Adds the raw argument as a word in the generated object file."
		}

	i_load_i =
		{ zero
		& aie_instruction = "load_i"
		, aie_arguments   = [INT]
		, aie_description = join "\n\n"
			[ "Take the top of the B-stack as a pointer and read an integer from that pointer with the argument as offset."
			, "See also {{`load_si16`}}, {{`load_si32`}}, {{`load_ui8`}}."
			]
		}
	i_load_si16 =
		{ zero
		& aie_instruction = "load_si16"
		, aie_arguments   = [INT]
		, aie_description = join "\n\n"
			[ "Take the top of the B-stack as a pointer and read a 16-bit signed integer from that pointer with the argument as offset."
Camil Staps's avatar
Camil Staps committed
512
			, "See also {{`load_i`}}, {{`load_si32`}}, {{`load_ui8`}}."
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
			]
		}
	i_load_si32 =
		{ zero
		& aie_instruction = "load_si32"
		, aie_arguments   = [INT]
		, aie_description = join "\n\n"
			[ "Take the top of the B-stack as a pointer and read a 32-bit signed integer from that pointer with the argument as offset."
			, "This instruction is only available on 64-bit systems. On 32-bit systems, {{`load_i`}} has the same effect."
			, "See also {{`load_i`}}, {{`load_si16`}}, {{`load_ui8`}}."
			]
		}
	i_load_ui8 =
		{ zero
		& aie_instruction = "load_ui8"
		, aie_arguments   = [INT]
		, aie_description = join "\n\n"
			[ "Take the top of the B-stack as a pointer and read a 8-bit unsigned integer from that pointer with the argument as offset."
			, "See also {{`load_i`}}, {{`load_si16`}}, {{`load_si32`}}."
			]
		}

	i_no_op =
		{ zero
		& aie_instruction = "no_op"
		, aie_description = join "\n"
			[ "Do nothing. This is for example useful in the `cast` function:\n"
			, "```clean"
			, "cast :: .a -> .b"
			, "cast _ = code {"
			, "\tno_op"
			, "}"
			, "```"
			]
		}

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
	i_push_r_arg_t =
		{ zero
		& aie_instruction = "push_r_arg_t"
		, aie_description = join " "
			[ "Gets the *n*th element from the type string of a record."
			, "The type string is on top of the B-stack; *n* below that."
			]
		}
	i_push_t_r_a =
		{ zero
		& aie_instruction = "push_t_r_a"
		, aie_arguments   = [A_OFFSET]
		, aie_description = "Push the address of the type string of the referenced record to the B-stack."
		}
	i_push_t_r_args =
		{ zero
		& aie_instruction = "push_t_r_args"
		, aie_description = "Pops a record from the A-stack, pushes its members in reversed order to both of the stacks, then pushes the address of the type string to the B-stack."
		}

569 570 571
directives :: [ABCInstructionEntry]
directives =
	[ d_d
572 573
	, d_n
	, d_nu
574 575
	, d_o
	, d_export
Camil Staps's avatar
Camil Staps committed
576
	, d_inline
577
	, d_module
Camil Staps's avatar
Camil Staps committed
578
	, d_depend
579 580 581 582 583 584 585 586 587
	, d_end
	, d_endinfo
	, d_start
	]
where
	d_d =
		{ zero
		& aie_instruction = ".d"
		, aie_arguments   = [A_OFFSET, B_OFFSET, STRING_]
588
		, aie_description = join " "
589 590 591 592 593
			[ "Indicates how many stack elements are on the stack when a jump follows."
			, "The first integer is the number of elements on the A-stack; the second that of B-stack elements."
			, "The optional third argument indicates the type of the B-stack elements, e.g. `bbi` for two booleans and an integer."
			]
		}
594 595 596 597
	d_n =
		{ zero
		& aie_instruction = ".n"
		, aie_arguments   = [A_OFFSET, LABEL]
598
		, aie_description = join " "
599 600 601 602 603 604 605 606 607 608 609 610 611 612
			[ "Indicates the arity of node entry labels."
			, "The label is the label of the corresponding descriptor, or `_` if it does not exist."
			, "\n\nThere are some special cases:\n\n"
			, "- An arity of `-1` is for tuple selectors;\n"
			, "- An arity of `-2` is for indirection nodes;\n"
			, "- An arity of `-3` is for record selectors of basic types;\n"
			, "- An arity of `-4` is for record selectors of non-basic types.\n\n"
			, "See also {{`.nu`}}."
			]
		}
	d_nu =
		{ zero
		& aie_instruction = ".nu"
		, aie_arguments   = [A_OFFSET, B_OFFSET, LABEL]
613
		, aie_description = join " "
614 615 616 617 618
			[ "Indicates the arity of node entry labels with arguments on the B-stack (otherwise, {{`.n`}} is used)."
			, "The first integer is the number of A-stack arguments; the second the number of B-stack arguments."
			, "The label is the label of the corresponding descriptor, or `_` if it does not exist."
			]
		}
619 620 621 622
	d_o =
		{ zero
		& aie_instruction = ".o"
		, aie_arguments   = [A_OFFSET, B_OFFSET, STRING_]
623
		, aie_description = join " "
624 625 626 627 628 629 630 631 632 633 634 635
			[ "Indicates how many stack elements are 'given back' to a calling function when a {{`rtn`}} follows."
			, "The first integer is the number of elements on the A-stack; the second that of B-stack elements."
			, "The optional third argument indicates the type of the B-stack elements, e.g. `bbi` for two booleans and an integer."
			]
		}

	d_export =
		{ zero
		& aie_instruction = ".export"
		, aie_arguments   = [LABEL]
		, aie_description = "Exports a label (allows linking)."
		}
Camil Staps's avatar
Camil Staps committed
636 637 638 639 640 641
	d_inline =
		{ zero
		& aie_instruction = ".inline"
		, aie_arguments   = [LABEL]
		, aie_description = "Indicates that a label can (should) be inlined (usually for performance reasons)."
		}
642 643 644 645

	d_module =
		{ zero
		& aie_instruction = ".module"
Camil Staps's avatar
Camil Staps committed
646 647 648 649 650 651 652 653
		, aie_arguments   = [LABEL, STRING]
		, aie_description = "Indicates the name of the module, and its label in the data segment."
		}
	d_depend =
		{ zero
		& aie_instruction = ".depend"
		, aie_arguments   = [STRING]
		, aie_description = "Indicates a module that this module depends on."
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
		}
	d_end =
		{ zero
		& aie_instruction = ".end"
		, aie_description = "Indicates the end of the ABC file."
		}
	d_endinfo =
		{ zero
		& aie_instruction = ".endinfo"
		, aie_description = "Indicates the end of the metadata in the ABC file."
		}
	d_start =
		{ zero
		& aie_instruction = ".start"
		, aie_arguments   = [LABEL]
		, aie_description = "Indicates the label to start execution at."
		}

Camil Staps's avatar
Camil Staps committed
672 673 674 675 676
/**
 * Instructions without documentation yet
 */
other_instructions :: [String]
other_instructions =
677
	[ "add_args"
Camil Staps's avatar
Camil Staps committed
678 679 680 681
	, "addLU"
	, "build"
	, "buildF_b"
	, "buildh"
682
	, "buildhr"
Camil Staps's avatar
Camil Staps committed
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
	, "catS"
	, "call"
	, "cmpS"
	, "ceilingR"
	, "copy_graph"
	, "code_channelP"
	, "create_channel"
	, "currentP"
	, "del_args"
	, "divLU"
	, "divU"
	, "eqD_b"
	, "eq_symbol"
	, "exit_false"
	, "fill1"
	, "fill1_r"
699
	, "fill2"
Camil Staps's avatar
Camil Staps committed
700
	, "fill2_r"
701
	, "fill3"
Camil Staps's avatar
Camil Staps committed
702
	, "fill3_r"
703 704 705 706
	, "fillF_b"
	, "fill_a"
	, "fill_r"
	, "fill_u"
Camil Staps's avatar
Camil Staps committed
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
	, "fillcaf"
	, "fillcp"
	, "fillcp_u"
	, "fillh"
	, "floordivI"
	, "getWL"
	, "get_desc_arity"
	, "get_desc_flags_b"
	, "get_desc0_number"
	, "gtU"
	, "in"
	, "is_record"
	, "ItoP"
	, "jmp_ap"
	, "jmp_ap_upd"
	, "jmp_upd"
	, "jmp_eval"
	, "jmp_eval_upd"
	, "jmp_not_eqZ"
	, "jrsr"
	, "jsr_ap"
	, "ltU"
	, "modI"
	, "mulUUL"
	, "new_ext_reducer"
	, "new_int_reducer"
	, "newP"
	, "out"
	, "print"
	, "printD"
	, "print_char"
	, "print_int"
	, "print_real"
	, "print_r_arg"
	, "print_sc"
	, "print_symbol"
	, "print_symbol_sc"
	, "pushcaf"
	, "push_finalizers"
	, "pushA_a"
	, "pushD"
	, "pushD_a"
	, "pushF_a"
	, "pushL"
	, "pushLc"
	, "pushzs"
	, "push_arg"
	, "push_arg_b"
	, "push_args"
	, "push_args_u"
	, "push_array"
	, "push_arraysize"
	, "push_b_a"
	, "push_node"
	, "push_node_u"
	, "push_a_r_args"
	, "push_r_args"
	, "push_r_args_a"
	, "push_r_args_b"
	, "push_r_args_u"
	, "push_r_arg_D"
	, "push_r_arg_u"
	, "push_wl_args"
	, "pushZ"
	, "pushZR"
	, "putWL"
	, "randomP"
	, "release"
	, "remU"
	, "replace"
	, "repl_arg"
	, "repl_args"
	, "repl_args_b"
	, "repl_r_args"
	, "repl_r_args_a"
	, "select"
	, "send_graph"
	, "send_request"
	, "set_continue"
	, "set_defer"
	, "set_entry"
	, "set_finalizers"
	, "setwait"
	, "shiftrU"
	, "sincosR"
	, "sliceS"
	, "stop_reducer"
	, "subLU"
	, "addIo"
	, "mulIo"
	, "subIo"
	, "suspend"
	, "testcaf"
	, "truncateR"
	, "update_a"
	, "updatepop_a"
	, "update_b"
	, "updatepop_b"
	, "updateS"
	, "update"
	, ".algtype"
	, ".caf"
	, ".code"
	, ".comp"
	, ".a"
	, ".desc"
	, ".desc0"
	, ".descn"
	, ".descexp"
	, ".descs"
	, ".keep"
	, ".impdesc"
	, ".implab"
	, ".implib"
	, ".impmod"
	, ".impobj"
	, ".newlocallabel"
	, ".n_string"
	, ".pb"
	, ".pd"
	, ".pe"
	, ".pl"
	, ".pld"
	, ".pn"
	, ".pt"
	, ".record"
	, ".string"
	]