[LLVMbugs] [Bug 20810] New: inconsistent llvm_unreachable handling causes infinite loops in release builds

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Fri Aug 29 14:35:52 PDT 2014


http://llvm.org/bugs/show_bug.cgi?id=20810

            Bug ID: 20810
           Summary: inconsistent llvm_unreachable handling causes infinite
                    loops in release builds
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: Support Libraries
          Assignee: unassignedbugs at nondot.org
          Reporter: dberlin at dberlin.org
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified

Reproduction:

Build with CMAKE_BUILD_TYPE=Release on Linux with compiler set to G++ and using
g++ > 4.5.


run llvm-lit on /test/CodeGen/R600/infinite-loop-evergreen.ll

It will take forever (not to *execute*, but to *compile*)

Here is what happens:
lib/Target/R600/AMDILCFGStructurizer.cpp has the following code at line 1737:

 MachineBasicBlock::iterator I = BranchMI;
  unsigned ImmReg = FuncRep->getRegInfo().createVirtualRegister(I32RC);
  llvm_unreachable("Extra register needed to handle CFG");
  MachineInstr *NewMI = insertInstrBefore(I, AMDGPU::BRANCH_COND_i32);
  MachineInstrBuilder MIB(*FuncRep, NewMI);
  MIB.addMBB(LoopHeader);
  MIB.addReg(ImmReg, false);
  SHOWNEWINSTR(NewMI);
  BranchMI->eraseFromParent();
  LoopLatch->addSuccessor(DummyExitBlk);


It expects the llvm_unreachable to abort (as do a lot of other places in the
compiler), but when it doesn't, it just happily continues on (going around and
around forever, it turns out)

include/Support/ErrorHandling.h has this:

/// Use this instead of assert(0).  It conveys intent more clearly and
/// allows compilers to omit some unnecessary code.
#ifndef NDEBUG
#define llvm_unreachable(msg) \
  ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
#elif defined(LLVM_BUILTIN_UNREACHABLE)
#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
#else
#define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal()
#endif

(Note the request to use instead of assert(0) )


llvm_unreachable_internal prints a message, calls *abort*, then calls
LLVM_BUILTIN_UNREACHABLE if it is defined.

But as per above, if LLVM_BUILTIN_UNREACHABLE and NDEBUG are defined, we just
call LLVM_BUILTIN_UNREACHABLE

LLVM_BUILTIN_UNREACHABLE is defined as:

/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
/// to an expression which states that it is undefined behavior for the
/// compiler to reach this point.  Otherwise is not defined.
#if __has_builtin(__builtin_unreachable) || __GNUC_PREREQ(4, 5)
# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
# define LLVM_BUILTIN_UNREACHABLE __assume(false)
#endif


Thus, this llvm_unreachable expression transforms to builtin_unreachable on GCC
4.5 or above (I expect windows has a similar problem unless assume also
aborts).

However, builtin_unreachable *does not abort*. In fact, in most cases, it does
nothing.  GCC only defines it as a hint to the compiler.


If we expect llvm_unreachable to abort, the right solution is to just remove
the line
#elif defined(LLVM_BUILTIN_UNREACHABLE)
#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE

It will then always do the right thing in llvm_unreachable_internal (including
calling the unreachable builtin).

If we don't expect it to abort, then the code in places like above needs to be
modified to abort rather than infinite loop forever.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20140829/89d27710/attachment.html>


More information about the llvm-bugs mailing list