void aesni256_cbc_decrypt(struct aesni256_ctx *ctx, const unsigned char *in,
                          unsigned char *out, int size, unsigned char iv[16]) {
  void *p1, *p2;
  if (size < 16) {
    return;
  }
  asm volatile("movdqu (%5), %%xmm1\n\t"
               "1:\n\t"
               "subl $0x10, %3\n\t"
               "movdqu (%4), %%xmm2\n\t"
               "pxor 0xe0(%6), %%xmm2\n\t"
               "aesdec 0xd0(%6), %%xmm2\n\t"
               "aesdec 0xc0(%6), %%xmm2\n\t"
               "aesdec 0xb0(%6), %%xmm2\n\t"
               "aesdec 0xa0(%6), %%xmm2\n\t"
               "aesdec 0x90(%6), %%xmm2\n\t"
               "aesdec 0x80(%6), %%xmm2\n\t"
               "aesdec 0x70(%6), %%xmm2\n\t"
               "aesdec 0x60(%6), %%xmm2\n\t"
               "aesdec 0x50(%6), %%xmm2\n\t"
               "aesdec 0x40(%6), %%xmm2\n\t"
               "aesdec 0x30(%6), %%xmm2\n\t"
               "aesdec 0x20(%6), %%xmm2\n\t"
               "aesdec 0x10(%6), %%xmm2\n\t"
               "aesdeclast 0x00(%6), %%xmm2\n\t"
               "pxor %%xmm1, %%xmm2\n\t"
               "movdqu (%4), %%xmm1\n\t"
               "movdqu %%xmm2, (%7)\n\t"
               "addq $0x10, %4\n\t"
               "addq $0x10, %7\n\t"
               "cmpl $0x0f, %3\n\t"
               "jg 1b\n\t"
               "movdqu %%xmm1, (%5)\n\t"
               : "=r"(size), "=r"(p1), "=r"(p2)
               : "0"(size), "1r"(in), "r"(iv), "r"(align16(ctx)), "2r"(out)
               : "%xmm1", "%xmm2", "memory");
}


x86 assembly (clang, -O0):
<aesni256_cbc_decrypt>:
push   %rbp
mov    %rsp,%rbp
sub    $0x50,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %ecx,-0x1c(%rbp)
mov    %r8,-0x28(%rbp)
cmpl   $0x10,-0x1c(%rbp)
jge    113a <aesni256_cbc_decrypt+0x2a>
jmp    121f <aesni256_cbc_decrypt+0x10f>
mov    -0x1c(%rbp),%eax
mov    %eax,-0x4c(%rbp)
mov    -0x10(%rbp),%rax
mov    %rax,-0x40(%rbp)
mov    -0x28(%rbp),%rax
mov    %rax,-0x48(%rbp)
mov    -0x8(%rbp),%rdi
mov    $0x0,%al
call   1030 <align16@plt>
mov    -0x4c(%rbp),%edx
mov    -0x48(%rbp),%rcx
mov    %eax,%esi
mov    -0x40(%rbp),%rax
mov    -0x18(%rbp),%rdi
movdqu (%rcx),%xmm1
sub    $0x10,%edx
movdqu (%rax),%xmm2
pxor   0xe0(%esi),%xmm2
aesdec 0xd0(%esi),%xmm2
aesdec 0xc0(%esi),%xmm2
aesdec 0xb0(%esi),%xmm2
aesdec 0xa0(%esi),%xmm2
aesdec 0x90(%esi),%xmm2
aesdec 0x80(%esi),%xmm2
aesdec 0x70(%esi),%xmm2
aesdec 0x60(%esi),%xmm2
aesdec 0x50(%esi),%xmm2
aesdec 0x40(%esi),%xmm2
aesdec 0x30(%esi),%xmm2
aesdec 0x20(%esi),%xmm2
aesdec 0x10(%esi),%xmm2
aesdeclast (%esi),%xmm2
pxor   %xmm1,%xmm2
movdqu (%rax),%xmm1
movdqu %xmm2,(%rdi)
add    $0x10,%rax
add    $0x10,%rdi
cmp    $0xf,%edx
jg     1170 <aesni256_cbc_decrypt+0x60>
movdqu %xmm1,(%rcx)
mov    %edx,-0x1c(%rbp)
mov    %rcx,-0x30(%rbp)
mov    %rax,-0x38(%rbp)
add    $0x50,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<aesni256_cbc_decrypt>:
cmp    $0x10,%ecx
jl     11e7 <aesni256_cbc_decrypt+0xd7>
push   %rbp
push   %r15
push   %r14
push   %rbx
push   %rax
mov    %r8,%r14
mov    %ecx,%ebp
mov    %rdx,%r15
mov    %rsi,%rbx
xor    %eax,%eax
call   1030 <align16@plt>
movdqu (%r14),%xmm1
sub    $0x10,%ebp
movdqu (%rbx),%xmm2
pxor   0xe0(%eax),%xmm2
aesdec 0xd0(%eax),%xmm2
aesdec 0xc0(%eax),%xmm2
aesdec 0xb0(%eax),%xmm2
aesdec 0xa0(%eax),%xmm2
aesdec 0x90(%eax),%xmm2
aesdec 0x80(%eax),%xmm2
aesdec 0x70(%eax),%xmm2
aesdec 0x60(%eax),%xmm2
aesdec 0x50(%eax),%xmm2
aesdec 0x40(%eax),%xmm2
aesdec 0x30(%eax),%xmm2
aesdec 0x20(%eax),%xmm2
aesdec 0x10(%eax),%xmm2
aesdeclast (%eax),%xmm2
pxor   %xmm1,%xmm2
movdqu (%rbx),%xmm1
movdqu %xmm2,(%r15)
add    $0x10,%rbx
add    $0x10,%r15
cmp    $0xf,%ebp
jg     1137 <aesni256_cbc_decrypt+0x27>
movdqu %xmm1,(%r14)
add    $0x8,%rsp
pop    %rbx
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
%struct.aesni256_ctx = type opaque
define void @aesni256_cbc_decrypt(%struct.aesni256_ctx* %0, i8* %1, i8* %2, i32 %3, i8* %4) {
%6 = alloca %struct.aesni256_ctx*
%7 = alloca i8*
%8 = alloca i8*
%9 = alloca i32
%10 = alloca i8*
%11 = alloca i8*
%12 = alloca i8*
store %struct.aesni256_ctx* %0, %struct.aesni256_ctx** %6
store i8* %1, i8** %7
store i8* %2, i8** %8
store i32 %3, i32* %9
store i8* %4, i8** %10
%13 = load i32, i32* %9
%14 = icmp slt i32 %13, 16
br i1 %14, label %15, label %16
15: ; preds = %5
br label %27
16: ; preds = %5
%17 = load i32, i32* %9
%18 = load i8*, i8** %7
%19 = load i8*, i8** %10
%20 = load %struct.aesni256_ctx*, %struct.aesni256_ctx** %6
%21 = call i32 (%struct.aesni256_ctx*, ...) bitcast (i32 (...)* @align16 to i32 (%struct.aesni256_ctx*, ...)*)(%struct.aesni256_ctx* %20)
%22 = load i8*, i8** %8
%23 = call { i32, i8*, i8* } asm sideeffect "movdqu ($5), %xmm1\0A\091:\0A\09subl $$0x10, $3\0A\09movdqu ($4), %xmm2\0A\09pxor 0xe0($6), %xmm2\0A\09aesdec 0xd0($6), %xmm2\0A\09aesdec 0xc0($6), %xmm2\0A\09aesdec 0xb0($6), %xmm2\0A\09aesdec 0xa0($6), %xmm2\0A\09aesdec 0x90($6), %xmm2\0A\09aesdec 0x80($6), %xmm2\0A\09aesdec 0x70($6), %xmm2\0A\09aesdec 0x60($6), %xmm2\0A\09aesdec 0x50($6), %xmm2\0A\09aesdec 0x40($6), %xmm2\0A\09aesdec 0x30($6), %xmm2\0A\09aesdec 0x20($6), %xmm2\0A\09aesdec 0x10($6), %xmm2\0A\09aesdeclast 0x00($6), %xmm2\0A\09pxor %xmm1, %xmm2\0A\09movdqu ($4), %xmm1\0A\09movdqu %xmm2, ($7)\0A\09addq $$0x10, $4\0A\09addq $$0x10, $7\0A\09cmpl $$0x0f, $3\0A\09jg 1b\0A\09movdqu %xmm1, ($5)\0A\09", "=r,=r,=r,0,1r,r,r,2r,~{xmm1},~{xmm2},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 %17, i8* %18, i8* %19, i32 %21, i8* %22)
%24 = extractvalue { i32, i8*, i8* } %23, 0
%25 = extractvalue { i32, i8*, i8* } %23, 1
%26 = extractvalue { i32, i8*, i8* } %23, 2
store i32 %24, i32* %9
store i8* %25, i8** %11
store i8* %26, i8** %12
br label %27
27: ; preds = %16, %15
ret void
}

LLVM IR (-O2):
%struct.aesni256_ctx = type opaque
define void @aesni256_cbc_decrypt(%struct.aesni256_ctx* %0, i8* %1, i8* %2, i32 %3, i8* %4) {
%6 = icmp slt i32 %3, 16
br i1 %6, label %10, label %7
7: ; preds = %5
%8 = tail call i32 (%struct.aesni256_ctx*, ...) bitcast (i32 (...)* @align16 to i32 (%struct.aesni256_ctx*, ...)*)(%struct.aesni256_ctx* %0)
%9 = tail call { i32, i8*, i8* } asm sideeffect "movdqu ($5), %xmm1\0A\091:\0A\09subl $$0x10, $3\0A\09movdqu ($4), %xmm2\0A\09pxor 0xe0($6), %xmm2\0A\09aesdec 0xd0($6), %xmm2\0A\09aesdec 0xc0($6), %xmm2\0A\09aesdec 0xb0($6), %xmm2\0A\09aesdec 0xa0($6), %xmm2\0A\09aesdec 0x90($6), %xmm2\0A\09aesdec 0x80($6), %xmm2\0A\09aesdec 0x70($6), %xmm2\0A\09aesdec 0x60($6), %xmm2\0A\09aesdec 0x50($6), %xmm2\0A\09aesdec 0x40($6), %xmm2\0A\09aesdec 0x30($6), %xmm2\0A\09aesdec 0x20($6), %xmm2\0A\09aesdec 0x10($6), %xmm2\0A\09aesdeclast 0x00($6), %xmm2\0A\09pxor %xmm1, %xmm2\0A\09movdqu ($4), %xmm1\0A\09movdqu %xmm2, ($7)\0A\09addq $$0x10, $4\0A\09addq $$0x10, $7\0A\09cmpl $$0x0f, $3\0A\09jg 1b\0A\09movdqu %xmm1, ($5)\0A\09", "=r,=r,=r,0,1r,r,r,2r,~{xmm1},~{xmm2},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 %3, i8* %1, i8* %4, i32 %8, i8* %2)
br label %10
10: ; preds = %5, %7
ret void
}