ldc icon indicating copy to clipboard operation
ldc copied to clipboard

Feature request: enable @callingConvention on function pointers

Open Dadoum opened this issue 1 year ago • 7 comments

In GDC, I can use @attribute("sysv_abi") to force the function to follow the Sys V calling convention.

In LDC, I tried to use @llvmAttr("sysv_abi"), but it didn't change the calling convention in the output.

And thanks for your work, LDC is great.

Dadoum avatar Apr 15 '23 14:04 Dadoum

This might be enough: https://github.com/ldc-developers/ldc/pull/4299

kinke avatar Apr 15 '23 21:04 kinke

Is there a way to add this attribute to a function pointer type?

Dadoum avatar Apr 15 '23 22:04 Dadoum

Is there a way to add this attribute to a function pointer type?

No there isn't yet: https://d.godbolt.org/z/bG1xzsr9b

JohanEngelen avatar Apr 16 '23 10:04 JohanEngelen

There should also be a semantic analysis check for identical calling conventions (function and pointer) on function pointer assignment.

JohanEngelen avatar Apr 16 '23 10:04 JohanEngelen

Is there a way to call one with inline LLVM IR currently? I can't find much documentation about it unfortunately.

Dadoum avatar May 19 '23 16:05 Dadoum

Is there a way to call one with inline LLVM IR currently? I can't find much documentation about it unfortunately.

I think so yes. You can add the calling convention to the call instruction. If you want to see how to do it, I recommend looking at Clang LLVM IR output of similar code using cpp.godbolt.org.

JohanEngelen avatar May 19 '23 21:05 JohanEngelen

I don't know if I should open another issue, but when I compile this:

import std.traits;
version (LDC) {
    import ldc.attributes;
    enum sysv = callingConvention("sysv_abi");
} else version (GNU) {
    import gcc.attributes;
    enum sysv = attribute("sysv_abi");
}
// ...
pragma(inline, false) auto androidInvoke(T, G...)(T delegate_, G params) {
    pragma(inline, true) extern(C) ReturnType!T internal(G params, void* del) @naked @sysv {
        asm {
            "jmp *%0" :: "r" (del);
        }
    }
    return internal(params, cast(void*) delegate_);
}

With GDC, this works flawlessly to call a sysv delegate. With LDC, it doesn't build, and gives this great error. (that's something I saw a lot while fiddling with asm and ir with LDC)

#0 0x00007f7abaa57ba5 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/lib64/llvm15/lib/libLLVM-15.so+0xc57ba5)
 #1 0x00007f7abaa57e2c (/usr/lib64/llvm15/lib/libLLVM-15.so+0xc57e2c)
 #2 0x00007f7abaa554d6 llvm::sys::RunSignalHandlers() (/usr/lib64/llvm15/lib/libLLVM-15.so+0xc554d6)
 #3 0x00007f7abaa5845d (/usr/lib64/llvm15/lib/libLLVM-15.so+0xc5845d)
 #4 0x00007f7ab925fb70 __restore_rt (/lib64/libc.so.6+0x3db70)
 #5 0x00007f7abb28ade2 llvm::SelectionDAGBuilder::visitBitCast(llvm::User const&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x148ade2)
 #6 0x00007f7abb27e5a8 llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x147e5a8)
 #7 0x00007f7abb3298d6 llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, bool&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x15298d6)
 #8 0x00007f7abb329140 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x1529140)
 #9 0x00007f7abb326593 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x1526593)
#10 0x00007f7abd7ae9ac (/usr/lib64/llvm15/lib/libLLVM-15.so+0x39ae9ac)
#11 0x00007f7abae45623 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0x1045623)
#12 0x00007f7ababc1e61 llvm::FPPassManager::runOnFunction(llvm::Function&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0xdc1e61)
#13 0x00007f7ababc8d03 llvm::FPPassManager::runOnModule(llvm::Module&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0xdc8d03)
#14 0x00007f7ababc25e8 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/usr/lib64/llvm15/lib/libLLVM-15.so+0xdc25e8)
#15 0x000000000085d035 (/usr/bin/ldc2+0x85d035)
#16 0x000000000085db98 writeModule(llvm::Module*, char const*) (/usr/bin/ldc2+0x85db98)
#17 0x000000000085b323 ldc::CodeGenerator::writeAndFreeLLModule(char const*) (/usr/bin/ldc2+0x85b323)
#18 0x000000000085b75f ldc::CodeGenerator::emit(Module*) (/usr/bin/ldc2+0x85b75f)
#19 0x0000000000833356 codegenModules(Array<Module*>&) (/usr/bin/ldc2+0x833356)
#20 0x0000000000619e9e mars_mainBody(Param&, Array<char const*>&, Array<char const*>&) (/usr/bin/ldc2+0x619e9e)
#21 0x00000000008318de cppmain() (/usr/bin/ldc2+0x8318de)
#22 0x00007f7ab9da0e0d _D2rt6dmain212_d_run_main2UAAamPUQgZiZ6runAllMFZv (/lib64/libdruntime-ldc-shared.so.102+0xe6e0d)
#23 0x00007f7ab9da0c27 _d_run_main2 (/lib64/libdruntime-ldc-shared.so.102+0xe6c27)
#24 0x00007f7ab9da0a7d _d_run_main (/lib64/libdruntime-ldc-shared.so.102+0xe6a7d)
#25 0x000000000051f3ec main (/usr/bin/ldc2+0x51f3ec)
#26 0x00007f7ab9249b4a __libc_start_call_main (/lib64/libc.so.6+0x27b4a)
#27 0x00007f7ab9249c0b __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x27c0b)
#28 0x0000000000521865 _start (/usr/bin/ldc2+0x521865)

I see that the code is quite hacky, but I don't understand why it fails to build when there is an argument used in the asm.

Dadoum avatar May 20 '23 01:05 Dadoum