Compile fails verification "GEP base pointer is not a vector or a vector of pointers"
Closed this issue · 13 comments
Full error is:
Verifying
GEP base pointer is not a vector or a vector of pointers
%7 = getelementptr inbounds %39, %39 %6, i64 0, i32 4
Error:
Module verification failed: GEP base pointer is not a vector or a vector of pointers
%7 = getelementptr inbounds %39, %39 %6, i64 0, i32 4
Info:
Please file an issue ticket. Use --noverify to bypass this error.
Ubuntu, ponyc version:
0.58.0-a161b7c [release]
Compiled with: LLVM 15.0.7 -- Clang-14.0.0-x86_64
Defaults: pic=true
Minimal Example (https://playground.ponylang.io/?gist=693d41462cb1b63f03eb8ae1a71f14c7)
type CBA is @{(): None}
actor Main
let maintag: Main tag = recover tag this end
new create(env: Env) =>
let act: MyActor[Main tag] = MyActor[Main tag]
actor MyActor[A: Any tag]
let cb: Callbacks[A] = Callbacks[A]
class Callbacks[A: Any tag]
var cbi: CBA = @{() => None}
More minimal:
actor Main
new create(env: Env) => None
let cb: Callbacks = Callbacks
class Callbacks
var cbi: @{(): None}
new create() =>
cbi = @{() => None}
If I change from bare functions to pony lambdas, it compiles and verifies.
actor Main
new create(env: Env) => None
let cb: Callbacks = Callbacks
class Callbacks
var cbi: {(): None}
new create() =>
cbi = {() => None}
If I run this with the --noverify option I get this:
red@adipose:~/projects/minimal$ ponyc --noverify
Building builtin -> /home/red/.local/share/ponyup/ponyc-release-0.58.0-x86_64-linux-ubuntu22.04/packages/builtin
Building . -> /home/red/projects/minimal
Generating
Reachability
Selector painting
Data prototypes
Data types
Function prototypes
Functions
Descriptors
Writing ./minimal.o
LLVM fatal error: Cannot emit physreg copy instruction
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0. Running pass 'Function Pass Manager' on module 'minimal'.
1. Running pass 'Post-RA pseudo instruction expansion pass' on function '@Callbacks_Deserialise'
Aborted (core dumped)
Backtrace:
red@adipose:~/projects/minimal$ lldb -- ponyc --noverify .
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'lldb.embedded_interpreter'
(lldb) target create "ponyc"
Current executable set to 'ponyc' (x86_64).
(lldb) settings set -- target.run-args "--noverify" "."
(lldb) run
Process 10669 launched: '/home/red/.local/share/ponyup/bin/ponyc' (x86_64)
Building builtin -> /home/red/.local/share/ponyup/ponyc-release-0.58.0-x86_64-linux-ubuntu22.04/packages/builtin
Building . -> /home/red/projects/minimal
Generating
Reachability
Selector painting
Data prototypes
Data types
Function prototypes
Functions
Descriptors
Writing ./minimal.o
LLVM fatal error: Cannot emit physreg copy instruction
Process 10669 stopped
* thread #1, name = 'ponyc', stop reason = signal SIGABRT
frame #0: 0x00007ffff7c969fc libc.so.6`__GI___pthread_kill at pthread_kill.c:44:76
(lldb) bt
* thread #1, name = 'ponyc', stop reason = signal SIGABRT
* frame #0: 0x00007ffff7c969fc libc.so.6`__GI___pthread_kill at pthread_kill.c:44:76
frame #1: 0x00007ffff7c969b0 libc.so.6`__GI___pthread_kill [inlined] __pthread_kill_internal(signo=6, threadid=140737352661696) at pthread_kill.c:78:10
frame #2: 0x00007ffff7c969b0 libc.so.6`__GI___pthread_kill(threadid=140737352661696, signo=6) at pthread_kill.c:89:10
frame #3: 0x00007ffff7c42476 libc.so.6`__GI_raise(sig=6) at raise.c:26:13
frame #4: 0x00007ffff7c287f3 libc.so.6`__GI_abort at abort.c:79:7
frame #5: 0x0000555557ba3c3c ponyc`llvm::report_fatal_error(llvm::Twine const&, bool) + 460
frame #6: 0x0000555557ba3a66 ponyc`llvm::report_fatal_error(char const*, bool) + 38
frame #7: 0x0000555556454fe8 ponyc`llvm::X86InstrInfo::copyPhysReg(llvm::MachineBasicBlock&, llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>, llvm::DebugLoc const&, llvm::MCRegister, llvm::MCRegister, bool) const + 2488
frame #8: 0x0000555556a4410a ponyc`(anonymous namespace)::ExpandPostRA::runOnMachineFunction(llvm::MachineFunction&) + 538
frame #9: 0x0000555556b24e5d ponyc`llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 493
frame #10: 0x0000555555d455fc ponyc`llvm::FPPassManager::runOnFunction(llvm::Function&) + 876
frame #11: 0x0000555555d4c853 ponyc`llvm::FPPassManager::runOnModule(llvm::Module&) + 51
frame #12: 0x0000555555d4617f ponyc`llvm::legacy::PassManagerImpl::run(llvm::Module&) + 2335
frame #13: 0x0000555556de1749 ponyc`LLVMTargetMachineEmit(LLVMOpaqueTargetMachine*, LLVMOpaqueModule*, llvm::raw_pwrite_stream&, LLVMCodeGenFileType, char**) + 409
frame #14: 0x0000555556de157c ponyc`LLVMTargetMachineEmitToFile + 172
frame #15: 0x0000555555bd9899 ponyc`genobj + 345
frame #16: 0x0000555555bd4cba ponyc`genexe + 570
frame #17: 0x0000555555bcceef ponyc`codegen + 143
frame #18: 0x0000555555bc62b4 ponyc`main + 884
frame #19: 0x00007ffff7c29d90 libc.so.6`__libc_start_call_main(main=(ponyc`main), argc=3, argv=0x00007fffffffe048) at libc_start_call_main.h:58:16
frame #20: 0x00007ffff7c29e40 libc.so.6`__libc_start_main_impl(main=(ponyc`main), argc=3, argv=0x00007fffffffe048, init=0x00007ffff7ffd040, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffe038) at libc-start.c:392:3
frame #21: 0x0000555555bc5e75 ponyc`_start + 37
(lldb)
The code in verifier that is going "nope"...
void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
Type *TargetTy = GEP.getPointerOperandType()->getScalarType();
Check(isa<PointerType>(TargetTy),
"GEP base pointer is not a vector or a vector of pointers", &GEP);
Check(GEP.getSourceElementType()->isSized(), "GEP into unsized type!", &GEP);
Here's the bad LLVM for when I compile with 0.58.0 locally in release mode:
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
define dso_local void @Callbacks_Deserialise(ptr nocapture readnone %0, ptr nocapture %1) unnamed_addr #9 !pony.abi !2 {
store ptr @10, ptr %1, align 8
%3 = getelementptr inbounds %36, ptr %1, i64 0, i32 1
%4 = load i64, ptr %3, align 8
%5 = getelementptr inbounds [0 x ptr], ptr @21, i64 0, i64 %4
%6 = load %35, ptr %5, align 8
%7 = getelementptr inbounds %35, %35 %6, i64 0, i32 4
%8 = load ptr, ptr addrspace(1) %7, align 8
store ptr %8, ptr %3, align 8
ret void
}
%7
is what goes "kaboom!'
Deserialize in the working code:
define dso_local void @Callbacks_Deserialise(ptr %0, ptr nocapture %1) unnamed_addr !pony.abi !2 {
store ptr @10, ptr %1, align 8
%3 = getelementptr inbounds %30, ptr %1, i64 0, i32 1
%4 = load i64, ptr %3, align 8
%5 = tail call ptr @pony_deserialise_offset(ptr %0, ptr null, i64 %4)
store ptr %5, ptr %3, align 8
ret void
}
@jemc I'm not very familiar with the lambda code. Do you know the difference between TK_BARELAMBDATYPE
and TK_BARELAMBDA
?
Also, any insight into this?
I'm going through to try and find "bare vs normal" lambda differences.
A big one in lambda.c
:
if(bare)
{
BUILD(bare_annotation, *astp,
NODE(TK_ANNOTATION,
ID("ponyint_bare")));
// Record the syntax pass as done to avoid the error about internal
// annotations.
ast_pass_record(bare_annotation, PASS_SYNTAX);
ast_setannotation(*astp, bare_annotation);
}
If we don't set the annotation, we do additional catch up and but don't do syntax (which avoids a compile error that is non-sensical). I'm not sure what else might end up different because of the syntax pass being marked as done.
Removing the call to deserialise_bare_interface
for type TK_INTERFACE in gendeserialise_element
in genserialise.c
gets rid of the issue so, it is something in deserialise_bare_interface
is the problem.
The issue was introduced in 0.54.1 when we switched to LLVM 15.
Code prior:
static void deserialise_bare_interface(compile_t* c, LLVMValueRef ptr)
{
LLVMValueRef type_id = LLVMBuildLoad_P(c->builder, ptr, "");
LLVMValueRef args[2];
args[0] = LLVMConstInt(c->i32, 0, false);
args[1] = LLVMBuildPtrToInt(c->builder, type_id, c->intptr, "");
LLVMValueRef desc = LLVMBuildInBoundsGEP_P(c->builder, c->desc_table, args, 2,
"");
desc = LLVMBuildLoad_P(c->builder, desc, "");
LLVMValueRef func = gendesc_instance(c, desc);
LLVMBuildStore(c->builder, func, ptr);
}
Code after:
static void deserialise_bare_interface(compile_t* c, LLVMValueRef ptr)
{
LLVMValueRef args[2];
args[0] = LLVMConstInt(c->i32, 0, false);
args[1] = LLVMBuildLoad2(c->builder, c->intptr, ptr, "");
LLVMValueRef desc = LLVMBuildInBoundsGEP2(c->builder,
LLVMArrayType(c->ptr, 0), c->desc_table, args, 2, "");
desc = LLVMBuildLoad2(c->builder, c->descriptor_type, desc, "");
LLVMValueRef func = gendesc_instance(c, desc);
LLVMBuildStore(c->builder, func, ptr);
}
@jemc you touched that code last, any ideas?
Try this:
static void deserialise_bare_interface(compile_t* c, LLVMValueRef ptr)
{
LLVMValueRef args[2];
args[0] = LLVMConstInt(c->i32, 0, false);
args[1] = LLVMBuildLoad2(c->builder, c->intptr, ptr, "");
LLVMValueRef desc = LLVMBuildInBoundsGEP2(c->builder,
LLVMArrayType(c->ptr, 0), c->desc_table, args, 2, "");
desc = LLVMBuildLoad2(c->builder, c->ptr, desc, "");
LLVMValueRef func = gendesc_instance(c, desc);
LLVMBuildStore(c->builder, func, ptr);
}
That's the fix!