-
-
Save amitin/7df4fbb806c0b48eb5bcaf614e5d93cd to your computer and use it in GitHub Desktop.
Illustrate for an issue related to custom CC and tail-call elimination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.10) | |
project(testllvm C) | |
set(CMAKE_C_STANDARD 99) | |
add_executable(testllvm test.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct _Context { | |
int data1; | |
int data2; | |
} Context; | |
typedef int CallFunc(Context*, int); | |
CallFunc handlerFunc0, handlerFunc1, terminatorFunc; | |
CallFunc *funcTable[] = { | |
handlerFunc0, | |
handlerFunc1, | |
terminatorFunc | |
}; | |
int starterFunc(Context *ctx) | |
{ | |
int startValue = ctx->data1 > ctx->data2 ? 1 : 0; | |
CallFunc *func = funcTable[startValue]; | |
int res = func(ctx, startValue); | |
if (res) { | |
ctx->data2 = res; | |
} else { | |
ctx->data1 = res; | |
} | |
return res; | |
} | |
int terminatorFunc(Context* ctx, int arg0) | |
{ | |
return arg0; | |
} | |
int handlerFunc0(Context* ctx, int arg0) | |
{ | |
ctx->data1++; | |
printf("Hello handlerFunc0!\n"); | |
return funcTable[++arg0](ctx, arg0); | |
} | |
int handlerFunc1(Context* ctx, int arg0) | |
{ | |
ctx->data2++; | |
printf("Hello handlerFunc1!\n"); | |
return funcTable[++arg0](ctx, arg0); | |
} | |
int main() | |
{ | |
Context ctx = {5, 6}; | |
return starterFunc(&ctx); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ModuleID = 'test.c' | |
source_filename = "test.c" | |
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" | |
target triple = "armv7-unknown-linux-gnueabihf" | |
; target triple = "x86_64-unknown-linux" | |
%struct._Context = type { i32, i32 } | |
@funcTable = dso_local local_unnamed_addr global [3 x i32 (%struct._Context*, i32)*] [i32 (%struct._Context*, i32)* @handlerFunc0, i32 (%struct._Context*, i32)* @handlerFunc1, i32 (%struct._Context*, i32)* @terminatorFunc], align 4 | |
@str = private unnamed_addr constant [20 x i8] c"Hello handlerFunc0!\00" | |
@str.2 = private unnamed_addr constant [20 x i8] c"Hello handlerFunc1!\00" | |
define internal cc10 i32 @handlerFunc0(%struct._Context*, i32) #0 { | |
%3 = getelementptr inbounds %struct._Context, %struct._Context* %0, i32 0, i32 0 | |
%4 = load i32, i32* %3, align 4 | |
%5 = add nsw i32 %4, 1 | |
store i32 %5, i32* %3, align 4 | |
%6 = tail call i32 @puts(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @str, i32 0, i32 0)) | |
%7 = add nsw i32 %1, 1 | |
%8 = getelementptr inbounds [3 x i32 (%struct._Context*, i32)*], [3 x i32 (%struct._Context*, i32)*]* @funcTable, i32 0, i32 %7 | |
%9 = load i32 (%struct._Context*, i32)*, i32 (%struct._Context*, i32)** %8, align 4 | |
%10 = tail call i32 %9(%struct._Context* %0, i32 %7) #3 | |
ret i32 %10 | |
} | |
define internal cc10 i32 @handlerFunc1(%struct._Context*, i32) #0 { | |
%3 = getelementptr inbounds %struct._Context, %struct._Context* %0, i32 0, i32 1 | |
%4 = load i32, i32* %3, align 4 | |
%5 = add nsw i32 %4, 1 | |
store i32 %5, i32* %3, align 4 | |
%6 = tail call i32 @puts(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @str.2, i32 0, i32 0)) | |
%7 = add nsw i32 %1, 1 | |
%8 = getelementptr inbounds [3 x i32 (%struct._Context*, i32)*], [3 x i32 (%struct._Context*, i32)*]* @funcTable, i32 0, i32 %7 | |
%9 = load i32 (%struct._Context*, i32)*, i32 (%struct._Context*, i32)** %8, align 4 | |
%10 = tail call i32 %9(%struct._Context* %0, i32 %7) #3 | |
ret i32 %10 | |
} | |
define internal cc10 i32 @terminatorFunc(%struct._Context* nocapture readnone, i32 returned) #0 { | |
ret i32 %1 | |
} | |
define internal i32 @starterFunc(%struct._Context*) local_unnamed_addr #0 { | |
%2 = getelementptr inbounds %struct._Context, %struct._Context* %0, i32 0, i32 0 | |
%3 = load i32, i32* %2, align 4 | |
%4 = getelementptr inbounds %struct._Context, %struct._Context* %0, i32 0, i32 1 | |
%5 = load i32, i32* %4, align 4 | |
%6 = icmp sgt i32 %3, %5 | |
%7 = zext i1 %6 to i32 | |
%8 = getelementptr inbounds [3 x i32 (%struct._Context*, i32)*], [3 x i32 (%struct._Context*, i32)*]* @funcTable, i32 0, i32 %7 | |
%9 = load i32 (%struct._Context*, i32)*, i32 (%struct._Context*, i32)** %8, align 4 | |
%10 = call i32 %9(%struct._Context* %0, i32 %7) #3 | |
%11 = icmp eq i32 %10, 0 | |
br i1 %11, label %13, label %12 | |
; <label>:12: ; preds = %1 | |
store i32 %10, i32* %4, align 4 | |
br label %14 | |
; <label>:13: ; preds = %1 | |
store i32 0, i32* %2, align 4 | |
br label %14 | |
; <label>:14: ; preds = %13, %12 | |
ret i32 %10 | |
} | |
declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #3 | |
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" } | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.text | |
.syntax unified | |
.eabi_attribute 67, "2.09" @ Tag_conformance | |
.eabi_attribute 6, 10 @ Tag_CPU_arch | |
.eabi_attribute 7, 65 @ Tag_CPU_arch_profile | |
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use | |
.eabi_attribute 9, 2 @ Tag_THUMB_ISA_use | |
.fpu neon | |
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access | |
.eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use | |
.eabi_attribute 20, 1 @ Tag_ABI_FP_denormal | |
.eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions | |
.eabi_attribute 23, 3 @ Tag_ABI_FP_number_model | |
.eabi_attribute 24, 1 @ Tag_ABI_align_needed | |
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved | |
.eabi_attribute 28, 1 @ Tag_ABI_VFP_args | |
.eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format | |
.eabi_attribute 14, 0 @ Tag_ABI_PCS_R9_use | |
.file "test.c" | |
.p2align 2 @ -- Begin function handlerFunc0 | |
.type handlerFunc0,%function | |
.code 32 @ @handlerFunc0 | |
handlerFunc0: | |
.fnstart | |
@ %bb.0: | |
ldr r7, [r4] | |
movw r0, :lower16:.Lstr | |
movt r0, :upper16:.Lstr | |
add r7, r7, #1 | |
str r7, [r4] | |
bl puts | |
movw r7, :lower16:funcTable | |
add r1, r5, #1 | |
movt r7, :upper16:funcTable | |
mov r0, r4 | |
ldr r2, [r7, r1, lsl #2] | |
bx r2 | |
.Lfunc_end0: | |
.size handlerFunc0, .Lfunc_end0-handlerFunc0 | |
.cantunwind | |
.fnend | |
@ -- End function | |
.p2align 2 @ -- Begin function handlerFunc1 | |
.type handlerFunc1,%function | |
.code 32 @ @handlerFunc1 | |
handlerFunc1: | |
.fnstart | |
@ %bb.0: | |
ldr r7, [r4, #4] | |
movw r0, :lower16:.Lstr.2 | |
movt r0, :upper16:.Lstr.2 | |
add r7, r7, #1 | |
str r7, [r4, #4] | |
bl puts | |
movw r7, :lower16:funcTable | |
add r1, r5, #1 | |
movt r7, :upper16:funcTable | |
mov r0, r4 | |
ldr r2, [r7, r1, lsl #2] | |
bx r2 | |
.Lfunc_end1: | |
.size handlerFunc1, .Lfunc_end1-handlerFunc1 | |
.cantunwind | |
.fnend | |
@ -- End function | |
.p2align 2 @ -- Begin function terminatorFunc | |
.type terminatorFunc,%function | |
.code 32 @ @terminatorFunc | |
terminatorFunc: | |
.fnstart | |
@ %bb.0: | |
mov r0, r5 | |
bx lr | |
.Lfunc_end2: | |
.size terminatorFunc, .Lfunc_end2-terminatorFunc | |
.cantunwind | |
.fnend | |
@ -- End function | |
.p2align 2 @ -- Begin function starterFunc | |
.type starterFunc,%function | |
.code 32 @ @starterFunc | |
starterFunc: | |
.fnstart | |
@ %bb.0: | |
.save {r4, r5, r11, lr} | |
push {r4, r5, r11, lr} | |
mov r4, r0 | |
ldr r0, [r0] | |
ldr r1, [r4, #4] | |
mov r5, #0 | |
cmp r0, r1 | |
mov r1, #0 | |
movw r0, :lower16:funcTable | |
movwgt r1, #1 | |
movt r0, :upper16:funcTable | |
ldr r2, [r0, r1, lsl #2] | |
mov r0, r4 | |
blx r2 | |
cmp r0, #0 | |
streq r5, [r4] | |
strne r0, [r4, #4] | |
pop {r4, r5, r11, pc} | |
.Lfunc_end3: | |
.size starterFunc, .Lfunc_end3-starterFunc | |
.cantunwind | |
.fnend | |
@ -- End function | |
.type funcTable,%object @ @funcTable | |
.data | |
.globl funcTable | |
.p2align 2 | |
funcTable: | |
.long handlerFunc0 | |
.long handlerFunc1 | |
.long terminatorFunc | |
.size funcTable, 12 | |
.type .Lstr,%object @ @str | |
.section .rodata.str1.16,"aMS",%progbits,1 | |
.p2align 4 | |
.Lstr: | |
.asciz "Hello handlerFunc0!" | |
.size .Lstr, 20 | |
.type .Lstr.2,%object @ @str.2 | |
.p2align 4 | |
.Lstr.2: | |
.asciz "Hello handlerFunc1!" | |
.size .Lstr.2, 20 | |
.section ".note.GNU-stack","",%progbits | |
.eabi_attribute 30, 1 @ Tag_ABI_optimization_goals |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment