systems-nuts / unifico

Compiler and build harness for heterogeneous-ISA binaries with the same stack layout.
4 stars 1 forks source link

BFS compilation segfault #230

Closed blackgeorge-boom closed 1 year ago

blackgeorge-boom commented 1 year ago
 [LLC] app_x86_64_init.o
~/llvm-9/toolchain/bin/llc -function-sections -data-sections -relocation-model=pic --trap-unreachable -optimize-regalloc -fast-isel=false -disable-machine-cse -disable-block-align --mc-relax-all -disable-x86-frame-obj-order -aarch64-csr-alignment=8 -align-bytes-to-four -reg-scavenging-slot -enable-misched=true -mattr=+aarch64-sized-imm,-multiply-with-imm,-non-zero-imm-to-mem,+force-vector-mem-op,+aarch64-constant-cost-model,+simple-reg-offset-addr,+avoid-opt-mul-1 -no-x86-call-frame-opt -march=x86-64 -filetype=obj -o app_x86_64_init.o app_opt.ll
llc: /home/blackgeorge/llvm-project/llvm/lib/CodeGen/StackMaps.cpp:246: const llvm::MachineOperand* llvm::StackMaps::parsePcnOperand(llvm::MachineInstr::const_mop_iterator, llvm::MachineInstr::const_mop_iterator, llvm::StackMaps::LocationVec&, llvm::StackMaps::LiveOutVec&, const llvm::Use*&) const: Assertion `(isAlloca || isTemporary) && "Did not find alloca value for direct memory reference"' failed.
Stack dump:
0.      Program arguments: /home/blackgeorge/llvm-9/toolchain/bin/llc -function-sections -data-sections -relocation-model=pic --trap-unreachable -optimize-regalloc -fast-isel=false -disable-machine-cse -disable-block-align --mc-relax-all -disable-x86-frame-obj-order -aarch64-csr-alignment=8 -align-bytes-to-four -reg-scavenging-slot -enable-misched=true -mattr=+aarch64-sized-imm,-multiply-with-imm,-non-zero-imm-to-mem,+force-vector-mem-op,+aarch64-constant-cost-model,+simple-reg-offset-addr,+avoid-opt-mul-1 -no-x86-call-frame-opt -march=x86-64 -filetype=obj -o app_x86_64_init.o app_opt.ll 
1.      Running pass 'Function Pass Manager' on module 'app_opt.ll'.
2.      Running pass 'X86 Assembly Printer' on function '@coo2csr'
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm3sys15PrintStackTraceERNS_11raw_ostreamE+0x37)[0x558ee332b23f]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x2d4f2d6)[0x558ee332b2d6]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm3sys17RunSignalHandlersEv+0x92)[0x558ee3329170]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x2d4ebc9)[0x558ee332abc9]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x153c0)[0x7f1b129873c0]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xcb)[0x7f1b1242718b]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x12b)[0x7f1b12406859]
/lib/x86_64-linux-gnu/libc.so.6(+0x25729)[0x7f1b12406729]
/lib/x86_64-linux-gnu/libc.so.6(+0x36f36)[0x7f1b12417f36]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZNK4llvm9StackMaps15parsePcnOperandEPKNS_14MachineOperandES3_RNS_11SmallVectorINS0_8LocationELj8EEERNS4_INS0_10LiveOutRegELj8EEERPKNS_3UseE+0x226)[0x558ee277625e]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm9StackMaps22recordPcnStackMapOpersERKNS_12MachineInstrEmPKNS_14MachineOperandES6_b+0x437)[0x558ee2779393]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm9StackMaps17recordPcnStackMapERKNS_12MachineInstrE+0xdc)[0x558ee277a224]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x12dac7f)[0x558ee18b6c7f]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x12def19)[0x558ee18baf19]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm10AsmPrinter16EmitFunctionBodyEv+0x887)[0x558ee2211887]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x12ccf4a)[0x558ee18a8f4a]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm19MachineFunctionPass13runOnFunctionERNS_8FunctionE+0x213)[0x558ee2544d97]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE+0x2c2)[0x558ee2a7b12a]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE+0xd9)[0x558ee2a7b43b]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x249f8c3)[0x558ee2a7b8c3]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE+0x112)[0x558ee2a7c0dc]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_ZN4llvm6legacy11PassManager3runERNS_6ModuleE+0x2b)[0x558ee2a7c2e7]
/home/blackgeorge/llvm-9/toolchain/bin/llc(+0x121cb1c)[0x558ee17f8b1c]
/home/blackgeorge/llvm-9/toolchain/bin/llc(main+0x580)[0x558ee17f7135]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7f1b124080b3]
/home/blackgeorge/llvm-9/toolchain/bin/llc(_start+0x2e)[0x558ee17f52be]
Aborted (core dumped)
blackgeorge-boom commented 1 year ago

This seems like an unhandled case of the current StackMaps infrastructure.

blackgeorge-boom commented 1 year ago

Minimal reproducible example:

#include <stdio.h>

struct S {
    int x, y;
    int* z, w;
};

void f(struct S s) {
    printf("hey!\n");
    s.x++;
    return;
}

int main() {
    struct S s = {1, 2};
    f(s);
}

When passing a struct by value and through memory, LLVM produces an IR of the following form for the callee:

define dso_local void @f(%struct.S* byval(%struct.S) align 8 %s) #0 {   <---
entry:
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @main__str_hey___, i64 0, i64 0)) #3
  call void (i64, i32, ...) @llvm.experimental.pcn.stackmap(i64 0, i32 0, %struct.S* %s)   <---
  %x = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 0
...
  ret void
}

The struct parameter %s has the attribute byval. This implies that the value is passed through memory, but also that the callee cannot modify the value of the caller (even though the argument is a pointer, because there is an implicit copy at the time of the call): https://discourse.llvm.org/t/how-does-byval-work/62397.

The problem with the Popcorn StackMaps is that they record the live value of struct %s as simply %struct.S* %s, without including the byval attribute as in the function definition. However, they can only handle pointers that are either temporary values or allocas, while %s is technically neither of the two (it doesn't have an alloca like a usual parameter, because of the byval attribute).

blackgeorge-boom commented 1 year ago

As a quick fix, we can modify the struct parameter and pass it through a pointer instead, without affecting the semantics of the program since it won't modify the contents of the pointer. The result is the following:

#include <stdio.h>

struct S {
    int x, y;
    int* z, w;
};

void f(struct S *s) {
    printf("hey!\n");
    s->x++;
    return;
}

int main() {
    struct S s = {1, 2};
    f(&s);
}

and

define dso_local void @f(%struct.S* %s) #0 {   <---
entry:
  %s.addr = alloca %struct.S*, align 8   <---
  store %struct.S* %s, %struct.S** %s.addr, align 8
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @main__str_hey___, i64 0, i64 0)) #3
  call void (i64, i32, ...) @llvm.experimental.pcn.stackmap(i64 0, i32 0, %struct.S** %s.addr)   <---
...
  ret void
}

Now, the StackMaps are recorded properly.

blackgeorge-boom commented 1 year ago

As a side note, if the struct that is passed by value, could fit in the argument registers after coercion of its fields, instead of being passed through memory, there would not be an issue:

#include <stdio.h>

struct S {
    int x, y;
};

void f(struct S s) {
    printf("hey!\n");
    s.x++;
    return;
}

int main() {
    struct S s = {1, 2};
    f(s);
}

and:

define dso_local void @f(i64 %s.coerce) #0 {   <---
entry:
  %s = alloca %struct.S, align 4   <---
  %0 = bitcast %struct.S* %s to i64*
  store i64 %s.coerce, i64* %0, align 4
  %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @main__str_hey___, i64 0, i64 0)) #3
  call void (i64, i32, ...) @llvm.experimental.pcn.stackmap(i64 0, i32 0, %struct.S* %s)   <---
...
  ret void
}

Notice that the struct that has only two integers is passed through an i64 register and is properly recorded in the stackmaps.

blackgeorge-boom commented 1 year ago

Closing this for now.