ldc icon indicating copy to clipboard operation
ldc copied to clipboard

cross module inlining fails when code contains switch with string argument and at least 7 cases

Open KytoDragon opened this issue 10 months ago • 4 comments

The following code

int main(string[] a) {
    switch (a[0]) {
        case "one":
            return 1;
        case "two":
            return 2;
        case "three":
            return 3;
        case "four":
            return 4;
        case "five":
            return 5;
        case "six":
            return 6;
        case "seven":
            return 7;
        default:
            return 0;
    }
}

when compiled with these options:

ldc2 -enable-inlining --enable-cross-module-inlining=true -Isource source\main.d -ofd-test.exe -link-internally

results in the following error:

lld-link: error: undefined symbol: _D4core8internal7switch___T8__switchTyaVxAyaa3_6f6e65VxQoa3_736978VxQBba3_74776fVxQBpa4_66697665VxQCfa4_666f7572VxQCva5_736576656eVxQDna5_7468726565ZQEsFNaNbNiNfMxQEsZ5casesyG7Aa
>>> referenced by d-test.obj:(_D4core8internal7switch___T8__switchTyaVxAyaa3_6f6e65VxQoa3_736978VxQBba3_74776fVxQBpa4_66697665VxQCfa4_666f7572VxQCva5_736576656eVxQDna5_7468726565ZQEsFNaNbNiNfMxQEsZi)
Error: linking with LLD failed

The identifier in question is defined in druntime here. Tested on Windows 10 with LDC 1.40.0.

KytoDragon avatar Dec 31 '24 11:12 KytoDragon

Can you help out and test with a small testcase whether cross-module inlining works for static variables inside the inlined function? Thanks

JohanEngelen avatar Dec 31 '24 13:12 JohanEngelen

I can confirm this bug on linux as well. I also confirmed the bug is present in the case when all of the variables are static ones inside of the function (though I now realize this is probably not what you meant):

(ldc-1.40.0)alex@compy  programming/ldc-bug-test cat source/app.d                                            22:25:09 25-01-20
import std.stdio;

int main(string[] args)
{
    static immutable string ONE = "one";
    static immutable string TWO = "two";
    static immutable string THREE = "three";
    static immutable string FOUR = "four";
    static immutable string FIVE = "five";
    static immutable string SIX = "six";
    static immutable string SEVEN = "seven";
    static immutable string testcase="asdf";
    //switch (args[0]) {
    switch (testcase) {
        case ONE:
            return 1;
        case TWO:
            return 2;
        case THREE:
            return 3;
        case FOUR:
            return 4;
        case FIVE:
            return 5;
        case SIX:
            return 6;
        case SEVEN:
            return 7;
        default:
            return 0;
    }
}
(ldc-1.40.0)alex@compy  programming/ldc-bug-test dub build --verbose --compiler=ldc2 --force -b release 2>&1 | ddemangle
Note: Failed to determine version of package ldc-bug-test at .. Assuming ~master.
Generating using build
Configuring dependent ldc-bug-test, deps:
    Starting Performing "release" build using ldc2 for x86_64.
    Building ldc-bug-test ~master: building configuration [application]
ldc2 -release -enable-inlining -Hkeep-all-bodies -O3 -w --oq -od=/home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ/obj -d-version=Have_ldc_bug_test -Isource/ source/app.d --enable-cross-module-inlining -c -of/home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ/ldc-bug-test.o -vcolumns
     Linking ldc-bug-test
ldc2 -of/home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ/ldc-bug-test /home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ/ldc-bug-test.o -L--no-as-needed
/usr/bin/ld: /home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ/ldc-bug-test.o: in function `_Dmain':
app.d:(.text._Dmain+0xb): undefined reference to `immutable(char[][7]) core.internal.switch_.__switch!(immutable(char), "one", "six", "two", "five", "four", "seven", "three").__switch(scope const(immutable(char)[])).cases'
collect2: error: ld returned 1 exit status
Error: /usr/bin/cc failed with status: 1
FAIL /home/alex/.dub/cache/ldc-bug-test/~master/build/application-release-Q_nYxZRIsAfltX3Ha9-VnQ ldc-bug-test executable
Error ldc2 failed with exit code 1.
(ldc-1.40.0)alex@compy  programming/ldc-bug-test ldc2 --version                                              22:25:14 25-01-20
LDC - the LLVM D compiler (1.40.0):
  based on DMD v2.110.0 and LLVM 19.1.3
  built with LDC - the LLVM D compiler (1.40.0)
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver4
  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
    xtensa      - Xtensa 32

apbryan avatar Jan 21 '25 03:01 apbryan

Here is what I think you actually wanted:

alex@compy  programming/ldc-bug-test2 tree                                                                   22:57:55 25-01-20
.
├── dub.sdl
├── foo
│   ├── dub.sdl
│   ├── libfoo.a
│   └── source
│       └── foo.d
├── ldc-bug-test2
└── source
    └── app.d

4 directories, 6 files
alex@compy  programming/ldc-bug-test2 cat dub.sdl                                                            22:57:57 25-01-20
name "ldc-bug-test2"
description "A minimal D application."
authors "alex"
copyright "Copyright © 2025, alex"
license "MPL-2.0"

dflags "--enable-cross-module-inlining" platform="ldc"

dependency "foo" path="./foo"
alex@compy  programming/ldc-bug-test2 cat source/app.d                                                       22:58:04 25-01-20
import std.stdio;
import foo;

void main()
{
    int a = doFoo!(["one", "two"])(1);
	writeln(a);
}
alex@compy  programming/ldc-bug-test2 cat foo/dub.sdl                                                        22:58:11 25-01-20
name "foo"
description "A minimal D application."
authors "alex"
copyright "Copyright © 2025, alex"
license "MPL-2.0"
alex@compy  programming/ldc-bug-test2 cat foo/source/foo.d                                                   22:58:19 25-01-20
module foo.foo;
import std.math;

int doFoo(labels...)(int a)
{
    //static immutable int[labels.length] b; // does not compile when line uncommented
    immutable int[labels.length] b;  //compiles
    return a + b[0];
}
alex@compy  programming/ldc-bug-test2 dub clean                                                              22:58:30 25-01-20
    Cleaning artifacts for package ldc-bug-test2 at /home/alex/.dub/cache/ldc-bug-test2/~master
alex@compy  programming/ldc-bug-test2 dub build --compiler=ldc2 -b release 2>&1 --verbose | ddemangle        22:59:11 25-01-20
Note: Failed to determine version of package ldc-bug-test2 at .. Assuming ~master.
  Version selection for dependency foo (foo) of ldc-bug-test2 is missing.
  Adding local foo in /home/alex/programming/ldc-bug-test2/foo
Note: Failed to determine version of package foo at .. Assuming ~master.
  Found dependency foo @./foo
Generating using build
Configuring dependent ldc-bug-test2, deps:"foo"
  Configuring dependent foo, deps:
    Starting Performing "release" build using ldc2 for x86_64.
  Up-to-date foo ~master: target for configuration [library] is up to date.
Using existing build in /home/alex/.dub/cache/foo/~master/build/library-release-HSpfiB7qMGgJmWdFzlw2rQ.
Copying target from /home/alex/.dub/cache/foo/~master/build/library-release-HSpfiB7qMGgJmWdFzlw2rQ/libfoo.a to /home/alex/programming/ldc-bug-test2/foo
Target '/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2' doesn't exist, need rebuild.
    Building ldc-bug-test2 ~master: building configuration [application]
ldc2 -release -enable-inlining -Hkeep-all-bodies -O3 -w --oq -od=/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/obj -d-version=Have_ldc_bug_test2 -d-version=Have_foo -Isource/ -Ifoo/source/ source/app.d --enable-cross-module-inlining -c -of/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o -vcolumns
     Linking ldc-bug-test2
ldc2 -of/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2 /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o ../../.dub/cache/foo/~master/build/library-release-HSpfiB7qMGgJmWdFzlw2rQ/libfoo.a -L--no-as-needed
/usr/bin/ld: /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o: in function `_Dmain':
app.d:(.text._Dmain+0x8): undefined reference to `immutable(int[1]) foo.foo.doFoo!(["one", "two"]).doFoo(int).b'
collect2: error: ld returned 1 exit status
Error: /usr/bin/cc failed with status: 1
FAIL /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g ldc-bug-test2 executable
Error ldc2 failed with exit code 1.

apbryan avatar Jan 21 '25 04:01 apbryan

When dub is run with --combined, the project does compile:

## Without --combined
alex@compy  programming/ldc-bug-test2 dub clean                                                                                                         20:50:43 25-01-21
    Cleaning artifacts for package ldc-bug-test2 at /home/alex/.dub/cache/ldc-bug-test2/~master
alex@compy  programming/ldc-bug-test2 dub build -b release --compiler=ldc2                                                                              20:50:45 25-01-21
    Starting Performing "release" build using ldc2 for x86_64.
    Building foo ~master: building configuration [library]
    Building ldc-bug-test2 ~master: building configuration [application]
     Linking ldc-bug-test2
/usr/bin/ld: /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o: in function `_Dmain':
app.d:(.text._Dmain+0x8): undefined reference to `_D3foo__T5doFooVAAyaA2a3_6f6e65a3_74776fZQBgFiZ1byG1i'
collect2: error: ld returned 1 exit status
Error: /usr/bin/cc failed with status: 1
Error ldc2 failed with exit code 1.


## With combined
alex@compy  programming/ldc-bug-test2 dub clean                                                                                                         20:50:49 25-01-21
    Cleaning artifacts for package ldc-bug-test2 at /home/alex/.dub/cache/ldc-bug-test2/~master
alex@compy  programming/ldc-bug-test2 dub build -b release --compiler=ldc2 --combined                                                                   20:50:52 25-01-21
    Starting Performing "release" build using ldc2 for x86_64.
    Building ldc-bug-test2 ~master: building configuration [application]
     Linking ldc-bug-test2

EDIT: --combined verbose output:

alex@compy  programming/ldc-bug-test2 dub clean                                                                                                         20:50:57 25-01-21
    Cleaning artifacts for package ldc-bug-test2 at /home/alex/.dub/cache/ldc-bug-test2/~master
alex@compy  programming/ldc-bug-test2 dub build -b release --compiler=ldc2 --combined --verbose                                                         20:54:54 25-01-21
Note: Failed to determine version of package ldc-bug-test2 at .. Assuming ~master.
  Version selection for dependency foo (foo) of ldc-bug-test2 is missing.
  Adding local foo in /home/alex/programming/ldc-bug-test2/foo
Note: Failed to determine version of package foo at .. Assuming ~master.
  Found dependency foo @./foo
Generating using build
Configuring dependent ldc-bug-test2, deps:
    Starting Performing "release" build using ldc2 for x86_64.
Target '/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2' doesn't exist, need rebuild.
    Building ldc-bug-test2 ~master: building configuration [application]
ldc2 -release -enable-inlining -Hkeep-all-bodies -O3 -w --oq -od=/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/obj -d-version=Have_ldc_bug_test2 -d-version=Have_foo -Isource/ -Ifoo/source/ source/app.d foo/source/foo.d --enable-cross-module-inlining -c -of/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o -vcolumns
     Linking ldc-bug-test2
ldc2 -of/home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2 /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2.o -L--no-as-needed
Copying target from /home/alex/.dub/cache/ldc-bug-test2/~master/build/application-release-NexKB60AKoQrI6295VyB-g/ldc-bug-test2 to /home/alex/programming/ldc-bug-test2

apbryan avatar Jan 22 '25 01:01 apbryan