void nibble_sort_word(unsigned long *w) {
  unsigned int b[16] = {0};
  unsigned long t = *w;
  for (int i = 0; i < 16; i++, t >>= 4) {
    b[t & 0xFUL]++;
  }
  for (int h = 60, i = 15; i >= 0; i--) {
    for (; b[i]; b[i]--, h -= 4) {
      t |= (unsigned long)i << h;
    }
  }
  *w = t;
}


x86 assembly (clang, -O0):
<nibble_sort_word>:
push   %rbp
mov    %rsp,%rbp
sub    $0x70,%rsp
mov    %rdi,-0x8(%rbp)
lea    -0x50(%rbp),%rdi
xor    %esi,%esi
mov    $0x40,%edx
call   1030 <memset@plt>
mov    -0x8(%rbp),%rax
mov    (%rax),%rax
mov    %rax,-0x58(%rbp)
movl   $0x0,-0x5c(%rbp)
cmpl   $0x10,-0x5c(%rbp)
jge    1175 <nibble_sort_word+0x65>
mov    -0x58(%rbp),%rax
and    $0xf,%rax
mov    -0x50(%rbp,%rax,4),%ecx
add    $0x1,%ecx
mov    %ecx,-0x50(%rbp,%rax,4)
mov    -0x5c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x5c(%rbp)
mov    -0x58(%rbp),%rax
shr    $0x4,%rax
mov    %rax,-0x58(%rbp)
jmp    113e <nibble_sort_word+0x2e>
movl   $0x3c,-0x60(%rbp)
movl   $0xf,-0x64(%rbp)
cmpl   $0x0,-0x64(%rbp)
jl     11e3 <nibble_sort_word+0xd3>
jmp    1192 <nibble_sort_word+0x82>
movslq -0x64(%rbp),%rax
cmpl   $0x0,-0x50(%rbp,%rax,4)
je     11d0 <nibble_sort_word+0xc0>
movslq -0x64(%rbp),%rax
mov    -0x60(%rbp),%ecx
shl    %cl,%rax
or     -0x58(%rbp),%rax
mov    %rax,-0x58(%rbp)
movslq -0x64(%rbp),%rax
mov    -0x50(%rbp,%rax,4),%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0x50(%rbp,%rax,4)
mov    -0x60(%rbp),%eax
sub    $0x4,%eax
mov    %eax,-0x60(%rbp)
jmp    1192 <nibble_sort_word+0x82>
jmp    11d5 <nibble_sort_word+0xc5>
mov    -0x64(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x64(%rbp)
jmp    1183 <nibble_sort_word+0x73>
mov    -0x58(%rbp),%rcx
mov    -0x8(%rbp),%rax
mov    %rcx,(%rax)
add    $0x70,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<nibble_sort_word>:
pxor   %xmm0,%xmm0
movdqa %xmm0,-0x18(%rsp)
movdqa %xmm0,-0x28(%rsp)
movdqa %xmm0,-0x38(%rsp)
movdqa %xmm0,-0x48(%rsp)
mov    (%rdi),%rax
mov    %eax,%ecx
and    $0xf,%ecx
addl   $0x1,-0x48(%rsp,%rcx,4)
mov    %rax,%rcx
shr    $0x2,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x6,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0xa,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0xe,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x12,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x16,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x1a,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x1e,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x22,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x26,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x2a,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x2e,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x32,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
mov    %rax,%rcx
shr    $0x36,%rcx
and    $0x3c,%ecx
addl   $0x1,-0x48(%rsp,%rcx,1)
shr    $0x3c,%rax
addl   $0x1,-0x48(%rsp,%rax,4)
mov    $0x3c,%r8d
mov    $0xf,%r11d
xor    %esi,%esi
movdqa 0xde5(%rip),%xmm8
movdqa 0xdec(%rip),%xmm12
movdqa 0xdf3(%rip),%xmm9
movdqa 0xdfa(%rip),%xmm10
movdqa 0xe01(%rip),%xmm11
jmp    1266 <nibble_sort_word+0x166>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
add    %r9d,%r8d
movl   $0x0,-0x48(%rsp,%r11,4)
sub    $0x1,%r11
jb     1455 <nibble_sort_word+0x355>
mov    -0x48(%rsp,%r11,4),%eax
test   %eax,%eax
je     1253 <nibble_sort_word+0x153>
lea    0x0(,%rax,4),%r9d
neg    %r9d
cmp    $0x4,%eax
jae    1290 <nibble_sort_word+0x190>
mov    %r8d,%ecx
jmp    1430 <nibble_sort_word+0x330>
nopw   0x0(%rax,%rax,1)
mov    %eax,%r10d
and    $0xfffffffc,%r10d
movd   %r8d,%xmm0
pshufd $0x50,%xmm0,%xmm3
paddd  %xmm8,%xmm3
movq   %rsi,%xmm6
movq   %r11,%xmm0
pshufd $0x44,%xmm0,%xmm13
lea    -0x4(%r10),%esi
mov    %esi,%ecx
shr    $0x2,%ecx
add    $0x1,%ecx
test   %esi,%esi
je     1446 <nibble_sort_word+0x346>
mov    %ecx,%esi
and    $0xfffffffe,%esi
xorpd  %xmm5,%xmm5
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movdqa %xmm3,%xmm7
paddd  %xmm12,%xmm7
pxor   %xmm0,%xmm0
movss  %xmm3,%xmm0
movdqa %xmm13,%xmm2
psllq  %xmm0,%xmm2
xorps  %xmm1,%xmm1
movdqa %xmm3,%xmm4
psrlq  $0x20,%xmm4
movdqa %xmm13,%xmm0
psllq  %xmm4,%xmm0
movss  %xmm7,%xmm1
movsd  %xmm2,%xmm0
movdqa %xmm13,%xmm4
psllq  %xmm1,%xmm4
orpd   %xmm6,%xmm0
psrlq  $0x20,%xmm7
movdqa %xmm13,%xmm2
psllq  %xmm7,%xmm2
movsd  %xmm4,%xmm2
orpd   %xmm5,%xmm2
movdqa %xmm3,%xmm1
paddd  %xmm9,%xmm1
movdqa %xmm3,%xmm4
paddd  %xmm10,%xmm4
xorpd  %xmm5,%xmm5
movss  %xmm1,%xmm5
movdqa %xmm13,%xmm7
psllq  %xmm5,%xmm7
xorps  %xmm5,%xmm5
psrlq  $0x20,%xmm1
movdqa %xmm13,%xmm6
psllq  %xmm1,%xmm6
movss  %xmm4,%xmm5
movsd  %xmm7,%xmm6
movdqa %xmm13,%xmm1
psllq  %xmm5,%xmm1
orpd   %xmm0,%xmm6
psrlq  $0x20,%xmm4
movdqa %xmm13,%xmm5
psllq  %xmm4,%xmm5
movsd  %xmm1,%xmm5
orpd   %xmm2,%xmm5
paddd  %xmm11,%xmm3
add    $0xfffffffe,%esi
jne    12e0 <nibble_sort_word+0x1e0>
test   $0x1,%cl
je     1401 <nibble_sort_word+0x301>
movdqa %xmm3,%xmm0
paddd  %xmm12,%xmm0
xorpd  %xmm1,%xmm1
movss  %xmm3,%xmm1
xorpd  %xmm2,%xmm2
movss  %xmm0,%xmm2
movdqa %xmm13,%xmm4
psllq  %xmm1,%xmm4
psrlq  $0x20,%xmm3
movdqa %xmm13,%xmm1
psllq  %xmm3,%xmm1
movsd  %xmm4,%xmm1
orpd   %xmm1,%xmm6
movdqa %xmm13,%xmm1
psllq  %xmm2,%xmm1
psrlq  $0x20,%xmm0
psllq  %xmm0,%xmm13
movsd  %xmm1,%xmm13
orpd   %xmm13,%xmm5
orpd   %xmm5,%xmm6
pshufd $0xee,%xmm6,%xmm0
por    %xmm6,%xmm0
movq   %xmm0,%rsi
cmp    %r10d,%eax
je     1250 <nibble_sort_word+0x150>
shl    $0x2,%r10d
mov    %r8d,%ecx
sub    %r10d,%ecx
and    $0x3,%eax
nopl   0x0(%rax)
mov    %r11,%rdx
shl    %cl,%rdx
or     %rdx,%rsi
add    $0xfffffffc,%ecx
add    $0xffffffff,%eax
jne    1430 <nibble_sort_word+0x330>
jmp    1250 <nibble_sort_word+0x150>
xorpd  %xmm5,%xmm5
test   $0x1,%cl
jne    13ac <nibble_sort_word+0x2ac>
jmp    1401 <nibble_sort_word+0x301>
mov    %rsi,(%rdi)
ret

LLVM IR (-O0):
define void @nibble_sort_word(i64* %0) {
%2 = alloca i64*
%3 = alloca [16 x i32]
%4 = alloca i64
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32
store i64* %0, i64** %2
%8 = bitcast [16 x i32]* %3 to i8*
%9 = load i64*, i64** %2
%10 = load i64, i64* %9
store i64 %10, i64* %4
store i32 0, i32* %5
br label %11
11: ; preds = %20, %1
%12 = load i32, i32* %5
%13 = icmp slt i32 %12, 16
br i1 %13, label %14, label %25
14: ; preds = %11
%15 = load i64, i64* %4
%16 = and i64 %15, 15
%17 = getelementptr inbounds [16 x i32], [16 x i32]* %3, i64 0, i64 %16
%18 = load i32, i32* %17
%19 = add i32 %18, 1
store i32 %19, i32* %17
br label %20
20: ; preds = %14
%21 = load i32, i32* %5
%22 = add nsw i32 %21, 1
store i32 %22, i32* %5
%23 = load i64, i64* %4
%24 = lshr i64 %23, 4
store i64 %24, i64* %4
br label %11
25: ; preds = %11
store i32 60, i32* %6
store i32 15, i32* %7
br label %26
26: ; preds = %53, %25
%27 = load i32, i32* %7
%28 = icmp sge i32 %27, 0
br i1 %28, label %29, label %56
29: ; preds = %26
br label %30
30: ; preds = %44, %29
%31 = load i32, i32* %7
%32 = sext i32 %31 to i64
%33 = getelementptr inbounds [16 x i32], [16 x i32]* %3, i64 0, i64 %32
%34 = load i32, i32* %33
%35 = icmp ne i32 %34, 0
br i1 %35, label %36, label %52
36: ; preds = %30
%37 = load i32, i32* %7
%38 = sext i32 %37 to i64
%39 = load i32, i32* %6
%40 = zext i32 %39 to i64
%41 = shl i64 %38, %40
%42 = load i64, i64* %4
%43 = or i64 %42, %41
store i64 %43, i64* %4
br label %44
44: ; preds = %36
%45 = load i32, i32* %7
%46 = sext i32 %45 to i64
%47 = getelementptr inbounds [16 x i32], [16 x i32]* %3, i64 0, i64 %46
%48 = load i32, i32* %47
%49 = add i32 %48, -1
store i32 %49, i32* %47
%50 = load i32, i32* %6
%51 = sub nsw i32 %50, 4
store i32 %51, i32* %6
br label %30
52: ; preds = %30
br label %53
53: ; preds = %52
%54 = load i32, i32* %7
%55 = add nsw i32 %54, -1
store i32 %55, i32* %7
br label %26
56: ; preds = %26
%57 = load i64, i64* %4
%58 = load i64*, i64** %2
store i64 %57, i64* %58
ret void
}

LLVM IR (-O2):
define void @nibble_sort_word(i64* nocapture %0) {
%2 = alloca [16 x i32]
%3 = bitcast [16 x i32]* %2 to i8*
%4 = load i64, i64* %0
%5 = and i64 %4, 15
%6 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %5
%7 = load i32, i32* %6
%8 = add i32 %7, 1
store i32 %8, i32* %6
%9 = lshr i64 %4, 4
%10 = and i64 %9, 15
%11 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %10
%12 = load i32, i32* %11
%13 = add i32 %12, 1
store i32 %13, i32* %11
%14 = lshr i64 %4, 8
%15 = and i64 %14, 15
%16 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %15
%17 = load i32, i32* %16
%18 = add i32 %17, 1
store i32 %18, i32* %16
%19 = lshr i64 %4, 12
%20 = and i64 %19, 15
%21 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %20
%22 = load i32, i32* %21
%23 = add i32 %22, 1
store i32 %23, i32* %21
%24 = lshr i64 %4, 16
%25 = and i64 %24, 15
%26 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %25
%27 = load i32, i32* %26
%28 = add i32 %27, 1
store i32 %28, i32* %26
%29 = lshr i64 %4, 20
%30 = and i64 %29, 15
%31 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %30
%32 = load i32, i32* %31
%33 = add i32 %32, 1
store i32 %33, i32* %31
%34 = lshr i64 %4, 24
%35 = and i64 %34, 15
%36 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %35
%37 = load i32, i32* %36
%38 = add i32 %37, 1
store i32 %38, i32* %36
%39 = lshr i64 %4, 28
%40 = and i64 %39, 15
%41 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %40
%42 = load i32, i32* %41
%43 = add i32 %42, 1
store i32 %43, i32* %41
%44 = lshr i64 %4, 32
%45 = and i64 %44, 15
%46 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %45
%47 = load i32, i32* %46
%48 = add i32 %47, 1
store i32 %48, i32* %46
%49 = lshr i64 %4, 36
%50 = and i64 %49, 15
%51 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %50
%52 = load i32, i32* %51
%53 = add i32 %52, 1
store i32 %53, i32* %51
%54 = lshr i64 %4, 40
%55 = and i64 %54, 15
%56 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %55
%57 = load i32, i32* %56
%58 = add i32 %57, 1
store i32 %58, i32* %56
%59 = lshr i64 %4, 44
%60 = and i64 %59, 15
%61 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %60
%62 = load i32, i32* %61
%63 = add i32 %62, 1
store i32 %63, i32* %61
%64 = lshr i64 %4, 48
%65 = and i64 %64, 15
%66 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %65
%67 = load i32, i32* %66
%68 = add i32 %67, 1
store i32 %68, i32* %66
%69 = lshr i64 %4, 52
%70 = and i64 %69, 15
%71 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %70
%72 = load i32, i32* %71
%73 = add i32 %72, 1
store i32 %73, i32* %71
%74 = lshr i64 %4, 56
%75 = and i64 %74, 15
%76 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %75
%77 = load i32, i32* %76
%78 = add i32 %77, 1
store i32 %78, i32* %76
%79 = lshr i64 %4, 60
%80 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %79
%81 = load i32, i32* %80
%82 = add i32 %81, 1
store i32 %82, i32* %80
br label %83
83: ; preds = %1, %175
%84 = phi i64 [ 15, %1 ], [ %178, %175 ]
%85 = phi i32 [ 60, %1 ], [ %177, %175 ]
%86 = phi i64 [ 0, %1 ], [ %176, %175 ]
%87 = getelementptr inbounds [16 x i32], [16 x i32]* %2, i64 0, i64 %84
%88 = load i32, i32* %87
%89 = icmp eq i32 %88, 0
br i1 %89, label %175, label %90
90: ; preds = %83
%91 = mul i32 %88, -4
%92 = icmp ult i32 %88, 4
br i1 %92, label %157, label %93
93: ; preds = %90
%94 = and i32 %88, -4
%95 = mul i32 %94, -4
%96 = add i32 %85, %95
%97 = and i32 %88, 3
%98 = insertelement <2 x i32> poison, i32 %85, i64 0
%99 = shufflevector <2 x i32> %98, <2 x i32> poison, <2 x i32> zeroinitializer
%100 = add <2 x i32> %99, <i32 0, i32 -4>
%101 = insertelement <2 x i64> <i64 poison, i64 0>, i64 %86, i64 0
%102 = insertelement <2 x i64> poison, i64 %84, i64 0
%103 = shufflevector <2 x i64> %102, <2 x i64> poison, <2 x i32> zeroinitializer
%104 = insertelement <2 x i64> poison, i64 %84, i64 0
%105 = shufflevector <2 x i64> %104, <2 x i64> poison, <2 x i32> zeroinitializer
%106 = add i32 %94, -4
%107 = lshr exact i32 %106, 2
%108 = add nuw nsw i32 %107, 1
%109 = and i32 %108, 1
%110 = icmp eq i32 %106, 0
br i1 %110, label %136, label %111
111: ; preds = %93
%112 = and i32 %108, 2147483646
br label %113
113: ; preds = %113, %111
%114 = phi <2 x i32> [ %100, %111 ], [ %133, %113 ]
%115 = phi <2 x i64> [ %101, %111 ], [ %131, %113 ]
%116 = phi <2 x i64> [ zeroinitializer, %111 ], [ %132, %113 ]
%117 = phi i32 [ 0, %111 ], [ %134, %113 ]
%118 = add <2 x i32> %114, <i32 -8, i32 -8>
%119 = zext <2 x i32> %114 to <2 x i64>
%120 = zext <2 x i32> %118 to <2 x i64>
%121 = shl <2 x i64> %103, %119
%122 = shl <2 x i64> %105, %120
%123 = or <2 x i64> %121, %115
%124 = or <2 x i64> %122, %116
%125 = add <2 x i32> %114, <i32 -16, i32 -16>
%126 = add <2 x i32> %114, <i32 -24, i32 -24>
%127 = zext <2 x i32> %125 to <2 x i64>
%128 = zext <2 x i32> %126 to <2 x i64>
%129 = shl <2 x i64> %103, %127
%130 = shl <2 x i64> %105, %128
%131 = or <2 x i64> %129, %123
%132 = or <2 x i64> %130, %124
%133 = add <2 x i32> %114, <i32 -32, i32 -32>
%134 = add i32 %117, 2
%135 = icmp eq i32 %134, %112
br i1 %135, label %136, label %113
136: ; preds = %113, %93
%137 = phi <2 x i64> [ undef, %93 ], [ %131, %113 ]
%138 = phi <2 x i64> [ undef, %93 ], [ %132, %113 ]
%139 = phi <2 x i32> [ %100, %93 ], [ %133, %113 ]
%140 = phi <2 x i64> [ %101, %93 ], [ %131, %113 ]
%141 = phi <2 x i64> [ zeroinitializer, %93 ], [ %132, %113 ]
%142 = icmp eq i32 %109, 0
br i1 %142, label %151, label %143
143: ; preds = %136
%144 = add <2 x i32> %139, <i32 -8, i32 -8>
%145 = zext <2 x i32> %139 to <2 x i64>
%146 = zext <2 x i32> %144 to <2 x i64>
%147 = shl <2 x i64> %103, %145
%148 = shl <2 x i64> %105, %146
%149 = or <2 x i64> %147, %140
%150 = or <2 x i64> %148, %141
br label %151
151: ; preds = %136, %143
%152 = phi <2 x i64> [ %137, %136 ], [ %149, %143 ]
%153 = phi <2 x i64> [ %138, %136 ], [ %150, %143 ]
%154 = or <2 x i64> %153, %152
%155 = call i64 @llvm.vector.reduce.or.v2i64(<2 x i64> %154)
%156 = icmp eq i32 %88, %94
br i1 %156, label %172, label %157
157: ; preds = %90, %151
%158 = phi i32 [ %85, %90 ], [ %96, %151 ]
%159 = phi i64 [ %86, %90 ], [ %155, %151 ]
%160 = phi i32 [ %88, %90 ], [ %97, %151 ]
br label %162
161: ; preds = %175
store i64 %176, i64* %0
ret void
162: ; preds = %157, %162
%163 = phi i32 [ %170, %162 ], [ %158, %157 ]
%164 = phi i64 [ %168, %162 ], [ %159, %157 ]
%165 = phi i32 [ %169, %162 ], [ %160, %157 ]
%166 = zext i32 %163 to i64
%167 = shl i64 %84, %166
%168 = or i64 %167, %164
%169 = add i32 %165, -1
%170 = add nsw i32 %163, -4
%171 = icmp eq i32 %169, 0
br i1 %171, label %172, label %162
172: ; preds = %162, %151
%173 = phi i64 [ %155, %151 ], [ %168, %162 ]
%174 = add i32 %91, %85
br label %175
175: ; preds = %172, %83
%176 = phi i64 [ %86, %83 ], [ %173, %172 ]
%177 = phi i32 [ %85, %83 ], [ %174, %172 ]
store i32 0, i32* %87
%178 = add nsw i64 %84, -1
%179 = icmp eq i64 %84, 0
br i1 %179, label %161, label %83
}