ldc
ldc copied to clipboard
LLVM does not accept generated inline assembly with variable+offset
Testcase:
void foo()
{
uint[4] a;
asm pure nothrow @nogc {
mov a, EAX;
mov a+4, EBX;
}
}
When compiled with ldc2 -c -fsanitize=address test.d, we get the error:
<inline asm>:1:16: error: unknown token in expression
movl %ebx, 4+(%rcx)
^
LLVM ERROR: Error parsing inline asm
Strangely, when I compile manually to LLVM IR and then use llc to obtain assembly output, everything works fine. So I can't reproduce it from LLVM IR onwards.
The inline asm looks like this in LLVM IR:
call void asm sideeffect "movl %eax, $0\0A\09movl %ebx, 4+$1", "=*m,=*m,~{memory}"([4 x i32]* %3, [4 x i32]* %3)
without -fsanitize=address, the $1 resolves to ebp plus an offset; with -fsanitize=address, the $1 resolves to a register without any offset and that's invalid (i.e. "4+(%rcx)" is not valid but "4+32(%rcx)" is). At least that's what I think is what's going on.
(btw, this prevents compilation of druntime with -fsanitize=address :()
Note: to get equal assembly output from llc as from ldc2, llc must be called with -O0 explicit.
Edit: and with the explicit -O0, I can reproduce it with llc. Perhaps an LLVM bug.
Edit: no, bug in our code: See https://lists.llvm.org/pipermail/llvm-dev/2017-August/116158.html
Testcase without ASan:
void foo()
{
align(32) uint[4] a;
asm pure nothrow @nogc {
mov a+4, EBX;
}
}
LLVM needs some work to support it: https://lists.llvm.org/pipermail/llvm-dev/2017-August/116244.html
There's some inline assembly included by windows.h for 32-bit Windows that triggers this bug—which is a real drag, so I've been toying around with the code that translates DMD-style assembly to LLVM inline assembly, and I think I've come up with a bodge that workarounds the issue: https://github.com/ldc-developers/ldc/pull/4632
There's some inline assembly included by windows.h for 32-bit Windows that triggers this bug
Note that similar problems wrt. missing (gcc) builtins and gcc-style inline assembly also happen on Posix platforms - if a .c file is compiled. Just importing a .c file is sufficient in many cases, when using a higher-level API only and only needing some function and struct declarations - all the inline functions aren't codegen'd nor analyzed in that case, making most problems go away.