char *__concatstring(out, s1, len1, s2, len2)
char *out, *s1;
int len1;
char *s2;
int len2;
{
  if (out) {
    if (s2 && ((s2 >= out && s2 < (out + len1 + len2)) ||
               (s2 + len2 > out && s2 <= out + len1))) {
      char *tmp = alloca(len2);
      memcpy(tmp, s2, len2);
      s2 = tmp;
    }
    if (s1)
      memmove(out, s1, len1);
    if (s2)
      memcpy(&out[len1], s2, len2);
  }
  return out;
}


x86 assembly (clang, -O0):
<__concatstring>:
push   %rbp
mov    %rsp,%rbp
sub    $0x30,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
mov    %rcx,-0x20(%rbp)
mov    %r8d,-0x24(%rbp)
cmpq   $0x0,-0x8(%rbp)
je     1221 <__concatstring+0x101>
cmpq   $0x0,-0x20(%rbp)
je     11dd <__concatstring+0xbd>
mov    -0x20(%rbp),%rax
cmp    -0x8(%rbp),%rax
jb     117e <__concatstring+0x5e>
mov    -0x20(%rbp),%rax
mov    -0x8(%rbp),%rcx
movslq -0x14(%rbp),%rdx
add    %rdx,%rcx
movslq -0x24(%rbp),%rdx
add    %rdx,%rcx
cmp    %rcx,%rax
jb     11ab <__concatstring+0x8b>
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
add    %rcx,%rax
cmp    -0x8(%rbp),%rax
jbe    11dd <__concatstring+0xbd>
mov    -0x20(%rbp),%rax
mov    -0x8(%rbp),%rcx
movslq -0x14(%rbp),%rdx
add    %rdx,%rcx
cmp    %rcx,%rax
ja     11dd <__concatstring+0xbd>
movslq -0x24(%rbp),%rcx
add    $0xf,%rcx
and    $0xfffffffffffffff0,%rcx
mov    %rsp,%rax
sub    %rcx,%rax
mov    %rax,%rsp
mov    %rax,-0x30(%rbp)
mov    -0x30(%rbp),%rdi
mov    -0x20(%rbp),%rsi
movslq -0x24(%rbp),%rdx
call   1030 <memcpy@plt>
mov    -0x30(%rbp),%rax
mov    %rax,-0x20(%rbp)
cmpq   $0x0,-0x10(%rbp)
je     11f9 <__concatstring+0xd9>
mov    -0x8(%rbp),%rdi
mov    -0x10(%rbp),%rsi
movslq -0x14(%rbp),%rdx
call   1040 <memmove@plt>
cmpq   $0x0,-0x20(%rbp)
je     121c <__concatstring+0xfc>
mov    -0x8(%rbp),%rdi
movslq -0x14(%rbp),%rax
add    %rax,%rdi
mov    -0x20(%rbp),%rsi
movslq -0x24(%rbp),%rdx
call   1030 <memcpy@plt>
jmp    1221 <__concatstring+0x101>
mov    -0x8(%rbp),%rax
mov    %rbp,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<__concatstring>:
push   %rbp
mov    %rsp,%rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
push   %rax
mov    %rdi,%rbx
test   %rdi,%rdi
je     11d0 <__concatstring+0xb0>
mov    %r8d,%r15d
mov    %rcx,%r14
mov    %edx,%r12d
mov    %rsi,%r13
test   %rcx,%rcx
je     1158 <__concatstring+0x38>
cmp    %rbx,%r14
jae    115d <__concatstring+0x3d>
movslq %r15d,%rdx
movslq %r12d,%rax
jmp    116f <__concatstring+0x4f>
xor    %r14d,%r14d
jmp    11a7 <__concatstring+0x87>
movslq %r12d,%rax
lea    (%rbx,%rax,1),%rcx
movslq %r15d,%rdx
add    %rdx,%rcx
cmp    %r14,%rcx
ja     1180 <__concatstring+0x60>
lea    (%r14,%rdx,1),%rcx
cmp    %rbx,%rcx
jbe    11a7 <__concatstring+0x87>
add    %rbx,%rax
cmp    %r14,%rax
jb     11a7 <__concatstring+0x87>
mov    %r15d,-0x2c(%rbp)
mov    %rsp,%r15
lea    0xf(%rdx),%rax
and    $0xfffffffffffffff0,%rax
sub    %rax,%r15
mov    %r15,%rsp
mov    %r15,%rdi
mov    %r14,%rsi
call   1030 <memcpy@plt>
mov    %r15,%r14
mov    -0x2c(%rbp),%r15d
test   %r13,%r13
je     11ba <__concatstring+0x9a>
movslq %r12d,%rdx
mov    %rbx,%rdi
mov    %r13,%rsi
call   1040 <memmove@plt>
test   %r14,%r14
je     11d0 <__concatstring+0xb0>
movslq %r12d,%rdi
add    %rbx,%rdi
movslq %r15d,%rdx
mov    %r14,%rsi
call   1030 <memcpy@plt>
mov    %rbx,%rax
lea    -0x28(%rbp),%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
ret

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

LLVM IR (-O2):
define i8* @__concatstring(i8* returned writeonly %0, i8* %1, i32 %2, i8* %3, i32 %4) {
%6 = icmp eq i8* %0, null
br i1 %6, label %42, label %7
7: ; preds = %5
%8 = icmp eq i8* %3, null
br i1 %8, label %31, label %9
9: ; preds = %7
%10 = icmp ult i8* %3, %0
br i1 %10, label %11, label %14
11: ; preds = %9
%12 = sext i32 %4 to i64
%13 = sext i32 %2 to i64
br label %20
14: ; preds = %9
%15 = sext i32 %2 to i64
%16 = getelementptr inbounds i8, i8* %0, i64 %15
%17 = sext i32 %4 to i64
%18 = getelementptr inbounds i8, i8* %16, i64 %17
%19 = icmp ugt i8* %18, %3
br i1 %19, label %28, label %20
20: ; preds = %11, %14
%21 = phi i64 [ %13, %11 ], [ %15, %14 ]
%22 = phi i64 [ %12, %11 ], [ %17, %14 ]
%23 = getelementptr inbounds i8, i8* %3, i64 %22
%24 = icmp ule i8* %23, %0
%25 = getelementptr inbounds i8, i8* %0, i64 %21
%26 = icmp ult i8* %25, %3
%27 = select i1 %24, i1 true, i1 %26
br i1 %27, label %31, label %28
28: ; preds = %20, %14
%29 = phi i64 [ %22, %20 ], [ %17, %14 ]
%30 = alloca i8, i64 %29
br label %31
31: ; preds = %28, %20, %7
%32 = phi i8* [ %30, %28 ], [ %3, %20 ], [ null, %7 ]
%33 = icmp eq i8* %1, null
br i1 %33, label %36, label %34
34: ; preds = %31
%35 = sext i32 %2 to i64
tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 %1, i64 %35, i1 false)
br label %36
36: ; preds = %34, %31
%37 = icmp eq i8* %32, null
br i1 %37, label %42, label %38
38: ; preds = %36
%39 = sext i32 %2 to i64
%40 = getelementptr inbounds i8, i8* %0, i64 %39
%41 = sext i32 %4 to i64
br label %42
42: ; preds = %36, %38, %5
ret i8* %0
}