# -*- C -*- | |

# bytecode.def - definitions of bytecodes for the stack machine. | |

# The production of the bytecode interpreter and compiler is | |

# heavily automated by using this file creatively. | |

# Various elementary data types are understood by the bytecode interpreter. | |

# Q[IU] - quarter word (byte) signed and unsigned integers (char). | |

# H[IU] - half word signed and unsigned integers (short int, maybe int). | |

# S[IU] - single word signed and unsigned integers (maybe int, long int). | |

# D[IU] - double word signed and unsigned integers (long long int). | |

# SF - single precision floating point (float). | |

# DF - double precision floating point (double). | |

# XF - extended precision floating point (long double). | |

# P - pointer type for address arithmetic and other purposes. | |

# The bytecode specification consists of a series of define_operator | |

# forms, that are parsed by preprocessors to automatically build | |

# various switch statements. | |

# define_operator(name, | |

# <C prototype code for implementing the operator>, | |

# <list of variations>) | |

# The <C prototype> is self explanatory. | |

# The <list of variations> consists of a (parenthesized list) of | |

# variation items, each of which is in itself a list. A variation | |

# item consists of a name suffix, the types of the input arguments | |

# expected on the stack (shallowest item first) and (optionally) the | |

# types of the output arguments (similarly ordered). Finally, the | |

# types of the literal arguments (if any) may appear. | |

# Substitution in the C prototype code is as follows: | |

# Substitution happens only after a dollar sign. To get a literal | |

# dollar sign (why would you ever want one anyway?) use $$. | |

# $R1 means "result 1" $TR1 means "type name of result one" | |

# $S1 means "source 1" and similarly with $TS1. | |

# $L1 means "literal (inline) argument 1" and $TL1 means type thereof. | |

# | |

# Notice that the number following $R doesn't affect the push order; | |

# it's used only for clarity and orthogonality, although it's checked | |

# to make sure it doesn't exceed the number of outputs. A $R reference | |

# results in a push, and represents the result lvalue. E.g. | |

# $R1 = 2\, $R2 = 17 | |

# will expand to: | |

# INTERP_PUSH($TR1) = 2, INTERP_PUSH($TR2) = 17 | |

# | |

# Opcode 0 should never happen. | |

define_operator(neverneverland, abort\(\), (())) | |

# Stack manipulations. | |

define_operator(drop, 0, ((, (SI)))) | |

define_operator(duplicate, 0, ((, (SI), (SI, SI)))) | |

define_operator(over, 0, ((, (SI), (SI, SI)))) | |

# Adjust stack pointer | |

define_operator(setstack, 0, ((SI,,,(SI)))) | |

define_operator(adjstack, 0, ((SI,,,(SI)))) | |

# Constants, loads, and stores. | |

define_operator(const, | |

$R1 = $L1, | |

((QI,, (QI), (QI)), (HI,, (HI), (HI)), | |

(SI,, (SI), (SI)), (DI,, (DI), (DI)), | |

(SF,, (SF), (SF)), (DF,, (DF), (DF)), | |

(XF,, (XF), (XF)), (P,, (P), (P)))) | |

define_operator(load, | |

$R1 = *\($TR1 *\) $S1, | |

((QI, (P), (QI)), (HI, (P), (HI)), | |

(SI, (P), (SI)), (DI, (P), (DI)), | |

(SF, (P), (SF)), (DF, (P), (DF)), | |

(XF, (P), (XF)), (P, (P), (P)))) | |

define_operator(store, | |

*\($TS2 *\) $S1 = $S2, | |

((QI, (P, QI)), (HI, (P, HI)), | |

(SI, (P, SI)), (DI, (P, DI)), | |

(SF, (P, SF)), (DF, (P, DF)), | |

(XF, (P, XF)), (P, (P, P)), | |

(BLK, (SI, BLK, BLK)))) | |

# Clear memory block | |

define_operator(clear, $S1 + $S2, ((BLK, (SI, BLK)))) | |

# Advance pointer by SI constant | |

define_operator(addconst, $R1 = $S1, ((PSI, (P), (P), (SI)))) | |

# newlocalSI is used for creating variable-sized storage during function | |

# initialization. | |

# Create local space, return pointer to block | |

define_operator(newlocal, $R1 = $S1, ((SI, (SI), (P)))) | |

# Push the address of a local variable. | |

define_operator(local, $R1 = locals + $L1, ((P,, (P), (SI)))) | |

# Push the address of an argument variable. | |

define_operator(arg, $R1 = args + $L1, ((P,, (P), (SI)))) | |

# Arithmetic conversions. | |

define_operator(convert, | |

$R1 = \($TR1\) $S1, | |

(# Signed integral promotions (sign extensions). | |

(QIHI, (QI), (HI)), (HISI, (HI), (SI)), (SIDI, (SI), (DI)), | |

(QISI, (QI), (SI)), | |

# Unsigned integral promotions (zero extensions). | |

(QUHU, (QU), (HU)), (HUSU, (HU), (SU)), (SUDU, (SU), (DU)), | |

(QUSU, (QU), (SU)), | |

# Floating promotions. | |

(SFDF, (SF), (DF)), (DFXF, (DF), (XF)), | |

# Integral truncation. | |

(HIQI, (HI), (QI)), (SIHI, (SI), (HI)), (DISI, (DI), (SI)), | |

(SIQI, (SI), (QI)), | |

# Unsigned truncation. | |

(SUQU, (SU), (QU)), | |

# Floating truncation. | |

(DFSF, (DF), (SF)), (XFDF, (XF), (DF)), | |

# Integral conversions to floating types. | |

(SISF, (SI), (SF)), (SIDF, (SI), (DF)), (SIXF, (SI), (XF)), | |

(SUSF, (SU), (SF)), (SUDF, (SU), (DF)), (SUXF, (SU), (XF)), | |

(DISF, (DI), (SF)), (DIDF, (DI), (DF)), (DIXF, (DI), (XF)), | |

(DUSF, (DU), (SF)), (DUDF, (DU), (DF)), (DUXF, (DU), (XF)), | |

# Floating conversions to integral types. | |

(SFSI, (SF), (SI)), (DFSI, (DF), (SI)), (XFSI, (XF), (SI)), | |

(SFSU, (SF), (SU)), (DFSU, (DF), (SU)), (XFSU, (XF), (SU)), | |

(SFDI, (SF), (DI)), (DFDI, (DF), (DI)), (XFDI, (XF), (DI)), | |

(SFDU, (SF), (DU)), (DFDU, (DF), (DU)), (XFDU, (XF), (DU)), | |

# Pointer/integer conversions. | |

(PSI, (P), (SI)), (SIP, (SI), (P)))) | |

# Truth value conversion. These are necessary because conversions of, e.g., | |

# floating types to integers may not function correctly for large values. | |

define_operator(convert, | |

$R1 = !!$S1, | |

((SIT, (SI), (T)), (DIT, (DI), (T)), | |

(SFT, (SF), (T)), (DFT, (DF), (T)), | |

(XFT, (XF), (T)), (PT, (P), (T)))) | |

# Bit field load/store. | |

# Load and zero-extend bitfield | |

define_operator(zxload, $R1 = $S1, ((BI, (SU, SU, P), (SU)))) | |

# Load and sign-extend bitfield | |

define_operator(sxload, $R1 = $S1, ((BI, (SU, SU, P), (SI)))) | |

# Store integer in bitfield | |

define_operator(sstore, $R1 = $S1, ((BI, (SU, SU, P, SI)))) | |

# Binary operations. | |

define_operator(add, | |

$R1 = $S1 + $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), | |

(SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), | |

(XF, (XF, XF), (XF)), | |

(PSI, (P, SI), (P)))) | |

define_operator(sub, | |

$R1 = $S1 - $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), | |

(SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), | |

(XF, (XF, XF), (XF)), | |

(PP, (P, P), (SI)))) | |

define_operator(mul, | |

$R1 = $S1 * $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), | |

(SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)), | |

(SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), | |

(XF, (XF, XF), (XF)))) | |

define_operator(div, | |

$R1 = $S1 / $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), | |

(SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)), | |

(SF, (SF, SF), (SF)), (DF, (DF, DF), (DF)), | |

(XF, (XF, XF), (XF)))) | |

define_operator(mod, | |

$R1 = $S1 % $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)), | |

(SU, (SU, SU), (SU)), (DU, (DU, DU), (DU)))) | |

define_operator(and, | |

$R1 = $S1 & $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) | |

define_operator(ior, | |

$R1 = $S1 | $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) | |

define_operator(xor, | |

$R1 = $S1 ^ $S2, | |

((SI, (SI, SI), (SI)), (DI, (DI, DI), (DI)))) | |

define_operator(lshift, | |

$R1 = $S1 << $S2, | |

((SI, (SI, SI), (SI)), (SU, (SU, SI), (SU)), | |

(DI, (DI, SI), (DI)), (DU, (DU, SI), (DU)))) | |

define_operator(rshift, | |

$R1 = $S1 >> $S2, | |

((SI, (SI, SI), (SI)), (SU, (SU, SI), (SU)), | |

(DI, (DI, SI), (DI)), (DU, (DU, SI), (DU)))) | |

define_operator(lt, | |

$R1 = $S1 < $S2, | |

((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), | |

(DI, (DI, DI), (T)), (DU, (DU, DU), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

define_operator(le, | |

$R1 = $S1 <= $S2, | |

((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), | |

(DI, (DI, DI), (T)), (DU, (DU, DU), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

define_operator(ge, | |

$R1 = $S1 >= $S2, | |

((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), | |

(DI, (DI, DI), (T)), (DU, (DU, DU), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

define_operator(gt, | |

$R1 = $S1 > $S2, | |

((SI, (SI, SI), (T)), (SU, (SU, SU), (T)), | |

(DI, (DI, DI), (T)), (DU, (DU, DU), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

define_operator(eq, | |

$R1 = $S1 == $S2, | |

((SI, (SI, SI), (T)), (DI, (DI, DI), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

define_operator(ne, | |

$R1 = $S1 != $S2, | |

((SI, (SI, SI), (T)), (DI, (DI, DI), (T)), | |

(SF, (SF, SF), (T)), (DF, (DF, DF), (T)), | |

(XF, (XF, XF), (T)), (P, (P, P), (T)))) | |

# Unary operations. | |

define_operator(neg, | |

$R1 = -$S1, | |

((SI, (SI), (SI)), (DI, (DI), (DI)), | |

(SF, (SF), (SF)), (DF, (DF), (DF)), | |

(XF, (XF), (XF)))) | |

define_operator(not, | |

$R1 = ~$S1, | |

((SI, (SI), (SI)), (DI, (DI), (DI)))) | |

define_operator(not, | |

$R1 = !$S1, | |

((T, (SI), (SI)))) | |

# Increment operations. | |

define_operator(predec, | |

$R1 = *\($TR1 *\) $S1 -= $S2, | |

((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), | |

(SI, (P, SI), (SI)), (DI, (P, DI), (DI)), | |

(P, (P, SI), (P)), (SF, (P, SF), (SF)), | |

(DF, (P, DF), (DF)), (XF, (P, XF), (XF)), | |

(BI, (SU, SU, P, SI), (SI)))) | |

define_operator(preinc, | |

$R1 = *\($TR1 *\) $S1 += $S2, | |

((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), | |

(SI, (P, SI), (SI)), (DI, (P, DI), (DI)), | |

(P, (P, SI), (P)), (SF, (P, SF), (SF)), | |

(DF, (P, DF), (DF)), (XF, (P, XF), (XF)), | |

(BI, (SU, SU, P, SI), (SI)))) | |

define_operator(postdec, | |

$R1 = *\($TR1 *\) $S1\, *\($TR1 *\) $S1 -= $S2, | |

((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), | |

(SI, (P, SI), (SI)), (DI, (P, DI), (DI)), | |

(P, (P, SI), (P)), (SF, (P, SF), (SF)), | |

(DF, (P, DF), (DF)), (XF, (P, XF), (XF)), | |

(BI, (SU, SU, P, SI), (SI)))) | |

define_operator(postinc, | |

$R1 = *\($TR1 *\) $S1\, *\($TR1 *\) $S1 += $S2, | |

((QI, (P, QI), (QI)), (HI, (P, HI), (HI)), | |

(SI, (P, SI), (SI)), (DI, (P, DI), (DI)), | |

(P, (P, SI), (P)), (SF, (P, SF), (SF)), | |

(DF, (P, DF), (DF)), (XF, (P, XF), (XF)), | |

(BI, (SU, SU, P, SI), (SI)))) | |

# Jumps. | |

define_operator(xjumpif, if \($S1\) pc = code->pc0 + $L1, ((, (T),, (SI)))) | |

define_operator(xjumpifnot, if \(! $S1\) pc = code->pc0 + $L1, ((, (T),, (SI)))) | |

define_operator(jump, pc = code->pc0 + $L1, ((,,,(SI)))) | |

# This is for GCC2. It jumps to the address on the stack. | |

define_operator(jump, pc = \(void *\) $S1, ((P,,))) | |

# Switches. In order to (eventually) support ranges we provide four different | |

# varieties of switches. Arguments are the switch index from the stack, the | |

# bytecode offset of the switch table, the size of the switch table, and | |

# the default label. | |

define_operator(caseSI, CASESI\($S1\, $L1\, $L2\, $L3\), ((, (SI),, (SI, SI, SI)))) | |

define_operator(caseSU, CASESU\($S1\, $L1\, $L2\, $L3\), ((, (SU),, (SI, SI, SI)))) | |

define_operator(caseDI, CASEDI\($S1\, $L1\, $L2\, $L3\), ((, (DI),, (SI, SI, SI)))) | |

define_operator(caseDU, CASEDU\($S1\, $L1\, $L2\, $L3\), ((, (DU),, (SI, SI, SI)))) | |

# Procedure call. | |

# Stack arguments are (deepest first): | |

# procedure arguments in reverse order. | |

# pointer to the place to hold the return value. | |

# address of the call description vector. | |

# pointer to the procedure to be called. | |

define_operator(call, CALL\($S1\, $S2\, $S3\, sp\), ((, (P, P, P)))) | |

# Procedure return. | |

# Pushes on interpreter stack: | |

# value of retptr (pointer to return value storage slot) | |

define_operator(return, $R1 = retptr, ((P,,(P)))) | |

# Really return. | |

define_operator(ret, return, (())) | |

# Print an obnoxious line number. | |

define_operator(linenote, fprintf\(stderr\, "%d\\n"\, $L1\), ((,,,(SI)))) |