void test_smartstrcat() {
  char *src1 = "Hello ";
  char *src2 = "world!";
  char *src3 = " Trunc ated";
  char dest[128] = {
      0,
  };
  char *p = (char *)dest;
  p = smartstrcat(p, src1, 128);
  do {
    if (strcmp(dest, "Hello ")) {
      printf("expected [%s == %s]\n", "dest", "\"Hello \"");
      printf(" a = \"%s\"\n", dest);
      printf(" b = \"%s\"\n", "Hello ");
      printf("%s -> FAILED\n", __func__);
      return;
    }
  } while (0);
  p = smartstrcat(p, src2, dest + 128 - p);
  do {
    if (strcmp(dest, "Hello world!")) {
      printf("expected [%s == %s]\n", "dest", "\"Hello world!\"");
      printf(" a = \"%s\"\n", dest);
      printf(" b = \"%s\"\n", "Hello world!");
      printf("%s -> FAILED\n", __func__);
      return;
    }
  } while (0);
  p = smartstrcat(p, src3, 6);
  do {
    if (strcmp(dest, "Hello world! Trunc")) {
      printf("expected [%s == %s]\n", "dest", "\"Hello world! Trunc\"");
      printf(" a = \"%s\"\n", dest);
      printf(" b = \"%s\"\n", "Hello world! Trunc");
      printf("%s -> FAILED\n", __func__);
      return;
    }
  } while (0);
  printf("%s -> OK\n", __func__);
}


x86 assembly (clang, -O0):
<test_smartstrcat>:
push   %rbp
mov    %rsp,%rbp
sub    $0xb0,%rsp
lea    0xeae(%rip),%rax
mov    %rax,-0x8(%rbp)
lea    0xf14(%rip),%rax
mov    %rax,-0x10(%rbp)
lea    0xe9f(%rip),%rax
mov    %rax,-0x18(%rbp)
lea    -0xa0(%rbp),%rdi
xor    %esi,%esi
mov    $0x80,%edx
call   1040 <memset@plt>
lea    -0xa0(%rbp),%rax
mov    %rax,-0xa8(%rbp)
mov    -0xa8(%rbp),%rdi
mov    -0x8(%rbp),%rsi
mov    $0x80,%edx
mov    $0x0,%al
call   1060 <smartstrcat@plt>
cltq
mov    %rax,-0xa8(%rbp)
lea    -0xa0(%rbp),%rdi
lea    0xe45(%rip),%rsi
call   1050 <strcmp@plt>
cmp    $0x0,%eax
je     1229 <test_smartstrcat+0xe9>
lea    0xe43(%rip),%rdi
lea    0xe51(%rip),%rsi
lea    0xe4f(%rip),%rdx
mov    $0x0,%al
call   1030 <printf@plt>
lea    -0xa0(%rbp),%rsi
lea    0xe43(%rip),%rdi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xe40(%rip),%rdi
lea    0xdf8(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xe36(%rip),%rdi
lea    0xe3d(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
jmp    1398 <test_smartstrcat+0x258>
jmp    122e <test_smartstrcat+0xee>
mov    -0xa8(%rbp),%rdi
mov    -0x10(%rbp),%rsi
lea    -0xa0(%rbp),%rdx
add    $0x80,%rdx
mov    -0xa8(%rbp),%rax
sub    %rax,%rdx
mov    $0x0,%al
call   1060 <smartstrcat@plt>
cltq
mov    %rax,-0xa8(%rbp)
lea    -0xa0(%rbp),%rdi
lea    0xdfc(%rip),%rsi
call   1050 <strcmp@plt>
cmp    $0x0,%eax
je     12dd <test_smartstrcat+0x19d>
lea    0xd8f(%rip),%rdi
lea    0xd9d(%rip),%rsi
lea    0xde6(%rip),%rdx
mov    $0x0,%al
call   1030 <printf@plt>
lea    -0xa0(%rbp),%rsi
lea    0xd8f(%rip),%rdi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xd8c(%rip),%rdi
lea    0xdaf(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xd82(%rip),%rdi
lea    0xd89(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
jmp    1398 <test_smartstrcat+0x258>
jmp    12e2 <test_smartstrcat+0x1a2>
mov    -0xa8(%rbp),%rdi
mov    -0x18(%rbp),%rsi
mov    $0x6,%edx
mov    $0x0,%al
call   1060 <smartstrcat@plt>
cltq
mov    %rax,-0xa8(%rbp)
lea    -0xa0(%rbp),%rdi
lea    0xd77(%rip),%rsi
call   1050 <strcmp@plt>
cmp    $0x0,%eax
je     137e <test_smartstrcat+0x23e>
lea    0xcee(%rip),%rdi
lea    0xcfc(%rip),%rsi
lea    0xd67(%rip),%rdx
mov    $0x0,%al
call   1030 <printf@plt>
lea    -0xa0(%rbp),%rsi
lea    0xcee(%rip),%rdi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xceb(%rip),%rdi
lea    0xd2a(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
lea    0xce1(%rip),%rdi
lea    0xce8(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
jmp    1398 <test_smartstrcat+0x258>
jmp    1383 <test_smartstrcat+0x243>
lea    0xd25(%rip),%rdi
lea    0xcc9(%rip),%rsi
mov    $0x0,%al
call   1030 <printf@plt>
add    $0xb0,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<test_smartstrcat>:
push   %r14
push   %rbx
sub    $0x88,%rsp
pxor   %xmm0,%xmm0
movdqa %xmm0,0x70(%rsp)
movdqa %xmm0,0x60(%rsp)
movdqa %xmm0,0x50(%rsp)
movdqa %xmm0,0x40(%rsp)
movdqa %xmm0,0x30(%rsp)
movdqa %xmm0,0x20(%rsp)
movdqa %xmm0,0x10(%rsp)
movdqa %xmm0,(%rsp)
lea    0xebc(%rip),%r14
mov    %rsp,%rbx
mov    %rbx,%rdi
mov    %r14,%rsi
mov    $0x80,%edx
xor    %eax,%eax
call   1040 <smartstrcat@plt>
mov    $0x6c6c6548,%ecx
xor    (%rsp),%ecx
mov    $0x206f6c,%edx
xor    0x3(%rsp),%edx
or     %ecx,%edx
je     119a <test_smartstrcat+0x7a>
lea    0xeb8(%rip),%rdx
jmp    1235 <test_smartstrcat+0x115>
movslq %eax,%rdi
sub    %rdi,%rbx
sub    $0xffffffffffffff80,%rbx
lea    0xee6(%rip),%rsi
mov    %rbx,%rdx
xor    %eax,%eax
call   1040 <smartstrcat@plt>
movabs $0x6f77206f6c6c6548,%rcx
20 77 6f
xor    (%rsp),%rcx
movabs $0x21646c726f7720,%rdx
xor    0x5(%rsp),%rdx
or     %rcx,%rdx
je     11e7 <test_smartstrcat+0xc7>
lea    0xead(%rip),%r14
lea    0xeb3(%rip),%rdx
jmp    1235 <test_smartstrcat+0x115>
movslq %eax,%rdi
lea    0xe36(%rip),%rsi
mov    $0x6,%edx
xor    %eax,%eax
call   1040 <smartstrcat@plt>
movdqa (%rsp),%xmm0
movdqu 0x3(%rsp),%xmm1
pcmpeqb 0xdf0(%rip),%xmm1
pcmpeqb 0xdf8(%rip),%xmm0
pand   %xmm1,%xmm0
pmovmskb %xmm0,%eax
cmp    $0xffff,%eax
je     128c <test_smartstrcat+0x16c>
lea    0xe79(%rip),%r14
lea    0xe85(%rip),%rdx
lea    0xdf7(%rip),%rdi
lea    0xe05(%rip),%rsi
xor    %eax,%eax
call   1030 <printf@plt>
lea    0xe05(%rip),%rdi
mov    %rsp,%rsi
xor    %eax,%eax
call   1030 <printf@plt>
lea    0xdff(%rip),%rdi
mov    %r14,%rsi
xor    %eax,%eax
call   1030 <printf@plt>
lea    0xdf9(%rip),%rdi
lea    0xe00(%rip),%rsi
xor    %eax,%eax
call   1030 <printf@plt>
add    $0x88,%rsp
pop    %rbx
pop    %r14
ret
lea    0xe3c(%rip),%rdi
jmp    1273 <test_smartstrcat+0x153>

LLVM IR (-O0):
@.str = [7 x i8] c"Hello \00"
@.str.1 = [7 x i8] c"world!\00"
@.str.2 = [12 x i8] c" Trunc ated\00"
@.str.3 = [21 x i8] c"expected [%s == %s]\0A\00"
@.str.4 = [5 x i8] c"dest\00"
@.str.5 = [9 x i8] c"\22Hello \22\00"
@.str.6 = [11 x i8] c" a = \22%s\22\0A\00"
@.str.7 = [11 x i8] c" b = \22%s\22\0A\00"
@.str.8 = [14 x i8] c"%s -> FAILED\0A\00"
@__func__.test_smartstrcat = [17 x i8] c"test_smartstrcat\00"
@.str.9 = [13 x i8] c"Hello world!\00"
@.str.10 = [15 x i8] c"\22Hello world!\22\00"
@.str.11 = [19 x i8] c"Hello world! Trunc\00"
@.str.12 = [21 x i8] c"\22Hello world! Trunc\22\00"
@.str.13 = [10 x i8] c"%s -> OK\0A\00"
define void @test_smartstrcat() {
%1 = alloca i8*
%2 = alloca i8*
%3 = alloca i8*
%4 = alloca [128 x i8]
%5 = alloca i8*
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0), i8** %1
store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i64 0, i64 0), i8** %2
store i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.2, i64 0, i64 0), i8** %3
%6 = bitcast [128 x i8]* %4 to i8*
%7 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
store i8* %7, i8** %5
%8 = load i8*, i8** %5
%9 = load i8*, i8** %1
%10 = call i32 (i8*, i8*, i32, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i32, ...)*)(i8* %8, i8* %9, i32 128)
%11 = sext i32 %10 to i64
%12 = inttoptr i64 %11 to i8*
store i8* %12, i8** %5
br label %13
13: ; preds = %0
%14 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%15 = call i32 @strcmp(i8* %14, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0))
%16 = icmp ne i32 %15, 0
br i1 %16, label %17, label %23
17: ; preds = %13
%18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i64 0, i64 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.5, i64 0, i64 0))
%19 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i64 0, i64 0), i8* %19)
%21 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0))
%22 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.8, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__func__.test_smartstrcat, i64 0, i64 0))
br label %66
23: ; preds = %13
br label %24
24: ; preds = %23
%25 = load i8*, i8** %5
%26 = load i8*, i8** %2
%27 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%28 = getelementptr inbounds i8, i8* %27, i64 128
%29 = load i8*, i8** %5
%30 = ptrtoint i8* %28 to i64
%31 = ptrtoint i8* %29 to i64
%32 = sub i64 %30, %31
%33 = call i32 (i8*, i8*, i64, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i64, ...)*)(i8* %25, i8* %26, i64 %32)
%34 = sext i32 %33 to i64
%35 = inttoptr i64 %34 to i8*
store i8* %35, i8** %5
br label %36
36: ; preds = %24
%37 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%38 = call i32 @strcmp(i8* %37, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i64 0, i64 0))
%39 = icmp ne i32 %38, 0
br i1 %39, label %40, label %46
40: ; preds = %36
%41 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i64 0, i64 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.10, i64 0, i64 0))
%42 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%43 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i64 0, i64 0), i8* %42)
%44 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i64 0, i64 0))
%45 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.8, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__func__.test_smartstrcat, i64 0, i64 0))
br label %66
46: ; preds = %36
br label %47
47: ; preds = %46
%48 = load i8*, i8** %5
%49 = load i8*, i8** %3
%50 = call i32 (i8*, i8*, i32, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i32, ...)*)(i8* %48, i8* %49, i32 6)
%51 = sext i32 %50 to i64
%52 = inttoptr i64 %51 to i8*
store i8* %52, i8** %5
br label %53
53: ; preds = %47
%54 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%55 = call i32 @strcmp(i8* %54, i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.11, i64 0, i64 0))
%56 = icmp ne i32 %55, 0
br i1 %56, label %57, label %63
57: ; preds = %53
%58 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i64 0, i64 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.12, i64 0, i64 0))
%59 = getelementptr inbounds [128 x i8], [128 x i8]* %4, i64 0, i64 0
%60 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i64 0, i64 0), i8* %59)
%61 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.11, i64 0, i64 0))
%62 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.8, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__func__.test_smartstrcat, i64 0, i64 0))
br label %66
63: ; preds = %53
br label %64
64: ; preds = %63
%65 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.13, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__func__.test_smartstrcat, i64 0, i64 0))
br label %66
66: ; preds = %64, %57, %40, %17
ret void
}

LLVM IR (-O2):
@.str = [7 x i8] c"Hello \00"
@.str.1 = [7 x i8] c"world!\00"
@.str.2 = [12 x i8] c" Trunc ated\00"
@.str.3 = [21 x i8] c"expected [%s == %s]\0A\00"
@.str.4 = [5 x i8] c"dest\00"
@.str.5 = [9 x i8] c"\22Hello \22\00"
@.str.6 = [11 x i8] c" a = \22%s\22\0A\00"
@.str.7 = [11 x i8] c" b = \22%s\22\0A\00"
@.str.8 = [14 x i8] c"%s -> FAILED\0A\00"
@__func__.test_smartstrcat = [17 x i8] c"test_smartstrcat\00"
@.str.9 = [13 x i8] c"Hello world!\00"
@.str.10 = [15 x i8] c"\22Hello world!\22\00"
@.str.11 = [19 x i8] c"Hello world! Trunc\00"
@.str.12 = [21 x i8] c"\22Hello world! Trunc\22\00"
@.str.13 = [10 x i8] c"%s -> OK\0A\00"
define void @test_smartstrcat() {
%1 = alloca [128 x i8]
%2 = getelementptr inbounds [128 x i8], [128 x i8]* %1, i64 0, i64 0
%3 = call i32 (i8*, i8*, i32, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i32, ...)*)(i8* %2, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0), i32 128)
%4 = sext i32 %3 to i64
%5 = call i32 @bcmp(i8* dereferenceable(7) %2, i8* dereferenceable(7) getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0), i64 7)
%6 = icmp eq i32 %5, 0
br i1 %6, label %7, label %21
7: ; preds = %0
%8 = inttoptr i64 %4 to i8*
%9 = getelementptr inbounds [128 x i8], [128 x i8]* %1, i64 0, i64 128
%10 = ptrtoint i8* %9 to i64
%11 = sub i64 %10, %4
%12 = call i32 (i8*, i8*, i64, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i64, ...)*)(i8* %8, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i64 0, i64 0), i64 %11)
%13 = call i32 @bcmp(i8* dereferenceable(13) %2, i8* dereferenceable(13) getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i64 0, i64 0), i64 13)
%14 = icmp eq i32 %13, 0
br i1 %14, label %15, label %21
15: ; preds = %7
%16 = sext i32 %12 to i64
%17 = inttoptr i64 %16 to i8*
%18 = call i32 (i8*, i8*, i32, ...) bitcast (i32 (...)* @smartstrcat to i32 (i8*, i8*, i32, ...)*)(i8* %17, i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.2, i64 0, i64 0), i32 6)
%19 = call i32 @bcmp(i8* dereferenceable(19) %2, i8* dereferenceable(19) getelementptr inbounds ([19 x i8], [19 x i8]* @.str.11, i64 0, i64 0), i64 19)
%20 = icmp eq i32 %19, 0
br i1 %20, label %27, label %21
21: ; preds = %15, %7, %0
%22 = phi i8* [ getelementptr inbounds ([9 x i8], [9 x i8]* @.str.5, i64 0, i64 0), %0 ], [ getelementptr inbounds ([15 x i8], [15 x i8]* @.str.10, i64 0, i64 0), %7 ], [ getelementptr inbounds ([21 x i8], [21 x i8]* @.str.12, i64 0, i64 0), %15 ]
%23 = phi i8* [ getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i64 0, i64 0), %0 ], [ getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i64 0, i64 0), %7 ], [ getelementptr inbounds ([19 x i8], [19 x i8]* @.str.11, i64 0, i64 0), %15 ]
%24 = call i32 (i8*, ...) @printf(i8* dereferenceable(1) getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i64 0, i64 0), i8* %22)
%25 = call i32 (i8*, ...) @printf(i8* dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i64 0, i64 0), i8* %2)
%26 = call i32 (i8*, ...) @printf(i8* dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.7, i64 0, i64 0), i8* %23)
br label %27
27: ; preds = %21, %15
%28 = phi i8* [ getelementptr inbounds ([10 x i8], [10 x i8]* @.str.13, i64 0, i64 0), %15 ], [ getelementptr inbounds ([14 x i8], [14 x i8]* @.str.8, i64 0, i64 0), %21 ]
%29 = call i32 (i8*, ...) @printf(i8* dereferenceable(1) %28, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @__func__.test_smartstrcat, i64 0, i64 0))
ret void
}