Long Branches

chris at mimsy.UUCP chris at mimsy.UUCP
Mon Jan 19 15:34:15 AEST 1987


In article <3950006 at nucsrl.UUCP> ram at 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 at mimsy.umd.edu



More information about the Comp.lang.c mailing list