Skip to content

Instantly share code, notes, and snippets.

@kavon
Last active April 19, 2017 14:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kavon/b80db874cf168bd0625cdd8ef7464f56 to your computer and use it in GitHub Desktop.
Save kavon/b80db874cf168bd0625cdd8ef7464f56 to your computer and use it in GitHub Desktop.
CPS Call Proposal Examples
;;;;;
; (1) a complete example
;;;;;
define cc18 {i8**, i64} @foo (i8** %sp, i64 %x) noinline {
store i8* blockaddress (@foo, %retpt), i8** %sp
%retV = call cc18 {i8**, i64} @bar(i8** %sp, i64 %x) ; the 'cps' call
br label %retpt
retpt:
; load parameters of this block
%newSP.x = extractvalue {i8**, i64} %retV, 1
%y.x = extractvalue {i8**, i64} %retV, 0
;;;;;
%y = ptrtoint i8** %y.x to i64
%newSP = inttoptr i64 %newSP.x to i8**
;;;;;
; perform a CPS return from @foo
%retAddr = load i8*, i8** %newSP
%retAddr1 = bitcast i8* %retAddr to {i8**, i64} (i8**, i64)*
%dummy = musttail call cc18 {i8**, i64} %retAddr1 (i8** %newSP, i64 %y)
ret {i8**, i64} %dummy
}
define cc18 {i8**, i64} @bar (i8** %sp, i64 %y) noinline {
%y1 = add i64 %y, 1
; perform a CPS return from @bar
%retAddr = load i8*, i8** %sp
%retAddr1 = bitcast i8* %retAddr to {i8**, i64} (i8**, i64)*
;;;;;
; for fun, move SP to another register when returning
%sp.1 = ptrtoint i8** %sp to i64
%y1.1 = inttoptr i64 %y1 to i8**
;;;;;
%dummy = musttail call cc18 {i8**, i64} %retAddr1 (i8** %y1.1, i64 %sp.1)
ret {i8**, i64} %dummy
}
+++++++++++++++++++++++++++++++++
+ What ISEL would produce for @foo with a custom lowering of the call.
+ the important parts are blocked off with plus symbols
+ (note: the numbers are messed up but this is the basic idea)
+++++++++++++++++++++++++++++++++
=== foo
Initial selection DAG: BB#0 'foo:'
SelectionDAG has 29 nodes:
t0: ch = EntryToken
t2: i64,ch = CopyFromReg t0, Register:i64 %vreg2
t6: i64 = Constant<0>
t9: i64 = GlobalAddress<{ i8**, i64 } (i8**, i64)* @bar> 0
t8: ch = store<ST8[%sp]> t0, BlockAddress:i64<@foo, %retpt> 0, t2, undef:i64
t11: ch,glue = callseq_start t8, TargetConstant:i64<0>
t13: ch,glue = CopyToReg t11, Register:i64 %RSI, t2
t4: i64,ch = CopyFromReg t0, Register:i64 %vreg3
t15: ch,glue = CopyToReg t13, Register:i64 %R11, t4, t13:1
++++++++++++++++++++++++ now a tail call ++++++++++++++++++++++++
t19: ch,glue = callseq_end t18, TargetConstant:i64<0>, TargetConstant:i64<0>, t18:1
t18: ch,glue = X86ISD::TC_RETURN t15, TargetGlobalAddress:i64<{ i8**, i64 } (i8**, i64)* @bar> 0, Register:i64 %RSI, Register:i64 %R11, RegisterMask:Untyped, t15:1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Initial selection DAG: BB#1 'foo:retpt'
SelectionDAG has 19 nodes:
t0: ch = EntryToken
++++++++ these were sunk from BB#0, appearing after call to @bar ++++++++++
t20: i64,ch,glue = CopyFromReg t19, Register:i64 %RSI, t19:1
t21: i64,ch,glue = CopyFromReg t20:1, Register:i64 %R11, t20:2
t22: i64,i64 = merge_values t20, t21
t24: ch = CopyToReg t0, Register:i64 %vreg0, t22
t26: ch = CopyToReg t0, Register:i64 %vreg1, t22:1
t27: ch = TokenFactor t24, t26
t28: ch = TokenFactor t27, t21:1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
t2: i64,ch = CopyFromReg t0, Register:i64 %vreg0
t4: i64,ch = CopyFromReg t2:1, Register:i64 %vreg1
t5: i64,i64 = merge_values t2, t4
t6: i64 = Constant<0>
t8: i64,ch = load<LD8[%newSP]> t0, t5:1, undef:i64
t10: ch,glue = callseq_start t8:1, TargetConstant:i64<0>
t12: ch,glue = CopyToReg t10, Register:i64 %RSI, t5:1
t14: ch,glue = CopyToReg t12, Register:i64 %R11, t5, t12:1
t15: ch,glue = callseq_end t14, TargetConstant:i64<0>, TargetConstant:i64<0>, t14:1
t18: ch,glue = X86ISD::TC_RETURN t15, t8, Constant:i32<0>, Register:i64 %RSI, Register:i64 %R11, RegisterMask:Untyped, t15:1
######
# (3) this is currently produced by llc (with a custom cc18 convention patch) for the cps_call.ll example.
# I have noted the areas that should fix this output using the isel idea.
######
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 11
.globl _foo
.align 4, 0x90
_foo: ## @foo
.cfi_startproc
## BB#0:
pushq %rax
Ltmp0:
.cfi_def_cfa_offset 16
leaq Ltmp1(%rip), %rax
movq %rax, (%rsi)
callq _bar # <-- will instead lower to: jmp _bar
movq %rsi, %rax # <-- will be sunk during isel
Ltmp1: ## Block address taken
## BB#1: ## %retpt
movq (%r11), %rcx
movq %r11, %rsi
movq %rax, %r11
popq %rax
jmpq *%rcx ## TAILCALL
.cfi_endproc
.globl _bar
.align 4, 0x90
_bar: ## @bar
.cfi_startproc
## BB#0:
pushq %rax
Ltmp2:
.cfi_def_cfa_offset 16
movq %rsi, %rax
leaq 1(%r11), %rsi
movq (%rax), %rcx
movq %rax, %r11
popq %rax
jmpq *%rcx ## TAILCALL
.cfi_endproc
.subsections_via_symbols
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment