unsigned short sqrt32(unsigned long n) {
  unsigned short c = 0x8000;
  unsigned short g = 0x8000;
  for (;;) {
    if (g * g > n)
      g ^= c;
    c >>= 1;
    if (c == 0)
      return g;
    g |= c;
  }
}


x86 assembly (clang, -O0):
<sqrt32>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
movw   $0x8000,-0xa(%rbp)
movw   $0x8000,-0xc(%rbp)
movzwl -0xc(%rbp),%eax
movzwl -0xc(%rbp),%ecx
imul   %ecx,%eax
cltq
cmp    -0x8(%rbp),%rax
jbe    1139 <sqrt32+0x39>
movzwl -0xa(%rbp),%ecx
movzwl -0xc(%rbp),%eax
xor    %ecx,%eax
mov    %ax,-0xc(%rbp)
movzwl -0xa(%rbp),%eax
sar    $0x1,%eax
mov    %ax,-0xa(%rbp)
movzwl -0xa(%rbp),%eax
cmp    $0x0,%eax
jne    1157 <sqrt32+0x57>
movzwl -0xc(%rbp),%eax
pop    %rbp
ret
movzwl -0xa(%rbp),%ecx
movzwl -0xc(%rbp),%eax
or     %ecx,%eax
mov    %ax,-0xc(%rbp)
jmp    1114 <sqrt32+0x14>

x86 assembly (clang, -O2):
<sqrt32>:
xor    %eax,%eax
cmp    $0x40000000,%rdi
mov    $0x4000,%ecx
mov    $0xc000,%edx
cmovb  %ecx,%edx
setae  %al
shl    $0xf,%eax
or     $0x4000,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0xe,%ecx
xor    %edx,%ecx
or     $0x2000,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0xd,%edx
xor    %ecx,%edx
or     $0x1000,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0xc,%ecx
xor    %edx,%ecx
or     $0x800,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0xb,%edx
xor    %ecx,%edx
or     $0x400,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0xa,%ecx
xor    %edx,%ecx
or     $0x200,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0x9,%edx
xor    %ecx,%edx
or     $0x100,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0x8,%ecx
xor    %edx,%ecx
or     $0x80,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0x7,%edx
xor    %ecx,%edx
or     $0x40,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0x6,%ecx
xor    %edx,%ecx
or     $0x20,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0x5,%edx
xor    %ecx,%edx
or     $0x10,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0x4,%ecx
xor    %edx,%ecx
or     $0x8,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
shl    $0x3,%edx
xor    %ecx,%edx
or     $0x4,%edx
movzwl %dx,%eax
imul   %eax,%eax
xor    %ecx,%ecx
cmp    %rdi,%rax
seta   %cl
shl    $0x2,%ecx
xor    %edx,%ecx
or     $0x2,%ecx
movzwl %cx,%eax
imul   %eax,%eax
xor    %edx,%edx
cmp    %rdi,%rax
seta   %dl
add    %edx,%edx
xor    %ecx,%edx
or     $0x1,%edx
movzwl %dx,%ecx
imul   %ecx,%ecx
xor    %eax,%eax
cmp    %rdi,%rcx
seta   %al
xor    %edx,%eax
ret

LLVM IR (-O0):
define zeroext i16 @sqrt32(i64 %0) {
%2 = alloca i64
%3 = alloca i16
%4 = alloca i16
store i64 %0, i64* %2
store i16 -32768, i16* %3
store i16 -32768, i16* %4
br label %5
5: ; preds = %31, %1
%6 = load i16, i16* %4
%7 = zext i16 %6 to i32
%8 = load i16, i16* %4
%9 = zext i16 %8 to i32
%10 = mul nsw i32 %7, %9
%11 = sext i32 %10 to i64
%12 = load i64, i64* %2
%13 = icmp ugt i64 %11, %12
br i1 %13, label %14, label %21
14: ; preds = %5
%15 = load i16, i16* %3
%16 = zext i16 %15 to i32
%17 = load i16, i16* %4
%18 = zext i16 %17 to i32
%19 = xor i32 %18, %16
%20 = trunc i32 %19 to i16
store i16 %20, i16* %4
br label %21
21: ; preds = %14, %5
%22 = load i16, i16* %3
%23 = zext i16 %22 to i32
%24 = ashr i32 %23, 1
%25 = trunc i32 %24 to i16
store i16 %25, i16* %3
%26 = load i16, i16* %3
%27 = zext i16 %26 to i32
%28 = icmp eq i32 %27, 0
br i1 %28, label %29, label %31
29: ; preds = %21
%30 = load i16, i16* %4
ret i16 %30
31: ; preds = %21
%32 = load i16, i16* %3
%33 = zext i16 %32 to i32
%34 = load i16, i16* %4
%35 = zext i16 %34 to i32
%36 = or i32 %35, %33
%37 = trunc i32 %36 to i16
store i16 %37, i16* %4
br label %5
}

LLVM IR (-O2):
define zeroext i16 @sqrt32(i64 %0) {
%2 = icmp ult i64 %0, 1073741824
%3 = select i1 %2, i16 16384, i16 -16384
%4 = zext i16 %3 to i32
%5 = mul nuw nsw i32 %4, %4
%6 = zext i32 %5 to i64
%7 = icmp ugt i64 %6, %0
%8 = select i1 %7, i16 16384, i16 0
%9 = xor i16 %8, %3
%10 = or i16 %9, 8192
%11 = zext i16 %10 to i32
%12 = mul nuw nsw i32 %11, %11
%13 = zext i32 %12 to i64
%14 = icmp ugt i64 %13, %0
%15 = select i1 %14, i16 8192, i16 0
%16 = xor i16 %15, %10
%17 = or i16 %16, 4096
%18 = zext i16 %17 to i32
%19 = mul nuw nsw i32 %18, %18
%20 = zext i32 %19 to i64
%21 = icmp ugt i64 %20, %0
%22 = select i1 %21, i16 4096, i16 0
%23 = xor i16 %22, %17
%24 = or i16 %23, 2048
%25 = zext i16 %24 to i32
%26 = mul nuw nsw i32 %25, %25
%27 = zext i32 %26 to i64
%28 = icmp ugt i64 %27, %0
%29 = select i1 %28, i16 2048, i16 0
%30 = xor i16 %29, %24
%31 = or i16 %30, 1024
%32 = zext i16 %31 to i32
%33 = mul nuw nsw i32 %32, %32
%34 = zext i32 %33 to i64
%35 = icmp ugt i64 %34, %0
%36 = select i1 %35, i16 1024, i16 0
%37 = xor i16 %36, %31
%38 = or i16 %37, 512
%39 = zext i16 %38 to i32
%40 = mul nuw nsw i32 %39, %39
%41 = zext i32 %40 to i64
%42 = icmp ugt i64 %41, %0
%43 = select i1 %42, i16 512, i16 0
%44 = xor i16 %43, %38
%45 = or i16 %44, 256
%46 = zext i16 %45 to i32
%47 = mul nuw nsw i32 %46, %46
%48 = zext i32 %47 to i64
%49 = icmp ugt i64 %48, %0
%50 = select i1 %49, i16 256, i16 0
%51 = xor i16 %50, %45
%52 = or i16 %51, 128
%53 = zext i16 %52 to i32
%54 = mul nuw nsw i32 %53, %53
%55 = zext i32 %54 to i64
%56 = icmp ugt i64 %55, %0
%57 = select i1 %56, i16 128, i16 0
%58 = xor i16 %57, %52
%59 = or i16 %58, 64
%60 = zext i16 %59 to i32
%61 = mul nuw nsw i32 %60, %60
%62 = zext i32 %61 to i64
%63 = icmp ugt i64 %62, %0
%64 = select i1 %63, i16 64, i16 0
%65 = xor i16 %64, %59
%66 = or i16 %65, 32
%67 = zext i16 %66 to i32
%68 = mul nuw nsw i32 %67, %67
%69 = zext i32 %68 to i64
%70 = icmp ugt i64 %69, %0
%71 = select i1 %70, i16 32, i16 0
%72 = xor i16 %71, %66
%73 = or i16 %72, 16
%74 = zext i16 %73 to i32
%75 = mul nuw nsw i32 %74, %74
%76 = zext i32 %75 to i64
%77 = icmp ugt i64 %76, %0
%78 = select i1 %77, i16 16, i16 0
%79 = xor i16 %78, %73
%80 = or i16 %79, 8
%81 = zext i16 %80 to i32
%82 = mul nuw nsw i32 %81, %81
%83 = zext i32 %82 to i64
%84 = icmp ugt i64 %83, %0
%85 = select i1 %84, i16 8, i16 0
%86 = xor i16 %85, %80
%87 = or i16 %86, 4
%88 = zext i16 %87 to i32
%89 = mul nuw nsw i32 %88, %88
%90 = zext i32 %89 to i64
%91 = icmp ugt i64 %90, %0
%92 = select i1 %91, i16 4, i16 0
%93 = xor i16 %92, %87
%94 = or i16 %93, 2
%95 = zext i16 %94 to i32
%96 = mul nuw nsw i32 %95, %95
%97 = zext i32 %96 to i64
%98 = icmp ugt i64 %97, %0
%99 = select i1 %98, i16 2, i16 0
%100 = xor i16 %99, %94
%101 = or i16 %100, 1
%102 = zext i16 %101 to i32
%103 = mul nuw nsw i32 %102, %102
%104 = zext i32 %103 to i64
%105 = icmp ugt i64 %104, %0
%106 = zext i1 %105 to i16
%107 = xor i16 %101, %106
ret i16 %107
}