This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Cast converted volatile access not generating buggy code

I have a code snippet as given below

static unsigned int ticks;

void IRQ_SomeTimer(void) {
   ticks ++;
}

int main()
{
  int sav_ticks;
  sav_ticks = ticks;
  while (sav_ticks + TIME_TO_WAIT > *(volatile unsigned int *)&ticks);
  /* Do somethine here */
  return 0;
}

This compiles and runs on ARM-Mx targets up to optimization level O2, at optimization level O3 the code generated for

while (sav_ticks + TIME_TO_WAIT > *(volatile unsigned int *)&ticks);

is the same as the code generated for

while (sav_ticks + TIME_TO_WAIT > ticks);

Hence the code generated by O3 never comes out of the while loop!! Is this a BUG in Keil armcc(?) I am using Keil U-Vision (MDK ARM 4.73).

Parents
  • "Preceding an expression by a parenthesized type name converts the value of the expression to the named type. This construction is called a cast [44]".

    And the note [44] says,

    "A cast does not yield an lvalue. Thus a cast to qualified type has the same effect as a cast to the unqualified version of the type"

    volatile is a qualifier - so I think that says that the compiler is correct to ignore the volatile in your cast...?

Reply
  • "Preceding an expression by a parenthesized type name converts the value of the expression to the named type. This construction is called a cast [44]".

    And the note [44] says,

    "A cast does not yield an lvalue. Thus a cast to qualified type has the same effect as a cast to the unqualified version of the type"

    volatile is a qualifier - so I think that says that the compiler is correct to ignore the volatile in your cast...?

Children
  • Well that settles it (Thank you Andrew Neil).

  • Well the funny thing is the code below shows error in Keil

    uint8_t x;
    *(const uint8_t *)&x = 0x48;
    

    It says the resulting expression from the Left hand side of the = operator is a non modifiable 'lvalue'. If cast to the qualified type has the same effect as cast to the unqualified type then the above should be perfectly valid!!

  • Oops I spoke too soon! After a little bit of analysis I think Footnote [44] of the standard (in draft foot note [86]) does not settle it after all!!

    So the note says "A cast does not yield an lvalue. Thus, a cast to a qualified type has the same effect as a cast to the unqualified version of the type." Let us look at what this says

    int x;
    long int y;
    y = (long) x;
    y = (volatile long) x;
    

    In the above code the type is "long" and the cast converts it to "volatile qualified long", hence the standard says the compiler to consider the cast to "volatile long" as the same as cast to "long".

    Well if we consider a type "int *" the volatile qualified type of "int *" is "int * volatile" and not "volatile int *" [this is totally a different type]. So according to the standards the compiler is free consider cast to "int *" and a cast to "int * volatile" as the same, but it is supposed to do the conversion according to standard given at 6.5.4 Cast operators paragraph 3

    Conversions that involve pointers, other than where permitted by the constraints of
    6.5.16.1, shall be specified by means of an explicit cast.
    

    In my original example I do a conversion of "uint32_t *" to "volatile uint32_t *" which is not permitted by the constraint specified in 6.5.16.1 [it permits conversion of "volatile uint32_t *" to "uint32_t *" but not vice-versa]. Hence the compiler should consider my explicit cast. It is indeed a bug in armcc.

    To shed more light on this as I mentioned before

    uint8_t x;
    *(const uint8_t *)&x = 0x48;
    

    the above code shown error [perfectly good] as the compiler did the conversion of type-x to type-y [Where type-x is "uint8_t *" and type-y is "const uint8_t *" and type-y is not a qualified type of type-x]

    Now considering the code below

    uint8_t x;
    *(uint8_t * const)&x = 0x48;
    

    compiles with a simple warning as given below

    main.c(15): warning:  #191-D: type qualifier is meaningless on cast type
    

    Which is apt according to the section of standards mentioned by "Andrew Neil"

    P.S: Please don't ask me why I am using const and not volatile.