/* Copyright (c) 1980 Regents of the University of California */
static char sccsid
[] = "@(#)asscan.c 4.6 9/8/80";
* This version of the assembler does not use fread and fwrite
* for the token buffering. The token buffers are integrals of BUFSIZ
* at all times, so we use direct read and write. fread and fwrite
* as supplied from BTL in stdio are HORRENDOUSLY inefficient,
* as they use putchar for each character, nested two deep in loops.
#define writeTEST(pointer, size, nelements, ioptr) \
write(ioptr->_file, pointer, nelements * size) != nelements * size
#define readTEST(pointer, size, nelements, ioptr) \
read(ioptr->_file, pointer, nelements * size) != nelements * size
* Variables to manage the token buffering.
* We scan (lexically analyze) a large number of tokens, and
* then parse all of the tokens in the scan buffer.
* This reduces procedure call overhead when the parser
* demands a token, allows for an efficient reread during
* the second pass, and confuses the line number reporting
* for errors encountered in the scanner and in the parser.
struct tokbufdesc
*bufstart
; /*where the buffer list begins*/
struct tokbufdesc
*buftail
; /*last one on the list*/
struct tokbufdesc
*emptybuf
; /*the one being filled*/
* If we are using VM, during the second pass we reclaim the used
* token buffers for saving the relocation information
struct tokbufdesc
*tok_free
; /* free pool */
struct tokbufdesc
*tok_temp
; /* temporary for doing list manipulation */
* Other token buffer managers
int bufno
; /*which buffer number: 0,1 for tmp file*/
struct tokbufdesc tokbuf
[2]; /*our initial increment of buffers*/
ptrall tokptr
; /*where the current token comes from*/
ptrall tokub
; /*the last token in the current token buffer*/
* Variables to manage the string buffering
int strno
; /*the current string being filled*/
struct strdesc strbuf
[3]; /*the string buffers; the first for nulls*/
struct strdesc
*strptr
; /*current string buffer being filled*/
bufstart
->tok_next
= buftail
;
tokbuf
[0].tok_count
= -1;
tokbuf
[1].tok_count
= -1;
emptybuf
= &tokbuf
[bufno
];
emptybuf
->toks
[emptybuf
->tok_count
++] = PARSEEOF
;
* Clean up the buffers that haven't been
if (tokbuf
[bufno
^ 1].tok_count
>= 0){
if (writeTEST((char *)&tokbuf
[bufno
^ 1], sizeof *emptybuf
, 1, tmpfil
)){
yyerror("Unexpected end of file writing the interpass tmp file");
* Ensure that we will read an End of file,
* if there are more than one file names
tokbuf
[bufno
].toks
[tokbuf
[bufno
].tok_count
++] = PARSEEOF
;
if (writeTEST((char *)&tokbuf
[bufno
], sizeof *emptybuf
, 1, tmpfil
))
} /*end of being pass 1*/
#define bstrlg(from, length) \
*(lgtype *)from = length; \
(char *)from += sizeof(lgtype) + length
#define bstrfromto(from,to) \
*(lgtype *)from = (char *)to - (char *)from - sizeof(lgtype); \
(char *)from += sizeof(lgtype) + (char *)to - (char *)from
(char *)from += sizeof(lgtype) + *(lgtype *)from
#define bskiplg(from, length) \
*(lgtype *)from = length; \
(char *)from += sizeof(lgtype) + length
#define bskipfromto(from, to) \
*(lgtype *)from = (toktype *)to - (toktype *)from - sizeof(lgtype); \
(char *)from += sizeof (lgtype) + (toktype *)to - (toktype *)from
#define eatskiplg(from) \
(toktype *)from += sizeof(lgtype) + *(lgtype *)from
extern int yylval
; /*global communication with parser*/
static int Lastjxxx
; /*this ONLY shuts up cc; see below*/
register struct exp
*locxp
;
bufptr
= tokptr
; /*copy in the global value*/
if (xp
>= &explist
[NEXP
])
yyerror("Too many expressions; try simplyfing");
glong(locxp
->e_xvalue
, bufptr
);
if (xp
>= &explist
[NEXP
])
yyerror("Too many expressions; try simplyfing");
gdouble( ( (union Double
*)locxp
)->dvalue
, bufptr
);
if (xp
>= &explist
[NEXP
])
yyerror("Too many expressions; try simplyfing");
glong(locxp
->e_xvalue
, bufptr
);
glong(locxp
->e_yvalue
, bufptr
);
lastnam
= (struct symtab
*)yylval
;
/* We can't cast Lastjxxx into (int *) here.. */
lastjxxx
= (struct symtab
*)Lastjxxx
;
strptr
= &strbuf
[strno
^= 1];
strptr
->str_lg
= *((lgtype
*)bufptr
);
(char *)bufptr
+ sizeof(lgtype
),
printf("P: %d T#: %4d, %s ",
passno
, bufptr
- firsttoken
, tok_to_name(val
));
case INT
: printf("val %d",
((struct exp
*)yylval
)->e_xvalue
);
case BFINT
: printf("val %d",
((struct exp
*)yylval
)->e_xvalue
);
case QUAD
: printf("val[msd] = 0x%x, val[lsd] = 0x%x.",
((struct exp
*)yylval
)->e_xvalue
,
((struct exp
*)yylval
)->e_yvalue
);
case FLTNUM
: printf("value %20.17f",
((union Double
*)yylval
)->dvalue
);
case NAME
: printf("\"%.8s\"",
((struct symtab
*)yylval
)->s_name
);
case INSTn
: printf("%.8s",
itab
[0xFF &yylval
]->s_name
);
case STRING
: printf("length %d ",
((struct strdesc
*)yylval
)->str_lg
);
((struct strdesc
*)yylval
)->str
);
} /*end of the debug switch*/
} else { /* start a new buffer */
tok_temp
= emptybuf
->tok_next
;
emptybuf
->tok_next
= tok_free
;
emptybuf
= emptybuf
->tok_next
;
struct tokbufdesc
*newdallop
;
emptybuf
= newdallop
= (struct tokbufdesc
*)
Calloc(TOKDALLOP
, sizeof (struct tokbufdesc
));
for (i
=0; i
< TOKDALLOP
; i
++){
buftail
->tok_next
= newdallop
;
} /*end of need to get more buffers*/
(toktype
*)bufptr
= &(emptybuf
->toks
[0]);
} else { /*don't use VM*/
emptybuf
= &tokbuf
[bufno
];
((toktype
*)bufptr
) = &(emptybuf
->toks
[0]);
* First check if there are things to write
if (emptybuf
->tok_count
>= 0){
if (writeTEST((char *)emptybuf
, sizeof *emptybuf
, 1, tmpfil
)){
yyerror("Unexpected end of file writing the interpass tmp file");
if (readTEST((char *)emptybuf
, sizeof *emptybuf
, 1, tmpfil
)){
yyerror("Unexpected end of file while reading the interpass tmp file");
} /*end of using a real live file*/
(char *)tokub
= (char *)bufptr
+ emptybuf
->tok_count
;
printf("created buffernumber %d with %d tokens\n",
bufno
, emptybuf
->tok_count
);
} /*end of reading/creating a new buffer*/
tokptr
= bufptr
; /*copy back the global value*/
register ptrall from
, to
;
register struct tokbufdesc
*middlebuf
;
* check if from and to are in the same buffer
* from and to DIFFER BY AT MOST 1 buffer and to is
* always ahead of from, with to being in the buffer emptybuf
* The hard part here is accounting for the case where the
* skip is to cross a buffer boundary; we must construct
* Figure out where the buffer boundary between from and to is
* It's easy in VM, as buffers increase to high memory, but
* w/o VM, we alternate between two buffers, and want
* to look at the exact middle of the contiguous buffer region.
middlebuf
= useVM
? emptybuf
: &tokbuf
[1];
if ( ( (toktype
*)from
> (toktype
*)middlebuf
)
^ ( (toktype
*)to
> (toktype
*)middlebuf
)
){ /*split across a buffer boundary*/
* Set the skip so it lands someplace beyond
* the end of this buffer.
* When we pull this skip out in the second pass,
* we will temporarily move the current pointer
* out beyond the end of the buffer, but immediately
* do a compare and fail the compare, and then reset
* all the pointers correctly to point into the next buffer.
bskiplg(from
, TOKBUFLG
+ 1);
* Now, force from to be in the same buffer as to
(toktype
*)from
= (toktype
*)&(emptybuf
->toks
[0]);
* Now, to and from are in the same buffer
yyerror("Internal error: bad skip construction");
if ( (diff
= (toktype
*)to
- (toktype
*)from
) >=
(sizeof(toktype
) + sizeof(lgtype
) + 1)) {
for ( ; diff
> 0; --diff
)
register char *to
, *from
;
int scanlineno
; /*the scanner's linenumber*/
* Maps characters to their use in assembly language
readonly
short type
[] = {
NEEDSBUF
, /*fill up the input buffer*/
SCANEOF
, /*hit the hard end of file*/
SP
, BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
, /*\0..^G*/
BADCHAR
,SP
, NL
, BADCHAR
,BADCHAR
,SP
, BADCHAR
,BADCHAR
, /*BS..SI*/
BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
, /*DLE..ETB*/
BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
,BADCHAR
, /*CAN..US*/
SP
, ORNOT
, DQ
, SH
, LITOP
, REGOP
, AND
, SQ
, /*sp .. '*/
LP
, RP
, MUL
, PLUS
, CM
, MINUS
, ALPH
, DIV
, /*( .. /*/
DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /*0 .. 7*/
DIG
, DIG
, COLON
, SEMI
, LSH
, BADCHAR
,RSH
, BADCHAR
, /*8 .. ?*/
BADCHAR
,ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*@ .. G*/
ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*H .. BADCHAR*/
ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*P .. V*/
ALPH
, ALPH
, ALPH
, LB
, BADCHAR
,RB
, XOR
, ALPH
,/*W .. _*/
SIZEQUOTE
,ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*` .. g*/
ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*h .. o*/
ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
, ALPH
,/*p .. v*/
ALPH
, ALPH
, ALPH
, BADCHAR
,IOR
, BADCHAR
,TILDE
, BADCHAR
,/*x .. del*/
* The table of possible uses for each character to test set inclusion.
* Different than the above table, which knows about tokens yylex
#define HEXFLAG 01 /* 'x' or 'X' */
#define HEXLDIGIT 02 /* 'a' .. 'f' */
#define HEXUDIGIT 04 /* 'A' .. 'F' */
#define ALPHA 010 /* 'A' .. 'Z', 'a' .. 'z', '_'*/
#define DIGIT 020 /* '0' .. '9' */
#define FLOATEXP 040 /* 'd' 'e' 'D' 'E' */
#define SIGN 0100 /* '+' .. '-'*/
#define REGDIGIT 0200 /* '0' .. '5' */
#define SZSPECBEGIN 0400 /* 'b', 'B', 'l', 'L', 'w', 'W' */
#define POINT 01000 /* '.' */
#define SPACE 02000 /* '\t' or ' ' */
#define BSESCAPE 04000 /* bnrtf */
#define STRESCAPE 010000 /* '"', '\\', '\n' */
#define OCTDIGIT 020000 /* '0' .. '7' */
#define FLOATFLAG 040000 /* 'd', 'D', 'f', 'F' */
readonly
short charsets
[] = {
0, 0, 0, 0, 0, 0, 0, 0, /*\0..^G*/
0, SPACE
, STRESCAPE
,0, 0, 0, 0, 0, /*BS..SI*/
0, 0, 0, 0, 0, 0, 0, 0, /*DLE..ETB*/
0, 0, 0, 0, 0, 0, 0, 0, /*CAN..US*/
/* dollar is an alpha character */
SPACE
, 0, STRESCAPE
,0, ALPHA
, 0, 0, 0, /*sp.. '*/
0, 0, 0, SIGN
, 0, SIGN
, POINT
+ALPHA
,0, /*( .. /*/
DIGIT+REGDIGIT+OCTDIGIT, DIGIT+REGDIGIT+OCTDIGIT, /*0..1*/
DIGIT
+REGDIGIT
+OCTDIGIT
, DIGIT
+REGDIGIT
+OCTDIGIT
, /*2..3*/
DIGIT
+REGDIGIT
+OCTDIGIT
, DIGIT
+REGDIGIT
+OCTDIGIT
, /*4..5*/
DIGIT
+OCTDIGIT
, DIGIT
+OCTDIGIT
, /*6..7*/
DIGIT
, DIGIT
, 0, 0, 0, 0, 0, 0, /*8..?*/
ALPHA
+HEXUDIGIT
,ALPHA
+HEXUDIGIT
+SZSPECBEGIN
, /*A..B*/
ALPHA
+HEXUDIGIT
,ALPHA
+HEXUDIGIT
+FLOATEXP
+FLOATFLAG
, /*C..D*/
ALPHA
+HEXUDIGIT
+FLOATEXP
,ALPHA
+HEXUDIGIT
+FLOATFLAG
, /*E..F*/
ALPHA
, ALPHA
, ALPHA
, ALPHA
, /*H..K*/
ALPHA
+SZSPECBEGIN
, ALPHA
, ALPHA
, ALPHA
, /*L..O*/
ALPHA
, ALPHA
, ALPHA
, ALPHA
, /*P..S*/
ALPHA
, ALPHA
, ALPHA
, ALPHA
+SZSPECBEGIN
, /*T..W*/
ALPHA
+HEXFLAG
, ALPHA
, ALPHA
, 0,STRESCAPE
,0, 0, ALPHA
,/*X.._*/
ALPHA
+HEXLDIGIT
,ALPHA
+HEXLDIGIT
+BSESCAPE
+SZSPECBEGIN
, /*a..b*/
ALPHA
+HEXLDIGIT
,ALPHA
+HEXLDIGIT
+FLOATEXP
+FLOATFLAG
, /*c..d*/
ALPHA
+HEXLDIGIT
+FLOATEXP
,ALPHA
+HEXLDIGIT
+BSESCAPE
+FLOATFLAG
, /*e..f*/
ALPHA
, ALPHA
, ALPHA
, ALPHA
, /*h..k*/
ALPHA
+SZSPECBEGIN
, ALPHA
, ALPHA
+BSESCAPE
, ALPHA
, /*l..o*/
ALPHA
, ALPHA
, ALPHA
+BSESCAPE
, ALPHA
, /*p..s*/
ALPHA
+BSESCAPE
, ALPHA
, ALPHA
, ALPHA
+SZSPECBEGIN
,/*t..w*/
ALPHA
+HEXFLAG
, ALPHA
, ALPHA
, 0,0, 0, 0, 0, /*x..del*/
#define INCHARSET(val, kind) (charsets[val] & (kind) )
static toktype oval
= NL
;
#define INBUFLG NINBUFFERS*BUFSIZ + 2
* We have two input buffers; the first one is reserved
* for catching the tail of a line split across a buffer
* boundary; the other one are used for snarfing a buffer
static char inbuffer
[INBUFLG
];
static char *InBufPtr
= 0;
#define getchar() *inbufptr++
#define ungetc(char) *--inbufptr = char
* fill the inbuffer from the standard input.
* Assert: there are always n COMPLETE! lines in the buffer area.
* Assert: there is always a \n terminating the last line
* Assert: after the \n, there is an EOFCHAR (hard end of file)
* or a NEEDCHAR (end of buffer)
* Assert: fgets always null pads the string it reads.
* Assert: no ungetc's are done at the end of a line or at the
* We read a complete buffer of characters in one single read.
* We then back scan within this buffer to find the end of the
* last complete line, and force the assertions, and save a pointer
* to the incomplete line.
* The next call to fillinbuffer will move the unread characters
* to the end of the first buffer, and then read another two buffers,
static char p_swapped
= '\0';
static char *p_start
= &inbuffer
[NINBUFFERS
* BUFSIZ
];
static char *p_stop
= &inbuffer
[NINBUFFERS
* BUFSIZ
];
inbufptr
= &inbuffer
[1*BUFSIZ
] - (p_stop
- p_start
);
for (to
= inbufptr
, from
= p_start
; from
< p_stop
;)
* Now, go read two full buffers (hopefully)
nread
= read(stdin
->_file
, &inbuffer
[1*BUFSIZ
], (NINBUFFERS
- 1)*BUFSIZ
);
p_stop
= from
= &inbuffer
[1*BUFSIZ
+ nread
];
while (*--from
!= '\n') /* back over the partial line */
from
++; /* first char of partial line */
*p_start
= NEEDCHAR
; /* force assertion */
struct tokbufdesc
*bufferbox
;
register int yylval
;/*lexical value*/
register toktype val
; /*the value returned; the character read*/
register int base
; /*the base of the number also counter*/
register struct symtab
*op
;
register unsigned char tag
;
register ptrall bufptr
; /*where to stuff tokens*/
ptrall lgbackpatch
; /*where to stuff a string length*/
ptrall bufub
; /*where not to stuff tokens*/
register int maxstrlg
; /*how long a string can be*/
long intval
; /*value of int*/
char fltchr
[64]; /*buffer for floating values*/
union Double fltval
; /*floating value returned*/
struct Quad quadval
; /*quad returned from immediate constant */
int linescrossed
; /*when doing strings and comments*/
(toktype
*)bufptr
= (toktype
*) & (bufferbox
->toks
[0]);
(toktype
*)bufub
= &(bufferbox
->toks
[AVAILTOKS
]);
inbufptr
= fillinbuffer();
if (inbufptr
== 0){ /*end of file*/
ptoken(bufptr
, PARSEEOF
);
val
= strlen(newfname
) + 1;
movestr( (char *)&( ( (lgtype
*)bufptr
)[1]), newfname
, val
);
switch(yylval
= (type
+2)[val
= getchar()]) {
inbufptr
= fillinbuffer();
case DIV
: /*process C style comments*/
if ( (val
= getchar()) == '*') { /*comment prelude*/
val
= getchar(); /*skip over the * */
inbufptr
= fillinbuffer();
val
= getchar(); /*pull in the new char*/
} else { /*just an ordinary DIV*/
* Attempt to recognize a C preprocessor
* style comment '^#[ \t]*[0-9]*[ \t]*".*"
val
= getchar(); /*bump the #*/
while (INCHARSET(val
, SPACE
))
val
= getchar();/*bump white */
if (INCHARSET(val
, DIGIT
)){
while(INCHARSET(val
, DIGIT
)){
intval
= intval
*10 + val
- '0';
while (INCHARSET(val
, SPACE
))
pint(bufptr
, intval
- 1);
* The '"' has already been
* it is given to the parser
* Well, its just an ordinary decadent comment
while ((val
!= '\n') && (val
!= EOFCHAR
))
val
= yylval
= oval
= NL
;
oval
= SP
; /*invalidate ^# meta comments*/
case REGOP
: /* % , could be used as modulo, or register*/
if (INCHARSET(val
, DIGIT
)){
if (INCHARSET( (val
= getchar()), REGDIGIT
))
* God only knows what the original author
* wanted this undocumented feature to
while(INCHARSET( (val
= getchar()), SIGN
)) {
if (INCHARSET(val
, SZSPECBEGIN
)){
if( (val
= getchar()) == '`' || val
== '^'){
yylval
|= 0100; /*convert to lower*/
if (yylval
== 'b') yylval
= 1;
else if (yylval
== 'w') yylval
= 2;
else if (yylval
== 'l') yylval
= 4;
val
= yylval
; /*restore first character*/
} while (INCHARSET ( (val
= getchar()), ALPHA
| DIGIT
));
while (INCHARSET(val
, SPACE
))
tag
= (op
= *lookup(1))->s_tag
;
if (tag
&& tag
!= LABELID
){
yylval
= ( (struct instab
*)op
)->i_opcode
;
* Its a name... (Labels are subsets ofname)
* Well, it appears to be a local label
* reference, but check to see if
* the next character makes it a floating
if (!(INCHARSET(forb
,(DIGIT
|SIGN
|FLOATEXP
|POINT
)))){
if (INCHARSET(val
, HEXFLAG
)){
if (INCHARSET(val
, FLOATFLAG
)){
while ( (cp
< &fltchr
[63]) &&
(DIGIT
|SIGN
|FLOATEXP
|POINT
)
fltval
.dvalue
= atof(fltchr
);
if (forb
== 'f' || forb
== 'b') {
ungetc(forb
); /* put back non zero */
while ( (val
= getchar()) == '0')
while ( INCHARSET( (val
= getchar()), DIGIT
) ||
(base
==16 && (INCHARSET(val
, HEXLDIGIT
|HEXUDIGIT
) )
if (INCHARSET(val
, HEXLDIGIT
))
else if (INCHARSET(val
, HEXUDIGIT
))
get_quad(base
, fltchr
, cp
, &quadval
);
* We allow the C style operators
* << and >>, as well as < and >
if ( (base
= getchar()) != val
)
if ( (val
= getchar()) =='(')
if ((yylval
= getchar()) == '\n')
scanlineno
++; /*not entirely correct*/
maxstrlg
= (char *)bufub
- (char *)bufptr
;
if (maxstrlg
< MAXSTRLG
) {
*(toktype
*)bufptr
= VOID
;
lgbackpatch
= bufptr
; /*this is where the size goes*/
bufptr
+= sizeof(lgtype
);
* be stuffed with characters from
&& !(INCHARSET( (val
= getchar()), STRESCAPE
))
if (maxstrlg
<= 0){ /*enough characters to fill a string buffer*/
ungetc('"'); /*will read it next*/
else if (val
== '"'); /*done*/
yywarning("New line embedded in a string constant.");
if ( (inbufptr
= fillinbuffer()) == 0)
} else { /* simple case */
val
= getchar(); /*skip the '\\'*/
if ( INCHARSET(val
, BSESCAPE
)){
case 'b': val
= '\b'; goto stuff
;
case 'f': val
= '\f'; goto stuff
;
case 'n': val
= '\n'; goto stuff
;
case 'r': val
= '\r'; goto stuff
;
case 't': val
= '\t'; goto stuff
;
if ( !(INCHARSET(val
,OCTDIGIT
)) ) goto stuff
;
while ( (base
< 3) && (INCHARSET(val
, OCTDIGIT
))){
base
++;intval
<<= 3;intval
+= val
- '0';
* bufptr now points at the next free slot
bstrfromto(lgbackpatch
, bufptr
);
yyerror("Illegal character mapped: %d, char read:(octal) %o",
* here with one token, so stuff it
case BFINT
: plong(bufptr
, yylval
);
case INT
: plong(bufptr
, intval
);
case QUAD
: plong(bufptr
, quadval
.quad_low_long
);
plong(bufptr
, quadval
.quad_high_long
);
case FLTNUM
: pdouble(bufptr
, fltval
.dvalue
);
case NAME
: pptr(bufptr
, (int)(struct symtab
*)yylval
);
case REG
: pchar(bufptr
, yylval
);
pptr(bufptr
, (int)(struct symtab
*)symalloc());
pptr(bufptr
, (int)(struct symtab
*)symalloc());
} /*end of the while to stuff the buffer*/
bufferbox
->tok_count
= (toktype
*)bufptr
- &(bufferbox
->toks
[0]);
* We put the last token in the buffer to be a MINUS
* symbol. This last token will never be picked up
* in the normal way, but can be looked at during
* a peekahead look that the short circuit expression
* evaluator uses to see if an expression is complicated.
* Consider the following situation:
* the peekahead would want to look across the buffer,
* but will look in the buffer end zone, see the minus, and
InBufPtr
= inbufptr
; /*copy this back*/
get_quad(radix
, cp_start
, cp_end
, quadptr
)
register char *cp
= cp_start
; /* r11 */
register struct Quad
*qp
= quadptr
; /* r10 */
register long temp
; /* r9 */
for (; cp
< cp_end
; cp
++){
asm ("ashq $3, (r10), (r10)");
asm ("ashq $4, (r10), (r10)");
asm ("ashq $1, (r10), __quadtemp");
asm ("ashq $3, (r10), (r10)");
asm ("addl2 __quadtemp, (r10)");
asm ("adwc __quadtemp+4, 4(r10)");