{eris}work>DT>D2T.tedit Wed 12 Mar 86 M Herring Table of contents overview of the players their calling sequences LAP variable names declarative section instruction section notes on D-LAP notes on T-LAP the D->T translation summary of the translation DDISASM D2T TASM the D->D translation summary of the translation T2D DASM current status See also D2TOpCodes.tedit which, grouping the opcodes by subject, attempts to say what this system does to each opcode. See also TAsmOpCodes.tedit which tries to do more or less the same thing for Tamarin opcodes. See also AsmInternals.tedit, which says more about how ASM works, what its inputs & outputs are, etc. f OVERVIEW OF THE PLAYERS -- DT runs the process of translating compiled D-machine code to compiled Tamarin code. First it calls DDISASM to convert the CCODEP to a symbolic list ("D-machine LAP" or "D-LAP"). Then D2T removes the specifically D-machine features of the D-LAP (in favor of specifically Tamarin features if necessary), producing Tamarin LAP ("T-LAP"). Then TASM assembles the T-LAP into the Tamarin equivalent of a CCODEP (at this writing, in a byte array). DD runs a related process that converts a CCODEP into another CCODEP that approximates a D-machine attempting to emulate a Tamarin running the output of DT. This is intended to test the translation process. In particular, DDISASM & D2T are run as above, then T2D is used to remove specifically Tamarin features in favor of D-machine ones, then DASM ( a variant of TASM) is used to assemble the new CCODEP. TASM & DASM are variants of ASM, a somewhat generic byte-code assembler. TAM.GETMACHINE enables ASM to access functions, etc, in the DASM & TASM files, which tailor ASM to the specific target machine. This includes pointing ASM to the specific opcode arrays. Since the opcode arrays are not maintained in the packages documented here, some of the Tamarin restrictions on the opcode set are not well documented here. TPC & DPC are variants of PC, a modified PRINTCODE that works on either D-machine CCODEPs or Tamarin object-code byte arrays. PC uses TAM.GETMACHINE in the same way that ASM does. D2DTEST includes the functions DDALL and DDLIST, which do as DD, but for many functions en masse. D2DTESTSUITE & DASMTESTSUITE are partial test suites. ff THEIR CALLING SEQUENCES (DDISASM fn errfile) => dlap. fn can be a CCODEP or a litatom with a CCODEP function definition. The D-LAP output has no generics, refers to pvars and fvars by (name original-slot#), refers to ivars by (name a-unique-negative-#), and has labels only at jump-to points (the label is the original pc). (D2T dlap errfile) => tlap. Remove specifically D-machine features from the LAP (in favor of specifically T-machine ones if necessary). This includes but is not limited to variable slot allocation, precise opcode availability, length of jumps, binding markers, and function calls. (T2D tlap errfile) => dlap. Removes those specifically T-machine features, that D2T might put in, in favor of something that will run on a D-machine. (As a test on this system.) (TASM tlap options errfile) => (ASM tlap 'T options errfile). The file TASM also defines the T machine to TAM.GETMACHINE. (DASM dlap options errfile) => (ASM dlap 'D options errfile). The file DASM also defines the D machine to TAM.GETMACHINE. (ASM lap machinetype options errfile) => (#errors . object-code-thingy). Also leaves stuff in global variables named \ASM.xxx. In addition to emitting byte code, ASM does a certain bit of macro work, mostly involving straight translation & de-genericization. ASM itself knows about variable allocation, stack modelling in general, the general style of jump instructions, etc. TAM.GETMACHINE tells ASM what the target machine is like. See AsmInternals.tedit for more details. (DT fn) => a byte array (representing Tamarin function format) unless errors. Runs DISASM, D2T, and TASM. fn is not redefined, but the output ccodep is saved as the function definition of the global TASMFN. Other things are saved similarly. (DD fn) => ccodep. Runs DDISASM, D2T, T2D, and DASM, resulting in a ccodep (if all goes well). fn is not redefined, but the output ccodep is saved as the function definition of the global DASMFN. Other things are saved similarly. D2DTEST's DDALL & DDLIST are for mass runs of (essentially) DD. They know how to smash the new function definitions back into the functions' definition cells. They also know when to skip a function & how to keep going despite errors. (TPC fn outfile) => (PC fn 'T outfile). This is in the file TASM. (DPC fn outfile) => (PC fn 'D outfile). This is in the file DASM. (PC fn machineType outfile) -- a printcode that works on either a D-machine CCODEP or a Tamarin code-object byte array. Both D-machine and Tamarin LAP (symbolic assembler source) are just lists. LAP is discussed below. ASM and PC show TAM.GETMACHINE their machineType argument to find out what the target machine is. This argument is decoded into (1) the "styles" of function header, stack modelling, etc., (2) a list of property names under which to look up macro-like things for a CAR-of-instruction, and (3) a list of property names under which to look up OPCODE records for a CAR-of-instruction,and (4) preamble code for each function-type and number of arguments. See AsmInternals.tedit for more details. ASM, TASM, DASM, DT & DD take an options, argument -- this can be NIL, D, or (D). If a D (for Debugging) is present, separate error messages are generated for each phase; see AsmInternals.tedit. All these functions (except for DT, DD, and the PCs) take a last, error-file, argument, which controls the routing of error messages & the handling of programmed aborts. (Everyone does programmed aborts via ASM.HELP.) ERRFILE is intended to be NIL except when running under NLSETQ. When ERRFILE is NIL, error messages are printed to T and ASM.HELP calls HELP. ERRFILE should be non-NIL only when doing things en masse. See AsmInternals.tedit for more details. f LAP -- LAP is really just a list of labels (litatoms), instructions (lists), and comments (lists starting with *). D-LAP and various dialects of T- LAP differ on some details of what instructions are allowed. We will discuss these later. The output of the phases other than ASM (or DASM or TASM) are LAP unless they have errors, in which case they are LAP but with error messages appended to individual instructions or inserted after instructions, etc. ASM's "listing" output is similar; see AsmInternals.tedit. There are pseudo-instructions & -labels. They describe the function header, etc. These are also referred to as "declarations". They end with a ":" by convention. Comments the second symbol of which is forT2D: are hints being passed from D2T to T2D. Labels generated within this system have $ in them. Schematically: ( (LAMBDA: FOO (I J)) (DFNHEADER: ...) ... name-table I/P/F/VARS: ... LOCAL: ... local-name-table I/P/F/VARS: ... CODE: ... instructions ... label ... instructions ... label ... instructions ... ) Generally, only the type+name+args pseudo-instruction & the CODE: pseudo-label are required, except that every variable that is used has to be declared in an I/P/F/VARS: declaration. Everything before the CODE: is entirely declarative; after the CODE: is the body of the function. A terminating (-X-) is optional (supplied if missing). ff variable names in LAP in general-- A variable name can be either a litatom, a string, or a list (litatom-or-string number). In either case it is the litatom itself that occurs in the name tables -- a variable with a string in its name does not show up in either name table. Officially, the number in a list-format variable name is just an identifier to separate variables which have the same name-table name, but-- DDISASM names pvars & fvars (name original-slot-number). It names ivars (name {-1 - ivar-number}). It names compiler-generated temporary variables ("pvar" original-slot-number). Other functions in this sequence may generate local pvar temporaries; their names will be strings with $ in them. ff declarative section of LAP in general-- A LAP list for a function has to start with a type+name+args pseudo-instruction: either LAMBDA: or NLAMBDA:, followed by the name of the function, followed by its argument list as it would occur in the DF definition of the function. ( As described above, variable names can be lists. Since a list which is a variable name can be distinguished from any list of variable names, there is no difficulty with declaring nospread functions.) A DFNHEADER: pseudo-instruction is optional as second instruction. DDISASM generates one, describing the header of the original ccodep. It is passed through the rest of the system for checking by ASM. [Historically, this checking has gotten weaker as reasons for evading it have arisen at various last moments.] Then follow specvar declarations if any -- the information in the name table of the function header. This is provided as pseudo-instructions consisting of IVARS: PVARS: or FVARS: followed by one or more variable names. Tamarins have VARS: and FVARS:. The order of the variable names in these declarations will be their order in the name table constructed, which is their order of scanning in free variable lookup, which is their reverse order of binding. Then if there are local variables, their declarations follow. These give the information for the local name table that follows the function header, as well as declaring variables that occur in no name table. This section, if present, must start with a LOCAL: pseudo-label to separate it from the specvar declarations. I/P/F/VARS: pseudo-instructions are used here just as described in the above paragraph. All variables used in the instruction section have to be declared as I/P/F/VARS: in the declaration section of the LAP. The variables in the argument list part of the type+name+args pseudo-instruction must be redeclared IVARS: (or, for a Tamarin, VARS:) so that they can be put in one or the other name table. (But the arglist variable of a lambda* function can be declared PVAR:. D2T precedes such a declaration with (* forT2D: arglistIsPvar); T2D needs this.) ff instruction section of LAP in general-- In the instruction section of a function's LAP, a list is an instruction or comment & anything else is a label. A label can be used (1) for jumping to, &/or (2) for "referencing the computation-stack depth at" (used by the TUNBIND & TDUNBIND opcodes only). Comments are implemented via the pseudo-opcode "*". D2T leaves hints for T2D in the form of comments. T2D swears not to look at those that don't start with * forT2D: . All the programs, when they do a "complex" transformation on a source instruction, leave the original of the source instruction in the output LAP in comment form. An instruction is an opcode (or a "generic" opcode) possibly with arguments. An instruction's arguments are symbolic, in some appropriate format -- the cases that need discussion are discussed below. Error messages get appended, in an "output listing", to the instruction they refer to, or if there is none, then some pseudo-instruction. They also get printed to T (or ERRFILE). ASM handles this in essentially the same way; see AsmInternals.tedit. A generic opcode is one that can instantiate to related opcodes of different instruction-lengths, or even to more complex opcode sequences, but defers this decision as late as reasonable. The generics available are: Variable-reference generics -- the complete 2-dimensional matrix of IVAR PVAR FVAR VAR by IVAR IVAR_ IVAR_^, with one variable-name argument. Variable-reference generics are implemented within ASM by an "expert" that uses whatever opcodes the target machine has from the set of variable-reference opcodes + POP. Jump generics -- JUMP FJUMP TJUMP NFJUMP NTJUMP, with one label argument. Jump generics are implemented within ASM by an "expert" that uses whatever opcodes the target machine has from the set of jump opcodes+ COPY + POP. FN -- with a numeric argument and a litatom argument. The FN generic is implemented via an AsmFn for the target machine. SIC -- with one numeric argument. The SIC generic is implemented via an AsmFn for the target machine. Remarks on the formats of some instructions in LAP: One-byte opcodes with an implicit argument (other than the FNk's and the internal constants like 'NIL) are expressed as the base opcode with one numeric argument. Opcodes with subopcodes show their subopcode as their argument. This can be numeric or symbolic. The TYPEP instruction knows a few types by name. Its argument can also be numeric. GETBITS.N.FD and PUTBITS.N.FD have 3 arguments: word offset, starting bit number, and number of bits (note: not "number of bits - 1"). ff notes on D-machine LAP -- The format of a BIND instruction is: (BIND list-of-PVARs-to-bind-nonNIL list-of-PVARs-to-bind-NIL) where the list of PVARs to bind non-NIL is in reverse the order that they will be bound by popping values off the stack. (ASM can only handle BINDs which reference at most one pvar total.) UNBIND and DUNBIND take no arguments. There are no TUNBIND nor TDUNBIND instructions. There are no ICONST nor PCONST opcodes but there is a GCONST opcode. IVAR references in a lambda-nospread function have numeric arguments. These are 0-based, rather than 1-based as with the InterLisp functions ARG & SETARG. (ASM cannot handle these. Thus there are no corresponding generics. D2T eliminates all IVAR opcodes in a lambda* function in favor of ARG0 etc.) ff notes on Tamarin LAP -- There are no BIND, UNBIND, or DUNBIND instructions. TUNBIND and TDUNBIND take one argument: a label, referring to the computation-stack level as of that label. (There is no way to state the stack level argument as a number in LAP.) There are no GETBITS.N.FD nor PUTBITS.N.FD opcodes. There are not GETBASE.N nor PUTBASE.N opcodes. There is no GCONST opcode but there are ICONST & PCONST opcodes. f THE D->T TRANSLATION ff summary of the translation-- The function header is of course changed, hopefully in accordance with the TFUNHDR record in the current TACCESS file. The name-table format is at this writing the same as that on a D-machine. Variables are allocated so-- The first 7 var slots are reserved for ivars. The 8th var slot is not used. Pvars may be rearranged: Specvars come first, then the localvars in the local name table, then any other local vars, then any temporaries that D2T may have generated, then any temporaries that TASM may generate. Pvars that existed in the original CCODEP retain their original ordering within these groups. All fvars follow all pvars; they retain their ordering. There is not yet any check for, nor handling of, pvar/fvar area overflow nor stack overflow. Entry-vector code is inserted for lambda and nlambda functions of 0..6 arguments. Other function types are not supported at this writing. These entry vectors are taken straight from the suggestively-named variables in the file TASM. All the variable-reference opcodes (e.g. IVAR thru FVARX_^) that are used on the D-machine are taken to the shortest possible corresponding opcode sequences on the Tamarin, given the opcde set there & the new variable-slot allocations. IVAR- and PVAR-type opcodex both => VAR-type opcodes. POP is used to simulate xVAR_^ if necessary. The argument byte of xVARX opcodes is in longwords relative to the 0th var slot. In lambda-nospread functions, (IVAR n) and (IVARX n) => (SIC n+1) (ARG0), and (IVARX_ n) => (SIC n+1) (SWAP) (FN2 \SETARG0). Opcodes' multi-byte in-line arguments are presented least significant byte first. (BIND (V1 .. Vn) (Vn+1 .. Vm)) => (VAR_^ Vn) .. (VAR_^ V1) ('NIL) (VAR_ Vn+2) .. (VAR_ Vm) (VAR_^ Vn+1). (UNBIND) => ('UNBIND) (VAR_ V2) .. (VAR_ Vm) (VAR_^ V1) (TUNBIND stackdepth), where the Vi are the pvars bound by the the corresponding BIND instruction, and stackdepth is that prevailing just following the code generated by that corresponding BIND. (DUNBIND) is taken to TDUNBIND in just the same way. (FNX n func), with n<7 => (FNn func). (FNX n func), with n>6 => (SIC n-6) (FN1 \VectorizeN) (FN7 func). (APPLYFN) is not supported at this writing. (CHECKAPPLY*) disappears. (SIC n) => (SICX n) and (SICX n) => (SICXX n). This is just a renaming. ('1) => (SICX 1), if '1 is not an opcode on the Tamarin. (SNIC -n) => (SICX n) or (SICXX n) followed by (NEG). (NOP) & all JUMP-type opcodes => the shortest opcode sequences that will work on the Tamarin given the opcode set there & the different code lengths in the new code object. Jump-arounds will be generated if necessary to simulate missing complex JUMP opcodes; COPY and POP may be used here. ASM does not know about "long NOPs" at this writing, and assumes that the semantics of the JUMP-type opcodes are exactly like those on the D-machine. (GCONST x), if x is a number in the Tamarin FIXP range [-2^30,2^30) => (ICONST x); in the ICONST, x is sign-extended to 32 bits. (GCONST x), otherwise => (PCONST n); in the PCONST, x is presented as a backwards-compatible type, i.e. not converted at all. Type opcodes are not implemented at this writing. (GETBASE.N wordoffset) => (COPY) (SIC wordoffset*2) (GETBASEBYTE) (LLSH8) (VAR_^ temp)(SIC wordoffset*2+1) (GETBASEBYTE) (VAR temp) (LOGOR2). (PUTBASE.N wordoffset) => (VAR_^ temp) (SIC wordoffset*2) (VAR temp) (LRSH8) (PUTBASEBYTE) (SIC wordoffset*2+1) (VAR temp) (PUTBASEBYTE). (GETBITS.N.FD wordoffset leftbit nbits) => <1> if the bits are within one byte of memory, then (SIC byteoffset) (GETBASEBYTE) else as GETBASE.N above, <2> 0..7 of (LRSH1), <3> (SIC mask) (LOGAND2) if needed. (PUTBITS.N.FD wordoffset leftbit nbits) => <1> (VAR_^ temp1), <2> if the target bits lie within one byte of memory then (COPY) (SIC byteoffset) (GETBASEBYTE) else as GETBASEBYTE.N except leaving the pointer on the stack under the target word gotten, <3> (SIC -mask) (NEG) (LOGAND2), <4> (VAR temp1) (SIC mask) (LOGAND2), <5> 0..7 of (LLSH1), <6> (LOGOR2) (VAR_^ temp1), <7> if the target bits lie within one byte of memory then (SIC byteoffset) (VAR temp1) (PUTBASEBYTE) else as PUTBASE.N . ff DDISASM -- outputs D-LAP DDISASM generates the DFNHEADER: pseudo-instruction, as the second instruction. Its argument list contains the original values of STK: PV: START: NTSIZE: NLOCALS: and FVAROFFSET: , in property-list format. DDISASM generates its variable-declaration pseudo-instructions in name-table order (which implies: specvar PVARS then IVARs then FVARs, then local PVARs then IVARs). Pvars & fvars are named with a list: (name-proper original-slot-number). Ivars are named with a list: (name-proper {-1 - ivar-number}). Compiler-generated temporary PVARs are named e.g. ("pvar" 3) so that ASM does not put them in either name table. DDISASM generates labels only for jump-to addresses. The labels generated are numbers: offsets into the CodeArray. DDISASM does not genericize opcodes. ff D2T -- inputs D-LAP and outputs T-LAP Like everybody else, whenever D2T performs a non-trivial translation, it inserts the input instruction as a comment before the resulting output instructions. Several other comments can be generated as hints to T2D. These start with " (* forT2D: ". (T2D swears not to look at comments not in this form.) They are (* forT2D: arglistIsPvar), .. BIND .., ..CHECKAPPLY* .., and .. FN7 .. . They are discussed below. IVARS: and PVARS: declarations are turned into VARS: declarations. In nospread functions, if the arglist variable is declared as a PVAR, D2T will insert, before the resulting VARS: declaration, a (* forD2T: arglistIsPvar). In lambda-nospread functions, D2T takes (IVAR n) and (IVARX n) => (SIC n+1) (ARG0) , and takes (IVARX_ n) => (SIC n+1) (SWAP) (FN2 \SETARG0) . D2T takes (BIND (V1 .. Vn) (Vn+1 .. Vm)) => --in the most general form-- (VAR_^ Vn) .. (VAR_^ V1) ('NIL) (VAR_ Vn+2) .. (VAR_ Vm) (VAR_^ V1) 45$BIND (* forT2D: BIND) . The (* forT2D: BIND) tells T2D where the BIND was; this is not strictly necessary, but makes T2D easier. D2T takes UNBIND => --in the most general form-- ('UNBIND) (VAR_ V2) .. (VAR_ Vm) (VAR_^ V1) (TUNBIND 45$BIND) , where the Vi & the label are those from the corresponding BIND. DUNBIND => TDUNBIND in the same way. D2T takes function calls with >6 arguments (FNX n func) => (* forT2D: FN7) (SIC n-6) (FN1 \VectorizeN) (FN 7 func). Note that a compiler would not do it this way, as it uses more stack depth than is necessary. D2T takes (CHECKAPPLY*) => (* forT2D: CHECKAPPLY*) . D2T takes (GCONST x) to: if x is a number in the Tamarin FIXP range [-2^30,2^30) then (ICONST x), else (PCONST n) D2T takes (GETBASE.N wordoffset) => (COPY) (SIC wordoffset*2) (GETBASEBYTE) (LLSH8) (VAR_^ "D2T$temp1")(SIC wordoffset*2+1) (GETBASEBYTE) (VAR "D2T$temp1") (LOGOR2), where "D2T$temp1" is a local pvar allocated by D2T. D2T takes (PUTBASE.N wordoffset) => (VAR_^ "D2T$temp1") (SIC wordoffset*2) (VAR "D2T$temp1") (LRSH8) (PUTBASEBYTE) (SIC wordoffset*2+1) (VAR "D2T$temp1") (PUTBASEBYTE), where "D2T$temp1" is a local pvar allocated by D2T. D2T takes (GETBITS.N.FD wordoffset leftbit nbits) => <1> if the bits are within one byte of memory, then (SIC byteoffset) (GETBASEBYTE) else as GETBASE.N above, <2> 0..7 of (LRSH1), <3> (SIC mask) (LOGAND2) if needed. D2T takes (PUTBITS.N.FD wordoffset leftbit nbits) => <1> (VAR_^ temp1), <2> if the target bits lie within one byte of memory then (COPY) (SIC byteoffset) (GETBASEBYTE) else as GETBASEBYTE.N except leaving the pointer on the stack under the target word gotten, <3> (SIC mask) (LOGAND2), <4> (VAR temp1) (SIC mask) (LOGAND2), <5> 0..7 of (LLSH1), <6> (LOGOR2) (VAR_^ temp1), <7> if the target bits lie within one byte of memory then (SIC byteoffset) (VAR temp1) (PUTBASEBYTE) else as PUTBASE.N . One or two temps may be used --"D2T$temp1" and "D2T$temp2"-- these are allocated by D2T. D2T genericizes all opcodes that have generics. D2T just passes the DFNHEADER: statement through. Tamarin-UFNs which D2T generates calls to-- \SETARG0, \VectorizeN. ffT ASM -- inputs T-LAP Opcodes are known by looking at their TOPCODE properties for OPCODE records. The names of the variable-reference- and jump- generics are hard-coded into the assembler, as is their stack effect; they are expanded by hard-coded heuristics which know about certain opcodes by name, and work with whatever subset of those opcodes are available. Other "generics" and "macro definitions" are found by looking at the TASMFN properties of the CARs of instructions. The generic (FN n func) is translated into one of FN0 .. FN7. The generic (SIC n) is translated into one of ('0), ('1), (SICX n), or (SICXX n), possibly followed by (NEG). The argument-byte of an X-format variable-reference opcode is in 32-bit words, that is, slot number. Multi-byte in-line arguments are presented least significant byte first. The output object is a byte array, with part of a T-machine function header. The first 8 var slots are reserved for ivars, period. TASM at this point refuses APPLYFN. Accepts TUNBIND and TDUNBIND; does not accept BIND, UNBIND nor DUNBIND. Accepts ICONST & PCONST; does not accept GCONST. See also AsmInternals.tedit. f THE D->D TRANSLATION ff summary of the translation-- The function header will hopefully be unchanged except inasmuch as D2T adds temporary pvars. Pvars may be rearranged: Specvars come first, then the localvars in the local name table, then any other local vars, then any temporaries that D2T may have generated, then any temporaries that DASM might generate. Pvars that existed in the original CCODEP retain their original ordering within these groups. All the variable-reference opcodes (e.g. IVAR thru FVARX_^) are taken to the shortest possible opcode sequences , given the new variable-slot allocations. POP is used to simulate xVAR_^ if necessary. In lambda-nospread functions, (IVAR n) and (IVARX n) => (SIC n+1) (ARG0), and (IVARX_ n) => (SIC n+1) (SWAP) (FN2 \SETARG0). (BIND (V1 .. Vn) (Vn+1 .. Vm)) => (VAR_^ Vn) .. (VAR_^ V1) ('NIL) (VAR_ Vn+2) .. (VAR_ Vm) (VAR_^ Vn+1) (BIND NIL NIL). (UNBIND) => (BIND NIL (V2)) (DUNBIND) .. (BIND NIL (Vm)) (DUNBIND) (BIND NIL (V1)) (DUNBIND) (UNBIND), where the Vi are the pvars bound by the the corresponding BIND instruction. (DUNBIND) is expanded to explicitly unbind the pvars in just the same way. ('0), ('1), (SIC n) & (SICX n) are not changed unless some instance was not as short as possible, in which case it will be replaced with the shorter form. (NOP) & all JUMP-type opcodes => the shortest opcode sequences feasible given the different code lengths in the new CCODEP. Jump-arounds will be generated if necessary to simulate missing complex JUMP opcodes; COPY and POP may be used here. (GETBASE.N wordoffset) => (COPY) (SIC wordoffset*2) (GETBASEBYTE) (LLSH8) (VAR_^ temp)(SIC wordoffset*2+1) (GETBASEBYTE) (VAR temp) (LOGOR2). (PUTBASE.N wordoffset) => (VAR_^ temp) (SIC wordoffset*2) (VAR temp) (LRSH8) (PUTBASEBYTE) (SIC wordoffset*2+1) (VAR temp) (PUTBASEBYTE). (GETBITS.N.FD wordoffset leftbit nbits) => <1> if the bits are within one byte of memory, then (SIC byteoffset) (GETBASEBYTE) else as GETBASE.N above, <2> 0..7 of (LRSH1), <3> (SIC mask) (LOGAND2) if needed. (PUTBITS.N.FD wordoffset leftbit nbits) => <1> (VAR_^ temp1), <2> if the target bits lie within one byte of memory then (COPY) (SIC byteoffset) (GETBASEBYTE) else as GETBASEBYTE.N except leaving the pointer on the stack under the target word gotten, <3> (SIC mask) (LOGAND2), <4> (VAR temp1) (SIC mask) (LOGAND2), <5> 0..7 of (LLSH1), <6> (LOGOR2) (VAR_^ temp1), <7> if the target bits lie within one byte of memory then (SIC byteoffset) (VAR temp1) (PUTBASEBYTE) else as PUTBASE.N . ff T2D -- inputs T-LAP and outputs D-LAP T2D is not guaranteed to work right except on the output of D2T. T2D takes VARS: declarations => IVARS: & PVARS: declarations. It does this by checking whether the variables are listed in the arglist of the type+name+arglist declaration, except that (* forT2D: arglistIsPvar) forces everything thereafter to be PVARS: . T2D takes (VAR x) , (VAR_ x) and (VAR_^ x) => the corresponding IVAR or PVAR references. T2D takes (* forT2D BIND) => (BIND NIL NIL) . T2D takes ('UNBIND) (VAR_ V2) .. (VAR_ Vn) (VAR_^ V1) => a series of instruction-pairs (BIND NIL (Vi)) (DUNBIND) . T2D takes (TUNBIND label) => (UNBIND) and (TDUNBIND label) => (DUNBIND) . T2D takes (* forT2D: FN7) (SIC n) (FN1 \VectorizeN) (FN 7 func) => (FN n+6 func) . T2D takes (* forT2D CHECKAPPLY*) => (CHECKAPPLY*) . T2D takes ICONST & PCONST => GCONST. T2D just passes the DFNHEADER: statement through. ff DASM -- inputs D-LAP If a DFNHEADER: statement is present, all of its clauses that have non-NIL values are checked against the corresponding values for the CodeArray being output. (Actually, this testing tends to get weaker with time, as reasons for avoiding it come up. (1) True NLOCALS being > the DFNHEADER:'s NLOCALS is considered ok, since the translation process may have generated new PVARs. (2) STARTPC isn't checked at all, since in case of lambda-nospread functions that don't look at their arguments, we generate no local name table, but the compiler does.) Variables are output to the name table and the local name table in the order: first pvars then ivars then fvars, in their order of declaration. All fvar slots follow all pvar slots, otherwise nothing is guaranteed about var slot order. Does not accept lambda-nospread numeric ivar references. Opcodes are known by looking at their DOPCODE properties for OPCODE records. The names of the variable-reference- and jump- generics are hard-coded into the assembler, as is their stack effect; they are expanded by hard-coded heuristics which know about certain opcodes by name, and work with whatever subset of those opcodes are available. Other "generics" and "macro definitions" are found by looking at the DASMFN properties of the CARs of instructions. The generic (FN n func) is translated to one of (FN0 func) .. (FN4 func) or (FNX n func) . The generic (SIC x) is translated with one of SIC , SNIC , SICX . The argument-byte of an X-format variable-reference opcode is in 16-bit words, that is, 2 * slot number. Multi-byte in-line arguments are presented most significant byte first. The output object is a CCODEP, with the usual D-machine style function header. Accepts BIND, UNBIND and DUNBIND. Does not accept BINDs other than (BIND NIL NIL), (BIND (one-pvar) NIL), and (BIND NIL (one-pvar)). Does not accept TUNBIND nor TDUNBIND. DASM can only handle those instances of the APPLYFN opcode where the number of arguments on the stack is a constant that can be deduced (easily) from the code. This is because for Tamarin, ASM has to be able to predict the stack frame size. The pattern that DASM knows how to handle is-- '0 / '1 / SIC n IVAR / FVAR / PVAR / GVAR / ACONST / COPY.N ... [ CHECKAPPLY* ] APPLYFN See also AsmInternals.tedit. f current status -- Wed 12 Mar 86 -- "released" versions are on {eris}current>DT> ; versions being worked on are on {eris}work>DT> . Stack modelling is due in PC, but not yet there. Bunches of opcodes not supported (except to pass them thru) -- in particular IPLUS.N and IDIFFERENCE.N ; and all the type opcodes. No transformation of data objects is done. Lambda-spread functions with >6 arguments not fully supported (no entry vector). Lambda- and nlambda nospread functions ditto. Var area and stack overflow neither detected nor handled. Var allocation crudest possible. 1 $H1$ $1  $MODERN ?1(DEFAULTFONT 1 (GACHA 10) (GACHA 8) (TERMINAL 8)) MODERN MODERN MODERN MODERN    d  J  QcNaR:+K3   '%%{Zod CCxH& !B h')) !'S  (u . I 0 / P 8A p(m 'xd4y  JK  PD   !            / wJ0 6;] )R     #-">$ ,62zw2       t% # Q   ! + )+ ,  5 $5      b        402E&p)>neIM6 /=]7 )   6"@C     #7 /   3    3   E  2  1&p)X4iHO`,< 1+\vDz