Chapter Contents

Previous

Next
Inline Machine Code Interface

Introduction

The SAS/C inline machine code interface feature extends the capabilities of your C program by enabling you to write more efficient code and to incorporate instructions that cannot normally be generated with a high-level language. None of the facilities provided with the inline machine code interface are portable.

The inline machine code interface enables a C program to generate OS/390 and CMS supervisor calls (SVCs), DIAGNOSE instructions and CMS SVC 202s, and miscellaneous assembler language instructions. You can use C variables and expressions as operands for these instructions and store results from them in C variables or storage locations addressed by C pointers.


Overview

The inline machine code interface consists of the following:

This discussion of the inline machine code interface is intended primarily for experienced OS/390 and CMS systems programmers. It is assumed that you are already

familiar with the concepts and methodologies involved in using built-in functions, supervisor calls, and assembler language interfaces.

This chapter provides the following:


Built-in functions

The SAS/C Compiler provides the following set of built-in functions that enable you to use machine code in C programming applications:
_ldregs loads register values.
_stregs stores register values.
_cc tests or saves the hardware condition code.
_diag generates a DIAGNOSE instruction.
_cms202 generates a CMS SVC 202 instruction.
svc202 or e_svc202 generates a CMS SVC 202 instruction with arguments.
_ossvc generates an OS/390 SVC instruction.
_osarmsvc generates an OS/390 SVC instruction to be issued in AR mode
_code generates a machine instruction or inline data.
_label defines an inline-code branch target.
_bbwd branch backward to a previously defined label.
_bfwd branch forward to a label defined later.
_branch alternate form of _bbwd / _bfwd for use in library code macros.

Each of the built-in functions is discussed in Functions.


_ldregs, _stregs, and _cc

Two framing functions, _ldregs and _stregs , enable you to set register values before issuing an instruction or series of instructions and then retrieve values from the registers after the instruction sequence is completed. Between these framing functions, you can call other built-in functions or issue macros that resemble assembly instructions. You can use the _cc function to access the condition code set by a generated DIAGNOSE, SVC, or machine instruction.


_diag, _cms202, and _ossvc

Several built-in functions issue specific supervisor call instructions: _diag , _cms202 , and _ossvc . Access to the DIAGNOSE instruction through the _diag function opens the way for using the multitude of CMS diagnose codes. With the _diag function, your program can interact with the console, examine real storage, read the system symbol table, execute timing functions, and so on. The _ossvc and _osarmsvc built-in functions can be used to invoke an OS/390 or CMS supervisor call to get access to many supervisor services that would otherwise be available only through the Assembler language. The _ossvc built-in function always issues the SVC in primary address space mode, while the _osarmsvc issues the SVC in access register mode if the compiler option has been specified.


_code

The inline machine code interface also provides a very flexible method for generating machine instructions or inline data. The _code function enables you to generate machine instructions directly from C without the overhead of a subroutine call.

Furthermore, the library provides header files defining macros to assist you in using _code to generate machine instructions.


_label

The _label function defines a location in an inline code block and associates it with a non-zero unsigned short constant. You can transfer control directly to a label defined with _label by using the _bbwd , _bfwd , or _branch function, or indirectly by using a library macro which calls one of these functions. The same label value may be assigned more than once in a compilation. The _bbwd and _bfwd functions always branch to the nearest definition of the target label in the appropriate direction. This property allows _label to be used in macros that are expanded repeatedly in a single compilation.


_bbwd and _bfwd

The _bbwd and _bfwd functions allow you to generate selected 370 branch instructions to labels defined with _label . The macro specifies the particular branch operation and any non-target information required by the instruction, for example, count registers.

All use of these functions and macros must be localized within a single block of inline code, beginning with an _ldregs call, and containing no C statements other than calls to inline machine code functions. The results of attempting to branch from one code block to another are unpredictable.


_branch, _blabel, and _flabel

The _bbwd and _bfwd functions are not convenient for symbolic use. For this reason, the _branch function and the _blabel and _flabel macros are provided. These are more complicated than _bbwd and _bfwd , but lend themselves more readily to symbolic use. _branch is a variant of _code in which the final halfword of an instruction can be specified in one of two special forms larger than a halfword. One of these forms is generated by _blabel , and the other by _flabel . To illustrate, the BCT macro defined in the <genl370.h> header file (after expansion of various inner macros) has the form:

#define BCT(r1,x,s)  _branch(0x80000000 >> (r1), 
                             0x4600 | ((r1) << 4) | (x), s)

The following uses of the BCT macro then behave as follows:

BCT(R1, 0, 6+b(3))      /* generates a BCT   1,6(0,3)      */
BCT(R1, 0, _blabel(2))  /* same effect as _bbwd(0x4610, 2) */
BCT(R1, 0, _flabel(2))  /* same effect as _bfwd(0x4610, 2) */

The macros in <genl370.h> for instructions supported by _bfwd and _bbwd have all been defined to use _branch .


Code Macros

Although the _code function provides a very flexible method for generating instructions, many machine instructions can be more easily generated using code macros. The macros available for use are provided in the following series of header files:

These header files provide appropriate macros for all IBM 370 machine instructions except UPT, SIE, and PC. (These three instructions cannot be supported because of conflicts in register use between the instructions and the compiled C code.)

Two other header files, <code.h> and <regs.h> , define basic-level macros that are used by the macros in the header files listed above. You can use the macros in <code.h> to simplify the arguments to the _code function. All of these header files are described in detail in Macros and Header Files.


Bit Masks for Using Registers

Several of the built-in functions use a 32-bit mask argument to indicate which registers the generated machine instructions should use. Starting from the left of the mask, bits 0 through 15 indicate whether general purpose registers 0 through 15 are used. Bits 16, 18, 20, and 22 indicate the use of floating-point registers 0, 2, 4, and 6, respectively. The remaining bits are not currently used and should be specified as 0.

The <regs.h> header file, which is included (via #include ) in both <svc.h> and <code.h> , contains macros named R0 through R15 for general registers 0 through 15, and F0, F2, F4, and F6 for floating-point registers 0, 2, 4, and 6. These macros enable you to symbolically specify the register mask. For example, coding the mask argument in the following way sets the bit mask to 0xc0010000, which requests the use of registers 0, 1, and 15:

R0+R1+R15

Registers for Use with the _code_stregs, and _idregs Functions summarizes the use of registers by _code , _ldregs , and _stregs .

When you compile with the armode option, you can use the inline machine code functions to execute instructions that modify the access registers (for instance, CPYA). An access register is considered to have the same register number as the corresponding general register. For example, the bit mask R2 indicates that general register 2, access register 2, or both may be modified by the instruction. See Developing Applications for Use with UNIX System Services OS/390 for more information on register masks.


Usage Notes

Some arguments to the built-in functions must be compile-time constants because the compiler has to know which registers or values to work with as it compiles the program.

CAUTION:
The compiler must be able to determine where inline machine code sequences begin and end. During sequences of inline machine code, you control the contents of the designated registers. In normal C code, the compiler controls the contents of all registers. Because of this difference, it is essential that the compiler be able to distinguish where inline machine code sequences begin and end.  [cautionend]

The following rules enable the compiler to differentiate between inline machine code and normal C code:

After the sequence ends, the compiler may again use all the registers and may generate instructions that would change the condition codes. Be careful that subsequent sequences do not depend on register values or condition code settings established in a prior sequence, because these may no longer be retained.

CAUTION:
Do not use general-purpose registers 4 through 13 with the _ldregs function. The compiler assigns general-purpose registers 6 through 11 and floating-point registers 4 and 6 to register variables. If your use of registers in _ldregs conflicts with the compiler's assignment of registers to register variables, the generated code may be suboptimal. General-purpose registers 0 through 3 and 14 through 15 may be used freely, as well as floating-point registers 0 and 2.  [cautionend]

Note that if you need to use floating-point register 4 or 6 and you specify optimize , you must use the freg(0) option to inhibit assignment of floating-point register variables.

Registers for Use with the _code_stregs, and _idregs Functions
Type of Register Register Number Name of Macro Bit in Mask
general-purpose 0-15 R0-15 0-15
floating-point 0 F0 16

2 F2 18

4 F4 20

6 F6 22

Registers for Use with the _code_stregs, and _idregs Functions shows the general-purpose and floating-point registers when they are used with the _code,_stregs, and _ldregs functions. No other registers are used with these functions.

The _ldregs and _stregs functions cannot be used to load or store long long values because a long long value requires two registers. You can, however, use the _ldregs function to put the address of a long long value into a register, and then use ordinary machine instructions to load or store portions of the long long value.


Inline Machine Code Usage Notes

Inline machine code sequences execute in access register mode if the compiler option armode is specified, and in primary address space mode otherwise. You can change mode within an inline code sequence so long as the mode is restored before returning to normal C code.

Note:    You should be very cautious about using any access register other than access register 1 in a function not compiled with the armode option. Functions not compiled with the armode option never save or restore the access registers. As a result, a modification of an access register by a non-armode function can cause a calling armode function to behave incorrectly.  [cautionend]

The _stregs function is defined to return int. This allows the _stregs function to be used to store an integer or a pointer from a single register. Two alternate forms of _stregs are available to store other types of data. The function _stfregs returns double, and the function _stpregs returns _ _far void *. Except for the difference in return type, these functions behave the same as _stregs. Note that the _stfregs function stores its return value in the highest floating register in the mask.


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.