Is there some way to see what the compiler is removing? I think this came up before and basically the answer was No.
I've come up against a much more complicated problem: the USB logical drive won't even format. Basically this is a removable block device implementation supplied by ST, which calls just two functions that interface onto the serial FLASH: write block (with transparent erase) and read block. The whole thing is interrupt driven, though it starts off as an RTOS thread. It works with -O0 but not with -Og. The two FLASH funcs are widely used elsewhere and appear to work fine, which leaves a large chunk of impenetrable USB code... The two funcs are these but they call other stuff, some of which is barely penetrable ST lib code
// Write a number of bytes to a single page through the buffer with built-in erase.
// 1/8/21 The last parm is actually a linear address within the device.
bool AT45dbxx_WritePage(
const uint8_t *data, // In Data to write
uint16_t len, // In Length of data to write (in bytes)
uint32_t page // In linear address, a multiple of 512
) {
HAL_StatusTypeDef status = HAL_OK;
if (len==0) return (status == HAL_OK);
page = page << AT45dbxx.Shift;
at45dbxx_resume();
at45dbxx_wait_busy();
B_HAL_GPIO_WritePin(_45DBXX_CS_GPIO, _45DBXX_CS_PIN, GPIO_PIN_RESET);
at45dbxx_tx_rx_byte(AT45DB_MNTHRUBF1);
at45dbxx_tx_rx_byte((page >> 16) & 0xff);
at45dbxx_tx_rx_byte((page >> 8) & 0xff);
at45dbxx_tx_rx_byte(page & 0xff);
status = B_HAL_SPI_Transmit(&_45DBXX_SPI, (uint8_t *) data, len, AT45DB_SPI_TIMEOUT_MS);
B_HAL_GPIO_WritePin(_45DBXX_CS_GPIO, _45DBXX_CS_PIN, GPIO_PIN_SET);
at45dbxx_wait_busy();
return (status == HAL_OK);
}
// Read a number of bytes from a single page
// 1/8/21 The last parm is actually a linear address within the device. May have to be a
// multiple of 512, too.
// The device command used (0Bh) allows a continuous read of the whole device. This does not
// appear to be allowed here.
bool AT45dbxx_ReadPage(
uint8_t *data, // Out Buffer to read data to
uint16_t len, // In Length of data to read (in bytes)
uint32_t page // In linear address, a multiple of 512
) {
HAL_StatusTypeDef status = HAL_OK;
if (len==0) return (status == HAL_OK);
page = page << AT45dbxx.Shift;
// Round down length to the page size
if (len > AT45dbxx.PageSize) {
len = AT45dbxx.PageSize;
}
at45dbxx_resume();
at45dbxx_wait_busy();
B_HAL_GPIO_WritePin(_45DBXX_CS_GPIO, _45DBXX_CS_PIN, GPIO_PIN_RESET);
at45dbxx_tx_rx_byte(AT45DB_RDARRAYHF);
at45dbxx_tx_rx_byte((page >> 16) & 0xff);
at45dbxx_tx_rx_byte((page >> 8) & 0xff);
at45dbxx_tx_rx_byte(page & 0xff);
at45dbxx_tx_rx_byte(0);
status = B_HAL_SPI_Receive(&_45DBXX_SPI, data, len, AT45DB_SPI_TIMEOUT_MS);
B_HAL_GPIO_WritePin(_45DBXX_CS_GPIO, _45DBXX_CS_PIN, GPIO_PIN_SET);
return (status == HAL_OK);
}
I can be very sure that all my "IO" references are volatile because I only ever use the ST defs and all are prefixed with __IO which is #defined as volatile.
To be honest I am happy to just continue the project with -O0 because it runs easily fast enough. It still removes code which manifestly never gets reached e.g. anything after a for( ;; ); but that's ok; I should not actually have any of that (except when testing when you want to insert say an LED flash loop near the start of main.c but don't want the other 99% of the product, including the RTOS and all the timer ISRs, stripped out
and then you have to fool the compiler by decrementing a unit32_t around that loop). With the other optimisation options I was seeing weird stuff where e.g. I had a variety of if() tests in a sequence, and at some point it decided that the expression being tested had to be always false, but I could not see that at all. Obviously the compiler could be way more clever than me in detecting an "impossible-true" situation, but the fact is that all those conditionals
were working correctly. I think the compiler was deciding that some flags (various bytes in a 512-byte buffer read from an eeprom) would always test false. Maybe that whole buffer should have been volatile, but that would not make sense to me if it fixed it. The bigger issue is that so much code could be broken in this way and retesting absolutely everything one has written in 6 months is just not viable. And some 90% of this project is libs from ST and such (ETH and USB) which are practically impenetrable and take months to do any debugging on, and debugging -O issues is very slow since it involves stepping through code, which is often impossible because the code is real-time.
The code size with -O0 and -Og is 220k and 160k which is quite a lot and suggests that stuff is being removed whole, somewhere.
Maybe there is a specific compiler option one could try to narrow it down? Where would these be specified in Cube?
As an aside, could optimisation break code where you call a function which has say 4 parameters but the 4th one is never used inside that function?