ldc icon indicating copy to clipboard operation
ldc copied to clipboard

Code gen bug

Open jamesragray opened this issue 1 year ago • 6 comments

The code:

struct Ele { long target; size_t n; }

struct NumWays {
	long[] using;
	long[Ele] lookup;
	auto find(long target, size_t n) {
		if(n==0) { return target==0; }
		if(target < using[n]) { return 0; }
		auto ret = find(target-using[n],n-1) + find(target,n-1);
		if(auto ptr = Ele(target,n) in lookup) { return *ptr; }
		return ret;
	}
}

void main(string[] args) {
}

when compiled with ldc2 produces:

Invalid bitcast
  %54 = bitcast i64 %53 to i32
LLVM ERROR: Broken module found, compilation aborted!
 #0 0x000058d081240cd7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6dcbcd7)
 #1 0x000058d08123eacc llvm::sys::RunSignalHandlers() (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6dc9acc)
 #2 0x000058d08124137f SignalHandler(int) Signals.cpp:0:0
 #3 0x0000713c7bc42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x0000713c7bc969fc __pthread_kill_implementation ./nptl/./nptl/pthread_kill.c:44:76
 #5 0x0000713c7bc969fc __pthread_kill_internal ./nptl/./nptl/pthread_kill.c:78:10
 #6 0x0000713c7bc969fc pthread_kill ./nptl/./nptl/pthread_kill.c:89:10
 #7 0x0000713c7bc42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x0000713c7bc287f3 abort ./stdlib/./stdlib/abort.c:81:7
 #9 0x000058d0811a99b2 llvm::report_fatal_error(llvm::Twine const&, bool) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6d349b2)
#10 0x000058d0811a97e6 (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6d347e6)
#11 0x000058d081038bcc (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6bc3bcc)
#12 0x000058d08151cc4d llvm::detail::PassModel<llvm::Module, llvm::VerifierPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module> >::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) ld-temp.o:0:0
#13 0x000058d08100f834 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> >::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x6b9a834)
#14 0x000058d081516ec6 runOptimizationPasses(llvm::Module*) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x70a1ec6)
#15 0x000058d0815a6ade writeModule(llvm::Module*, char const*) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x7131ade)
#16 0x000058d0815a5baa ldc::CodeGenerator::writeAndFreeLLModule(char const*) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x7130baa)
#17 0x000058d07dfe4e90 codegenModules(Array<Module*>&) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x3b6fe90)
#18 0x000058d07df83dc1 mars_tryMain(Param&, Array<char const*>&) (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x3b0edc1)
#19 0x000058d07dfe7ac0 cppmain() (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x3b72ac0)
#20 0x000058d0817610fd _D2rt6dmain212_d_run_main2UAAamPUQgZiZ6runAllMFZv (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x72ec0fd)
#21 0x000058d081760ed8 _d_run_main2 (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x72ebed8)
#22 0x000058d081760ced _d_run_main (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x72ebced)
#23 0x000058d0815a31c8 main (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x712e1c8)
#24 0x0000713c7bc29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#25 0x0000713c7bc29e40 call_init ./csu/../csu/libc-start.c:128:20
#26 0x0000713c7bc29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#27 0x000058d07dfec37e _start (/home/james/dlang/ldc-1.39.0/bin/ldc2+0x3b7737e)
Aborted (core dumped)

ldc2 version produces:

LDC - the LLVM D compiler (1.39.0):
  based on DMD v2.109.1 and LLVM 18.1.6
  built with LDC - the LLVM D compiler (1.39.0)
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver2
  http://dlang.org - http://wiki.dlang.org/LDC


  Registered Targets:
    aarch64     - AArch64 (little endian)
    aarch64_32  - AArch64 (little endian ILP32)
    aarch64_be  - AArch64 (big endian)
    amdgcn      - AMD GCN GPUs
    arm         - ARM
    arm64       - ARM64 (little endian)
    arm64_32    - ARM64 (little endian ILP32)
    armeb       - ARM (big endian)
    avr         - Atmel AVR Microcontroller
    bpf         - BPF (host endian)
    bpfeb       - BPF (big endian)
    bpfel       - BPF (little endian)
    hexagon     - Hexagon
    lanai       - Lanai
    loongarch32 - 32-bit LoongArch
    loongarch64 - 64-bit LoongArch
    mips        - MIPS (32-bit big endian)
    mips64      - MIPS (64-bit big endian)
    mips64el    - MIPS (64-bit little endian)
    mipsel      - MIPS (32-bit little endian)
    msp430      - MSP430 [experimental]
    nvptx       - NVIDIA PTX 32-bit
    nvptx64     - NVIDIA PTX 64-bit
    ppc32       - PowerPC 32
    ppc32le     - PowerPC 32 LE
    ppc64       - PowerPC 64
    ppc64le     - PowerPC 64 LE
    r600        - AMD GPUs HD2XXX-HD6XXX
    riscv32     - 32-bit RISC-V
    riscv64     - 64-bit RISC-V
    sparc       - Sparc
    sparcel     - Sparc LE
    sparcv9     - Sparc V9
    spirv       - SPIR-V Logical
    spirv32     - SPIR-V 32-bit
    spirv64     - SPIR-V 64-bit
    systemz     - SystemZ
    thumb       - Thumb
    thumbeb     - Thumb (big endian)
    ve          - VE
    wasm32      - WebAssembly 32-bit
    wasm64      - WebAssembly 64-bit
    x86         - 32-bit X86: Pentium-Pro and above
    x86-64      - 64-bit X86: EM64T and AMD64
    xcore       - XCore

jamesragray avatar Dec 30 '24 11:12 jamesragray

Also replacing auto find... by long find... causes it to go away.

thewilsonator avatar Dec 30 '24 11:12 thewilsonator

Looks like a frontend issue at first glance - the type of ret is a 32-bit integer, making no sense.

Edit: To be precise, even the recursive find() invocation results are 32-bit.

kinke avatar Dec 30 '24 16:12 kinke

AST output does correctly infer long: https://d.godbolt.org/z/TdW41qn81

JohanEngelen avatar Dec 30 '24 19:12 JohanEngelen

AST output does correctly infer long: https://d.godbolt.org/z/TdW41qn81

I think the problem is this:

int ret = this.find(target - this.using[n], n - 1LU) + this.find(target, n - 1LU);

This code is lowered to

  %29 = sub i64 %28, 1, !dbg !68                  ; [#uses = 1] [debug line = bug.d:9:3]
  %30 = call i64 @_D3bug7NumWays4findMFNaNbNiNflmZl(ptr nonnull %.this_arg, i64 %27, i64 %29) #0, !dbg !68 ; [#uses = 1] [debug line = bug.d:9:3] [display name = find]
  %31 = add i64 %26, %30, !dbg !68                ; [#uses = 1] [debug line = bug.d:9:3]
  %32 = bitcast i64 %31 to i32, !dbg !68          ; [#uses = 1] [debug line = bug.d:9:3]

liushuyu avatar Feb 28 '25 13:02 liushuyu

The problem is definitely in the frontend.

kinke avatar Feb 28 '25 14:02 kinke

I have made a simpler reproducer:

extern (C) long stub();

auto recursive(long a, size_t n)
{
    if (a < n)
        return 0;
    auto ret = recursive(a, n);
    if (n < 10)
        return stub();
    return ret;
}

The condition to trigger the bug is this: the recursive function call-site is sandwiched between two other usages that also need type inference.

liushuyu avatar Feb 28 '25 14:02 liushuyu