#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */

/* Variables and functions */
size_t aes_calclength(char *, size_t const);
int /*<<< orphan*/ aes_invcipher(int const, char const *, char const *, char *);
int /*<<< orphan*/ memcpy(char *, char const *, int);
size_t aes_pcbcdec(const int bits, const char *in, const size_t length,
                   const char *key, const char *iv, char *out) {
  char blk[16], vector[16];
  memcpy(vector, iv, 16);
  for (size_t d = 0; d + 15 < length; d += 16) {
    memcpy(blk, in + d, 16);
    aes_invcipher(bits, in + d, key, blk);
    for (short i = 0; i < 16; i++)
      *(out + d + i) = blk[i] ^ vector[i];
    for (short i = 0; i < 16; i++)
      vector[i] = *(in + d + i) ^ *(out + d + i);
  }
  return aes_calclength(out, length);
}


x86 assembly (clang, -O0):
<aes_pcbcdec>:
push   %rbp
mov    %rsp,%rbp
sub    $0x60,%rsp
mov    %edi,-0x4(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
mov    %r8,-0x28(%rbp)
mov    %r9,-0x30(%rbp)
lea    -0x50(%rbp),%rdi
mov    -0x28(%rbp),%rsi
mov    $0x10,%edx
call   1040 <memcpy@plt>
movq   $0x0,-0x58(%rbp)
mov    -0x58(%rbp),%rax
add    $0xf,%rax
cmp    -0x18(%rbp),%rax
jae    1264 <aes_pcbcdec+0x134>
lea    -0x40(%rbp),%rdi
mov    -0x10(%rbp),%rsi
add    -0x58(%rbp),%rsi
mov    $0x10,%edx
call   1040 <memcpy@plt>
mov    -0x4(%rbp),%edi
mov    -0x10(%rbp),%rsi
add    -0x58(%rbp),%rsi
mov    -0x20(%rbp),%rdx
lea    -0x40(%rbp),%rcx
call   1030 <aes_invcipher@plt>
movw   $0x0,-0x5a(%rbp)
movswl -0x5a(%rbp),%eax
cmp    $0x10,%eax
jge    11f7 <aes_pcbcdec+0xc7>
movswq -0x5a(%rbp),%rax
movsbl -0x40(%rbp,%rax,1),%eax
movswq -0x5a(%rbp),%rcx
movsbl -0x50(%rbp,%rcx,1),%ecx
xor    %ecx,%eax
mov    %al,%dl
mov    -0x30(%rbp),%rax
add    -0x58(%rbp),%rax
movswl -0x5a(%rbp),%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x5a(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0x5a(%rbp)
jmp    11af <aes_pcbcdec+0x7f>
movw   $0x0,-0x5c(%rbp)
movswl -0x5c(%rbp),%eax
cmp    $0x10,%eax
jge    124e <aes_pcbcdec+0x11e>
mov    -0x10(%rbp),%rax
add    -0x58(%rbp),%rax
movswl -0x5c(%rbp),%ecx
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    -0x30(%rbp),%rcx
add    -0x58(%rbp),%rcx
movswl -0x5c(%rbp),%edx
movslq %edx,%rdx
movsbl (%rcx,%rdx,1),%ecx
xor    %ecx,%eax
mov    %al,%cl
movswq -0x5c(%rbp),%rax
mov    %cl,-0x50(%rbp,%rax,1)
mov    -0x5c(%rbp),%ax
add    $0x1,%ax
mov    %ax,-0x5c(%rbp)
jmp    11fd <aes_pcbcdec+0xcd>
jmp    1253 <aes_pcbcdec+0x123>
mov    -0x58(%rbp),%rax
add    $0x10,%rax
mov    %rax,-0x58(%rbp)
jmp    1169 <aes_pcbcdec+0x39>
mov    -0x30(%rbp),%rdi
mov    -0x18(%rbp),%rsi
call   1050 <aes_calclength@plt>
add    $0x60,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<aes_pcbcdec>:
push   %rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
sub    $0x38,%rsp
mov    %r9,%r12
mov    %rcx,0x8(%rsp)
mov    %rdx,%r14
mov    %rsi,%rbx
mov    %edi,%r13d
lea    0x10(%rsp),%rdi
mov    %r8,%rsi
mov    $0x10,%edx
call   1040 <memcpy@plt>
cmp    $0x10,%r14
jb     11d6 <aes_pcbcdec+0xa6>
mov    $0xf,%r15d
lea    0x20(%rsp),%rbp
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
mov    %rbp,%rdi
mov    %rbx,%rsi
mov    $0x10,%edx
call   1040 <memcpy@plt>
mov    %r13d,%edi
mov    %rbx,%rsi
mov    0x8(%rsp),%rdx
mov    %rbp,%rcx
call   1030 <aes_invcipher@plt>
movaps 0x10(%rsp),%xmm0
xorps  0x20(%rsp),%xmm0
movups %xmm0,-0xf(%r12,%r15,1)
movups (%rbx),%xmm1
movss  -0xf(%r12,%r15,1),%xmm2
movss  %xmm2,%xmm0
xorps  %xmm1,%xmm0
movaps %xmm0,0x10(%rsp)
add    $0x10,%rbx
add    $0x10,%r15
cmp    %r14,%r15
jb     1180 <aes_pcbcdec+0x50>
mov    %r12,%rdi
mov    %r14,%rsi
call   1050 <aes_calclength@plt>
add    $0x38,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
define i64 @aes_pcbcdec(i32 %0, i8* %1, i64 %2, i8* %3, i8* %4, i8* %5) {
%7 = alloca i32
%8 = alloca i8*
%9 = alloca i64
%10 = alloca i8*
%11 = alloca i8*
%12 = alloca i8*
%13 = alloca [16 x i8]
%14 = alloca [16 x i8]
%15 = alloca i64
%16 = alloca i16
%17 = alloca i16
store i32 %0, i32* %7
store i8* %1, i8** %8
store i64 %2, i64* %9
store i8* %3, i8** %10
store i8* %4, i8** %11
store i8* %5, i8** %12
%18 = getelementptr inbounds [16 x i8], [16 x i8]* %14, i64 0, i64 0
%19 = load i8*, i8** %11
%20 = call i32 @memcpy(i8* %18, i8* %19, i32 16)
store i64 0, i64* %15
br label %21
21: ; preds = %99, %6
%22 = load i64, i64* %15
%23 = add i64 %22, 15
%24 = load i64, i64* %9
%25 = icmp ult i64 %23, %24
br i1 %25, label %26, label %102
26: ; preds = %21
%27 = getelementptr inbounds [16 x i8], [16 x i8]* %13, i64 0, i64 0
%28 = load i8*, i8** %8
%29 = load i64, i64* %15
%30 = getelementptr inbounds i8, i8* %28, i64 %29
%31 = call i32 @memcpy(i8* %27, i8* %30, i32 16)
%32 = load i32, i32* %7
%33 = load i8*, i8** %8
%34 = load i64, i64* %15
%35 = getelementptr inbounds i8, i8* %33, i64 %34
%36 = load i8*, i8** %10
%37 = getelementptr inbounds [16 x i8], [16 x i8]* %13, i64 0, i64 0
%38 = call i32 @aes_invcipher(i32 %32, i8* %35, i8* %36, i8* %37)
store i16 0, i16* %16
br label %39
39: ; preds = %63, %26
%40 = load i16, i16* %16
%41 = sext i16 %40 to i32
%42 = icmp slt i32 %41, 16
br i1 %42, label %43, label %66
43: ; preds = %39
%44 = load i16, i16* %16
%45 = sext i16 %44 to i64
%46 = getelementptr inbounds [16 x i8], [16 x i8]* %13, i64 0, i64 %45
%47 = load i8, i8* %46
%48 = sext i8 %47 to i32
%49 = load i16, i16* %16
%50 = sext i16 %49 to i64
%51 = getelementptr inbounds [16 x i8], [16 x i8]* %14, i64 0, i64 %50
%52 = load i8, i8* %51
%53 = sext i8 %52 to i32
%54 = xor i32 %48, %53
%55 = trunc i32 %54 to i8
%56 = load i8*, i8** %12
%57 = load i64, i64* %15
%58 = getelementptr inbounds i8, i8* %56, i64 %57
%59 = load i16, i16* %16
%60 = sext i16 %59 to i32
%61 = sext i32 %60 to i64
%62 = getelementptr inbounds i8, i8* %58, i64 %61
store i8 %55, i8* %62
br label %63
63: ; preds = %43
%64 = load i16, i16* %16
%65 = add i16 %64, 1
store i16 %65, i16* %16
br label %39
66: ; preds = %39
store i16 0, i16* %17
br label %67
67: ; preds = %95, %66
%68 = load i16, i16* %17
%69 = sext i16 %68 to i32
%70 = icmp slt i32 %69, 16
br i1 %70, label %71, label %98
71: ; preds = %67
%72 = load i8*, i8** %8
%73 = load i64, i64* %15
%74 = getelementptr inbounds i8, i8* %72, i64 %73
%75 = load i16, i16* %17
%76 = sext i16 %75 to i32
%77 = sext i32 %76 to i64
%78 = getelementptr inbounds i8, i8* %74, i64 %77
%79 = load i8, i8* %78
%80 = sext i8 %79 to i32
%81 = load i8*, i8** %12
%82 = load i64, i64* %15
%83 = getelementptr inbounds i8, i8* %81, i64 %82
%84 = load i16, i16* %17
%85 = sext i16 %84 to i32
%86 = sext i32 %85 to i64
%87 = getelementptr inbounds i8, i8* %83, i64 %86
%88 = load i8, i8* %87
%89 = sext i8 %88 to i32
%90 = xor i32 %80, %89
%91 = trunc i32 %90 to i8
%92 = load i16, i16* %17
%93 = sext i16 %92 to i64
%94 = getelementptr inbounds [16 x i8], [16 x i8]* %14, i64 0, i64 %93
store i8 %91, i8* %94
br label %95
95: ; preds = %71
%96 = load i16, i16* %17
%97 = add i16 %96, 1
store i16 %97, i16* %17
br label %67
98: ; preds = %67
br label %99
99: ; preds = %98
%100 = load i64, i64* %15
%101 = add i64 %100, 16
store i64 %101, i64* %15
br label %21
102: ; preds = %21
%103 = load i8*, i8** %12
%104 = load i64, i64* %9
%105 = call i64 @aes_calclength(i8* %103, i64 %104)
ret i64 %105
}

LLVM IR (-O2):
define i64 @aes_pcbcdec(i32 %0, i8* %1, i64 %2, i8* %3, i8* %4, i8* %5) {
%7 = alloca <16 x i8>
%8 = alloca <16 x i8>
%9 = getelementptr inbounds <16 x i8>, <16 x i8>* %7, i64 0, i64 0
%10 = getelementptr inbounds <16 x i8>, <16 x i8>* %8, i64 0, i64 0
%11 = call i32 @memcpy(i8* %10, i8* %4, i32 16)
%12 = icmp ugt i64 %2, 15
br i1 %12, label %15, label %13
13: ; preds = %15, %6
%14 = call i64 @aes_calclength(i8* %5, i64 %2)
ret i64 %14
15: ; preds = %6, %15
%16 = phi i64 [ %32, %15 ], [ 0, %6 ]
%17 = getelementptr inbounds i8, i8* %1, i64 %16
%18 = call i32 @memcpy(i8* %9, i8* %17, i32 16)
%19 = call i32 @aes_invcipher(i32 %0, i8* %17, i8* %3, i8* %9)
%20 = getelementptr inbounds i8, i8* %5, i64 %16
%21 = load <16 x i8>, <16 x i8>* %7
%22 = load <16 x i8>, <16 x i8>* %8
%23 = xor <16 x i8> %22, %21
%24 = bitcast i8* %20 to <16 x i8>*
store <16 x i8> %23, <16 x i8>* %24
%25 = bitcast i8* %20 to <4 x i8>*
%26 = load <4 x i8>, <4 x i8>* %25
%27 = bitcast i8* %17 to <16 x i8>*
%28 = load <16 x i8>, <16 x i8>* %27
%29 = shufflevector <4 x i8> %26, <4 x i8> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
%30 = shufflevector <16 x i8> %29, <16 x i8> %23, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31>
%31 = xor <16 x i8> %30, %28
store <16 x i8> %31, <16 x i8>* %8
%32 = add i64 %16, 16
%33 = or i64 %32, 15
%34 = icmp ult i64 %33, %2
br i1 %34, label %15, label %13
}