#ifndef __C_ASM_LOADED #define __C_ASM_LOADED 1 #pragma __nostandard #if !defined(__VAX) && ((!defined(__DECCXX)) || (__DECCXX_VER >= 50300000)) /**************************************************************************** ** ** - Prototypes for asm intrinsic functions ** ***************************************************************************** ** Header is nonstandard ***************************************************************************** ** ** Copyright 2003 Hewlett-Packard Development Company, L.P. ** ** Confidential computer software. Valid license from HP and/or ** its subsidiaries required for possession, use, or copying. ** ** Consistent with FAR 12.211 and 12.212, Commercial Computer Software, ** Computer Software Documentation, and Technical Data for Commercial ** Items are licensed to the U.S. Government under vendor's standard ** commercial license. ** ** Neither HP nor any of its subsidiaries shall be liable for technical ** or editorial errors or omissions contained herein. The information ** in this document is provided "as is" without warranty of any kind and ** is subject to change without notice. The warranties for HP products ** are set forth in the express limited warranty statements accompanying ** such products. Nothing herein should be construed as constituting an ** additional warranty. ** ***************************************************************************** */ #include #ifdef __cplusplus extern "C" { #endif #if defined(__INITIAL_POINTER_SIZE) # pragma __required_pointer_size __save # pragma __required_pointer_size 32 #endif /* ** DEC C supports in-line assembly code, commonly called ** ASMs on UNIX platforms. ** ** Like builtin-functions, ASMs are implemented with a function-call ** syntax. But unlike built-in functions, to use ASMs you must include ** this header file containing prototypes for the three types ** of ASMs, and the #pragma intrinsic preprocessor directive: ** ** __int64 asm(const char*, ...); // integer return, e.g. MULQ ** float fasm(const char*, ...); // single precision return, e.g. MULS ** double dasm(const char*, ...); // double precision return, e.g. MULT ** #pragma intrinsic (asm, fasm, dasm) ** ** Parameters: ** ** The first argument to the asm, fasm, or dasm function contains ** the instruction(s) to be generated inline, using the metalanguage ** (see below) that describes the interpretation of the arguments ** and the instructions themselves. ** ** Subsequent arguments provide the source and destination values ** (if any) for the instruction being generated, and any other values ** used in the generated instructions. These values are made available ** to the instructions via the normal argument passing conventions of ** the calling standard (e.g. the first integer argument is available ** in register R16). ** ** Return value: ** ** The choice of which function you call determines the type of ** the function value if the function is used in an expression. ** But it is up to the user-written instructions to ensure that ** the intended value of that type is placed in the register ** mandated by the calling standard for that type in order for ** the value to be made available to the calling code. ** ** Note that the #pragma intrinsic directive is required. It notifies ** the compiler that these functions are not user-defined functions, ** and that special processing should be applied to analyze at ** compile-time the first argument and generate machine-code ** instructions as specified by the contents of the string. ** ** The metalanguage for the argument references has the following form: ** ** : ** | ** | ** ** : "$" number ** ** : "%" ** ** : number ** | ** | "f" number | "F" number ** | "r" number | "R" number ** ** : // argument registers: R16-R21 ** "a0" | "a1" | "a2" | "a3" | "a4" | "a5" ** ** // return value: R0 or F0, depending on type ** | "v0" ** ** // scratch registers: R1, R22-R24, R28 ** | "t0" | "t1" | "t2" | "t3" | "t4" ** ** // save registers: R2-R15 ** | "s0" | "s1" | "s2" | "s3" | "s4" | "s5" | "s6" ** | "s7" | "s8" | "s7" | "s8" | "s9" | "s10" ** | "s11" | "s12" | "s13" ** ** // stack pointer: R30 ** | "sp" | "SP" | "$sp" | "$SP" ** ** | "RA" | "ra" // return addr: R26 ** | "PV" | "pv" // procedure value: R27 ** | "AI" | "ai" // arg info: R25 ** | "FP" | "fp" // frame pointer: R29 ** | "RZ" | "rz" | "zero" // sink/source: R31 == 0 ** ** Syntactically, the metalanguage can appear anywhere within ** an instruction sequence. ** ** The literal string that contains instructions, operands, and ** metalanguage must follow the general form: ** ** : ** | ";" ** | error ** | error ** ** : instruction_operand ** | directive ** ** ** An instruction_operand is generally recognized as an assembly ** language instruction separated by whitespace from a sequence of ** comma-separated operands. ** ** You can code multiple instruction sequences into one literal ** string, separating them by semicolons. Since the C language ** concatentates adjacent string literals into a single string, ** successive instructions can be written as separate strings ** one-per-line as is normally done in assembly language, as long ** as each instruction is terminated by a semicolon as shown in the ** examples. ** ** There are semantic and syntax rules associated with ASMs: ** ** o The first argument to an ASM call is interpreted as the ** instructions to be assembled in the metalanguage, and must ** be fully understood by the compiler at compile time. ** Therefore, it must be a literal string (or a macro expanding ** to a literal string) and not a runtime value containing a string. ** Thus the following are not allowed: indirections, table lookups, ** structure de-references, and so on. ** ** o The remaining arguments are loaded into the argument ** registers like normal function arguments, except that ** the SECOND argument to the ASM call is treated as the FIRST ** argument for purposes of the calling standard. ** ** For example, in the following test, the six arguments are ** loaded into arg registers a0 through a5, and the result of ** each subexpression is stored in the value return register ** v0. Since v0 is the calling-standard's return value register ** (R0 for an integer function) the result of the final mulq ** is the value returned by the "call": ** ** if (asm("mulq %a0, %a1, %v0;" ** "mulq %a2, %v0, %v0;" ** "mulq %a3, %v0, %v0;" ** "mulq %a4, %v0, %v0;" ** "mulq %a5, %v0, %v0;", 1, 2, 3, 4, 5, 6) != 720){ ** error_cnt++; ** printf ("Test failed\n"); ** } ** ** o A return register must be specified in the metalanguage ** for the result to appear in the expected place. ** ** The following example does not work. There is no value ** loaded into the floating-point return register. Furthermore, ** it results in a compile-time warning stating that r2 is used ** before it is set, because the arguments are loaded into the ** arg registers and not into r2: ** ** z = fasm("mulq %r2, %a1 %r5", x=10, y=5); ** ** A correct version of the above would be: ** ** z = fasm("mulq %a0, %a1, %a1;" ** "stq %a1, 0(%a2);" ** "ldt %f0, 0(%a2);" ** "cvtqf %f0, %f0;", x=10, y=5, &temp); ** ** Note that the memory location used for the transfer ** from integer to floating register is made available ** to the asm code by passing as an argument the address ** of a variable allocated in the C code for that purpose. ** ** o For intructions that do not take any argument and do ** not have a return type, leave out the arguments. For ** example: ** ** asm("mb"); */ /* ** Function prototypes ** ** Note that there is no support for 64 bit character pointers */ __int64 asm (const char *,...); double dasm (const char *, ...); float fasm (const char*, ...); #pragma intrinsic(asm) #pragma intrinsic(dasm) #pragma intrinsic(fasm) /* ** Restore the users pointer context */ #if defined(__INITIAL_POINTER_SIZE) # pragma __required_pointer_size __restore #endif #ifdef __cplusplus } #endif #endif /* !defined(__VAX) && !_DECCXX */ #pragma __standard #endif /* __C_ASM_LOADED */