This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/TM4C1294NCPDT: Can a class wrapper for mutex gate be removed due to optimization?

Part Number: TM4C1294NCPDT


Tool/software: TI C/C++ Compiler

tirtos_tivac_2_10_01_38

CCS6

arm_5.1.11

I want to use a class wrapper to protect global variables to be accessed by different thread, like the following code (Note, some initiazation code is removed for simplicity):

GateMutexPri_Handle g_MutexHandle;

class MutexGateC:
{
public:
  MutexGateC()
  {
    m_IArg = GateMutexPri_enter(g_MutexHandle);
  }

  ~MutexGateC()
  {
    GateMutexPri_leave(g_MutexHandle, m_IArg);
  }

private:  
  IArg m_IArg;
};

class HwiGateC:
{
public:
  HwiGateC()
  {
    m_Key = Hwi_disable();
  }

  ~HwiGateC()
  {
    Hwi_restore(m_Key);
  }

private:  
  UInt m_Key;
};

Uint g_resource1;

Uint g_resource2;

void Func1(void)
{
  MutexGateC m();

  g_resource1++;
}

void Func2(void)
{
  HwiGateC h();

  g_resource2++;
}

 

My question, in function "Func1" and "Func2", can variable "m" and "h" be removed due to optimization, because it looks like the variables are never referenced? If it is possible, then on which optimization level? Thanks

  • Careful, you declared m and h to be functions (see "most vexing parse").

    That said, once you correct the definitions, the compiler should be able to inline constructors and destructors at almost any optimization level.

  • Thank and I didn't notice "Most vexing parse" before.

    So if I use "MutexGateC m" and "HwiGateC h", the variables won't be removed due to optimization because they looks not referenced by remaining code of the function? It is guaranteed by standard?

  • Jianyi Bao said:
    So if I use "MutexGateC m" and "HwiGateC h", the variables won't be removed due to optimization because they looks not referenced by remaining code of the function?

    They could be removed.  The compiler uses many methods to identify and remove computations where the result is never used.  Some of these methods are applied at all optimization levels.  That said, the higher the optimization level, the more successful these methods tend to be.

    Jianyi Bao said:
    It is guaranteed by standard?

    Details about compiler optimization are not part of the standard.

    Thanks and regards,

    -George

  • It's entirely possible that the variables will be removed, but the traces of the constructor and destructor that call functions will remain.
  • If you need to make sure the variables aren't removed or otherwise optimized, you need to declare them as volatile.
  • Hi, pf,

    What do you mean by "the traces of.. will remain"?

  • I use "MutexGateC m" and "HwiGateC h" in my code, and checked the generated assembly code, at both optimization level 2 (global optimization) and 4(whole program optimization), and found that the construtor and destructor are called at the beginning and the end of the caller. So does it mean it's safe to use this code for protection from multithread accessing?
  • Jianyi Bao said:

    Hi, pf,

    What do you mean by "the traces of.. will remain"?

    It's complicated. C++ describes the behavior of an abstract machine, not what an actual binary will look like. In essence, the compiler is free to output any binary that

    1. returns the correct value from main
    2. performs I/O the same way as the abstract machine
    3. performs all volatile accesses the same way as the abstract machine

    As an example (I'm sorry, I don't know who first came up with this), clang compiles the following C code:

    #include <stdint.h>
    
    int mystery(uint64_t x)
    {
        int sum = 0;
        while(x)
        {
            sum++;
            x &= x - 1;
        }
        return sum;
    }

    to just

    mystery(unsigned long): # @mystery(unsigned long)
      popcnt rax, rdi
      ret

    There's no loop, no 'sum' variable... the compiler detected that the function is counting 1s in its input and so replaced the whole loop with a single popcnt instruction.

    That said, a compiler cannot remove or transform code the behavior of which it does not know. A function call that is only resolved at link-time cannot be removed, because it could perform arbitrary I/O (link-time optimizations not considered).

    Therefore, what people tell you is:

    1. You will probably not be able to clearly identify a MutexGateC 'object' in your binary
    2. But the calls to GateMutexPri_enter and GateMutexPri_leave will still be there


  • Thanks, Markus.