It seems like LLVM happily creates function calls that pass in labels
but doesn't know how to emit them.
For the source c code:
__asm__ __volatile__ ( ".byte 0x0f, 0x36, 0x00" : : "a" (&&label) : "memory" );
llvm-g++ -emit-llvm generates:
tail call void asm sideeffect ".byte 0x0f, 0x36, 0x00",
"{ax},~{dirflag},~{fpsr},~{flags},~{memory}"( label %label ) nounwind
However, trying to assemble x86 binaries fails:
cc1plus: /mounts/zion/disks/0/localhome/tbrethou/2.2/testing/llvm-2.2/include/llvm/CodeGen/ValueTypes.h:212:
unsigned int llvm::MVT::getSizeInBits(llvm::MVT::ValueType): Assertion
`isExtendedVT(VT) && "ValueType has no known size!"' failed.
At global scope: internal compiler error: Aborted
This also happens if I craft my own function to take a label and llvm-as:
declare void @foo(label)
call void @bar( label %label )
llvm-as[0x826fa54]
llvm-as[0x826fd1a]
[0x8cd420]
llvm-as(llvm::PATypeHolder::operator llvm::Type*() const+0x11)[0x816e93b]
llvm-as(llvm::Value::getType() const+0x14)[0x816e952]
llvm-as(llvmAsmparse()+0xccc4)[0x818a14e]
llvm-as[0x818c15c]
llvm-as(llvm::RunVMAsmParser(std::basic_string<char,
std::char_traits<char>, std::allocator<char> > const&,
_IO_FILE*)+0x4a)[0x818c5aa]
llvm-as(llvm::ParseAssemblyFile(std::basic_string<char,
std::char_traits<char>, std::allocator<char> > const&,
llvm::ParseError*)+0xf3)[0x8178d65]
llvm-as(main+0x84)[0x815aeb6]
/lib/libc.so.6(__libc_start_main+0xdc)[0x6e8dec]
llvm-as(__gxx_personality_v0+0x2a9)[0x815aa81]
llvm-as: llvm version 2.0 DEBUG build with assertions.
llvm-g++: gcc version 4.2.1 (Based on Apple Inc. build 5546) (LLVM build 2.2)
Ed
Yep, this isn't supported. We can't quite enforce it as invalid at this moment, but don't expect it to work. The only think you can do with labels is branch/switch/invoke to them and use them as the block operand to phi nodes.
Note that using the address of a label in GCC for anything other than an indirect jump is also undefined and doesn't work in general.
-Chris
That's a little bit disappointing for me. Is there some way in LLVM to
get the address of a label and put it in a register for use within
that function?
I'm using a special instruction that effectively branches to the value
in that register.
pseudo-LLVM:
%tmp = label %label
br label %tmp
Except it doesn't behave like a (un)conditional branch of course;
otherwise, I would just use the standard LLVM BranchInst.
Ed
No. The reason we don't allow this is because it violates the CFG. The compiler needs to know where and how control flow happens so that dataflow analysis and code motion does not corrupt the behavior of the program being compiled.
We do plan to eventually optimize indirect goto more aggressively, but this is a big and nasty project.
-Chris
So if I *don't* violate the CFG, would I still need to do something
close to "big and nasty"?
; save the address of %otherPath to use later
call @llvm.checkpoint(label %otherPath)
; trick the rest of the compiler to think data flows to both paths *from here*
br i1 @opaqueButAlwaysTrue, label %normalPath, label %otherPath
normalPath:
; do some work..
call void @work()
; rollback and erase any data changes since the checkpoint and
; continue at the label given to @checkpoint
call @llvm.rollback()
unreachable
otherPath:
; we arrive here because @rollback reverted data to @checkpoint
; and it said to go to label %otherPath
Right now I'm looking into making a new Inst that inherits BranchInst
because I can give it BasicBlock*/labels and potentially change the
CodeGen to emit a series of x86 instructions that does the
functionality while not being optimized away by the rest of the
compiler.
Ed
No. The reason we don't allow this is because it violates the CFG.
So if I *don't* violate the CFG, would I still need to do something
close to "big and nasty"?
It sounds like you're doing something STM like, have you contacted Torvald to see if he has ideas or insight?
http://llvm.org/pubs/2008-02-23-TRANSACT-TangerObjBased.html
-Chris
Yeah, this is TM-like with the begin/end/abort+rollback. Thanks for
the pointer, but it seems like Tanger's implementation doesn't support
explicit aborts probably "Because our txns never abort." So there
wasn't a need to give a label to tanger_begin() to lead to an abort
block.
Ed
Tanger uses setjmp to jump back to the begin() after rolling back memory
updates. This is rather brute-force and custom-build stack rollback and
jumping back to begin could be faster, but it works. Tanger assumes that
transactions are used like "atomic { }" blocks, so a transaction nevers
starts and ends in different functions, for example.
BTW, supporting application-controlled rollback would be very easy (just allow
applications to call the STM abort function).
Torvald