Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Assertion failed: (i == DstIdx || !MI->getOperand(i).isReg() || MI->getOperand(i).getReg() != RegA), function processTiedPairs, #39955

Open Quuxplusone opened 5 years ago

Quuxplusone commented 5 years ago
Bugzilla Link PR40985
Status NEW
Importance P enhancement
Reported by Dimitry Andric (dimitry@andric.com)
Reported on 2019-03-06 10:26:57 -0800
Last modified on 2021-07-04 04:39:24 -0700
Version trunk
Hardware PC All
CC alkis@evlogimenos.com, clattner@nondot.org, cnsun@uwaterloo.ca, craig.topper@gmail.com, htmldeveloper@gmail.com, llvm-bugs@lists.llvm.org
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
As reported in https://bugs.freebsd.org/234232, building the devel/aws-
checksums port (see also <https://github.com/awslabs/aws-checksums>) results in
a clang assertion:

Assertion failed: (i == DstIdx || !MI->getOperand(i).isReg() || MI-
>getOperand(i).getReg() != RegA), function processTiedPairs, file
lib/CodeGen/TwoAddressInstructionPass.cpp, line 1547.

Minimized test case:

/* clang -cc1 -triple x86_64-- -S crc32c_sse42_asm-min.c */
int a, b;
void c() { asm("" : "+c"(b) : "c"(a)); }
Quuxplusone commented 5 years ago

This reduced case isn't valid code according to gcc. It says ecx should be bound to b for input and output. And the ecx should also be bound to a for input. Clang doesn't diagnose that properly and hits the same error from the larger bug. Is it possible this wasn't reduced correctly?

Quuxplusone commented 5 years ago
(In reply to Craig Topper from comment #1)
> This reduced case isn't valid code according to gcc. It says ecx should be
> bound to b for input and output. And the ecx should also be bound to a for
> input. Clang doesn't diagnose that properly and hits the same error from the
> larger bug. Is it possible this wasn't reduced correctly?

Possibly.  I've used creduce, and it tries to simplify inline asm quite a lot.
The original code is full of +c constraints, like:

asm("loop_small_%=: CRC32B (%[in]), %[crc]" : "+c"(crc) : [crc] "c"(crc), [in]
"r"(input));

So probably a better minimized case is:

unsigned f(const unsigned char *input)
{
  unsigned crc = ~0;
  asm("crc32b (%[in]), %[crc]" : "+c"(crc) : [crc] "c"(crc), [in] "r"(input));
  return ~crc;
}

though gcc 8 requires at least -O1, otherwise it says the constraints are
impossible.  With -O1 or higher, it produces:

$ gcc8 -O2 -S crc32c_sse42_asm-min-2.c -o -
        .file   "crc32c_sse42_asm-min-2.c"
        .text
        .p2align 4,,15
        .globl  f
        .type   f, @function
f:
.LFB0:
        .cfi_startproc
        movl    $-1, %ecx
#APP
# 4 "crc32c_sse42_asm-min-2.c" 1
        crc32b (%rdi), %ecx
# 0 "" 2
#NO_APP
        movl    %ecx, %eax
        notl    %eax
        ret
        .cfi_endproc
.LFE0:
        .size   f, .-f
        .ident  "GCC: (FreeBSD Ports Collection) 8.3.0"
        .section        .note.GNU-stack,"",@progbits
Quuxplusone commented 3 years ago
Still occurs as of 2020-11-08, with llvmorg-12-init-10988-g43df29e2062:

$ ~/ins/llvmorg-12-init-10988-g43df29e2062/bin/clang -cc1 -triple x86_64-- -S
crc32c_sse42_asm-min.c
Assertion failed: (i == DstIdx || !MI->getOperand(i).isReg() || MI-
>getOperand(i).getReg() != RegA), function processTiedPairs, file
/home/dim/src/llvm/llvm-project/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp,
line 1415.
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash
backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: /home/dim/ins/llvmorg-12-init-10988-
g43df29e2062/bin/clang -cc1 -triple x86_64-- -S crc32c_sse42_asm-min.c
1.      <eof> parser at end of file
2.      Code generation
3.      Running pass 'Function Pass Manager' on module 'crc32c_sse42_asm-min.c'.
4.      Running pass 'Two-Address instruction pass' on function '@c'
#0 0x000000000204a3c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int)
(/home/dim/ins/llvmorg-12-init-10988-g43df29e2062/bin/clang+0x204a3c8)
#1 0x00000000020481d8 llvm::sys::RunSignalHandlers() (/home/dim/ins/llvmorg-12-
init-10988-g43df29e2062/bin/clang+0x20481d8)
#2 0x000000000204ab56 SignalHandler(int) (/home/dim/ins/llvmorg-12-init-10988-
g43df29e2062/bin/clang+0x204ab56)
#3 0x0000000805898b90 handle_signal /usr/src/lib/libthr/thread/thr_sig.c:0:3
Abort trap
Quuxplusone commented 3 years ago
A possible duplicate.

$ clang-trunk -v
clang version 13.0.0 (https://github.com/llvm/llvm-project.git
6b0d266036f73f5ee9556d211a7d0946091ff3b2)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/cnsun/usr/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

$ cat mutant.c
a;
fn1() {
  int b;
  __asm__(" # a: %x0, b: %x1" : "+d"(a), "+d"(b));
}

$ clang-trunk  mutant.c
mutant.c:1:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]
a;
^
mutant.c:2:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-
int]
fn1() {
^
mutant.c:5:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
clang-13: /tmp/tmp.OKn6kNiY8c-clang-builder/llvm-
project/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp:1398: void
{anonymous}::TwoAddressInstructionPass::processTiedPairs(llvm::MachineInstr*,
{anonymous}::TwoAddressInstructionPass::TiedPairList&, unsigned int&):
Assertion `i == DstIdx || !MI->getOperand(i).isReg() || MI-
>getOperand(i).getReg() != RegA' failed.
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash
backtrace, preprocessed source, and associated run script.
Stack dump:
0.  Program arguments: /scratch/software/clang-trunk/bin/clang-13 -cc1 -triple
x86_64-unknown-linux-gnu -emit-obj -mrelax-all --mrelax-relocations -disable-
free -main-file-name mutant.c -mrelocation-model static -mframe-pointer=all -
fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-
cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-
dir=/scratch/cnsun/workspace/perses-
fuzzer/default_c_finding_folder/crash_20210703_122112_04d6/delta/perses_result -
resource-dir /scratch/software/clang-trunk/lib/clang/13.0.0 -c-isystem . -c-
isystem /usr/local/include/cmsith -internal-isystem /scratch/software/clang-
trunk/lib/clang/13.0.0/include -internal-isystem /usr/local/include -internal-
isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -
internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-
isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-
dir=/scratch/cnsun/workspace/perses-
fuzzer/default_c_finding_folder/crash_20210703_122112_04d6/delta/perses_result -
ferror-limit 19 -fgnuc-version=4.2.1 -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o
/tmp/mutant-697d2f.o -x c mutant.c
1.  <eof> parser at end of file
2.  Code generation
3.  Running pass 'Function Pass Manager' on module 'mutant.c'.
4.  Running pass 'Two-Address instruction pass' on function '@fn1'
 #0 0x0000557ae7446714 PrintStackTraceSignalHandler(void*) Signals.cpp:0:0
 #1 0x0000557ae7443ece SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f311de463c0 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x153c0)
 #3 0x00007f311d8e518b raise /build/glibc-ZN95T4/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
 #4 0x00007f311d8c4859 abort /build/glibc-ZN95T4/glibc-2.31/stdlib/abort.c:81:7
 #5 0x00007f311d8c4729 get_sysdep_segment_value /build/glibc-ZN95T4/glibc-2.31/intl/loadmsgcat.c:509:8
 #6 0x00007f311d8c4729 _nl_load_domain /build/glibc-ZN95T4/glibc-2.31/intl/loadmsgcat.c:970:34
 #7 0x00007f311d8d5f36 (/lib/x86_64-linux-gnu/libc.so.6+0x36f36)
 #8 0x0000557ae688fe30 (anonymous namespace)::TwoAddressInstructionPass::processTiedPairs(llvm::MachineInstr*, llvm::SmallVector<std::pair<unsigned int, unsigned int>, 4u>&, unsigned int&) TwoAddressInstructionPass.cpp:0:0
 #9 0x0000557ae6891a86 (anonymous namespace)::TwoAddressInstructionPass::runOnMachineFunction(llvm::MachineFunction&) TwoAddressInstructionPass.cpp:0:0
#10 0x0000557ae6655388
llvm::MachineFunctionPass::runOnFunction(llvm::Function&)
(/scratch/software/clang-trunk/bin/clang-13+0x2ba4388)
#11 0x0000557ae6b37555 llvm::FPPassManager::runOnFunction(llvm::Function&)
(/scratch/software/clang-trunk/bin/clang-13+0x3086555)
#12 0x0000557ae6b37799 llvm::FPPassManager::runOnModule(llvm::Module&)
(/scratch/software/clang-trunk/bin/clang-13+0x3086799)
#13 0x0000557ae6b38892 llvm::legacy::PassManagerImpl::run(llvm::Module&)
(/scratch/software/clang-trunk/bin/clang-13+0x3087892)
#14 0x0000557ae777f1c2 (anonymous
namespace)::EmitAssemblyHelper::EmitAssemblyWithNewPassManager(clang::BackendAction,
std::unique_ptr<llvm::raw_pwrite_stream,
std::default_delete<llvm::raw_pwrite_stream> >) BackendUtil.cpp:0:0
#15 0x0000557ae7780c7d clang::EmitBackendOutput(clang::DiagnosticsEngine&,
clang::HeaderSearchOptions const&, clang::CodeGenOptions const&,
clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef,
llvm::Module*, clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream,
std::default_delete<llvm::raw_pwrite_stream> >) (/scratch/software/clang-
trunk/bin/clang-13+0x3ccfc7d)
#16 0x0000557ae85b775f
clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&)
(/scratch/software/clang-trunk/bin/clang-13+0x4b0675f)
#17 0x0000557ae966f419 clang::ParseAST(clang::Sema&, bool, bool)
(/scratch/software/clang-trunk/bin/clang-13+0x5bbe419)
#18 0x0000557ae85b62a8 clang::CodeGenAction::ExecuteAction()
(/scratch/software/clang-trunk/bin/clang-13+0x4b052a8)
#19 0x0000557ae7e59399 clang::FrontendAction::Execute()
(/scratch/software/clang-trunk/bin/clang-13+0x43a8399)
#20 0x0000557ae7dec3b6
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&)
(/scratch/software/clang-trunk/bin/clang-13+0x433b3b6)
#21 0x0000557ae7f370c0
clang::ExecuteCompilerInvocation(clang::CompilerInstance*)
(/scratch/software/clang-trunk/bin/clang-13+0x44860c0)
#22 0x0000557ae4d29846 cc1_main(llvm::ArrayRef<char const*>, char const*,
void*) (/scratch/software/clang-trunk/bin/clang-13+0x1278846)
#23 0x0000557ae4d25b88 ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&)
driver.cpp:0:0
#24 0x0000557ae4c53156 main (/scratch/software/clang-trunk/bin/clang-
13+0x11a2156)
#25 0x00007f311d8c60b3 __libc_start_main /build/glibc-ZN95T4/glibc-
2.31/csu/../csu/libc-start.c:342:3
#26 0x0000557ae4d256fe _start (/scratch/software/clang-trunk/bin/clang-
13+0x12746fe)
clang-13: error: unable to execute command: Aborted (core dumped)
clang-13: error: clang frontend command failed due to signal (use -v to see
invocation)
clang version 13.0.0 (https://github.com/llvm/llvm-project.git
6b0d266036f73f5ee9556d211a7d0946091ff3b2)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/cnsun/usr/bin
clang-13: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-13: note: diagnostic msg: /tmp/mutant-187aed.c
clang-13: note: diagnostic msg: /tmp/mutant-187aed.sh
clang-13: note: diagnostic msg:

********************
Quuxplusone commented 3 years ago
Note that the whole assertion block:

#ifndef NDEBUG
    // First, verify that we don't have a use of "a" in the instruction
    // (a = b + a for example) because our transformation will not
    // work. This should never occur because we are in SSA form.
    for (unsigned i = 0; i != MI->getNumOperands(); ++i)
      assert(i == DstIdx ||
             !MI->getOperand(i).isReg() ||
             MI->getOperand(i).getReg() != RegA);
#endif

was added a *very* long time ago by Alkis Evlogimenos in r10682:
<https://github.com/llvm/llvm-project/commit/08c5311729b684619e307b561fbecc0095e85bfe>:

Date:   Mon Jan 5 02:25:45 2004 +0000

    Currently we cannot handle two-address instructions of the form:
    A = B op C where A == C, but this cannot really occur in practice
    because of SSA form. Add an assert to check that just to be safe.

    llvm-svn: 10682

So my question to Alkis (and Chris, since he moved some stuff in this pass
around in 2004 too): is this "currently we cannot handle" comment still
applicable at all? Since if you compile LLVM with assertions turned off, this
whole block is now simply skipped, and the resulting assembly appears to work
Just Fine? :)
Quuxplusone commented 3 years ago

Another note is about the minimized test case:

unsigned f(const unsigned char *input) { unsigned crc = ~0; asm("crc32b (%[in]), %[crc]" : "+c"(crc) : [crc] "c"(crc), [in] "r"(input)); return ~crc; }

compiled with gcc (10.3.0) -O1 -S results in:

f: .LFB0: .cfi_startproc movl $-1, %ecx

APP

4 "crc32c_sse42_asm-min-2.c" 1

    crc32b (%rdi), %ecx

0 "" 2

NO_APP

    movl    %ecx, %eax
    notl    %eax
    ret

and compiled with clang (12.0.0, disabled assertions) -O1 -S results in:

f: # @f .cfi_startproc

%bb.0:

    movl    $-1, %ecx
    movl    $-1, %ecx           # <<< huh?
    #APP
    crc32b  (%rdi), %ecx
    #NO_APP
    movl    %ecx, %eax
    notl    %eax
    retq

So for some weird reason, clang duplicates the movl $-1, %ecx instruction? Maybe this is what the assertion originall was trying to guard against?