IAR compiler problem - or brainfurt ?

I have a “logic issue” with the attached code segment. This code segment does nothing except show the problem. The comments describe the sections which work as expected, and where it quits working as expected. Does this look like a compiler problem (IAR for ARM, V5.4), or am I off in the weeds ? I am compiling for a STM32.

uint32_t sum;

uint16_t num1;

uint16_t num2;

sum = 0;

//***********************************************

// These following two statements work correctly.

// For these statements, num < 2, so sum = 0xAAAA

// is executed.

//***********************************************

num1 = 0;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 1;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

//***********************************************

// The next group of statements work correctly.

// num2 >= 2, and num2 < 10. sum = 0xAAAA is

// not executed.

//***********************************************

num1 = 2;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 3;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 4;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 5;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 6;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 7;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 8;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 9;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 10;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

//***********************************

// Stops working here. Why ?

// same conditions exist as above.

// Neither statement should evaluate

// to true, so sum = 0xAAAA should

// not be executed, but it does.

//**********************************

num1 = 11;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 12;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 13;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 14;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

num1 = 15;

num2 = 0;

if( (num1 < 2) || (num2 > 10) )

sum = 0xAAAA;

In such cases I usually look at the listing of the machine code produced by the compiler, to see if it is correct (or if not, what it is doing wrong). Is that an option here? You can also try turning off code optimization for a test, to see if that makes a difference.

Here is the disassembly view of the first statement. This is typical of each of the “if” statement section with the exception of the values loaded for num1(r2) and num2 (r0). The disassembly code looks very odd to me. It appears as if they are using the SUBS for a compare, but I have no idea what the UXTH is doing here. The optomization level is set at

“Low”.

// num1 = 0;

// num2 = 0;

// if( (num1 < 2) || (num2 > 10) )

// sum = 0xAAAA;

MOVS r2,#0

MOVS r0,#0

SUBS r2,r2,#2

UXTH r2,r2

CMP r2,#9

BCC.N ??FreqCheck_1

MOVW r1,#43690

??FreqCheck_1

UXTH is extend half word to word, but in any case this doesn’t make sense to me. Why compare R2 to 9? R0 (num2) isn’t even referenced. What follows label FreqCheck_1?

Well, Well, Well. Turning the optomizer off (None) solved the problem. Each test case works correctly. Here is a typical “if” structure. Notice the two compares. Also notice the inefficiency of using r7 as a temp register. But, this actually works.

I assume that the extend is done so that 32 bit compares can be done on the 16 bit data.

MOVS r7,#0

MOVS r5,r7

MOVS r7,#0

MOVS r6,r7

UXTH r5,r5

CMP r5,#2

BCC.N ??FreqCheck_1

UXTH r6,r6

CMP r6,#11

BCC.N ??FreqCheck_2

FreqCheck_1:

MOVW r7,#43690

MOVS r4,r7

FreqCheck_2:

Congratulations, sounds like a bug report.

FYI - they (IAR) fixed this sometime after version 5.4. Here is a code snippet from Version 6.50 with optimizer set on Low. Looks, and works, just like one would expect.

27 void test(void)

28 {

29 unsigned short num1;

30 unsigned short num2;

31 unsigned short sum;

32

33 num1 = 0;

\ test:

\ 00000000 0x2000 MOVS R0,#+0

34 num2 = 0;

\ 00000002 0x2100 MOVS R1,#+0

35 if( (num1 < 2) || (num2 > 10) )

\ 00000004 0xB280 UXTH R0,R0 ;; ZeroExt R0,R0,#+16,#+16

\ 00000006 0x2802 CMP R0,#+2

\ 00000008 0xDB02 BLT.N ??test_0

\ 0000000A 0xB289 UXTH R1,R1 ;; ZeroExt R1,R1,#+16,#+16

\ 0000000C 0x290B CMP R1,#+11

\ 0000000E 0xDB01 BLT.N ??test_1

36 sum = 0xAAAA;

\ ??test_0:

\ 00000010 0xF64A 0x22AA MOVW R2,#+43690