#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 */
typedef double GLint;
typedef double GLdouble;

/* Variables and functions */
double GL_FALSE;
double GL_TRUE;
int /*<<< orphan*/ __gluInvertMatrixd(double *, double *);
int /*<<< orphan*/ __gluMultMatricesd(double const *, double const *, double *);
int /*<<< orphan*/ __gluMultMatrixVecd(double *, double *, double *);
GLint gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
                   const GLdouble modelMatrix[16],
                   const GLdouble projMatrix[16], const GLint viewport[4],
                   GLdouble *objx, GLdouble *objy, GLdouble *objz) {
  double finalMatrix[16];
  double in[4];
  double out[4];
  __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
  if (!__gluInvertMatrixd(finalMatrix, finalMatrix))
    return (GL_FALSE);
  in[0] = winx;
  in[1] = winy;
  in[2] = winz;
  in[3] = 1.0;
  in[0] = (in[0] - viewport[0]) / viewport[2];
  in[1] = (in[1] - viewport[1]) / viewport[3];
  in[0] = in[0] * 2 - 1;
  in[1] = in[1] * 2 - 1;
  in[2] = in[2] * 2 - 1;
  __gluMultMatrixVecd(finalMatrix, in, out);
  if (out[3] == 0.0)
    return (GL_FALSE);
  out[0] /= out[3];
  out[1] /= out[3];
  out[2] /= out[3];
  *objx = out[0];
  *objy = out[1];
  *objz = out[2];
  return (GL_TRUE);
}


x86 assembly (clang, -O0):
<gluUnProject>:
push   %rbp
mov    %rsp,%rbp
sub    $0x110,%rsp
movsd  %xmm0,-0x10(%rbp)
movsd  %xmm1,-0x18(%rbp)
movsd  %xmm2,-0x20(%rbp)
mov    %rdi,-0x28(%rbp)
mov    %rsi,-0x30(%rbp)
mov    %rdx,-0x38(%rbp)
mov    %rcx,-0x40(%rbp)
mov    %r8,-0x48(%rbp)
mov    %r9,-0x50(%rbp)
mov    -0x28(%rbp),%rdi
mov    -0x30(%rbp),%rsi
lea    -0xd0(%rbp),%rdx
call   1030 <__gluMultMatricesd@plt>
lea    -0xd0(%rbp),%rdi
lea    -0xd0(%rbp),%rsi
call   1040 <__gluInvertMatrixd@plt>
cmp    $0x0,%eax
jne    11a7 <gluUnProject+0x77>
mov    0x2e4f(%rip),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x8(%rbp)
jmp    135f <gluUnProject+0x22f>
movsd  -0x10(%rbp),%xmm0
movsd  %xmm0,-0xf0(%rbp)
ff
movsd  -0x18(%rbp),%xmm0
movsd  %xmm0,-0xe8(%rbp)
ff
movsd  -0x20(%rbp),%xmm0
movsd  %xmm0,-0xe0(%rbp)
ff
movsd  0xe32(%rip),%xmm0
movsd  %xmm0,-0xd8(%rbp)
ff
movsd  -0xf0(%rbp),%xmm0
ff
mov    -0x38(%rbp),%rax
subsd  (%rax),%xmm0
mov    -0x38(%rbp),%rax
divsd  0x10(%rax),%xmm0
movsd  %xmm0,-0xf0(%rbp)
ff
movsd  -0xe8(%rbp),%xmm0
ff
mov    -0x38(%rbp),%rax
subsd  0x8(%rax),%xmm0
mov    -0x38(%rbp),%rax
divsd  0x18(%rax),%xmm0
movsd  %xmm0,-0xe8(%rbp)
ff
movsd  -0xf0(%rbp),%xmm0
ff
addsd  %xmm0,%xmm0
movsd  0xdcb(%rip),%xmm1
addsd  %xmm1,%xmm0
movsd  %xmm0,-0xf0(%rbp)
ff
movsd  -0xe8(%rbp),%xmm0
ff
addsd  %xmm0,%xmm0
movsd  0xdab(%rip),%xmm1
addsd  %xmm1,%xmm0
movsd  %xmm0,-0xe8(%rbp)
ff
movsd  -0xe0(%rbp),%xmm0
ff
addsd  %xmm0,%xmm0
movsd  0xd8b(%rip),%xmm1
addsd  %xmm1,%xmm0
movsd  %xmm0,-0xe0(%rbp)
ff
lea    -0xd0(%rbp),%rdi
lea    -0xf0(%rbp),%rsi
lea    -0x110(%rbp),%rdx
call   1050 <__gluMultMatrixVecd@plt>
movsd  -0xf8(%rbp),%xmm0
ff
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
jne    12cb <gluUnProject+0x19b>
jp     12cb <gluUnProject+0x19b>
mov    0x2d2b(%rip),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x8(%rbp)
jmp    135f <gluUnProject+0x22f>
movsd  -0xf8(%rbp),%xmm1
ff
movsd  -0x110(%rbp),%xmm0
ff
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x110(%rbp)
ff
movsd  -0xf8(%rbp),%xmm1
ff
movsd  -0x108(%rbp),%xmm0
ff
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x108(%rbp)
ff
movsd  -0xf8(%rbp),%xmm1
ff
movsd  -0x100(%rbp),%xmm0
ff
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x100(%rbp)
ff
movsd  -0x110(%rbp),%xmm0
ff
mov    -0x40(%rbp),%rax
movsd  %xmm0,(%rax)
movsd  -0x108(%rbp),%xmm0
ff
mov    -0x48(%rbp),%rax
movsd  %xmm0,(%rax)
movsd  -0x100(%rbp),%xmm0
ff
mov    -0x50(%rbp),%rax
movsd  %xmm0,(%rax)
mov    0x2c82(%rip),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x8(%rbp)
movsd  -0x8(%rbp),%xmm0
add    $0x110,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<gluUnProject>:
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
sub    $0xf0,%rsp
mov    %r9,%r14
mov    %r8,%r15
mov    %rcx,%r12
mov    %rdx,%r13
movsd  %xmm2,0x8(%rsp)
movapd %xmm1,0x30(%rsp)
movapd %xmm0,0x40(%rsp)
lea    0x70(%rsp),%rbx
mov    %rbx,%rdx
call   1030 <__gluMultMatricesd@plt>
mov    %rbx,%rdi
mov    %rbx,%rsi
call   1040 <__gluInvertMatrixd@plt>
mov    0x2e6b(%rip),%rbx
test   %eax,%eax
je     1239 <gluUnProject+0x109>
movabs $0x3ff0000000000000,%rax
mov    %rax,0x68(%rsp)
movapd 0x40(%rsp),%xmm1
unpcklpd 0x30(%rsp),%xmm1
movupd 0x0(%r13),%xmm0
subpd  %xmm0,%xmm1
movupd 0x10(%r13),%xmm0
divpd  %xmm0,%xmm1
addpd  %xmm1,%xmm1
addpd  0xe40(%rip),%xmm1
movapd %xmm1,0x50(%rsp)
movsd  0x8(%rsp),%xmm0
addsd  %xmm0,%xmm0
addsd  0xe38(%rip),%xmm0
movsd  %xmm0,0x60(%rsp)
lea    0x70(%rsp),%rdi
lea    0x50(%rsp),%rsi
lea    0x10(%rsp),%rdx
call   1050 <__gluMultMatrixVecd@plt>
movsd  0x28(%rsp),%xmm0
xorpd  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
jne    1204 <gluUnProject+0xd4>
jnp    1239 <gluUnProject+0x109>
movsd  0x10(%rsp),%xmm1
movsd  0x18(%rsp),%xmm2
divsd  %xmm0,%xmm1
divsd  %xmm0,%xmm2
movsd  0x20(%rsp),%xmm3
divsd  %xmm0,%xmm3
movsd  %xmm1,(%r12)
movsd  %xmm2,(%r15)
movsd  %xmm3,(%r14)
mov    0x2d9f(%rip),%rbx
movsd  (%rbx),%xmm0
add    $0xf0,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
ret

LLVM IR (-O0):
@GL_FALSE = global double 0.000000e+00
@GL_TRUE = global double 0.000000e+00
define double @gluUnProject(double %0, double %1, double %2, double* %3, double* %4, double* %5, double* %6, double* %7, double* %8) {
%10 = alloca double
%11 = alloca double
%12 = alloca double
%13 = alloca double
%14 = alloca double*
%15 = alloca double*
%16 = alloca double*
%17 = alloca double*
%18 = alloca double*
%19 = alloca double*
%20 = alloca [16 x double]
%21 = alloca [4 x double]
%22 = alloca [4 x double]
store double %0, double* %11
store double %1, double* %12
store double %2, double* %13
store double* %3, double** %14
store double* %4, double** %15
store double* %5, double** %16
store double* %6, double** %17
store double* %7, double** %18
store double* %8, double** %19
%23 = load double*, double** %14
%24 = load double*, double** %15
%25 = getelementptr inbounds [16 x double], [16 x double]* %20, i64 0, i64 0
%26 = call i32 @__gluMultMatricesd(double* %23, double* %24, double* %25)
%27 = getelementptr inbounds [16 x double], [16 x double]* %20, i64 0, i64 0
%28 = getelementptr inbounds [16 x double], [16 x double]* %20, i64 0, i64 0
%29 = call i32 @__gluInvertMatrixd(double* %27, double* %28)
%30 = icmp ne i32 %29, 0
br i1 %30, label %33, label %31
31: ; preds = %9
%32 = load double, double* @GL_FALSE
store double %32, double* %10
br label %110
33: ; preds = %9
%34 = load double, double* %11
%35 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
store double %34, double* %35
%36 = load double, double* %12
%37 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 1
store double %36, double* %37
%38 = load double, double* %13
%39 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 2
store double %38, double* %39
%40 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 3
store double 1.000000e+00, double* %40
%41 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
%42 = load double, double* %41
%43 = load double*, double** %16
%44 = getelementptr inbounds double, double* %43, i64 0
%45 = load double, double* %44
%46 = fsub double %42, %45
%47 = load double*, double** %16
%48 = getelementptr inbounds double, double* %47, i64 2
%49 = load double, double* %48
%50 = fdiv double %46, %49
%51 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
store double %50, double* %51
%52 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 1
%53 = load double, double* %52
%54 = load double*, double** %16
%55 = getelementptr inbounds double, double* %54, i64 1
%56 = load double, double* %55
%57 = fsub double %53, %56
%58 = load double*, double** %16
%59 = getelementptr inbounds double, double* %58, i64 3
%60 = load double, double* %59
%61 = fdiv double %57, %60
%62 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 1
store double %61, double* %62
%63 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
%64 = load double, double* %63
%65 = call double @llvm.fmuladd.f64(double %64, double 2.000000e+00, double -1.000000e+00)
%66 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
store double %65, double* %66
%67 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 1
%68 = load double, double* %67
%69 = call double @llvm.fmuladd.f64(double %68, double 2.000000e+00, double -1.000000e+00)
%70 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 1
store double %69, double* %70
%71 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 2
%72 = load double, double* %71
%73 = call double @llvm.fmuladd.f64(double %72, double 2.000000e+00, double -1.000000e+00)
%74 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 2
store double %73, double* %74
%75 = getelementptr inbounds [16 x double], [16 x double]* %20, i64 0, i64 0
%76 = getelementptr inbounds [4 x double], [4 x double]* %21, i64 0, i64 0
%77 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 0
%78 = call i32 @__gluMultMatrixVecd(double* %75, double* %76, double* %77)
%79 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 3
%80 = load double, double* %79
%81 = fcmp oeq double %80, 0.000000e+00
br i1 %81, label %82, label %84
82: ; preds = %33
%83 = load double, double* @GL_FALSE
store double %83, double* %10
br label %110
84: ; preds = %33
%85 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 3
%86 = load double, double* %85
%87 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 0
%88 = load double, double* %87
%89 = fdiv double %88, %86
store double %89, double* %87
%90 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 3
%91 = load double, double* %90
%92 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 1
%93 = load double, double* %92
%94 = fdiv double %93, %91
store double %94, double* %92
%95 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 3
%96 = load double, double* %95
%97 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 2
%98 = load double, double* %97
%99 = fdiv double %98, %96
store double %99, double* %97
%100 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 0
%101 = load double, double* %100
%102 = load double*, double** %17
store double %101, double* %102
%103 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 1
%104 = load double, double* %103
%105 = load double*, double** %18
store double %104, double* %105
%106 = getelementptr inbounds [4 x double], [4 x double]* %22, i64 0, i64 2
%107 = load double, double* %106
%108 = load double*, double** %19
store double %107, double* %108
%109 = load double, double* @GL_TRUE
store double %109, double* %10
br label %110
110: ; preds = %84, %82, %31
%111 = load double, double* %10
ret double %111
}

LLVM IR (-O2):
@GL_FALSE = global double 0.000000e+00
@GL_TRUE = global double 0.000000e+00
define double @gluUnProject(double %0, double %1, double %2, double* %3, double* %4, double* nocapture %5, double* nocapture writeonly %6, double* nocapture writeonly %7, double* nocapture writeonly %8) {
%10 = alloca [16 x double]
%11 = alloca [4 x double]
%12 = alloca [4 x double]
%13 = bitcast [16 x double]* %10 to i8*
%14 = bitcast [4 x double]* %11 to i8*
%15 = bitcast [4 x double]* %12 to i8*
%16 = getelementptr inbounds [16 x double], [16 x double]* %10, i64 0, i64 0
%17 = call i32 @__gluMultMatricesd(double* %3, double* %4, double* %16)
%18 = call i32 @__gluInvertMatrixd(double* %16, double* %16)
%19 = icmp eq i32 %18, 0
br i1 %19, label %50, label %20
20: ; preds = %9
%21 = getelementptr inbounds [4 x double], [4 x double]* %11, i64 0, i64 0
%22 = getelementptr inbounds [4 x double], [4 x double]* %11, i64 0, i64 2
%23 = getelementptr inbounds [4 x double], [4 x double]* %11, i64 0, i64 3
store double 1.000000e+00, double* %23
%24 = getelementptr inbounds double, double* %5, i64 2
%25 = bitcast double* %5 to <2 x double>*
%26 = load <2 x double>, <2 x double>* %25
%27 = insertelement <2 x double> poison, double %0, i64 0
%28 = insertelement <2 x double> %27, double %1, i64 1
%29 = fsub <2 x double> %28, %26
%30 = bitcast double* %24 to <2 x double>*
%31 = load <2 x double>, <2 x double>* %30
%32 = fdiv <2 x double> %29, %31
%33 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %32, <2 x double> <double 2.000000e+00, double 2.000000e+00>, <2 x double> <double -1.000000e+00, double -1.000000e+00>)
%34 = bitcast [4 x double]* %11 to <2 x double>*
store <2 x double> %33, <2 x double>* %34
%35 = call double @llvm.fmuladd.f64(double %2, double 2.000000e+00, double -1.000000e+00)
store double %35, double* %22
%36 = getelementptr inbounds [4 x double], [4 x double]* %12, i64 0, i64 0
%37 = call i32 @__gluMultMatrixVecd(double* %16, double* %21, double* %36)
%38 = getelementptr inbounds [4 x double], [4 x double]* %12, i64 0, i64 3
%39 = load double, double* %38
%40 = fcmp oeq double %39, 0.000000e+00
br i1 %40, label %50, label %41
41: ; preds = %20
%42 = load double, double* %36
%43 = fdiv double %42, %39
%44 = getelementptr inbounds [4 x double], [4 x double]* %12, i64 0, i64 1
%45 = load double, double* %44
%46 = fdiv double %45, %39
%47 = getelementptr inbounds [4 x double], [4 x double]* %12, i64 0, i64 2
%48 = load double, double* %47
%49 = fdiv double %48, %39
store double %43, double* %6
store double %46, double* %7
store double %49, double* %8
br label %50
50: ; preds = %20, %9, %41
%51 = phi double* [ @GL_TRUE, %41 ], [ @GL_FALSE, %9 ], [ @GL_FALSE, %20 ]
%52 = load double, double* %51
ret double %52
}