void fill_bits(int x, int nbits, char *bits) {
  for (int i = 0; i < nbits; i++)
    bits[nbits - i - 1] = (x & (1 << i)) ? '1' : '0';
}


x86 assembly (clang, -O0):
<fill_bits>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %esi,-0x8(%rbp)
mov    %rdx,-0x10(%rbp)
movl   $0x0,-0x14(%rbp)
mov    -0x14(%rbp),%eax
cmp    -0x8(%rbp),%eax
jge    1163 <fill_bits+0x63>
mov    -0x4(%rbp),%edx
mov    -0x14(%rbp),%ecx
mov    $0x1,%eax
shl    %cl,%eax
and    %eax,%edx
mov    $0x30,%eax
mov    $0x31,%ecx
cmp    $0x0,%edx
cmovne %ecx,%eax
mov    %al,%dl
mov    -0x10(%rbp),%rax
mov    -0x8(%rbp),%ecx
sub    -0x14(%rbp),%ecx
sub    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x14(%rbp)
jmp    1115 <fill_bits+0x15>
pop    %rbp
ret

x86 assembly (clang, -O2):
<fill_bits>:
test   %esi,%esi
jle    1362 <fill_bits+0x262>
mov    %esi,%r8d
cmp    $0x10,%esi
jae    1118 <fill_bits+0x18>
xor    %r11d,%r11d
jmp    12f4 <fill_bits+0x1f4>
lea    -0x1(%r8),%r9
lea    -0x1(%rsi),%eax
mov    %eax,%r10d
sub    %r9d,%r10d
xor    %r11d,%r11d
cmp    %eax,%r10d
jg     12f4 <fill_bits+0x1f4>
shr    $0x20,%r9
jne    12f4 <fill_bits+0x1f4>
mov    %r8d,%r11d
and    $0xfffffff0,%r11d
movd   %edi,%xmm0
pshufd $0x0,%xmm0,%xmm12
movdqa 0xeab(%rip),%xmm14
movdqa 0xeb3(%rip),%xmm2
movdqa 0xebb(%rip),%xmm3
movdqa 0xec3(%rip),%xmm4
movdqa 0xeca(%rip),%xmm9
movdqa 0xed1(%rip),%xmm13
pxor   %xmm11,%xmm11
movdqa 0xed3(%rip),%xmm8
movdqa 0xeda(%rip),%xmm10
mov    %r11,%r9
nopl   0x0(%rax)
movdqa %xmm4,%xmm0
pslld  $0x17,%xmm0
paddd  %xmm9,%xmm0
cvttps2dq %xmm0,%xmm0
pshufd $0xf5,%xmm0,%xmm7
pmuludq %xmm13,%xmm0
pshufd $0xe8,%xmm0,%xmm5
pmuludq %xmm13,%xmm7
pshufd $0xe8,%xmm7,%xmm0
punpckldq %xmm0,%xmm5
movdqa %xmm3,%xmm0
pslld  $0x17,%xmm0
paddd  %xmm9,%xmm0
cvttps2dq %xmm0,%xmm0
pshufd $0xf5,%xmm0,%xmm6
pmuludq %xmm13,%xmm0
pshufd $0xe8,%xmm0,%xmm7
pmuludq %xmm13,%xmm6
pshufd $0xe8,%xmm6,%xmm0
punpckldq %xmm0,%xmm7
movdqa %xmm2,%xmm0
pslld  $0x17,%xmm0
paddd  %xmm9,%xmm0
cvttps2dq %xmm0,%xmm0
pshufd $0xf5,%xmm0,%xmm6
pmuludq %xmm13,%xmm0
pshufd $0xe8,%xmm0,%xmm0
pmuludq %xmm13,%xmm6
pshufd $0xe8,%xmm6,%xmm6
punpckldq %xmm6,%xmm0
movdqa %xmm14,%xmm6
pslld  $0x17,%xmm6
paddd  %xmm9,%xmm6
cvttps2dq %xmm6,%xmm6
pshufd $0xf5,%xmm6,%xmm1
pmuludq %xmm13,%xmm6
pshufd $0xe8,%xmm6,%xmm6
pmuludq %xmm13,%xmm1
pshufd $0xe8,%xmm1,%xmm1
punpckldq %xmm1,%xmm6
pand   %xmm12,%xmm6
pand   %xmm12,%xmm0
pand   %xmm12,%xmm7
pand   %xmm12,%xmm5
pcmpeqd %xmm11,%xmm5
pcmpeqd %xmm11,%xmm7
packssdw %xmm7,%xmm5
pcmpeqd %xmm11,%xmm0
pcmpeqd %xmm11,%xmm6
packssdw %xmm6,%xmm0
packsswb %xmm0,%xmm5
paddb  %xmm8,%xmm5
cltq
movdqa %xmm5,%xmm0
punpcklbw %xmm11,%xmm0
pshufd $0x4e,%xmm0,%xmm0
pshuflw $0x1b,%xmm0,%xmm0
pshufhw $0x1b,%xmm0,%xmm0
punpckhbw %xmm11,%xmm5
pshufd $0x4e,%xmm5,%xmm1
pshuflw $0x1b,%xmm1,%xmm1
pshufhw $0x1b,%xmm1,%xmm1
packuswb %xmm0,%xmm1
movdqu %xmm1,-0xf(%rdx,%rax,1)
paddd  %xmm10,%xmm4
paddd  %xmm10,%xmm3
paddd  %xmm10,%xmm2
paddd  %xmm10,%xmm14
add    $0xfffffff0,%eax
add    $0xfffffffffffffff0,%r9
jne    11a0 <fill_bits+0xa0>
cmp    %r8,%r11
je     1362 <fill_bits+0x262>
mov    %r11,%r10
not    %r10
test   $0x1,%r8b
je     131c <fill_bits+0x21c>
bt     %r11d,%edi
mov    $0x31,%r9b
adc    $0xff,%r9b
mov    %r11d,%eax
not    %eax
add    %esi,%eax
cltq
mov    %r9b,(%rdx,%rax,1)
or     $0x1,%r11
add    %r8,%r10
je     1362 <fill_bits+0x262>
mov    %r11d,%eax
not    %eax
add    %esi,%eax
nopl   0x0(%rax,%rax,1)
bt     %r11d,%edi
mov    $0x31,%cl
adc    $0xff,%cl
cltq
mov    %cl,(%rdx,%rax,1)
lea    0x1(%r11),%ecx
movzbl %cl,%ecx
bt     %ecx,%edi
mov    $0x31,%cl
adc    $0xff,%cl
lea    -0x1(%rax),%esi
movslq %esi,%rsi
mov    %cl,(%rdx,%rsi,1)
add    $0x2,%r11
add    $0xfffffffe,%eax
cmp    %r8,%r11
jne    1330 <fill_bits+0x230>
ret

LLVM IR (-O0):
define void @fill_bits(i32 %0, i32 %1, i8* %2) {
%4 = alloca i32
%5 = alloca i32
%6 = alloca i8*
%7 = alloca i32
store i32 %0, i32* %4
store i32 %1, i32* %5
store i8* %2, i8** %6
store i32 0, i32* %7
br label %8
8: ; preds = %28, %3
%9 = load i32, i32* %7
%10 = load i32, i32* %5
%11 = icmp slt i32 %9, %10
br i1 %11, label %12, label %31
12: ; preds = %8
%13 = load i32, i32* %4
%14 = load i32, i32* %7
%15 = shl i32 1, %14
%16 = and i32 %13, %15
%17 = icmp ne i32 %16, 0
%18 = zext i1 %17 to i64
%19 = select i1 %17, i32 49, i32 48
%20 = trunc i32 %19 to i8
%21 = load i8*, i8** %6
%22 = load i32, i32* %5
%23 = load i32, i32* %7
%24 = sub nsw i32 %22, %23
%25 = sub nsw i32 %24, 1
%26 = sext i32 %25 to i64
%27 = getelementptr inbounds i8, i8* %21, i64 %26
store i8 %20, i8* %27
br label %28
28: ; preds = %12
%29 = load i32, i32* %7
%30 = add nsw i32 %29, 1
store i32 %30, i32* %7
br label %8
31: ; preds = %8
ret void
}

LLVM IR (-O2):
define void @fill_bits(i32 %0, i32 %1, i8* nocapture writeonly %2) {
%4 = icmp sgt i32 %1, 0
br i1 %4, label %5, label %61
5: ; preds = %3
%6 = zext i32 %1 to i64
%7 = icmp ult i32 %1, 16
br i1 %7, label %40, label %8
8: ; preds = %5
%9 = add nsw i64 %6, -1
%10 = add i32 %1, -1
%11 = trunc i64 %9 to i32
%12 = sub i32 %10, %11
%13 = icmp sgt i32 %12, %10
%14 = icmp ugt i64 %9, 4294967295
%15 = or i1 %13, %14
br i1 %15, label %40, label %16
16: ; preds = %8
%17 = and i64 %6, 4294967280
%18 = insertelement <16 x i32> poison, i32 %0, i64 0
%19 = shufflevector <16 x i32> %18, <16 x i32> poison, <16 x i32> zeroinitializer
%20 = getelementptr inbounds i8, i8* %2, i64 -15
br label %21
21: ; preds = %21, %16
%22 = phi i64 [ 0, %16 ], [ %35, %21 ]
%23 = phi <16 x i32> [ <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>, %16 ], [ %36, %21 ]
%24 = trunc i64 %22 to i32
%25 = shl nuw <16 x i32> <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>, %23
%26 = and <16 x i32> %25, %19
%27 = icmp eq <16 x i32> %26, zeroinitializer
%28 = select <16 x i1> %27, <16 x i8> <i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48, i8 48>, <16 x i8> <i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49, i8 49>
%29 = xor i32 %24, -1
%30 = add i32 %29, %1
%31 = sext i32 %30 to i64
%32 = shufflevector <16 x i8> %28, <16 x i8> poison, <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
%33 = getelementptr inbounds i8, i8* %20, i64 %31
%34 = bitcast i8* %33 to <16 x i8>*
store <16 x i8> %32, <16 x i8>* %34
%35 = add nuw i64 %22, 16
%36 = add <16 x i32> %23, <i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16, i32 16>
%37 = icmp eq i64 %35, %17
br i1 %37, label %38, label %21
38: ; preds = %21
%39 = icmp eq i64 %17, %6
br i1 %39, label %61, label %40
40: ; preds = %8, %5, %38
%41 = phi i64 [ 0, %8 ], [ 0, %5 ], [ %17, %38 ]
%42 = xor i64 %41, -1
%43 = and i64 %6, 1
%44 = icmp eq i64 %43, 0
br i1 %44, label %57, label %45
45: ; preds = %40
%46 = trunc i64 %41 to i32
%47 = shl nuw i32 1, %46
%48 = and i32 %47, %0
%49 = icmp eq i32 %48, 0
%50 = select i1 %49, i8 48, i8 49
%51 = trunc i64 %41 to i32
%52 = xor i32 %51, -1
%53 = add i32 %52, %1
%54 = sext i32 %53 to i64
%55 = getelementptr inbounds i8, i8* %2, i64 %54
store i8 %50, i8* %55
%56 = or i64 %41, 1
br label %57
57: ; preds = %45, %40
%58 = phi i64 [ %41, %40 ], [ %56, %45 ]
%59 = sub nsw i64 0, %6
%60 = icmp eq i64 %42, %59
br i1 %60, label %61, label %62
61: ; preds = %57, %62, %38, %3
ret void
62: ; preds = %57, %62
%63 = phi i64 [ %85, %62 ], [ %58, %57 ]
%64 = trunc i64 %63 to i32
%65 = shl nuw i32 1, %64
%66 = and i32 %65, %0
%67 = icmp eq i32 %66, 0
%68 = select i1 %67, i8 48, i8 49
%69 = trunc i64 %63 to i32
%70 = xor i32 %69, -1
%71 = add i32 %70, %1
%72 = sext i32 %71 to i64
%73 = getelementptr inbounds i8, i8* %2, i64 %72
store i8 %68, i8* %73
%74 = add nuw nsw i64 %63, 1
%75 = trunc i64 %74 to i32
%76 = shl nuw i32 1, %75
%77 = and i32 %76, %0
%78 = icmp eq i32 %77, 0
%79 = select i1 %78, i8 48, i8 49
%80 = trunc i64 %74 to i32
%81 = xor i32 %80, -1
%82 = add i32 %81, %1
%83 = sext i32 %82 to i64
%84 = getelementptr inbounds i8, i8* %2, i64 %83
store i8 %79, i8* %84
%85 = add nuw nsw i64 %63, 2
%86 = icmp eq i64 %85, %6
br i1 %86, label %61, label %62
}