void upperTriSolve(double **U, int n, double *b, double *x) {
  int i, j;
  for (i = 0; i < n; i++) {
    x[i] = b[i];
  }
  for (j = n - 1; j > 0; j--) {
    x[j] /= U[j][j];
    for (i = 0; i < j; i++) {
      x[i] -= x[j] * U[i][j];
    }
  }
  x[0] /= U[0][0];
}


x86 assembly (clang, -O0):
<upperTriSolve>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
movl   $0x0,-0x24(%rbp)
mov    -0x24(%rbp),%eax
cmp    -0xc(%rbp),%eax
jge    114e <upperTriSolve+0x4e>
mov    -0x18(%rbp),%rax
movslq -0x24(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    111a <upperTriSolve+0x1a>
mov    -0xc(%rbp),%eax
sub    $0x1,%eax
mov    %eax,-0x28(%rbp)
cmpl   $0x0,-0x28(%rbp)
jle    1213 <upperTriSolve+0x113>
mov    -0x8(%rbp),%rax
movslq -0x28(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm1
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
movl   $0x0,-0x24(%rbp)
mov    -0x24(%rbp),%eax
cmp    -0x28(%rbp),%eax
jge    1200 <upperTriSolve+0x100>
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm1
movq   %xmm0,%rdx
movabs $0x8000000000000000,%rsi
xor    %rsi,%rdx
movq   %rdx,%xmm0
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    1193 <upperTriSolve+0x93>
jmp    1205 <upperTriSolve+0x105>
mov    -0x28(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x28(%rbp)
jmp    1157 <upperTriSolve+0x57>
mov    -0x8(%rbp),%rax
mov    (%rax),%rax
movsd  (%rax),%xmm1
mov    -0x20(%rbp),%rax
movsd  (%rax),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax)
pop    %rbp
ret

x86 assembly (clang, -O2):
<upperTriSolve>:
push   %rbx
test   %esi,%esi
jle    1317 <upperTriSolve+0x217>
mov    %esi,%r8d
cmp    $0x4,%esi
jb     1127 <upperTriSolve+0x27>
lea    (%rdx,%r8,8),%rax
cmp    %rcx,%rax
jbe    119c <upperTriSolve+0x9c>
lea    (%rcx,%r8,8),%rax
cmp    %rdx,%rax
jbe    119c <upperTriSolve+0x9c>
xor    %ebx,%ebx
mov    %rbx,%r9
not    %r9
add    %r8,%r9
mov    %r8,%rax
and    $0x3,%rax
je     1154 <upperTriSolve+0x54>
nopl   0x0(%rax,%rax,1)
movsd  (%rdx,%rbx,8),%xmm0
movsd  %xmm0,(%rcx,%rbx,8)
add    $0x1,%rbx
add    $0xffffffffffffffff,%rax
jne    1140 <upperTriSolve+0x40>
cmp    $0x3,%r9
jb     128c <upperTriSolve+0x18c>
xchg   %ax,%ax
movsd  (%rdx,%rbx,8),%xmm0
movsd  %xmm0,(%rcx,%rbx,8)
movsd  0x8(%rdx,%rbx,8),%xmm0
movsd  %xmm0,0x8(%rcx,%rbx,8)
movsd  0x10(%rdx,%rbx,8),%xmm0
movsd  %xmm0,0x10(%rcx,%rbx,8)
movsd  0x18(%rdx,%rbx,8),%xmm0
movsd  %xmm0,0x18(%rcx,%rbx,8)
add    $0x4,%rbx
cmp    %rbx,%r8
jne    1160 <upperTriSolve+0x60>
jmp    128c <upperTriSolve+0x18c>
mov    %r8d,%ebx
and    $0xfffffffc,%ebx
lea    -0x4(%rbx),%rax
mov    %rax,%r10
shr    $0x2,%r10
add    $0x1,%r10
mov    %r10d,%r9d
and    $0x3,%r9d
cmp    $0xc,%rax
jae    11c3 <upperTriSolve+0xc3>
xor    %r11d,%r11d
jmp    123c <upperTriSolve+0x13c>
and    $0xfffffffffffffffc,%r10
xor    %r11d,%r11d
nopw   0x0(%rax,%rax,1)
movups (%rdx,%r11,8),%xmm0
movups 0x10(%rdx,%r11,8),%xmm1
movups %xmm0,(%rcx,%r11,8)
movups %xmm1,0x10(%rcx,%r11,8)
movups 0x20(%rdx,%r11,8),%xmm0
movups 0x30(%rdx,%r11,8),%xmm1
movups %xmm0,0x20(%rcx,%r11,8)
movups %xmm1,0x30(%rcx,%r11,8)
movups 0x40(%rdx,%r11,8),%xmm0
movups 0x50(%rdx,%r11,8),%xmm1
movups %xmm0,0x40(%rcx,%r11,8)
movups %xmm1,0x50(%rcx,%r11,8)
movupd 0x60(%rdx,%r11,8),%xmm0
movupd 0x70(%rdx,%r11,8),%xmm1
movupd %xmm0,0x60(%rcx,%r11,8)
movupd %xmm1,0x70(%rcx,%r11,8)
add    $0x10,%r11
add    $0xfffffffffffffffc,%r10
jne    11d0 <upperTriSolve+0xd0>
test   %r9,%r9
je     1283 <upperTriSolve+0x183>
lea    (%rcx,%r11,8),%r10
add    $0x10,%r10
lea    (%rdx,%r11,8),%r11
add    $0x10,%r11
shl    $0x5,%r9
xor    %eax,%eax
nopw   0x0(%rax,%rax,1)
movupd -0x10(%r11,%rax,1),%xmm0
movupd (%r11,%rax,1),%xmm1
movupd %xmm0,-0x10(%r10,%rax,1)
movupd %xmm1,(%r10,%rax,1)
add    $0x20,%rax
cmp    %rax,%r9
jne    1260 <upperTriSolve+0x160>
cmp    %r8,%rbx
jne    1129 <upperTriSolve+0x29>
cmp    $0x2,%esi
jl     1317 <upperTriSolve+0x217>
add    $0xffffffff,%esi
mov    (%rdi),%r9
jmp    12aa <upperTriSolve+0x1aa>
nopl   (%rax)
add    $0xffffffffffffffff,%rsi
cmp    $0x3,%r10
jl     1317 <upperTriSolve+0x217>
mov    %r8,%r10
add    $0xffffffffffffffff,%r8
mov    %r8d,%eax
mov    (%rdi,%rax,8),%rbx
movsd  (%rcx,%rax,8),%xmm0
divsd  (%rbx,%rax,8),%xmm0
movsd  %xmm0,(%rcx,%rax,8)
mulsd  (%r9,%rax,8),%xmm0
movsd  (%rcx),%xmm1
subsd  %xmm0,%xmm1
movsd  %xmm1,(%rcx)
cmp    $0x1,%rsi
je     12a0 <upperTriSolve+0x1a0>
mov    $0x1,%ebx
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
movsd  (%rcx,%rax,8),%xmm0
mov    (%rdi,%rbx,8),%rdx
movsd  (%rcx,%rbx,8),%xmm1
mulsd  (%rdx,%rax,8),%xmm0
subsd  %xmm0,%xmm1
movsd  %xmm1,(%rcx,%rbx,8)
add    $0x1,%rbx
cmp    %rbx,%rsi
jne    12f0 <upperTriSolve+0x1f0>
jmp    12a0 <upperTriSolve+0x1a0>
mov    (%rdi),%rax
movsd  (%rcx),%xmm0
divsd  (%rax),%xmm0
movsd  %xmm0,(%rcx)
pop    %rbx
ret

LLVM IR (-O0):
define void @upperTriSolve(double** %0, i32 %1, double* %2, double* %3) {
%5 = alloca double**
%6 = alloca i32
%7 = alloca double*
%8 = alloca double*
%9 = alloca i32
%10 = alloca i32
store double** %0, double*** %5
store i32 %1, i32* %6
store double* %2, double** %7
store double* %3, double** %8
store i32 0, i32* %9
br label %11
11: ; preds = %25, %4
%12 = load i32, i32* %9
%13 = load i32, i32* %6
%14 = icmp slt i32 %12, %13
br i1 %14, label %15, label %28
15: ; preds = %11
%16 = load double*, double** %7
%17 = load i32, i32* %9
%18 = sext i32 %17 to i64
%19 = getelementptr inbounds double, double* %16, i64 %18
%20 = load double, double* %19
%21 = load double*, double** %8
%22 = load i32, i32* %9
%23 = sext i32 %22 to i64
%24 = getelementptr inbounds double, double* %21, i64 %23
store double %20, double* %24
br label %25
25: ; preds = %15
%26 = load i32, i32* %9
%27 = add nsw i32 %26, 1
store i32 %27, i32* %9
br label %11
28: ; preds = %11
%29 = load i32, i32* %6
%30 = sub nsw i32 %29, 1
store i32 %30, i32* %10
br label %31
31: ; preds = %80, %28
%32 = load i32, i32* %10
%33 = icmp sgt i32 %32, 0
br i1 %33, label %34, label %83
34: ; preds = %31
%35 = load double**, double*** %5
%36 = load i32, i32* %10
%37 = sext i32 %36 to i64
%38 = getelementptr inbounds double*, double** %35, i64 %37
%39 = load double*, double** %38
%40 = load i32, i32* %10
%41 = sext i32 %40 to i64
%42 = getelementptr inbounds double, double* %39, i64 %41
%43 = load double, double* %42
%44 = load double*, double** %8
%45 = load i32, i32* %10
%46 = sext i32 %45 to i64
%47 = getelementptr inbounds double, double* %44, i64 %46
%48 = load double, double* %47
%49 = fdiv double %48, %43
store double %49, double* %47
store i32 0, i32* %9
br label %50
50: ; preds = %76, %34
%51 = load i32, i32* %9
%52 = load i32, i32* %10
%53 = icmp slt i32 %51, %52
br i1 %53, label %54, label %79
54: ; preds = %50
%55 = load double*, double** %8
%56 = load i32, i32* %10
%57 = sext i32 %56 to i64
%58 = getelementptr inbounds double, double* %55, i64 %57
%59 = load double, double* %58
%60 = load double**, double*** %5
%61 = load i32, i32* %9
%62 = sext i32 %61 to i64
%63 = getelementptr inbounds double*, double** %60, i64 %62
%64 = load double*, double** %63
%65 = load i32, i32* %10
%66 = sext i32 %65 to i64
%67 = getelementptr inbounds double, double* %64, i64 %66
%68 = load double, double* %67
%69 = load double*, double** %8
%70 = load i32, i32* %9
%71 = sext i32 %70 to i64
%72 = getelementptr inbounds double, double* %69, i64 %71
%73 = load double, double* %72
%74 = fneg double %59
%75 = call double @llvm.fmuladd.f64(double %74, double %68, double %73)
store double %75, double* %72
br label %76
76: ; preds = %54
%77 = load i32, i32* %9
%78 = add nsw i32 %77, 1
store i32 %78, i32* %9
br label %50
79: ; preds = %50
br label %80
80: ; preds = %79
%81 = load i32, i32* %10
%82 = add nsw i32 %81, -1
store i32 %82, i32* %10
br label %31
83: ; preds = %31
%84 = load double**, double*** %5
%85 = getelementptr inbounds double*, double** %84, i64 0
%86 = load double*, double** %85
%87 = getelementptr inbounds double, double* %86, i64 0
%88 = load double, double* %87
%89 = load double*, double** %8
%90 = getelementptr inbounds double, double* %89, i64 0
%91 = load double, double* %90
%92 = fdiv double %91, %88
store double %92, double* %90
ret void
}

LLVM IR (-O2):
define void @upperTriSolve(double** nocapture %0, i32 %1, double* nocapture %2, double* nocapture %3) {
%5 = icmp sgt i32 %1, 0
br i1 %5, label %6, label %172
6: ; preds = %4
%7 = zext i32 %1 to i64
%8 = icmp ult i32 %1, 4
br i1 %8, label %94, label %9
9: ; preds = %6
%10 = getelementptr double, double* %3, i64 %7
%11 = getelementptr double, double* %2, i64 %7
%12 = icmp ugt double* %11, %3
%13 = icmp ugt double* %10, %2
%14 = and i1 %12, %13
br i1 %14, label %94, label %15
15: ; preds = %9
%16 = and i64 %7, 4294967292
%17 = add nsw i64 %16, -4
%18 = lshr exact i64 %17, 2
%19 = add nuw nsw i64 %18, 1
%20 = and i64 %19, 3
%21 = icmp ult i64 %17, 12
br i1 %21, label %73, label %22
22: ; preds = %15
%23 = and i64 %19, 9223372036854775804
br label %24
24: ; preds = %24, %22
%25 = phi i64 [ 0, %22 ], [ %70, %24 ]
%26 = phi i64 [ 0, %22 ], [ %71, %24 ]
%27 = getelementptr inbounds double, double* %2, i64 %25
%28 = bitcast double* %27 to <2 x double>*
%29 = load <2 x double>, <2 x double>* %28
%30 = getelementptr inbounds double, double* %27, i64 2
%31 = bitcast double* %30 to <2 x double>*
%32 = load <2 x double>, <2 x double>* %31
%33 = getelementptr inbounds double, double* %3, i64 %25
%34 = bitcast double* %33 to <2 x double>*
store <2 x double> %29, <2 x double>* %34
%35 = getelementptr inbounds double, double* %33, i64 2
%36 = bitcast double* %35 to <2 x double>*
store <2 x double> %32, <2 x double>* %36
%37 = or i64 %25, 4
%38 = getelementptr inbounds double, double* %2, i64 %37
%39 = bitcast double* %38 to <2 x double>*
%40 = load <2 x double>, <2 x double>* %39
%41 = getelementptr inbounds double, double* %38, i64 2
%42 = bitcast double* %41 to <2 x double>*
%43 = load <2 x double>, <2 x double>* %42
%44 = getelementptr inbounds double, double* %3, i64 %37
%45 = bitcast double* %44 to <2 x double>*
store <2 x double> %40, <2 x double>* %45
%46 = getelementptr inbounds double, double* %44, i64 2
%47 = bitcast double* %46 to <2 x double>*
store <2 x double> %43, <2 x double>* %47
%48 = or i64 %25, 8
%49 = getelementptr inbounds double, double* %2, i64 %48
%50 = bitcast double* %49 to <2 x double>*
%51 = load <2 x double>, <2 x double>* %50
%52 = getelementptr inbounds double, double* %49, i64 2
%53 = bitcast double* %52 to <2 x double>*
%54 = load <2 x double>, <2 x double>* %53
%55 = getelementptr inbounds double, double* %3, i64 %48
%56 = bitcast double* %55 to <2 x double>*
store <2 x double> %51, <2 x double>* %56
%57 = getelementptr inbounds double, double* %55, i64 2
%58 = bitcast double* %57 to <2 x double>*
store <2 x double> %54, <2 x double>* %58
%59 = or i64 %25, 12
%60 = getelementptr inbounds double, double* %2, i64 %59
%61 = bitcast double* %60 to <2 x double>*
%62 = load <2 x double>, <2 x double>* %61
%63 = getelementptr inbounds double, double* %60, i64 2
%64 = bitcast double* %63 to <2 x double>*
%65 = load <2 x double>, <2 x double>* %64
%66 = getelementptr inbounds double, double* %3, i64 %59
%67 = bitcast double* %66 to <2 x double>*
store <2 x double> %62, <2 x double>* %67
%68 = getelementptr inbounds double, double* %66, i64 2
%69 = bitcast double* %68 to <2 x double>*
store <2 x double> %65, <2 x double>* %69
%70 = add nuw i64 %25, 16
%71 = add nuw i64 %26, 4
%72 = icmp eq i64 %71, %23
br i1 %72, label %73, label %24
73: ; preds = %24, %15
%74 = phi i64 [ 0, %15 ], [ %70, %24 ]
%75 = icmp eq i64 %20, 0
br i1 %75, label %92, label %76
76: ; preds = %73, %76
%77 = phi i64 [ %89, %76 ], [ %74, %73 ]
%78 = phi i64 [ %90, %76 ], [ 0, %73 ]
%79 = getelementptr inbounds double, double* %2, i64 %77
%80 = bitcast double* %79 to <2 x double>*
%81 = load <2 x double>, <2 x double>* %80
%82 = getelementptr inbounds double, double* %79, i64 2
%83 = bitcast double* %82 to <2 x double>*
%84 = load <2 x double>, <2 x double>* %83
%85 = getelementptr inbounds double, double* %3, i64 %77
%86 = bitcast double* %85 to <2 x double>*
store <2 x double> %81, <2 x double>* %86
%87 = getelementptr inbounds double, double* %85, i64 2
%88 = bitcast double* %87 to <2 x double>*
store <2 x double> %84, <2 x double>* %88
%89 = add nuw i64 %77, 4
%90 = add i64 %78, 1
%91 = icmp eq i64 %90, %20
br i1 %91, label %92, label %76
92: ; preds = %76, %73
%93 = icmp eq i64 %16, %7
br i1 %93, label %112, label %94
94: ; preds = %9, %6, %92
%95 = phi i64 [ 0, %9 ], [ 0, %6 ], [ %16, %92 ]
%96 = xor i64 %95, -1
%97 = add nsw i64 %96, %7
%98 = and i64 %7, 3
%99 = icmp eq i64 %98, 0
br i1 %99, label %109, label %100
100: ; preds = %94, %100
%101 = phi i64 [ %106, %100 ], [ %95, %94 ]
%102 = phi i64 [ %107, %100 ], [ 0, %94 ]
%103 = getelementptr inbounds double, double* %2, i64 %101
%104 = load double, double* %103
%105 = getelementptr inbounds double, double* %3, i64 %101
store double %104, double* %105
%106 = add nuw nsw i64 %101, 1
%107 = add i64 %102, 1
%108 = icmp eq i64 %107, %98
br i1 %108, label %109, label %100
109: ; preds = %100, %94
%110 = phi i64 [ %95, %94 ], [ %106, %100 ]
%111 = icmp ult i64 %97, 3
br i1 %111, label %112, label %119
112: ; preds = %109, %119, %92
%113 = icmp sgt i32 %1, 1
br i1 %113, label %114, label %172
114: ; preds = %112
%115 = add nsw i32 %1, -1
%116 = zext i32 %115 to i64
%117 = zext i32 %1 to i64
%118 = load double*, double** %0
br label %141
119: ; preds = %109, %119
%120 = phi i64 [ %136, %119 ], [ %110, %109 ]
%121 = getelementptr inbounds double, double* %2, i64 %120
%122 = load double, double* %121
%123 = getelementptr inbounds double, double* %3, i64 %120
store double %122, double* %123
%124 = add nuw nsw i64 %120, 1
%125 = getelementptr inbounds double, double* %2, i64 %124
%126 = load double, double* %125
%127 = getelementptr inbounds double, double* %3, i64 %124
store double %126, double* %127
%128 = add nuw nsw i64 %120, 2
%129 = getelementptr inbounds double, double* %2, i64 %128
%130 = load double, double* %129
%131 = getelementptr inbounds double, double* %3, i64 %128
store double %130, double* %131
%132 = add nuw nsw i64 %120, 3
%133 = getelementptr inbounds double, double* %2, i64 %132
%134 = load double, double* %133
%135 = getelementptr inbounds double, double* %3, i64 %132
store double %134, double* %135
%136 = add nuw nsw i64 %120, 4
%137 = icmp eq i64 %136, %7
br i1 %137, label %112, label %119
138: ; preds = %159, %141
%139 = icmp sgt i64 %142, 2
%140 = add nsw i64 %143, -1
br i1 %139, label %141, label %172
141: ; preds = %138, %114
%142 = phi i64 [ %117, %114 ], [ %144, %138 ]
%143 = phi i64 [ %116, %114 ], [ %140, %138 ]
%144 = add nsw i64 %142, -1
%145 = and i64 %144, 4294967295
%146 = getelementptr inbounds double*, double** %0, i64 %145
%147 = load double*, double** %146
%148 = getelementptr inbounds double, double* %147, i64 %145
%149 = load double, double* %148
%150 = getelementptr inbounds double, double* %3, i64 %145
%151 = load double, double* %150
%152 = fdiv double %151, %149
store double %152, double* %150
%153 = getelementptr inbounds double, double* %118, i64 %145
%154 = load double, double* %153
%155 = load double, double* %3
%156 = fneg double %152
%157 = tail call double @llvm.fmuladd.f64(double %156, double %154, double %155)
store double %157, double* %3
%158 = icmp eq i64 %143, 1
br i1 %158, label %138, label %159
159: ; preds = %141, %159
%160 = phi i64 [ %170, %159 ], [ 1, %141 ]
%161 = load double, double* %150
%162 = getelementptr inbounds double*, double** %0, i64 %160
%163 = load double*, double** %162
%164 = getelementptr inbounds double, double* %163, i64 %145
%165 = load double, double* %164
%166 = getelementptr inbounds double, double* %3, i64 %160
%167 = load double, double* %166
%168 = fneg double %161
%169 = tail call double @llvm.fmuladd.f64(double %168, double %165, double %167)
store double %169, double* %166
%170 = add nuw nsw i64 %160, 1
%171 = icmp eq i64 %170, %143
br i1 %171, label %138, label %159
172: ; preds = %138, %4, %112
%173 = load double*, double** %0
%174 = load double, double* %173
%175 = load double, double* %3
%176 = fdiv double %175, %174
store double %176, double* %3
ret void
}