int rd_round(double n) {
  const int floor = (int)n;
  const double rem = n >= 0 ? n - floor : floor - n;
  if (rem < 0.5) {
    return floor;
  } else if (rem > 0.5) {
    return n > 0 ? floor + 1 : floor - 1;
  } else if (floor % 2 == 0) {
    return floor;
  }
  return n > 0 ? floor + 1 : floor - 1;
}


x86 assembly (clang, -O0):
<rd_round>:
push   %rbp
mov    %rsp,%rbp
movsd  %xmm0,-0x10(%rbp)
cvttsd2si -0x10(%rbp),%eax
mov    %eax,-0x14(%rbp)
movsd  -0x10(%rbp),%xmm0
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
jb     113b <rd_round+0x3b>
movsd  -0x10(%rbp),%xmm0
cvtsi2sdl -0x14(%rbp),%xmm1
subsd  %xmm1,%xmm0
movsd  %xmm0,-0x28(%rbp)
jmp    114a <rd_round+0x4a>
cvtsi2sdl -0x14(%rbp),%xmm0
subsd  -0x10(%rbp),%xmm0
movsd  %xmm0,-0x28(%rbp)
movsd  -0x28(%rbp),%xmm0
movsd  %xmm0,-0x20(%rbp)
movsd  0xea4(%rip),%xmm0
ucomisd -0x20(%rbp),%xmm0
jbe    1172 <rd_round+0x72>
mov    -0x14(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1215 <rd_round+0x115>
movsd  -0x20(%rbp),%xmm0
movsd  0xe81(%rip),%xmm1
ucomisd %xmm1,%xmm0
jbe    11bd <rd_round+0xbd>
movsd  -0x10(%rbp),%xmm0
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
jbe    11a9 <rd_round+0xa9>
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    11b2 <rd_round+0xb2>
mov    -0x14(%rbp),%eax
sub    $0x1,%eax
mov    %eax,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1215 <rd_round+0x115>
mov    -0x14(%rbp),%eax
mov    $0x2,%ecx
cltd
idiv   %ecx
cmp    $0x0,%edx
jne    11dc <rd_round+0xdc>
mov    -0x14(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1215 <rd_round+0x115>
jmp    11e1 <rd_round+0xe1>
jmp    11e6 <rd_round+0xe6>
movsd  -0x10(%rbp),%xmm0
xorps  %xmm1,%xmm1
ucomisd %xmm1,%xmm0
jbe    1206 <rd_round+0x106>
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x30(%rbp)
jmp    120f <rd_round+0x10f>
mov    -0x14(%rbp),%eax
sub    $0x1,%eax
mov    %eax,-0x30(%rbp)
mov    -0x30(%rbp),%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<rd_round>:
cvttsd2si %xmm0,%eax
cvttpd2dq %xmm0,%xmm1
cvtdq2pd %xmm1,%xmm2
movapd %xmm0,%xmm3
subsd  %xmm2,%xmm3
subsd  %xmm0,%xmm2
xorpd  %xmm1,%xmm1
cmpnlesd %xmm0,%xmm1
andpd  %xmm1,%xmm2
andnpd %xmm3,%xmm1
orpd   %xmm2,%xmm1
movsd  0xecb(%rip),%xmm2
ucomisd %xmm1,%xmm2
ja     115c <rd_round+0x5c>
ucomisd 0xebd(%rip),%xmm1
ja     1149 <rd_round+0x49>
test   $0x1,%al
je     115c <rd_round+0x5c>
xorpd  %xmm1,%xmm1
xor    %ecx,%ecx
ucomisd %xmm1,%xmm0
seta   %cl
lea    (%rax,%rcx,2),%eax
add    $0xffffffff,%eax
ret

LLVM IR (-O0):
define i32 @rd_round(double %0) {
%2 = alloca i32
%3 = alloca double
%4 = alloca i32
%5 = alloca double
store double %0, double* %3
%6 = load double, double* %3
%7 = fptosi double %6 to i32
store i32 %7, i32* %4
%8 = load double, double* %3
%9 = fcmp oge double %8, 0.000000e+00
br i1 %9, label %10, label %15
10: ; preds = %1
%11 = load double, double* %3
%12 = load i32, i32* %4
%13 = sitofp i32 %12 to double
%14 = fsub double %11, %13
br label %20
15: ; preds = %1
%16 = load i32, i32* %4
%17 = sitofp i32 %16 to double
%18 = load double, double* %3
%19 = fsub double %17, %18
br label %20
20: ; preds = %15, %10
%21 = phi double [ %14, %10 ], [ %19, %15 ]
store double %21, double* %5
%22 = load double, double* %5
%23 = fcmp olt double %22, 5.000000e-01
br i1 %23, label %24, label %26
24: ; preds = %20
%25 = load i32, i32* %4
store i32 %25, i32* %2
br label %59
26: ; preds = %20
%27 = load double, double* %5
%28 = fcmp ogt double %27, 5.000000e-01
br i1 %28, label %29, label %40
29: ; preds = %26
%30 = load double, double* %3
%31 = fcmp ogt double %30, 0.000000e+00
br i1 %31, label %32, label %35
32: ; preds = %29
%33 = load i32, i32* %4
%34 = add nsw i32 %33, 1
br label %38
35: ; preds = %29
%36 = load i32, i32* %4
%37 = sub nsw i32 %36, 1
br label %38
38: ; preds = %35, %32
%39 = phi i32 [ %34, %32 ], [ %37, %35 ]
store i32 %39, i32* %2
br label %59
40: ; preds = %26
%41 = load i32, i32* %4
%42 = srem i32 %41, 2
%43 = icmp eq i32 %42, 0
br i1 %43, label %44, label %46
44: ; preds = %40
%45 = load i32, i32* %4
store i32 %45, i32* %2
br label %59
46: ; preds = %40
br label %47
47: ; preds = %46
br label %48
48: ; preds = %47
%49 = load double, double* %3
%50 = fcmp ogt double %49, 0.000000e+00
br i1 %50, label %51, label %54
51: ; preds = %48
%52 = load i32, i32* %4
%53 = add nsw i32 %52, 1
br label %57
54: ; preds = %48
%55 = load i32, i32* %4
%56 = sub nsw i32 %55, 1
br label %57
57: ; preds = %54, %51
%58 = phi i32 [ %53, %51 ], [ %56, %54 ]
store i32 %58, i32* %2
br label %59
59: ; preds = %57, %44, %38, %24
%60 = load i32, i32* %2
ret i32 %60
}

LLVM IR (-O2):
define i32 @rd_round(double %0) {
%2 = fptosi double %0 to i32
%3 = fcmp ult double %0, 0.000000e+00
%4 = sitofp i32 %2 to double
%5 = fsub double %0, %4
%6 = fsub double %4, %0
%7 = select i1 %3, double %6, double %5
%8 = fcmp olt double %7, 5.000000e-01
br i1 %8, label %22, label %9
9: ; preds = %1
%10 = fcmp ogt double %7, 5.000000e-01
br i1 %10, label %11, label %15
11: ; preds = %9
%12 = fcmp ogt double %0, 0.000000e+00
%13 = select i1 %12, i32 1, i32 -1
%14 = add nsw i32 %13, %2
br label %22
15: ; preds = %9
%16 = and i32 %2, 1
%17 = icmp eq i32 %16, 0
br i1 %17, label %22, label %18
18: ; preds = %15
%19 = fcmp ogt double %0, 0.000000e+00
%20 = select i1 %19, i32 1, i32 -1
%21 = add nsw i32 %20, %2
br label %22
22: ; preds = %15, %1, %18, %11
%23 = phi i32 [ %14, %11 ], [ %21, %18 ], [ %2, %1 ], [ %2, %15 ]
ret i32 %23
}