double frexp(double x, int *exptr) {
  union {
    double d;
    unsigned char c[8];
  } u;
  u.d = x;
  *exptr = (int)(((u.c[7] & 0x7f) << 4) | (u.c[6] >> 4)) - 1022;
  u.c[7] &= 0x80;
  u.c[7] |= 0x3f;
  u.c[6] &= 0x0f;
  u.c[6] |= 0xe0;
  return u.d;
}


x86 assembly (clang, -O0):
<frexp>:
push   %rbp
mov    %rsp,%rbp
movsd  %xmm0,-0x8(%rbp)
mov    %rdi,-0x10(%rbp)
movsd  -0x8(%rbp),%xmm0
movsd  %xmm0,-0x18(%rbp)
movzbl -0x11(%rbp),%ecx
and    $0x7f,%ecx
shl    $0x4,%ecx
movzbl -0x12(%rbp),%eax
sar    $0x4,%eax
or     %eax,%ecx
sub    $0x3fe,%ecx
mov    -0x10(%rbp),%rax
mov    %ecx,(%rax)
movzbl -0x11(%rbp),%eax
and    $0x80,%eax
mov    %al,-0x11(%rbp)
movzbl -0x11(%rbp),%eax
or     $0x3f,%eax
mov    %al,-0x11(%rbp)
movzbl -0x12(%rbp),%eax
and    $0xf,%eax
mov    %al,-0x12(%rbp)
movzbl -0x12(%rbp),%eax
or     $0xe0,%eax
mov    %al,-0x12(%rbp)
movsd  -0x18(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<frexp>:
movq   %xmm0,%rax
movabs $0x800fffffffffffff,%rcx
ff 0f 80
and    %rax,%rcx
shr    $0x34,%rax
and    $0x7ff,%eax
add    $0xfffffc02,%eax
mov    %eax,(%rdi)
movabs $0x3fe0000000000000,%rax
or     %rcx,%rax
movq   %rax,%xmm0
ret

LLVM IR (-O0):
%union.anon = type { double }
define double @frexp(double %0, i32* %1) {
%3 = alloca double
%4 = alloca i32*
%5 = alloca %union.anon
store double %0, double* %3
store i32* %1, i32** %4
%6 = load double, double* %3
%7 = bitcast %union.anon* %5 to double*
store double %6, double* %7
%8 = bitcast %union.anon* %5 to [8 x i8]*
%9 = getelementptr inbounds [8 x i8], [8 x i8]* %8, i64 0, i64 7
%10 = load i8, i8* %9
%11 = zext i8 %10 to i32
%12 = and i32 %11, 127
%13 = shl i32 %12, 4
%14 = bitcast %union.anon* %5 to [8 x i8]*
%15 = getelementptr inbounds [8 x i8], [8 x i8]* %14, i64 0, i64 6
%16 = load i8, i8* %15
%17 = zext i8 %16 to i32
%18 = ashr i32 %17, 4
%19 = or i32 %13, %18
%20 = sub nsw i32 %19, 1022
%21 = load i32*, i32** %4
store i32 %20, i32* %21
%22 = bitcast %union.anon* %5 to [8 x i8]*
%23 = getelementptr inbounds [8 x i8], [8 x i8]* %22, i64 0, i64 7
%24 = load i8, i8* %23
%25 = zext i8 %24 to i32
%26 = and i32 %25, 128
%27 = trunc i32 %26 to i8
store i8 %27, i8* %23
%28 = bitcast %union.anon* %5 to [8 x i8]*
%29 = getelementptr inbounds [8 x i8], [8 x i8]* %28, i64 0, i64 7
%30 = load i8, i8* %29
%31 = zext i8 %30 to i32
%32 = or i32 %31, 63
%33 = trunc i32 %32 to i8
store i8 %33, i8* %29
%34 = bitcast %union.anon* %5 to [8 x i8]*
%35 = getelementptr inbounds [8 x i8], [8 x i8]* %34, i64 0, i64 6
%36 = load i8, i8* %35
%37 = zext i8 %36 to i32
%38 = and i32 %37, 15
%39 = trunc i32 %38 to i8
store i8 %39, i8* %35
%40 = bitcast %union.anon* %5 to [8 x i8]*
%41 = getelementptr inbounds [8 x i8], [8 x i8]* %40, i64 0, i64 6
%42 = load i8, i8* %41
%43 = zext i8 %42 to i32
%44 = or i32 %43, 224
%45 = trunc i32 %44 to i8
store i8 %45, i8* %41
%46 = bitcast %union.anon* %5 to double*
%47 = load double, double* %46
ret double %47
}

LLVM IR (-O2):
define double @frexp(double %0, i32* nocapture writeonly %1) {
%3 = bitcast double %0 to i64
%4 = lshr i64 %3, 52
%5 = trunc i64 %4 to i32
%6 = and i32 %5, 2047
%7 = add nsw i32 %6, -1022
store i32 %7, i32* %1
%8 = and i64 %3, -9218868437227405313
%9 = or i64 %8, 4602678819172646912
%10 = bitcast i64 %9 to double
ret double %10
}