void substituicao_descendente(double **U, double **Y, int dim, double **X) {
  int i, j;
  for (i = dim - 1; i >= 0; i--) {
    X[i][0] = Y[i][0];
    for (j = i + 1; j < dim; j++) {
      X[i][0] -= U[i][j] * X[j][0];
    }
    X[i][0] /= U[i][i];
  }
}


x86 assembly (clang, -O0):
<substituicao_descendente>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
mov    %rcx,-0x20(%rbp)
mov    -0x14(%rbp),%eax
sub    $0x1,%eax
mov    %eax,-0x24(%rbp)
cmpl   $0x0,-0x24(%rbp)
jl     11fc <substituicao_descendente+0xfc>
mov    -0x10(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movsd  (%rax),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movsd  %xmm0,(%rax)
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
cmp    -0x14(%rbp),%eax
jge    11c1 <substituicao_descendente+0xc1>
mov    -0x8(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movsd  (%rax),%xmm2
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movsd  (%rax),%xmm1
movq   %xmm0,%rcx
movabs $0x8000000000000000,%rdx
xor    %rdx,%rcx
movq   %rcx,%xmm0
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,(%rax)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    114f <substituicao_descendente+0x4f>
mov    -0x8(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movslq -0x24(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm1
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
mov    (%rax,%rcx,8),%rax
movsd  (%rax),%xmm0
divsd  %xmm1,%xmm0
movsd  %xmm0,(%rax)
mov    -0x24(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x24(%rbp)
jmp    111c <substituicao_descendente+0x1c>
pop    %rbp
ret

x86 assembly (clang, -O2):
<substituicao_descendente>:
push   %r15
push   %r14
push   %rbx
test   %edx,%edx
jle    11cc <substituicao_descendente+0xcc>
mov    %edx,%r14d
xor    %r11d,%r11d
mov    %r14,%r8
jmp    1138 <substituicao_descendente+0x38>
nopl   0x0(%rax,%rax,1)
divsd  (%r15,%r10,8),%xmm0
movsd  %xmm0,(%rdx)
add    $0x1,%r11d
cmp    $0x1,%r9
jle    11cc <substituicao_descendente+0xcc>
mov    %r8,%r9
add    $0xffffffffffffffff,%r8
mov    %r8d,%r10d
mov    (%rsi,%r10,8),%rax
movsd  (%rax),%xmm0
mov    (%rcx,%r10,8),%rdx
movsd  %xmm0,(%rdx)
mov    (%rdi,%r10,8),%r15
cmp    %r14,%r9
jge    1120 <substituicao_descendente+0x20>
test   $0x1,%r11b
jne    1170 <substituicao_descendente+0x70>
mov    %r9,%rax
cmp    $0x1,%r11d
jne    1190 <substituicao_descendente+0x90>
jmp    1120 <substituicao_descendente+0x20>
nopl   0x0(%rax)
movsd  (%r15,%r9,8),%xmm1
mov    (%rcx,%r9,8),%rax
mulsd  (%rax),%xmm1
subsd  %xmm1,%xmm0
movsd  %xmm0,(%rdx)
lea    0x1(%r9),%rax
cmp    $0x1,%r11d
je     1120 <substituicao_descendente+0x20>
movsd  (%r15,%rax,8),%xmm1
mov    (%rcx,%rax,8),%rbx
mulsd  (%rbx),%xmm1
subsd  %xmm1,%xmm0
movsd  %xmm0,(%rdx)
movsd  0x8(%r15,%rax,8),%xmm1
mov    0x8(%rcx,%rax,8),%rbx
mulsd  (%rbx),%xmm1
subsd  %xmm1,%xmm0
movsd  %xmm0,(%rdx)
add    $0x2,%rax
cmp    %eax,%r14d
jne    1190 <substituicao_descendente+0x90>
jmp    1120 <substituicao_descendente+0x20>
pop    %rbx
pop    %r14
pop    %r15
ret

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

LLVM IR (-O2):
define void @substituicao_descendente(double** nocapture %0, double** nocapture %1, i32 %2, double** nocapture %3) {
%5 = icmp sgt i32 %2, 0
br i1 %5, label %6, label %69
6: ; preds = %4
%7 = zext i32 %2 to i64
%8 = zext i32 %2 to i64
br label %9
9: ; preds = %6, %61
%10 = phi i32 [ 0, %6 ], [ %68, %61 ]
%11 = phi i64 [ %8, %6 ], [ %67, %61 ]
%12 = phi i64 [ %7, %6 ], [ %13, %61 ]
%13 = add nsw i64 %12, -1
%14 = and i64 %13, 4294967295
%15 = getelementptr inbounds double*, double** %1, i64 %14
%16 = load double*, double** %15
%17 = load double, double* %16
%18 = getelementptr inbounds double*, double** %3, i64 %14
%19 = load double*, double** %18
store double %17, double* %19
%20 = icmp slt i64 %11, %7
%21 = getelementptr inbounds double*, double** %0, i64 %14
%22 = load double*, double** %21
br i1 %20, label %23, label %61
23: ; preds = %9
%24 = and i32 %10, 1
%25 = icmp eq i32 %24, 0
br i1 %25, label %35, label %26
26: ; preds = %23
%27 = getelementptr inbounds double, double* %22, i64 %12
%28 = load double, double* %27
%29 = getelementptr inbounds double*, double** %3, i64 %12
%30 = load double*, double** %29
%31 = load double, double* %30
%32 = fneg double %28
%33 = tail call double @llvm.fmuladd.f64(double %32, double %31, double %17)
store double %33, double* %19
%34 = add nsw i64 %12, 1
br label %35
35: ; preds = %26, %23
%36 = phi double [ undef, %23 ], [ %33, %26 ]
%37 = phi double [ %17, %23 ], [ %33, %26 ]
%38 = phi i64 [ %12, %23 ], [ %34, %26 ]
%39 = icmp eq i32 %10, 1
br i1 %39, label %61, label %40
40: ; preds = %35, %40
%41 = phi double [ %57, %40 ], [ %37, %35 ]
%42 = phi i64 [ %58, %40 ], [ %38, %35 ]
%43 = getelementptr inbounds double, double* %22, i64 %42
%44 = load double, double* %43
%45 = getelementptr inbounds double*, double** %3, i64 %42
%46 = load double*, double** %45
%47 = load double, double* %46
%48 = fneg double %44
%49 = tail call double @llvm.fmuladd.f64(double %48, double %47, double %41)
store double %49, double* %19
%50 = add nsw i64 %42, 1
%51 = getelementptr inbounds double, double* %22, i64 %50
%52 = load double, double* %51
%53 = getelementptr inbounds double*, double** %3, i64 %50
%54 = load double*, double** %53
%55 = load double, double* %54
%56 = fneg double %52
%57 = tail call double @llvm.fmuladd.f64(double %56, double %55, double %49)
store double %57, double* %19
%58 = add nsw i64 %42, 2
%59 = trunc i64 %58 to i32
%60 = icmp eq i32 %59, %2
br i1 %60, label %61, label %40
61: ; preds = %35, %40, %9
%62 = phi double [ %17, %9 ], [ %36, %35 ], [ %57, %40 ]
%63 = getelementptr inbounds double, double* %22, i64 %14
%64 = load double, double* %63
%65 = fdiv double %62, %64
store double %65, double* %19
%66 = icmp sgt i64 %11, 1
%67 = add nsw i64 %11, -1
%68 = add i32 %10, 1
br i1 %66, label %9, label %69
69: ; preds = %61, %4
ret void
}