float roundf(float x) {
  union {
    float f;
    int i;
    struct {
      int i1;
    };
  } u = {x};
  int exp = ((u.i1 >> 23) & 0xFF) - 127;
  if (exp >= 24)
    return x;
  if (exp < -1)
    return u.i &= 0x80000000, u.f;
  if (exp == -1)
    return u.i1 & 0x80000000 ? -1.0f : 1.0f;
  if (u.i & (0x00400000 >> exp))
    u.i += 0x00800000 >> exp;
  return u.i &= ~(0x000FFFFF >> exp), u.f;
}


x86 assembly (clang, -O0):
<roundf>:
push   %rbp
mov    %rsp,%rbp
movss  %xmm0,-0x8(%rbp)
movss  -0x8(%rbp),%xmm0
movss  %xmm0,-0x10(%rbp)
mov    -0x10(%rbp),%eax
sar    $0x17,%eax
and    $0xff,%eax
sub    $0x7f,%eax
mov    %eax,-0x14(%rbp)
cmpl   $0x18,-0x14(%rbp)
jl     113d <roundf+0x3d>
movss  -0x8(%rbp),%xmm0
movss  %xmm0,-0x4(%rbp)
jmp    11f6 <roundf+0xf6>
cmpl   $0xffffffff,-0x14(%rbp)
jge    1161 <roundf+0x61>
mov    -0x10(%rbp),%eax
and    $0x80000000,%eax
mov    %eax,-0x10(%rbp)
movss  -0x10(%rbp),%xmm0
movss  %xmm0,-0x4(%rbp)
jmp    11f6 <roundf+0xf6>
cmpl   $0xffffffff,-0x14(%rbp)
jne    11af <roundf+0xaf>
mov    -0x10(%rbp),%eax
and    $0x80000000,%eax
movss  0xe85(%rip),%xmm0
movss  0xe81(%rip),%xmm1
movss  %xmm1,-0x1c(%rbp)
cmp    $0x0,%eax
movss  %xmm0,-0x18(%rbp)
jne    11a0 <roundf+0xa0>
movss  -0x1c(%rbp),%xmm0
movss  %xmm0,-0x18(%rbp)
movss  -0x18(%rbp),%xmm0
movss  %xmm0,-0x4(%rbp)
jmp    11f6 <roundf+0xf6>
mov    -0x10(%rbp),%eax
mov    -0x14(%rbp),%ecx
mov    $0x400000,%edx
sar    %cl,%edx
mov    %edx,%ecx
and    %ecx,%eax
cmp    $0x0,%eax
je     11d9 <roundf+0xd9>
mov    -0x14(%rbp),%ecx
mov    $0x800000,%eax
sar    %cl,%eax
add    -0x10(%rbp),%eax
mov    %eax,-0x10(%rbp)
mov    -0x14(%rbp),%ecx
mov    $0xfffff,%eax
sar    %cl,%eax
xor    $0xffffffff,%eax
and    -0x10(%rbp),%eax
mov    %eax,-0x10(%rbp)
movss  -0x10(%rbp),%xmm0
movss  %xmm0,-0x4(%rbp)
movss  -0x4(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<roundf>:
movd   %xmm0,%eax
mov    %eax,%ecx
shr    $0x17,%ecx
movzbl %cl,%ecx
cmp    $0x96,%ecx
ja     114d <roundf+0x4d>
cmp    $0x7d,%ecx
ja     1123 <roundf+0x23>
and    $0x80000000,%eax
movd   %eax,%xmm0
ret
add    $0xffffff81,%ecx
cmp    $0xffffffff,%ecx
je     114e <roundf+0x4e>
mov    %eax,%edx
shl    %cl,%edx
shl    $0x9,%edx
sar    $0x1f,%edx
mov    $0x800000,%esi
shr    %cl,%esi
mov    $0xfff00000,%edi
sar    %cl,%edi
and    %edx,%esi
add    %eax,%esi
and    %edi,%esi
movd   %esi,%xmm0
ret
pand   0xeaa(%rip),%xmm0
por    0xeb2(%rip),%xmm0
ret

LLVM IR (-O0):
%union.anon = type { float }
%struct.anon = type { i32 }
define float @roundf(float %0) {
%2 = alloca float
%3 = alloca float
%4 = alloca %union.anon
%5 = alloca i32
store float %0, float* %3
%6 = bitcast %union.anon* %4 to float*
%7 = load float, float* %3
store float %7, float* %6
%8 = bitcast %union.anon* %4 to %struct.anon*
%9 = getelementptr inbounds %struct.anon, %struct.anon* %8, i32 0, i32 0
%10 = load i32, i32* %9
%11 = ashr i32 %10, 23
%12 = and i32 %11, 255
%13 = sub nsw i32 %12, 127
store i32 %13, i32* %5
%14 = load i32, i32* %5
%15 = icmp sge i32 %14, 24
br i1 %15, label %16, label %18
16: ; preds = %1
%17 = load float, float* %3
store float %17, float* %2
br label %60
18: ; preds = %1
%19 = load i32, i32* %5
%20 = icmp slt i32 %19, -1
br i1 %20, label %21, label %27
21: ; preds = %18
%22 = bitcast %union.anon* %4 to i32*
%23 = load i32, i32* %22
%24 = and i32 %23, -2147483648
store i32 %24, i32* %22
%25 = bitcast %union.anon* %4 to float*
%26 = load float, float* %25
store float %26, float* %2
br label %60
27: ; preds = %18
%28 = load i32, i32* %5
%29 = icmp eq i32 %28, -1
br i1 %29, label %30, label %38
30: ; preds = %27
%31 = bitcast %union.anon* %4 to %struct.anon*
%32 = getelementptr inbounds %struct.anon, %struct.anon* %31, i32 0, i32 0
%33 = load i32, i32* %32
%34 = and i32 %33, -2147483648
%35 = icmp ne i32 %34, 0
%36 = zext i1 %35 to i64
%37 = select i1 %35, float -1.000000e+00, float 1.000000e+00
store float %37, float* %2
br label %60
38: ; preds = %27
%39 = bitcast %union.anon* %4 to i32*
%40 = load i32, i32* %39
%41 = load i32, i32* %5
%42 = ashr i32 4194304, %41
%43 = and i32 %40, %42
%44 = icmp ne i32 %43, 0
br i1 %44, label %45, label %51
45: ; preds = %38
%46 = load i32, i32* %5
%47 = ashr i32 8388608, %46
%48 = bitcast %union.anon* %4 to i32*
%49 = load i32, i32* %48
%50 = add nsw i32 %49, %47
store i32 %50, i32* %48
br label %51
51: ; preds = %45, %38
%52 = load i32, i32* %5
%53 = ashr i32 1048575, %52
%54 = xor i32 %53, -1
%55 = bitcast %union.anon* %4 to i32*
%56 = load i32, i32* %55
%57 = and i32 %56, %54
store i32 %57, i32* %55
%58 = bitcast %union.anon* %4 to float*
%59 = load float, float* %58
store float %59, float* %2
br label %60
60: ; preds = %51, %30, %21, %16
%61 = load float, float* %2
ret float %61
}

LLVM IR (-O2):
define float @roundf(float %0) {
%2 = bitcast float %0 to i32
%3 = lshr i32 %2, 23
%4 = and i32 %3, 255
%5 = add nsw i32 %4, -127
%6 = icmp ugt i32 %4, 150
br i1 %6, label %26, label %7
7: ; preds = %1
%8 = icmp ult i32 %4, 126
br i1 %8, label %9, label %12
9: ; preds = %7
%10 = and i32 %2, -2147483648
%11 = bitcast i32 %10 to float
br label %26
12: ; preds = %7
%13 = icmp eq i32 %5, -1
br i1 %13, label %14, label %16
14: ; preds = %12
%15 = tail call float @llvm.copysign.f32(float 1.000000e+00, float %0)
br label %26
16: ; preds = %12
%17 = lshr i32 4194304, %5
%18 = and i32 %17, %2
%19 = icmp eq i32 %18, 0
%20 = lshr i32 8388608, %5
%21 = ashr i32 -1048576, %5
%22 = select i1 %19, i32 0, i32 %20
%23 = add nsw i32 %22, %2
%24 = and i32 %23, %21
%25 = bitcast i32 %24 to float
br label %26
26: ; preds = %1, %16, %14, %9
%27 = phi float [ %11, %9 ], [ %15, %14 ], [ %25, %16 ], [ %0, %1 ]
ret float %27
}