[LLVMdev] All CallInsts mayHaveSideEffects

Thomas B. Jablin tjablin at cs.princeton.edu
Mon May 10 17:28:09 PDT 2010


Hi,

All CallInsts should return true for Instruction::mayHaveSideEffects() because functions are not guaranteed to halt.

Inliner::runOnSCC calls isInstructionTriviallyDead to determine whether code can be dead code eliminated. isInstructionTriviallyDead returns true if Instruction::mayHaveSideEffects() returns false. A function that potentially runs forever based on its input but does not write to memory will be dead code eliminated when the Inliner runs.

Here is a simple example of how things can go horribly wrong:

#include <stdio.h>
#include <stdlib.h>

void inf(void) {
  while(1);
}

int main(int argc, char **argv) {
  inf();
  return 0;
}

void foo(void) {
  printf("Hello world!\n");
  exit(0);
}

For recent versions of clang (svn rev 102637) when compiled with -O1 or higher the result is:
Hello world!

The reason is that LLVM annotates inf as noreturn, so the ret instruction at the end of main is replaced with unreachable. Then the inf function is dead-code eliminated by the Inliner pass. Thus main will consist of a single unreachable instruction, which allows control to fall through to the foo function.

My suggested patch is as follows:

Index: include/llvm/Instruction.h
===================================================================
--- include/llvm/Instruction.h  (revision 102637)
+++ include/llvm/Instruction.h  (working copy)
@@ -245,7 +245,9 @@
   /// instructions which don't used the returned value.  For cases where this
   /// matters, isSafeToSpeculativelyExecute may be more appropriate.
   bool mayHaveSideEffects() const {
-    return mayWriteToMemory() || mayThrow();
+    const unsigned opcode = getOpcode();
+    return mayWriteToMemory() || mayThrow() ||
+      opcode == Call || opcode == Invoke;
   }
 
   /// isSafeToSpeculativelyExecute - Return true if the instruction does not

Sincerely yours,
Tom



More information about the llvm-dev mailing list