[comp.lang.c] Long Branches

ram@nucsrl.UUCP (01/17/87)

   I have a problem in using the C compiler and VAX assembler in our local
4.3BSD(VAX) site.  I have a program which has a huge(>900lines) case statement.

       /*   Whoever said that programmers(pro) don't use case/switch */

The assembler chokes on (>32K long) long branches.  Apparently
there is a flag "-J" for such purposes (in the assembler)
which does not seem to work.

The man page for "as" lists under Bugs
---------------
BUGS
     -J should be eliminated; the assembler should automatically
     choose among byte, word and long branches.
_______________

That does not seem to work either.

The ouput of the C compiler was 
___________________________
Assembler:
"/tmp/ctm088343", line 2565: brw: Branch too far(50148b): try -J flag
"/tmp/ctm088343", line 2823: brw: Branch too far(48806b): try -J flag
"/tmp/ctm088343", line 2922: brw: Branch too far(48313b): try -J flag
"/tmp/ctm088343", line 12658: Case will branch too far
"/tmp/ctm088343", line 12659: Case will branch too far
"/tmp/ctm088343", line 12664: Case will branch too far
__________________________

and the ouput of a seperate assembly had the same error message(predictably). 

Assembler:
"prolog.s", line 13337: Case will branch too far
"prolog.s", line 13338: Case will branch too far
"prolog.s", line 13339: Case will branch too far
"prolog.s", line 13340: Case will branch too far


         This piece of code did compile in a Gould machine but not on the 
Vax (Code is portable).  Could somebody explain and help me solve this 
problem.



                                             Renu Raman
                                           ...ihnp4!nucsrl!ram
                                          Northwestern Univ. Comp. Sci. Lab.
                                          Evanston  IL  60201

ark@alice.UUCP (01/19/87)

In article <3950006@nucsrl.UUCP>, ram@nucsrl.UUCP writes:
> 
>    I have a problem in using the C compiler and VAX assembler in our local
> 4.3BSD(VAX) site.  I have a program which has a huge(>900lines) case statement.
> 
>        /*   Whoever said that programmers(pro) don't use case/switch */
> 
> The assembler chokes on (>32K long) long branches.  Apparently
> there is a flag "-J" for such purposes (in the assembler)
> which does not seem to work.

The trouble is that a case statement does not generate jump instructions
on the VAX.  Instead it generates a CASE instruction.  This instruction
also comes in three flavors: byte, word, and longword offsets.  It would
not be enough for the assembler to translate the CASEW the compiler
probably generates into a CASEL: the jump table must be translated from
words to longwords too.

Portable solutions?  I suppose the best bet is to make the switch statement
smaller.  One way to do this might be to replace some of the bigger cases
by jumps to code outside the switch statement itself.  Ick.

chris@mimsy.UUCP (01/19/87)

In article <3950006@nucsrl.UUCP> ram@nucsrl.UUCP (Raman Renu) writes:
>... using the C compiler and VAX assembler in our local 4.3BSD(VAX) site.
>I have a program which has a huge(>900lines) case statement.

>The assembler chokes on (>32K long) long branches.

This may seem a nit, but no, the assembler chokes on >32K *word*
branches.  This is an important distinction.  The pseudo-ops `jbr'
expand into one of `brb' or `brw', but not `jmp'.  The Vax does
not have a long branch instruction, just a long jump instruction
(the difference is that one takes an offset, the other an address).

>Apparently there is a flag "-J" for such purposes (in the assembler)
>which does not seem to work.

Indeed, it does work.  Look more closely at the error messages!

>The ouput of the C compiler was 

(To be technical, these errors are from the assembler.)

>Assembler:
>"/tmp/ctm088343", line 2565: brw: Branch too far(50148b): try -J flag
>"/tmp/ctm088343", line 2823: brw: Branch too far(48806b): try -J flag
>"/tmp/ctm088343", line 2922: brw: Branch too far(48313b): try -J flag
>"/tmp/ctm088343", line 12658: Case will branch too far
>"/tmp/ctm088343", line 12659: Case will branch too far
>"/tmp/ctm088343", line 12664: Case will branch too far

Three are `branch too far, try -J'.  Three are something else.

>and the ouput of a seperate assembly [with -J] had the same error
>message(predictably). 

No, not the same!

>Assembler:
>"prolog.s", line 13337: Case will branch too far
>"prolog.s", line 13338: Case will branch too far
>"prolog.s", line 13339: Case will branch too far
>"prolog.s", line 13340: Case will branch too far

All three `branch too far, try -J's are gone.  There is one new `case
will branch too far' message (because the code got bigger).

The problem is that the Vax `case' instruction has only a word offset
for its branches.  If you look at the result of compiling a switch
statement, you can see this yourself:

	f()
	{
		extern int sw;

		switch (sw) {
	#define CASE(n) case n: f/**/n(); break /* kludge; no ## yet */
		CASE(0); CASE(1); CASE(2); CASE(3);
		CASE(4); CASE(5); CASE(6); CASE(7);
		}
	}

The switch compiles as:

		casel	r0,$0,$7	# note that this is a `long' case
	L35:
		.word	L19-L35		# For case 0, branch to L19,
		.word	L21-L35		# and so on.
		.word	L23-L35		# Note that these are only word
		.word	L25-L35		# offsets; no long offsets are
		.word	L27-L35		# available.
		.word	L29-L35
		.word	L31-L35
		.word	L33-L35

There is nothing the assembler can do at this point.  You have
several alternatives: alter the compiler to produce a series of
if/else tests (preferably via a -J flag); edit the assembly to be
a series of if/else tests; or restructure your C code, splitting
up the switch statement or making the cases shorter.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

herndon@umn-cs.UUCP (01/19/87)

I've had this problem a few times.  Try invoking the optimizer
on your file.  The optimizer gets the assembly code before the
assembler does, recognizes that the branch is inappropriate
(or something, anyway) and generates an appropriate branch.
  The only problem is that the optimizer adds significant
time to the compilation process.

				Robert Herndon
				...!ihnp4!umn-cs!herndon
				herndon@umn-cs.ARPA

ram@nucsrl.UUCP (Raman Renu) (01/19/87)

   I have a problem in using the C compiler and VAX assembler in our local
4.3BSD(VAX) site.  I have a program which has a huge(>900lines) switch
statement.

       /*   Whoever said that programmers(pro) don't use case/switch */

The assembler chokes on (>32K long) long branches.  Apparently
there is a flag "-J" for such purposes (in the assembler)
which does not seem to work.

The man page for "as" lists under Bugs
---------------
BUGS
     -J should be eliminated; the assembler should automatically
     choose among byte, word and long branches.
_______________

That does not seem to work either.

The ouput of the C compiler was 
___________________________
Assembler:
"/tmp/ctm088343", line 2565: brw: Branch too far(50148b): try -J flag
"/tmp/ctm088343", line 2823: brw: Branch too far(48806b): try -J flag
"/tmp/ctm088343", line 2922: brw: Branch too far(48313b): try -J flag
"/tmp/ctm088343", line 12658: Case will branch too far
"/tmp/ctm088343", line 12659: Case will branch too far
"/tmp/ctm088343", line 12664: Case will branch too far
__________________________

and the ouput of a seperate assembly had the same error message(predictably). 

Assembler:
"prolog.s", line 13337: Case will branch too far
"prolog.s", line 13338: Case will branch too far
"prolog.s", line 13339: Case will branch too far
"prolog.s", line 13340: Case will branch too far


         This piece of code did compile in a Gould machine but not on the 
Vax (Code is portable).  Could somebody explain and help me solve this 
problem.



                                             Renu Raman
                                           ...ihnp4!nucsrl!ram
                                          Northwestern Univ. Comp. Sci. Lab.
                                          Evanston  IL  60201

firth@sei.cmu.edu (Robert Firth) (01/20/87)

In article <6552@alice.uUCp> ark@alice.UUCP writes:
>In article <3950006@nucsrl.UUCP>, ram@nucsrl.UUCP writes:
>> 
>>    I have a problem in using the C compiler and VAX assembler in our local
>> 4.3BSD(VAX) site.  I have a program which has a huge(>900lines) case statement.
>> 
>>        /*   Whoever said that programmers(pro) don't use case/switch */
>> 
>> The assembler chokes on (>32K long) long branches.  Apparently
>> there is a flag "-J" for such purposes (in the assembler)
>> which does not seem to work.
>
>The trouble is that a case statement does not generate jump instructions
>on the VAX.  Instead it generates a CASE instruction.  This instruction
>also comes in three flavors: byte, word, and longword offsets.  It would
>not be enough for the assembler to translate the CASEW the compiler
>probably generates into a CASEL: the jump table must be translated from
>words to longwords too.

Sorry, the B/W/L forms refer to the size of the INDEX into the case
statement.  The displacements are always encoded as 16-bit relative
offests.

>Portable solutions?  I suppose the best bet is to make the switch statement
>smaller.  One way to do this might be to replace some of the bigger cases
>by jumps to code outside the switch statement itself.  Ick.

Replace the code in the case arms by routine calls.  A monolithic chunk of
code more than 32k bytes long might even be improved by this change.

amos@instable.UUCP (Amos Shapir) (01/20/87)

A portable kludge solution to the problem: the VAX BSD compiler
generates 'casel' instructions only for switches in which the value range
is dense, i.e. there are a lot of used values between the highest and lowest
case values (I think the criterion is (hi-lo)/nused>=1/3 ).
Otherwise, it generates a set of if's, creating in effect a binary search tree.
If you add a dummy case with a value that is way out of the range, if's
should be created instead of a casel.
After that, if the branches are still too long, just do 'sed s/brw/jmp/'
on the assembly file.
-- 
	Amos Shapir
National Semiconductor (Israel)
6 Maskit st. P.O.B. 3007, Herzlia 46104, Israel
(011-972) 52-522261  amos%nsta@nsc 34.48'E 32.10'N

donn@utah-cs.UUCP (Donn Seeley) (01/20/87)

Renu Raman asks what one must do in order to compile a huge switch
statement on a VAX using the 4.3 BSD PCC.  The real answer, as has been
suggested by Robert Firth, is to use structured coding techniques to
avoid creating monstrous Fortran-style functions.  Sometimes one must
contend with mechanically generated C code, however, and in such cases
it can be useful to know about hacks to squeeze such awful code through
the compiler.

As Robert Firth says, the VAX CASEx instructions are limited to 16-bit
branch offsets; it's this restriction which produces the assembler
warning 'Case will branch too far'.  (Other VAX instructions which have
unexpectedly limited displacement sizes include ACBx, AOBxxx and
SOBxxx...)  It is possible to force the VAX 4.3 BSD PCC to produce
actual tests and jumps instead of a CASEL, however.  Unfortunately this
is not conditioned on a compiler flag, so the technique qualifies as a
hack.

The compiler will use a 'heap' switch if there are more than 8 case
labels and the difference between the greatest and the least case
labels is greater than three times the number of labels (this controls
the density of the CASEL branch table).  A typical switch uses
low-numbered case labels; if you throw in a 'case 0x7fffffff:' with the
default label, this should force the compiler to use a 'heap' switch
instead of a CASEL switch.  A 'heap' switch is a jumble of tests and
branches; if these are assembled with the -J flag, they will be able to
span a distance of greater than 32 Kb.

Robert Herndon suggested that the peephole optimizer can 'fix' huge
switch statements.  The peephole optimizer won't replace CASEL
switches, but it will sometimes rearrange code so that a switch will
squeeze inside the range.  I don't know if the peephole optimizer will
handle most 'typical' huge switches, but I was able to cook up an
example just now which was beyond its capacity, so it's not a panacea.

People can produce Fortran regardless of the actual coding language,

Donn Seeley    University of Utah CS Dept    donn@cs.utah.edu
40 46' 6"N 111 50' 34"W    (801) 581-5668    utah-cs!donn

tps@sdchem.UUCP (Tom Stockfisch) (01/21/87)

In article <53900001@umn-cs.UUCP> herndon@umn-cs.UUCP (Robert Herndon) writes:
>I've had this problem a few times.  Try invoking the optimizer
>on your file.  The optimizer gets the assembly code before the
>assembler does, recognizes that the branch is inappropriate
>(or something, anyway) and generates an appropriate branch.

Are you sure your optimizer isn't just optimizing away enough instructions
to make the switch no longer span >64K bytes?  I had the optimizer on
a vax 4.2BSD system save me this way once.

By the way, I don't think a huge switch is necessarily indicative of
a poorly structured program.  The switch could be the result of preprocessor
replacement or be generated by another program such as yacc.  In the program
I wrote where I ran into this trouble my longest function consisted of
40 source code lines, and all the others were less than 20.  The whole
source file was ~250 lines (including copious comments), yet "cc" generated
a ".s" file of 1.2 megabytes.

|| Tom Stockfisch, UCSD Chemistry	tps%chem@sdcsvax.UCSD

herndon@umn-cs.UUCP (01/23/87)

  The code in question appears to the York Prolog interpreter.
I had exactly the same problem with the interpreter and found
that turning on the optimizer fixed the problem.  I did not
actually examine the assembler code produced.  I often ran
into strange problems with the BSD 4.2 C compiler and didn't
really have time to putz around trying to fix the compiler.
  As I recall, the York interpreter itself had some problems.
Variable lookup was very slow (linear search; not even a hashing
scheme) and the initialization time was long (that I fixed by
'checkpointing' the interpreter after initialization and
constructing an executable binary image of the initialized
interpreter).  The code appeared to be otherwise well written
in strict ISO pascal.
  We later got Cprolog -- York is now (virtually) unused.
It is much faster, has better debugging features, ...

				Robert Herndon
				...!ihnp4!umn-cs!herndon
				herndon@umn-cs.ARPA
				Dept. of Computer Science,
				Univ. of Minnesota,
				136 Lind Hall, 207 Church St. SE
				Minneapolis, MN  55455

jsdy@hadron.UUCP (02/05/87)

In article <3950007@nucsrl.UUCP> ram@nucsrl.UUCP (Raman Renu) writes:
>   I have a problem in using the C compiler and VAX assembler in our local
>4.3BSD(VAX) site.  I have a program which has a huge(>900lines) switch
>statement.
>The assembler chokes on (>32K long) long branches.

We had this problem on an Altos [29]86, 8086 Xenix machine.
Never thought that I'd see it on a Vax!  The compiler should
correctly interpret this.  However, the only portable solution
we could figure out that was (relatively) quick and easy was
to translate the case into if/else if/else if/ ...

Speaking of which, I'd like to promote the use of the form:
	if (...) {
		...
	} else if (...) {
		...
	} else if (...) {
		...  ...
	}
instead of indenting each successive "if".  Where appropriate
only, of course.  This is advocated in one of the early C Style
books.
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
			jsdy@hadron.COM (not yet domainised)

tropp@cthce.UUCP (02/10/87)

In article <449@hadron.UUCP> jsdy@hadron.UUCP (Joseph S. D. Yao) writes:
|In article <3950007@nucsrl.UUCP> ram@nucsrl.UUCP (Raman Renu) writes:
||   I have a problem in using the C compiler and VAX assembler in our local
||4.3BSD(VAX) site.  I have a program which has a huge(>900lines) switch
||statement.
||The assembler chokes on (>32K long) long branches.
|
|Speaking of which, I'd like to promote the use of the form:
|	if (...) {
|		...
|	} else if (...) {
|		...
|	} else if (...) {
|		...  ...
|	}
From 4.2BSD(VAX) as man page:

     -J   Use long branches to resolve jumps when byte-
          displacement branches are insufficient.  This must be
          used when a compiler-generated assembly contains
          branches of more than 32k bytes.