void get_viewport(int width, int height, const int *aspect_ratio, int *vp) {
  vp[2] = width;
  vp[3] = width * aspect_ratio[1] / (double)aspect_ratio[0];
  if (vp[3] > height) {
    vp[3] = height;
    vp[2] = height * aspect_ratio[0] / (double)aspect_ratio[1];
  }
  vp[0] = (width - vp[2]) / 2.0;
  vp[1] = (height - vp[3]) / 2.0;
}


x86 assembly (clang, -O0):
<get_viewport>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %esi,-0x8(%rbp)
mov    %rdx,-0x10(%rbp)
mov    %rcx,-0x18(%rbp)
mov    -0x4(%rbp),%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,0x8(%rax)
mov    -0x4(%rbp),%eax
mov    -0x10(%rbp),%rcx
imul   0x4(%rcx),%eax
cvtsi2sd %eax,%xmm0
mov    -0x10(%rbp),%rax
cvtsi2sdl (%rax),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,0xc(%rax)
mov    -0x18(%rbp),%rax
mov    0xc(%rax),%eax
cmp    -0x8(%rbp),%eax
jle    1182 <get_viewport+0x82>
mov    -0x8(%rbp),%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,0xc(%rax)
mov    -0x8(%rbp),%eax
mov    -0x10(%rbp),%rcx
imul   (%rcx),%eax
cvtsi2sd %eax,%xmm0
mov    -0x10(%rbp),%rax
cvtsi2sdl 0x4(%rax),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,0x8(%rax)
mov    -0x4(%rbp),%eax
mov    -0x18(%rbp),%rcx
sub    0x8(%rcx),%eax
cvtsi2sd %eax,%xmm0
movsd  0xe68(%rip),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,(%rax)
mov    -0x8(%rbp),%eax
mov    -0x18(%rbp),%rcx
sub    0xc(%rcx),%eax
cvtsi2sd %eax,%xmm0
movsd  0xe44(%rip),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%ecx
mov    -0x18(%rbp),%rax
mov    %ecx,0x4(%rax)
pop    %rbp
ret

x86 assembly (clang, -O2):
<get_viewport>:
mov    %edi,0x8(%rcx)
mov    0x4(%rdx),%eax
imul   %edi,%eax
cvtsi2sd %eax,%xmm0
cvtsi2sdl (%rdx),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%eax
mov    %eax,0xc(%rcx)
mov    %edi,%r8d
cmp    %esi,%eax
jle    1149 <get_viewport+0x49>
mov    %esi,0xc(%rcx)
mov    (%rdx),%eax
imul   %esi,%eax
xorps  %xmm0,%xmm0
cvtsi2sd %eax,%xmm0
xorps  %xmm1,%xmm1
cvtsi2sdl 0x4(%rdx),%xmm1
divsd  %xmm1,%xmm0
cvttsd2si %xmm0,%r8d
mov    %r8d,0x8(%rcx)
mov    %esi,%eax
sub    %r8d,%edi
xorps  %xmm0,%xmm0
cvtsi2sd %edi,%xmm0
movsd  0xea5(%rip),%xmm1
mulsd  %xmm1,%xmm0
cvttsd2si %xmm0,%edx
mov    %edx,(%rcx)
sub    %eax,%esi
xorps  %xmm0,%xmm0
cvtsi2sd %esi,%xmm0
mulsd  %xmm1,%xmm0
cvttsd2si %xmm0,%eax
mov    %eax,0x4(%rcx)
ret

LLVM IR (-O0):
define void @get_viewport(i32 %0, i32 %1, i32* %2, i32* %3) {
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32*
%8 = alloca i32*
store i32 %0, i32* %5
store i32 %1, i32* %6
store i32* %2, i32** %7
store i32* %3, i32** %8
%9 = load i32, i32* %5
%10 = load i32*, i32** %8
%11 = getelementptr inbounds i32, i32* %10, i64 2
store i32 %9, i32* %11
%12 = load i32, i32* %5
%13 = load i32*, i32** %7
%14 = getelementptr inbounds i32, i32* %13, i64 1
%15 = load i32, i32* %14
%16 = mul nsw i32 %12, %15
%17 = sitofp i32 %16 to double
%18 = load i32*, i32** %7
%19 = getelementptr inbounds i32, i32* %18, i64 0
%20 = load i32, i32* %19
%21 = sitofp i32 %20 to double
%22 = fdiv double %17, %21
%23 = fptosi double %22 to i32
%24 = load i32*, i32** %8
%25 = getelementptr inbounds i32, i32* %24, i64 3
store i32 %23, i32* %25
%26 = load i32*, i32** %8
%27 = getelementptr inbounds i32, i32* %26, i64 3
%28 = load i32, i32* %27
%29 = load i32, i32* %6
%30 = icmp sgt i32 %28, %29
br i1 %30, label %31, label %49
31: ; preds = %4
%32 = load i32, i32* %6
%33 = load i32*, i32** %8
%34 = getelementptr inbounds i32, i32* %33, i64 3
store i32 %32, i32* %34
%35 = load i32, i32* %6
%36 = load i32*, i32** %7
%37 = getelementptr inbounds i32, i32* %36, i64 0
%38 = load i32, i32* %37
%39 = mul nsw i32 %35, %38
%40 = sitofp i32 %39 to double
%41 = load i32*, i32** %7
%42 = getelementptr inbounds i32, i32* %41, i64 1
%43 = load i32, i32* %42
%44 = sitofp i32 %43 to double
%45 = fdiv double %40, %44
%46 = fptosi double %45 to i32
%47 = load i32*, i32** %8
%48 = getelementptr inbounds i32, i32* %47, i64 2
store i32 %46, i32* %48
br label %49
49: ; preds = %31, %4
%50 = load i32, i32* %5
%51 = load i32*, i32** %8
%52 = getelementptr inbounds i32, i32* %51, i64 2
%53 = load i32, i32* %52
%54 = sub nsw i32 %50, %53
%55 = sitofp i32 %54 to double
%56 = fdiv double %55, 2.000000e+00
%57 = fptosi double %56 to i32
%58 = load i32*, i32** %8
%59 = getelementptr inbounds i32, i32* %58, i64 0
store i32 %57, i32* %59
%60 = load i32, i32* %6
%61 = load i32*, i32** %8
%62 = getelementptr inbounds i32, i32* %61, i64 3
%63 = load i32, i32* %62
%64 = sub nsw i32 %60, %63
%65 = sitofp i32 %64 to double
%66 = fdiv double %65, 2.000000e+00
%67 = fptosi double %66 to i32
%68 = load i32*, i32** %8
%69 = getelementptr inbounds i32, i32* %68, i64 1
store i32 %67, i32* %69
ret void
}

LLVM IR (-O2):
define void @get_viewport(i32 %0, i32 %1, i32* nocapture %2, i32* nocapture %3) {
%5 = getelementptr inbounds i32, i32* %3, i64 2
store i32 %0, i32* %5
%6 = getelementptr inbounds i32, i32* %2, i64 1
%7 = load i32, i32* %6
%8 = mul nsw i32 %7, %0
%9 = sitofp i32 %8 to double
%10 = load i32, i32* %2
%11 = sitofp i32 %10 to double
%12 = fdiv double %9, %11
%13 = fptosi double %12 to i32
%14 = getelementptr inbounds i32, i32* %3, i64 3
store i32 %13, i32* %14
%15 = icmp sgt i32 %13, %1
br i1 %15, label %16, label %24
16: ; preds = %4
store i32 %1, i32* %14
%17 = load i32, i32* %2
%18 = mul nsw i32 %17, %1
%19 = sitofp i32 %18 to double
%20 = load i32, i32* %6
%21 = sitofp i32 %20 to double
%22 = fdiv double %19, %21
%23 = fptosi double %22 to i32
store i32 %23, i32* %5
br label %24
24: ; preds = %16, %4
%25 = phi i32 [ %1, %16 ], [ %13, %4 ]
%26 = phi i32 [ %23, %16 ], [ %0, %4 ]
%27 = sub nsw i32 %0, %26
%28 = sitofp i32 %27 to double
%29 = fmul double %28, 5.000000e-01
%30 = fptosi double %29 to i32
store i32 %30, i32* %3
%31 = sub nsw i32 %1, %25
%32 = sitofp i32 %31 to double
%33 = fmul double %32, 5.000000e-01
%34 = fptosi double %33 to i32
%35 = getelementptr inbounds i32, i32* %3, i64 1
store i32 %34, i32* %35
ret void
}