Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!husc6!think!ames!sdcsvax!ucsdhub!hp-sdd!hplabs!hp-pcd!uoregon!omepd!mcg From: mcg@omepd (Steven McGeady) Newsgroups: comp.lang.c Subject: Re: Inline assembler; a quiz (long; sorry) Message-ID: <830@omepd> Date: Mon, 22-Jun-87 03:27:11 EDT Article-I.D.: omepd.830 Posted: Mon Jun 22 03:27:11 1987 Date-Received: Tue, 23-Jun-87 04:36:02 EDT References: <608@zen.UUCP> <2299@hoptoad.uucp> <21211@sun.uucp> <464@winchester.UUCP> <829@omepd> Reply-To: mcg@omepd.UUCP (Steven McGeady) Organization: Intel Corp., Hillsboro Lines: 369 My colleague, Jim Valerio, posted a long response (with which I agree) to John Mashey's negative comments about the value of asm inserts in C. Jim includes a long batch of example code, which, I fear, will be incomprehensible to someone who doesn't know the meaning of the constructs used in the asm inserts. Herewith follows a (slightly sanitized) version of the specification for the asm inserts that Jim refers to. They were designed by Jim and myself based on some ideas gleaned from the 3B2 PCC-2 C compiler. This specification is implemented in an existing compiler. Questions may be addressed to me. S. McGeady Intel Corp. (503) 696-4393 This specification is: (c) Copyright, 1986, 1987, Intel Corporation, all rights reserved Assembly-Language Inclusion in C Code Third Draft S. McGeady Jim Valerio Language Software Group Component Development Support Oregon Microcomputer Engineering Intel Corp. Introduction and Background The mechanism defined here is very similar to, and derived from the mechanism provided by the AT&T System V.3 PCC2 (QCC) compilers for the 3b2 and Intel 386 processors. In this draft of this document, the mechanism has been significantly extended and generalized from the PCC2 version, but retains its flavor. 1. Traditional Mechanism If the keyword 'asm' is seen, immediately followed by a parenthesis and a quoted string, e.g.: asm("movq g0,r0"); then the quoted string is stripped of the quotes and emitted. If the compiler is generating assembly language output, the compiler does no interpretation on the string. The string may be an instruction, pseudo- operation, or any other string, whether legal or illegal P7 assembly language. If the compiler is generating COFF output, the compiler transparently switches to assembly-output mode. The front_end emits a special return code to the driver instructing it to invoke the assembler. The asm() statement may occur anywhere a C statement may occur. The asm() statement is *not* an expression, and has no return value. Unlike the PCC-class of compilers, asm() may not occur in declaration sections of programs. Since the compiler does complex data reordering, assembler directives (e.g. .align) embedded in the data section may not have the intended effect. The traditional mechanism is provided in the compiler as well as a new mechanism that is defined below. 2. New Mechanism If a function declaration has the storage class asm, e.g.: asm int foo() {...} then the function declaration and any formal parameters are parsed normally, but formal declarations of the formal parameters must be present, in the prototyped form, and text within the function block (between the '{'...'}') is interpreted specially. The interpretation is described below. This form of asm insertion effectively allows the programmer to dynamically define new code-generation templates to be used by the compiler. A single assembly insertion may specify several templates, of which one is matched at code-generation time. This allows very flexible in-line insertion of special-purpose code sequences which would otherwise need to be hard- wired into the compiler. The declaration of an assembly insertion is the same as for any other procedure. The declaration specifies the types of the arguments, in the new (function prototype) style. Asm insertions must be defined before any use in a module in order to get well-defined semantics. A program that calls a procedure with the name of a later-defined asm function is in error, though this error may go undiagnosed by the compiler. The code within the block describes a set of assembly-language sequences which may be expanded in-line at the site of calls to the named function. For example: asm int test(int a, int b) { % reglit a,b,return; label lab1; lab1: test a,b move a,return beq lab1 } main() { register int x,y; register int a; ... a = test(x,y); } generates this code: _main: # entry code # ... # x is in r4, y is in r5, a is in r6 L0001: test r4,r5 mov r4,g0 beg L0001 mov g0,r6 # ... 2.1 Syntax of Asm Functions The contents of an asm block are interpreted as follows: asm_block:: asm_line + ; asm_line:: '%' [control]* | expansion_line | blank_line ; control:: arg_def | 'error' [text] ';' | 'call' [text] ';' | 'spillall' ';' ; arg_def:: [ class name [',' name ]* ';']* | 'use' reg [',' reg*]* ';' ; name:: formal_param_id | local_var_id ; expansion_line:: text [operand [',' operand]*] | label ';' ; operand:: formal_param_id | formal_param_id '('[[0-9]+['-'[0-9]+]]')' | local_var_id | local_var_id '('[[0-9]+[0-9]+]] ')' | 'return' | 'return('[[0-9]+['-'[0-9]+]] ')' ; class:: 'reglit' | 'reglit('[[0-9]+[0-9]+]]')' | 'tmpreg' | 'tmpreg('[[0-9]+['-'[0-9]+]] ')' | 'freglit' | 'ftmpreg' | 'const' | 'const('[[0-9]+[':'[0-9]+]]')' | 'label' | 'void' ; Storage classes have the following meanings: reglit - any register, or constant that can be used as a literal reglit(n) - same as reglit, except a register pair, triple or quad tempreg - any register being used as a temporary (anonymous variable,compiler temporary) tempreg(n) - as above, except a pair, triple, or quad freglit - any floating-point register or literal ftmpreg - any floating-point register being used as a temporary (anonymous variable, compiler temporary) const - any constant const(n) - any constant with the given value or range These storage classes are also available, but may not be applied to formal parameters: label - a label use - special (see below) void - applied only to 'return' (see below) Paramater and variable names (defined in an argument definition statement) may be any C identifiers, except that identifiers that are assembler reserved words are reserved (specifically register names). Each control line (those beginning with '%') marks the beginning of an assembler expansion leaf. An expansion leaf is a section of code that will be expanded inline in the calling routing if the actual parameters provided by the caller match those defined in the argument definition statement. Control lines may be continued by a backslash character'. There can be only one control line per expansion leaf. An assembler pseudo-function may have zero or more expansion leaves, %error leafs, or %call leaves. Each leaf represents a different set of code that may be expanded into the caller under certain circumstances, except %error which signals a compile-time error to the user. 2.2. Expansion Semantics When a call to an asm pseudo-function occurs, a part of the contents of the asm pseudo-function is expanded in-line at the call location, using the following rules: 1) The actual arguments are coerced into the types of the formal arguments to the asm function, if necessary. If this coercion occurs, or if they were expressions, these values will be in temporary registers, (tmpreg or ftmpreg) otherwise they will be in registers or memory locations. 2) The storage classes (register, temporary registers, floating-register, constant, or memory) of the actual arguments and the return value are ascertained, and the asm block is searched for argument definition control lines that define corresponding storage classes for the formal parameters of asm pseudo-function using the following rules: a) tmpreg and tmpreg(n) match actual arguments that are in one or more temporary registers as the result of coercions or because the argument was an expression; if the actual arguments are in memory (not currently allocated to a register), then a set of temporary registers is allocated and code is emitted prior to the assembly insert to move the value into these registers; if the actual argument is a constant, it is handled as though the the argument was in memory, but a loadconst instruction is emitted instead of a normal load; n is 1,2,3,4. b) reglit and reglit(n) match actual arguments that are in one or more local or global registers, or are integer literals; if the actual argument is in memory, or the constant is out of literal range, then the rules for tmpreg are used; n is 1,2,3,4. c) ftmpreg matches an actual argument that is in a floating-point register, and is a temporary, as defined above; if the actual is in memory, then a floating point temporary register is allocated and code is emitted to move the value there; d) freglit matches an actual argument that is in a floating-point register, or a floating-point literal; if the actual argument is in memory, then a floating point temporary register is allocated and code is emitted to move the value there; e) const matches any constant expression(integral type); const(n) matches a constant expression whose value is n; const(n..m) matches a constant expression in the (inclusive) range n..m; as a special case; f) the return specifier is handled specially: the return specifier void is matched only if the return value of the insertion is not used; a return specifier typed as reglit or tmpreg (or their length-specified variants) matches a return destination in the appropriate number of registers; if the return destination is in memory, then a set of registers is allocated and code is generated after the assembly insertion to move the return value from the allocated registers into the appropriate memory location; the same applies to freglit and ftmpreg for floating-point returns; any return specifier matches an ignored return value - a register is allocated for the return value, but is otherwise ignored; g) label, void, and use never match actual arguments - application of label or use class to a formal argument is an error. 3) If a leaf is found all of whose formal argument storage class match the actual argument storages classes, the code in the leaf is expanded, using the leaf expansion rules below; 4) If the leaf matched is a %call, the asm pseudo-function call is coerced to a call to the argument to the %call control, or, if there is no argument, to a call to an external procedure of the same name as asm pseudo-function. The compiler generates normal function-call entry code; if no match or no %error line is found then a default call to an external procedure with the same name as the asm pseudo-function will be generated. 5) If the %error specification is matched, a compile-time error is generated and no code is expanded; if the %spillall specification is found, all aliased values currently cached in registers are spilled to memory by the compiler; 6) If parameters are found in the argument definition control line that do not correspond to formal parameters, then these parameters are considered local variables. These local variables may be of any register storage class except use and const. If a register variable is introduced, a temporary variable is allocated by the compiler (potentially of the global or local class). If a memory variable is allocated, an integer-wide place on the caller's stack is allocated. If the storage class is label, a compiler-generated label is allocated. 7) If the storage class use is found in an argument definition control line, it serves to inform the compiler that the registers listed as the use statement's parameters are used by the code in the asm leaf, and those registers, if live at entry to the asm block must be saved prior to entry and restored upon exit from the asm block. 8) During expansion, any token which fully matches a parameter is substituted with the value of that paramater, as defined above. No explicit checking of the validity of the resulting assembler statement is performed. For reglit or treglit parameters, if the parameter was specified as a register set (multiple registers), then the identifier for this parameter may have "(n)", specifying which if the registers in the set to use, in the range 0..3; 2.3 Special Notes 1) Assembly inserts are not allowed to return or have as parameters aggregates longer than 4 words; 2) Enums are handled as normal integers; 3) Char and short types are promoted using the normal rules; 4) Preprocessing is done inside asm inserts as within any other text; This means that lines that have a '#' as the first non_white character are in error unless they are preprocessor control lines. 5) Assembly inserts are not allowed to specify register sets longer than 4 words; 6) A return must be specified as a register class. ----------------------------------------------------------- the end -----------------------------------------------------------