[comp.lang.c] Arguments in included assembler instructions

cik@l.cc.purdue.edu.UUCP (01/01/87)

Many times I have found it necessary to include asm instructions
in a C program.  It should be possible to do this in such a way
that the compiler will substitute the locations of variables for
the variable names in the asm instructions.  I know of ways to do
the job; one person to whom I showed this pointed out that if the
compiler were changed this could break.  This would not be the case
if the suggested enhancement were made.
-- 
(Usual disclaimer line.)
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
(decvax,ihnp4,uiucdcs)!pur-ee!stat-l!cik
(decwrl,hplabs,ucbvax)!purdue!stat-l!cik
hrubin@l.cc.purdue.edu

greg@utcsri.UUCP (Gregory Smith) (01/06/87)

In article <488@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>
>Many times I have found it necessary to include asm instructions
>in a C program.  It should be possible to do this in such a way
>that the compiler will substitute the locations of variables for
>the variable names in the asm instructions.  I know of ways to do
>the job; one person to whom I showed this pointed out that if the
>compiler were changed this could break.  This would not be the case
>if the suggested enhancement were made.

Yes. Someone suggested a 'printf-like' capability for asm() a while back.
EG on a 68000 machine, to get the user stack pointer in supervisor code:

	... char *user_sp;
	...
	asm(" move usp,%a", user_sp );

'%a' would change either to (1) the appropriate extern name (eg "_user_sp"),
if user_sp were external, (2) the appropriate local symbol if user_sp were
local static, or (3) the appropriate stack-indexed or frame-indexed address
if user_sp were auto.

The above code would then be immune to a large class of compiler
changes. In particular, changes to (1) name translation conventions, (2) local
symbol allocation method, (3) stack allocation and addressing conventions.

Other bells and whistles could be added, but this would be the most
useful feature. Of course, different features would be useful with
different machines.

guy%gorodish@Sun.COM (Guy Harris) (01/06/87)

> >Many times I have found it necessary to include asm instructions
> >in a C program.  It should be possible to do this in such a way
> >that the compiler will substitute the locations of variables for
> >the variable names in the asm instructions.  I know of ways to do
> >the job; one person to whom I showed this pointed out that if the
> >compiler were changed this could break.  This would not be the case
> >if the suggested enhancement were made.
> 
> Yes. Someone suggested a 'printf-like' capability for asm() a while back.
> EG on a 68000 machine, to get the user stack pointer in supervisor code:

The WE32K compiler that AT&T-IS puts out has what looks like a rather nice
new kind of "asm" facility.  To quote from the release notes from S5R2.1 on
the 3B2:

	The enhanced "asm" facility allows the user to define constructs
	that look like static C functions.  Each "asm" macro has one
	definition and zero or more uses per source file.  The definition
	must appear in the same file with the uses (or be #included),
	and the same "asm" macro can be defined multiply (and differently)
	in several files.

	   The "asm" macro definition declares a return type for the macro
	code, specifies patterns for the formal parameters, and provides
	bodies of code to expand when the patterns match.  When it 
	encounters an "asm" macro call, the compiler replaces uses of
	the formal parameters by its idea of the assembly language
	locations of the actual arguments as it expands the code body.

	   The uses of an "asm" macro look like normal C function calls.
	They can be used in expressions and they can return values.  The
	arguments to an "asm" macro can be arbitrary expressions, except
	that they can not contain uses of the same or other "asm" macros.

	   When the argument to an "asm" macro is a function name or
	structure, the compiler generates code to compute a pointer to the
	structure or function, and the resulting pointer is used as the
	actual argument of the macro.

The example they give:

	asm void SPL(newpri)
	{
	%	reg newpri;
		spl newpri
	%	con newpri;
		movw newpri,%r0
		spl %r0
	}

This says that "SPL" is a function returning no value and taking one
argument.  If the argument is in a register, it just generates an "spl"
instruction using that register.  If it's a constant, it generates a "movw"
to move it into r0 and then generates an "spl" using r0.

The set of storage modes it recognizes are:

	"treg" - a compiler-selected temporary register.

	"ureg" - a register variable.

	"reg" - a "treg" or "ureg".

	"con" - a compile-time constant.

	"mem" - any allowed machine addressing mode, including "reg"
		and "con".

	"lab" - a new label.  This is not used with a formal parameter;
		it causes a new label to be generated.

	"error" - generates an error.  This is used if code cannot be
		generated for certain operand types.

If a value is returned, the code generated by the macro must "do the right
thing", e.g. return the value in the register used for function return
values.

So if you say

	SPL(3);

it will generate

	movw	&3,%r0
	spl	%r0

The example given for getting the user stack pointer from supervisor mode on
a 68K would look something like:

	asm char *
	get_user_sp()
	{
		movec	usp,a0
	}

(assuming an implementation where pointer types are returned in A0).

If you wanted something that copied the user SP into its argument (this is a
function that modifies its argument - "asm" functions can do this), it would
read like

	asm void
	get_user_sp(user_sp)
	{
	%	reg user_sp;
		movec	usp,user_sp
	%	mem user_sp;
		movec	usp,a0
		movea	a0,user_sp
	}

(I am assuming that this would just generate a "movec" if "user_sp" was a
register and the "movec"/"movea" pair otherwise).