Skip to content

Instantly share code, notes, and snippets.

@amitin
Created July 17, 2019 20:08
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 amitin/7df4fbb806c0b48eb5bcaf614e5d93cd to your computer and use it in GitHub Desktop.
Save amitin/7df4fbb806c0b48eb5bcaf614e5d93cd to your computer and use it in GitHub Desktop.
Illustrate for an issue related to custom CC and tail-call elimination
cmake_minimum_required(VERSION 3.10)
project(testllvm C)
set(CMAKE_C_STANDARD 99)
add_executable(testllvm test.c)
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);
}
; 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" }
.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