[LLVMdev] LLVM GHC Backend: Tables Next To Code

Chris Lattner clattner at apple.com
Wed Feb 15 12:16:02 PST 2012


On Feb 14, 2012, at 10:30 AM, David Terei wrote:

> Hmm writing a blog post about TNTC is beyond the time I have right now.

Sure, understandable.  I'm surprised someone else hasn't already :)

> Here is some high level documentation of the layout of Heap objects in GHC:
> 
> http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects#InfoTables
> 
> With TNTC enabled we generate code for closures of this form:
> 
> .text
> 	.align 8
> 	.long	Main_main1_srt-(Main_main1_info)+0
> 	.long	0
> 	.quad	4294967299
> 	.quad	0
> 	.quad	270582939663
> .globl Main_main1_info
> .type Main_main1_info, @object
> Main_main1_info:
> .Lc1Df:
> 	leaq -8(%rbp),%rax
> 	cmpq %r15,%rax
> 	jb .Lc1Dh

Ok.  I'd strongly recommend the approach of generating the table inside the prolog of the function.  This means you'd get something like this:

.text
	.align 8
.globl Main_main1_info
.type Main_main1_info, @object
Main_main1_info:
.Lc1Df:
	jmp .Ltmp
	.long	Main_main1_srt-(Main_main1_info)+0
	.long	0
	.quad	4294967299
	.quad	0
	.quad	270582939663
.Ltmp:
	leaq -8(%rbp),%rax
	cmpq %r15,%rax
	jb .Lc1Dh


Since the jmp is a fixed 2 bytes (0xEB, tablesize), all references to the table can still be done with trivial pc/RIP-relative addressing within the closure, and you just need one pointer for both the table and the closure data.

If you want to get extra special and tricky, you could be even more devious by storing "Main_main1_info + 2 + table size" as the canonical pointer.  If you jump to *that* when dispatching to the closure, then you completely avoid the runtime overhead of the extra unconditional jump and get exactly the same code you're getting with GHC's native code generator.

To access the table in LLVM IR, you'll be generating some truly special (i.e. horrible :) IR along the lines of (e.g. to load the 4294967299 field):

 load (gep (bitcast @Main_main1_info to i64*), 0, 2)

The code generator probably isn't smart enough to turn that into a rip-relative memory access, but adding that should be straight-forward.

The tricky bit will be figuring out how to ensure that the inline asm blob containing the table will come before the standard prolog. Perhaps this can be handled by the existing GHC calling convention, or through creative use of the naked attribute.

-Chris




More information about the llvm-dev mailing list