tcc816 - limit in total number of "if / else if" in code?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
tcc816 - limit in total number of "if / else if" in code?
by on (#214613)
Hi again, I've encountered a new issue with PVSNESLib.

Do you know if there is a limit in the total numbers of "if / else if / else" that can appear in the C code converted into ASM with tcc816?

With my current codebase, I'm regularly getting the following error with tcc816.

Code:
    game.asm:23: INPUT_NUMBER: Out of 16bit range.
    game.asm:23: ERROR: Couldn't parse "sbc".


The ASM instruction causing the error is this one (as I lack any ASM skill, I'm not sure of what it does):
Code:
sbc #__init_locals


At first, as I've mentionned previously with my SNESmod related issue, I thought that it was some kind of "limitation" in the total number of instructions that can happen in the C code. But after lots of testing, I've figured out the issue:
tcc816 doesn't seem to be able to process code with too many "if / else if / else" instructions.

Indeed, whenever I hit this issue, if I remove regular instructions, it doesn't solve the issue. If I remove some if / else if / if instead, the code gets compiled again. A "else if" has the same "weight" for this limit as a single "if". Likewise, using an OR (condition 1 || condition 2) seems to be counted as "2" instead of "1" for this limit. Of course, this limit is happening even if the code is split in several functions (i.e. even with code spanned over several rom banks): it's the total number of "if" in the code that make tcc816 unable to compile for some reason.

Regarding my current codebase, I have about 2000 lines of C code, organized in several functions, but all the code is written in a single C file (besides the code coming from the PVSNESlib itself, and the ASM files used to store the graphics and audio assets).

Do any of you have encountered this issue before?

If not, maybe you have some ideas of the source of the problem (I remembered reading here that tcc816 isn't able to "shorcut" if conditions or something like that, I don't know if it's related to the issue I'm having).

Thanks again a lot for your help!
Re: tcc816 - limit in total number of "if / else if" in code
by on (#214616)
I don't have familiarity with this assembler, but the error seems to imply the value of __init_locals is greater than 65535.

I suppose another possibility is that the sbc instruction itself is now somehow out of bounds, i.e. past a bank boundary. Assuming you're using mode 20 (that's a memory mapping mode on the SNES, not a graphics mode), are your resulting segments reaching sizes that exceed 32KBytes (32768 bytes) or around there?
Re: tcc816 - limit in total number of "if / else if" in code
by on (#214620)
koitsu wrote:
I don't have familiarity with this assembler, but the error seems to imply the value of __init_locals is greater than 65535.

The tcc compiler in PVSNESLib generates code for the WLA-DX assembler. I'm assuming that __init_locals is part of the C implementation that tcc uses.

drludos wrote:
The ASM instruction causing the error is this one (as I lack any ASM skill, I'm not sure of what it does):
Code:
sbc #__init_locals

sbc stands for "Subtract with Borrow". It takes whatever is in the Accumulator (i.e. whatever number the CPU has computed so far), and subtracts whatever #__init_locals is. The pound sign means "this isn't an address to read from but a constant number". Since it's a constant, this certainly raises questions on how that value is being set in the first place.

Quote:
If not, maybe you have some ideas of the source of the problem (I remembered reading here that tcc816 isn't able to "shorcut" if conditions or something like that, I don't know if it's related to the issue I'm having).

Not shortcut, but short circuit. Short circuiting works like this:

Code:
if (a == b && c == d) {}

In the above if statement, if the first expression (a == b) is determined to be false, it doesn't bother processing the rest (c == d).

I don't think the lack of short circuiting is the cause here. The issue is likely something to do with the memory layout, and the inclusion or lack of short circuiting shouldn't do much to change that.

Edit: For some reason I am unable to find __init_locals in the WLA-DX or PVSNESLib repositories, or in the tcc source archive...
Re: tcc816 - limit in total number of "if / else if" in code
by on (#214695)
Thank you a lot for your replies!

Thanks to Shiru, I now have the solution to this issue. He encountered the problem in the past, and solved this issue on this very forum
http://forums.nesdev.com/viewtopic.php?p=93412
(It was in the "NESdev" section, and I focused my searches in the "SNESdev" one, silly me!)

To summarize, TCC generates "local labels" in the ASM code it produces. I don't know what these labels are used for, but TCC816 has an hard limit of 1000 local labels for each C source code file. By adding too much code in a single file, I simply went over this limit. The link offer a fixed version of TCC816 than can allow for up to 20.000 labels, created by Mic_!

HihiDanni wrote:
Not shortcut, but short circuit. Short circuiting works like this:

Code:
if (a == b && c == d) {}

In the above if statement, if the first expression (a == b) is determined to be false, it doesn't bother processing the rest (c == d).

I don't think the lack of short circuiting is the cause here. The issue is likely something to do with the memory layout, and the inclusion or lack of short circuiting shouldn't do much to change that.


Woaw, thanks for detailing that, I wasn't aware of such an issue. Now I get why C code is slower than ASM code for the SNES. Regarding your example, if I write the following C code instead, would it solve the issue:
Code:
if (a == b) {
 if(c == d) {}
}


Oh, and does this issue also implies that TCC generated code won't shortcircuit if / else if conditions?
For example, will it still evaluate all of the following "else if" statements, even when the first "if" condition is true?
Code:
if (a == b) {}
else if( c == d) {}
else if( e == f) {}


Thanks again a lot for your help!