# Optimization kills the switch statement that I need to use in a function

Optimization kills the switch statement that I need to use in a function Hi all, how are you?. I'm doing a project with a STM32F103C6 (it has 32KB flash) and I had to activate optimization options to not run out of memory, right now the optimization options is -Og. After activate optimization a function that I have to know the position of a substring and after that I'm trying to use a switch statement that the compiler is killing and obviously I can't but I don't know why.

Here are de function definitions:

void Selec_Opera(char *ent, uint8_t dim)
{
volatile uint8_t pos = 0;
volatile uint8_t lugar = 0;
//  uint8_t com[T_COMANDO] = {0};
pos = strindex(comandos, (char *) eComando);
for(lugar = 0; T_COMANDO*lugar <= pos; lugar++)
{
asm("nop");
}
switch(lugar)
{
case 0x01:
{
lugar++;
}
break;
case 0x02:
{
lugar++;
}
break;
case 0x03:
{
lugar++;
}
break;
case 0x04:
{
lugar++;
}
break;
case 0x05:
{
lugar++;
}
break;
case 0x06:
{
lugar++;
}
break;
case 7:
{
lugar++;
}
break;
default:
{
lugar = 25;
}
break;
}
}

volatile uint8_t strindex(char s[], char t[])
{
uint8_t i, j, k;
for (i = 0; s[i] != '\0'; i++)
{
for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++);
if (k > 0 && t[k] == '\0')
return i;
}
return -1;
}


and I'm calling Selec_Opera() from main like follows:

while (1)
{
if(HAL_I2C_Slave_Receive(&hi2c1, eComando, T_COMANDO, HAL_MAX_DELAY) != HAL_OK)
{
codigoError = 20;
Error_Handler();
}
else
{
Selec_Opera((char *) eComando, T_COMANDO);
}
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}


The I2C function is working well, the problem is with the function Selec_Opera(). If you wanna know T_COMANDO is defined as 4 and eComando is the array where I'm storing the received stream.

When the Selec_Opera() function is being executed it can be seen that almost all the switch options are not compiled, some pictures can show correctly what I'm tring to explain.

The following image shows that when I'm doing a debug session the debug file has the text but almost all the "switch" options code hasn't been included in the executable file (I need this)

only option 7 and default are included, I've tried only for test with reduced options and the behavior is the same, only the last numbered option and the default option are included in the code (this can be seen because at left is written the memory position of the instruction)

I've tested the "for" statement and it is working well selecting the position where the string is so I don't know what is happening with the switch.

Can anyone help with this?. Thanks in advance for the help.

• Can you show the assembler code? It most likely got optimized to if(lugar<=7)lugar++;else lugar=25; Aug 27 '20 at 10:51
• pos = strindex(comandos, (char *) eComando); What's commandos and eCommando? || You do nothing with with the arguments *ent and dim || After the for loop, lugar will always be pos / 4. || No need for the switch statement: lugar = lugar < 8 ? lugar + 1 : 25; || Lastly, why volatile? Aug 27 '20 at 10:54
• Your code still works correctly with optimizations turn on, right? Or how does the behavior of the code change?
– Codo
Aug 27 '20 at 10:56
• Reading again over the code. What does Selec_Opera even supposed to do? It's a void function and you only play with variables that are inside the scope of that function. Aug 27 '20 at 11:02
• Your use of volatile disturbs me. Aug 27 '20 at 11:07

As all cases except default are the same code, the compiler is allowed to reduce that to a single case + default. Why not? There is no need to bloat the result code with the same instuctions several times.

In fact the code is simple

if((lugar>0) && (lugar < 8)){
++lugar;
}else{
lugar = 25;
}


and that is exactly what the compiler will generate I guess

• Thanks @schnedan, that is exactly what was happening
– vram
Aug 27 '20 at 11:28
• @Swedgin correct me if I am wrong, but the original code does not count +1 if lugar is 0 but executes the default case... Aug 27 '20 at 11:38
• @schnedan yes you are right. I overlooked that fact. Aug 27 '20 at 11:55
• actually where the lugar++ are is going to be a different function for each case but I've put it that way for lack of experience.
– vram
Aug 27 '20 at 13:44
• @vram oh, so that is placeholder code. It’s optimizing it lol... Aug 27 '20 at 19:52

The switch statements gets killed because it gets optimized to lugar = (lugar > 0) && (lugar < 7) ? lugar + 1 : 25.

If lugar is smaller than 8 and not equal to 0 you always do +1 otherwise it's equal to 25. Your code only needs an if statement. Hence only 2 options remain in the optimized code.

• Thanks @Swedgin, that is exactly what was happening
– vram
Aug 27 '20 at 11:28

volatile access isn't allowed to be optimized, but the compiler can optimize the surrounding code. Your code reads lugar once and then writes to it once. Those two accesses are not allowed to be optimized out. This means that the code may get optimized into something similar to this:

tmp = lugar;
if(tmp>0 && tmp < 8)
tmp++;
else
tmp = 25;
lugar = tmp;


The important part here is that the number of side effects (read/writes on the volatile variable) stay the same and aren't re-ordered.

volatile aside, switch statements are almost always optimized into something more efficient - don't expect to be able to single step through them in optimized C code. When there are no volatile around, they often get replaced by function pointer lookup tables.