void call_func(void *func, int nb_args, void **args, unsigned char *args_type) {
  switch (nb_args) {
  case 0:
    ((void (*)())func)();
    break;
  case 1:
    ((void (*)())func)(args[0]);
    break;
  case 2:
    ((void (*)())func)(args[0], args[1]);
    break;
  case 3:
    ((void (*)())func)(args[0], args[1], args[2]);
    break;
  case 4:
    ((void (*)())func)(args[0], args[1], args[2], args[3]);
    break;
  case 5:
    ((void (*)())func)(args[0], args[1], args[2], args[3], args[4]);
    break;
  default:
    return;
  }
}


x86 assembly (clang, -O0):
<call_func>:
push   %rbp
mov    %rsp,%rbp
sub    $0x30,%rsp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
mov    -0xc(%rbp),%eax
mov    %rax,-0x28(%rbp)
sub    $0x5,%rax
ja     11fc <call_func+0xfc>
mov    -0x28(%rbp),%rax
lea    0xecd(%rip),%rcx
movslq (%rcx,%rax,4),%rax
add    %rcx,%rax
jmp    *%rax
mov    $0x0,%al
call   *-0x8(%rbp)
jmp    1201 <call_func+0x101>
mov    -0x8(%rbp),%rcx
mov    -0x18(%rbp),%rax
mov    (%rax),%rdi
mov    $0x0,%al
call   *%rcx
jmp    1201 <call_func+0x101>
mov    -0x8(%rbp),%rcx
mov    -0x18(%rbp),%rax
mov    (%rax),%rdi
mov    -0x18(%rbp),%rax
mov    0x8(%rax),%rsi
mov    $0x0,%al
call   *%rcx
jmp    1201 <call_func+0x101>
mov    -0x8(%rbp),%rcx
mov    -0x18(%rbp),%rax
mov    (%rax),%rdi
mov    -0x18(%rbp),%rax
mov    0x8(%rax),%rsi
mov    -0x18(%rbp),%rax
mov    0x10(%rax),%rdx
mov    $0x0,%al
call   *%rcx
jmp    1201 <call_func+0x101>
mov    -0x8(%rbp),%r8
mov    -0x18(%rbp),%rax
mov    (%rax),%rdi
mov    -0x18(%rbp),%rax
mov    0x8(%rax),%rsi
mov    -0x18(%rbp),%rax
mov    0x10(%rax),%rdx
mov    -0x18(%rbp),%rax
mov    0x18(%rax),%rcx
mov    $0x0,%al
call   *%r8
jmp    1201 <call_func+0x101>
mov    -0x8(%rbp),%r9
mov    -0x18(%rbp),%rax
mov    (%rax),%rdi
mov    -0x18(%rbp),%rax
mov    0x8(%rax),%rsi
mov    -0x18(%rbp),%rax
mov    0x10(%rax),%rdx
mov    -0x18(%rbp),%rax
mov    0x18(%rax),%rcx
mov    -0x18(%rbp),%rax
mov    0x20(%rax),%r8
mov    $0x0,%al
call   *%r9
jmp    1201 <call_func+0x101>
jmp    1201 <call_func+0x101>
add    $0x30,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<call_func>:
cmp    $0x5,%esi
ja     111f <call_func+0x1f>
mov    %rdi,%r9
mov    %esi,%eax
lea    0xeef(%rip),%rcx
movslq (%rcx,%rax,4),%rax
add    %rcx,%rax
jmp    *%rax
xor    %eax,%eax
jmp    *%r9
ret
mov    (%rdx),%rdi
xor    %eax,%eax
jmp    *%r9
mov    (%rdx),%rdi
mov    0x8(%rdx),%rsi
xor    %eax,%eax
jmp    *%r9
mov    (%rdx),%rdi
mov    0x8(%rdx),%rsi
mov    0x10(%rdx),%rdx
xor    %eax,%eax
jmp    *%r9
mov    (%rdx),%rdi
mov    0x8(%rdx),%rsi
mov    0x10(%rdx),%rax
mov    0x18(%rdx),%rcx
mov    %rax,%rdx
xor    %eax,%eax
jmp    *%r9
mov    (%rdx),%rdi
mov    0x8(%rdx),%rsi
mov    0x10(%rdx),%rax
mov    0x18(%rdx),%rcx
mov    0x20(%rdx),%r8
mov    %rax,%rdx
xor    %eax,%eax
jmp    *%r9

LLVM IR (-O0):
define void @call_func(i8* %0, i32 %1, i8** %2, i8* %3) {
%5 = alloca i8*
%6 = alloca i32
%7 = alloca i8**
%8 = alloca i8*
store i8* %0, i8** %5
store i32 %1, i32* %6
store i8** %2, i8*** %7
store i8* %3, i8** %8
%9 = load i32, i32* %6
switch i32 %9, label %78 [
i32 0, label %10
i32 1, label %13
i32 2, label %20
i32 3, label %30
i32 4, label %43
i32 5, label %59
]
10: ; preds = %4
%11 = load i8*, i8** %5
%12 = bitcast i8* %11 to void (...)*
br label %79
13: ; preds = %4
%14 = load i8*, i8** %5
%15 = bitcast i8* %14 to void (...)*
%16 = load i8**, i8*** %7
%17 = getelementptr inbounds i8*, i8** %16, i64 0
%18 = load i8*, i8** %17
%19 = bitcast void (...)* %15 to void (i8*, ...)*
br label %79
20: ; preds = %4
%21 = load i8*, i8** %5
%22 = bitcast i8* %21 to void (...)*
%23 = load i8**, i8*** %7
%24 = getelementptr inbounds i8*, i8** %23, i64 0
%25 = load i8*, i8** %24
%26 = load i8**, i8*** %7
%27 = getelementptr inbounds i8*, i8** %26, i64 1
%28 = load i8*, i8** %27
%29 = bitcast void (...)* %22 to void (i8*, i8*, ...)*
br label %79
30: ; preds = %4
%31 = load i8*, i8** %5
%32 = bitcast i8* %31 to void (...)*
%33 = load i8**, i8*** %7
%34 = getelementptr inbounds i8*, i8** %33, i64 0
%35 = load i8*, i8** %34
%36 = load i8**, i8*** %7
%37 = getelementptr inbounds i8*, i8** %36, i64 1
%38 = load i8*, i8** %37
%39 = load i8**, i8*** %7
%40 = getelementptr inbounds i8*, i8** %39, i64 2
%41 = load i8*, i8** %40
%42 = bitcast void (...)* %32 to void (i8*, i8*, i8*, ...)*
br label %79
43: ; preds = %4
%44 = load i8*, i8** %5
%45 = bitcast i8* %44 to void (...)*
%46 = load i8**, i8*** %7
%47 = getelementptr inbounds i8*, i8** %46, i64 0
%48 = load i8*, i8** %47
%49 = load i8**, i8*** %7
%50 = getelementptr inbounds i8*, i8** %49, i64 1
%51 = load i8*, i8** %50
%52 = load i8**, i8*** %7
%53 = getelementptr inbounds i8*, i8** %52, i64 2
%54 = load i8*, i8** %53
%55 = load i8**, i8*** %7
%56 = getelementptr inbounds i8*, i8** %55, i64 3
%57 = load i8*, i8** %56
%58 = bitcast void (...)* %45 to void (i8*, i8*, i8*, i8*, ...)*
br label %79
59: ; preds = %4
%60 = load i8*, i8** %5
%61 = bitcast i8* %60 to void (...)*
%62 = load i8**, i8*** %7
%63 = getelementptr inbounds i8*, i8** %62, i64 0
%64 = load i8*, i8** %63
%65 = load i8**, i8*** %7
%66 = getelementptr inbounds i8*, i8** %65, i64 1
%67 = load i8*, i8** %66
%68 = load i8**, i8*** %7
%69 = getelementptr inbounds i8*, i8** %68, i64 2
%70 = load i8*, i8** %69
%71 = load i8**, i8*** %7
%72 = getelementptr inbounds i8*, i8** %71, i64 3
%73 = load i8*, i8** %72
%74 = load i8**, i8*** %7
%75 = getelementptr inbounds i8*, i8** %74, i64 4
%76 = load i8*, i8** %75
%77 = bitcast void (...)* %61 to void (i8*, i8*, i8*, i8*, i8*, ...)*
br label %79
78: ; preds = %4
br label %79
79: ; preds = %78, %59, %43, %30, %20, %13, %10
ret void
}

LLVM IR (-O2):
define void @call_func(i8* nocapture %0, i32 %1, i8** nocapture %2, i8* nocapture readnone %3) {
switch i32 %1, label %42 [
i32 0, label %5
i32 1, label %7
i32 2, label %10
i32 3, label %15
i32 4, label %22
i32 5, label %31
]
5: ; preds = %4
%6 = bitcast i8* %0 to void (...)*
tail call void (...) %6()
br label %42
7: ; preds = %4
%8 = load i8*, i8** %2
%9 = bitcast i8* %0 to void (i8*, ...)*
tail call void (i8*, ...) %9(i8* %8)
br label %42
10: ; preds = %4
%11 = load i8*, i8** %2
%12 = getelementptr inbounds i8*, i8** %2, i64 1
%13 = load i8*, i8** %12
%14 = bitcast i8* %0 to void (i8*, i8*, ...)*
tail call void (i8*, i8*, ...) %14(i8* %11, i8* %13)
br label %42
15: ; preds = %4
%16 = load i8*, i8** %2
%17 = getelementptr inbounds i8*, i8** %2, i64 1
%18 = load i8*, i8** %17
%19 = getelementptr inbounds i8*, i8** %2, i64 2
%20 = load i8*, i8** %19
%21 = bitcast i8* %0 to void (i8*, i8*, i8*, ...)*
tail call void (i8*, i8*, i8*, ...) %21(i8* %16, i8* %18, i8* %20)
br label %42
22: ; preds = %4
%23 = load i8*, i8** %2
%24 = getelementptr inbounds i8*, i8** %2, i64 1
%25 = load i8*, i8** %24
%26 = getelementptr inbounds i8*, i8** %2, i64 2
%27 = load i8*, i8** %26
%28 = getelementptr inbounds i8*, i8** %2, i64 3
%29 = load i8*, i8** %28
%30 = bitcast i8* %0 to void (i8*, i8*, i8*, i8*, ...)*
tail call void (i8*, i8*, i8*, i8*, ...) %30(i8* %23, i8* %25, i8* %27, i8* %29)
br label %42
31: ; preds = %4
%32 = load i8*, i8** %2
%33 = getelementptr inbounds i8*, i8** %2, i64 1
%34 = load i8*, i8** %33
%35 = getelementptr inbounds i8*, i8** %2, i64 2
%36 = load i8*, i8** %35
%37 = getelementptr inbounds i8*, i8** %2, i64 3
%38 = load i8*, i8** %37
%39 = getelementptr inbounds i8*, i8** %2, i64 4
%40 = load i8*, i8** %39
%41 = bitcast i8* %0 to void (i8*, i8*, i8*, i8*, i8*, ...)*
tail call void (i8*, i8*, i8*, i8*, i8*, ...) %41(i8* %32, i8* %34, i8* %36, i8* %38, i8* %40)
br label %42
42: ; preds = %4, %31, %22, %15, %10, %7, %5
ret void
}