* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)pccaseop.c 8.1 (Berkeley) 6/6/93";
* and the rest of the file
* its constant label, line number (for errors), and location label.
* the PCC_FORCE operator puts its operand into a register.
* these to keep from thinking of it as r0 all over.
#if defined(vax) || defined(tahoe)
* given a tree for a case statement, generate code for it.
* this computes the expression into a register,
* puts down the code for each of the cases,
* and then decides how to do the case switching.
* [3] list of cased statements:
* [2] list of constant labels
* find out the type of the case expression
* even if the expression has errors (exprtype == NIL), continue.
exprtype
= rvalue( tcase
->expr
, NLNIL
, RREQ
);
if ( exprtype
!= NLNIL
) {
if ( isnta( exprtype
, "bcsi" ) ) {
error("Case selectors cannot be %ss" , nameof( exprtype
) );
if ( exprtype
-> class != RANGE
) {
rangetype
= exprtype
-> type
;
if ( rangetype
== NLNIL
) {
low
= rangetype
-> range
[0];
high
= rangetype
-> range
[1];
if ( exprtype
!= NLNIL
) {
* compute and save the case expression.
* also, put expression into a register
* save its c-type and jump to the code to do the switch.
exprctype
= p2type( exprtype
);
exprnlp
= tmpalloc( (long) (sizeof (long)), nl
+ T4INT
, NOREG
);
putRV((char *) 0 , cbn
, exprnlp
-> value
[ NL_OFFS
] ,
exprnlp
-> extra_flags
, PCCT_INT
);
(void) rvalue( tcase
->expr
, NLNIL
, RREQ
);
sconv((int) exprctype
, (int) PCCT_INT
);
putop( PCC_ASSIGN
, PCCT_INT
);
putop( PCC_FORCE
, PCCT_INT
);
putdot( filename
, line
);
putjbr( (long) swlabel
);
* count the number of cases
* and allocate table for cases, lines, and labels
* default case goes in ctab[0].
for ( cstatlp
= tcase
->stmnt_list
; cstatlp
!= TR_NIL
;
cstatlp
= cstatlp
->list_node
.next
) {
cstatp
= cstatlp
->list_node
.list
;
if ( cstatp
== TR_NIL
) {
for ( casep
= cstatp
->c_stmnt
.const_list
; casep
!= TR_NIL
;
casep
= casep
->list_node
.next
) {
ctab
= (struct ct
*) malloc( count
* sizeof( struct ct
) );
if ( ctab
== (struct ct
*) 0 ) {
error("Ran out of memory (case)");
* pick up default label and label for after case statement.
ctab
[0].clabel
= (int) getlab();
* generate code for each case
* filling in ctab for each.
* nr is for error if no case falls out bottom.
for ( cstatlp
= tcase
->stmnt_list
; cstatlp
!= TR_NIL
;
cstatlp
= cstatlp
->list_node
.next
) {
cstatp
= cstatlp
->list_node
.list
;
if ( cstatp
== TR_NIL
) {
line
= cstatp
->c_stmnt
.line_no
;
for ( casep
= cstatp
->c_stmnt
.const_list
; casep
!= TR_NIL
;
casep
= casep
->list_node
.next
) {
gconst( casep
->list_node
.list
);
if( exprtype
== NLNIL
|| con
.ctype
== NIL
) {
if ( incompat( con
.ctype
, exprtype
, TR_NIL
) ) {
cerror("Case label type clashed with case selector expression type");
if ( con
.crval
< low
|| con
.crval
> high
) {
error("Case label out of range");
ctab
[ count
].cconst
= con
.crval
;
ctab
[ count
].cline
= line
;
ctab
[ count
].clabel
= (int) label
;
statement( cstatp
->c_stmnt
.stmnt
);
nr
= (nr
&& noreach
)?TRUE
:FALSE
;
putjbr( (long) endlabel
);
* default action is to call error
(void) putlab( (char *) ctab
[0].clabel
);
putleaf( PCC_ICON
, 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN
| PCCT_INT
, PCCTM_PTR
) , "_CASERNG" );
putRV((char *) 0 , cbn
, exprnlp
-> value
[ NL_OFFS
] ,
exprnlp
-> extra_flags
, PCCT_INT
);
putop( PCC_CALL
, PCCT_INT
);
putdot( filename
, line
);
qsort( &ctab
[1] , count
, sizeof (struct ct
) , casecmp
);
for ( ctp
= &ctab
[1] ; ctp
< &ctab
[ count
] ; ctp
++ ) {
if ( ctp
[0].cconst
== ctp
[1].cconst
) {
error("Multiply defined label in case, lines %d and %d" ,
(char *) ctp
[0].cline
, (char *) ctp
[1].cline
);
* choose a switch algorithm and implement it:
* direct switch >= 1/3 full and >= 4 cases.
* binary switch not direct switch and > 8 cases.
* ifthenelse not direct or binary switch.
(void) putlab( swlabel
);
if ( ctab
[ count
].cconst
- ctab
[1].cconst
< 3 * count
&& count
>= 4 ) {
directsw( ctab
, count
);
} else if ( count
> 8 ) {
binarysw( ctab
, count
);
(void) putlab( endlabel
);
int fromlabel
= (int) getlab();
* We have a table of absolute addresses.
* subl2 to make r0 a 0-origin byte offset.
* cmpl check against upper limit.
* jlssu error if out of bounds.
* ashl to make r0 a 0-origin long offset,
* jmp and indirect through it.
putprintf(" subl2 $%d,%s", 0, (int) ctab
[1].cconst
, (int) FORCENAME
);
putprintf(" cmpl $%d,%s", 0,
(int) (ctab
[count
].cconst
- ctab
[1].cconst
),
putprintf(" jlssu %s%d", 0, (int) LABELPREFIX
, ctab
[0].clabel
);
putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME
, (int) FORCENAME
);
putprintf(" jmp *%s%d(%s)", 0,
(int) LABELPREFIX
, fromlabel
, (int) FORCENAME
);
* We can use the VAX casel instruction with a table
* of short relative offsets.
putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME
,
(int) (ctab
[ count
].cconst
- ctab
[1].cconst
));
* We have a table of absolute addresses.
* subl2 to make r0 a 0-origin byte offset.
* cmpl check against upper limit.
* jlssu error if out of bounds.
* shal to make r0 a 0-origin long offset,
* jmp and indirect through it.
putprintf(" subl2 $%d,%s", 0, (int) ctab
[1].cconst
, (int) FORCENAME
);
putprintf(" cmpl $%d,%s", 0,
(int) (ctab
[count
].cconst
- ctab
[1].cconst
),
putprintf(" jlssu %s%d", 0, (int) LABELPREFIX
, ctab
[0].clabel
);
putprintf(" shal $2,%s,%s", 0, (int) FORCENAME
, (int) FORCENAME
);
putprintf(" jmp *%s%d(%s)", 0,
(int) LABELPREFIX
, fromlabel
, (int) FORCENAME
);
* We can use the TAHOE casel instruction with a table
* of short relative offsets.
putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME
,
(int) (ctab
[ count
].cconst
- ctab
[1].cconst
));
putprintf(" .align 1", 0);
* subl to make d0 a 0-origin byte offset.
* cmpl check against upper limit.
* bhi error if out of bounds.
putprintf(" subl #%d,%s", 0, ctab
[1].cconst
, FORCENAME
);
putprintf(" cmpl #%d,%s", 0,
ctab
[count
].cconst
- ctab
[1].cconst
, FORCENAME
);
putprintf(" bhi %s%d", 0, LABELPREFIX
, ctab
[0].clabel
);
* We have a table of absolute addresses.
* asll to make d0 a 0-origin long offset.
* movl pick up a jump-table entry
* jmp and indirect through it.
putprintf(" asll #2,%s", 0, FORCENAME
, FORCENAME
);
putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME
, ADDRTEMP
);
putprintf(" jmp %s@", 0, ADDRTEMP
);
* We have a table of relative addresses.
* addw to make d0 a 0-origin word offset.
* movw pick up a jump-table entry
* jmp and indirect through it.
putprintf(" addw %s,%s", 0, FORCENAME
, FORCENAME
);
putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME
, FORCENAME
);
putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME
);
(void) putlab( (char *) fromlabel
);
if ( j
== ctab
[ i
].cconst
) {
putprintf( " .long " , 1 );
putprintf( PREFIXFORMAT
, 0 , (int) LABELPREFIX
, ctab
[ i
].clabel
);
putprintf( " .word " , 1 );
putprintf( PREFIXFORMAT
, 1 , (int) LABELPREFIX
, ctab
[ i
].clabel
);
putprintf( PREFIXFORMAT
, 0 , (int) LABELPREFIX
, fromlabel
);
putprintf( " .long " , 1 );
putprintf( PREFIXFORMAT
, 0 , (int) LABELPREFIX
, ctab
[ 0 ].clabel
);
putprintf( " .word " , 1 );
putprintf( PREFIXFORMAT
, 1 , (int) LABELPREFIX
, ctab
[ 0 ].clabel
);
putprintf( PREFIXFORMAT
, 0 , (int) LABELPREFIX
, fromlabel
);
# if defined(vax) || defined(tahoe)
* execution continues here if value not in range of case.
putjbr( (long) ctab
[0].clabel
);
* special case out default label and start recursion.
bsrecur( ctab
[0].clabel
, &ctab
[0] , count
);
* recursive log( count ) search.
bsrecur( deflabel
, ctab
, count
)
} else if ( count
== 1 ) {
# if defined(vax) || defined(tahoe)
putprintf(" cmpl %s,$%d", 0, (int) FORCENAME
, (int) ctab
[1].cconst
);
putprintf(" jeql %s%d", 0, (int) LABELPREFIX
, ctab
[1].clabel
);
putprintf(" cmpl #%d,%s", 0, ctab
[1].cconst
, (int) FORCENAME
);
putprintf(" jeq L%d", 0, (int) LABELPREFIX
, ctab
[1].clabel
);
int half
= ( count
+ 1 ) / 2;
int gtrlabel
= (int) getlab();
# if defined(vax) || defined(tahoe)
putprintf(" cmpl %s,$%d", 0, (int) FORCENAME
, (int) ctab
[half
].cconst
);
putprintf(" jgtr %s%d", 0, (int) LABELPREFIX
, gtrlabel
);
putprintf(" jeql %s%d", 0, (int) LABELPREFIX
, ctab
[half
].clabel
);
putprintf(" cmpl #%d,%s", 0, (int) ctab
[half
].cconst
, (int) FORCENAME
);
putprintf(" jgt %s%d", 0, (int) LABELPREFIX
, gtrlabel
);
putprintf(" jeq %s%d", 0, (int) LABELPREFIX
, ctab
[half
].clabel
);
bsrecur( deflabel
, &ctab
[0] , half
- 1 );
(void) putlab((char *) gtrlabel
);
bsrecur( deflabel
, &ctab
[ half
] , count
- half
);
for ( i
= 1 ; i
<= count
; i
++ ) {
# if defined(vax) || defined(tahoe)
putprintf(" cmpl %s,$%d", 0, (int) FORCENAME
, (int) ctab
[i
].cconst
);
putprintf(" jeql %s%d", 0, (int) LABELPREFIX
, ctab
[i
].clabel
);
putprintf(" cmpl #%d,%s", 0, (int) ctab
[i
].cconst
, (int) FORCENAME
);
putprintf(" jeq %s%d", 0, (int) LABELPREFIX
, ctab
[i
].clabel
);
putjbr((long) ctab
[0].clabel
);
if ( this -> cconst
< that
-> cconst
) {
} else if ( this -> cconst
> that
-> cconst
) {