void mask_addr(struct in6_addr *addr, int bits) {
  int sz = 128;
  unsigned char *b = (unsigned char *)addr;
  while (bits > 0) {
    switch (bits) {
    case 1:
      *b &= 0x80;
      break;
    case 2:
      *b &= 0xc0;
      break;
    case 3:
      *b &= 0xe0;
      break;
    case 4:
      *b &= 0xf0;
      break;
    case 5:
      *b &= 0xf8;
      break;
    case 6:
      *b &= 0xfc;
      break;
    case 7:
      *b &= 0xfe;
      break;
    }
    b++;
    bits -= 8;
    sz -= 8;
  }
  while (sz) {
    *b = 0;
    b++;
    sz -= 8;
  }
}


x86 assembly (clang, -O0):
<mask_addr>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
movl   $0x80,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x18(%rbp)
cmpl   $0x0,-0xc(%rbp)
jle    11f7 <mask_addr+0xf7>
mov    -0xc(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,%ecx
mov    %rcx,-0x20(%rbp)
sub    $0x6,%eax
ja     11d4 <mask_addr+0xd4>
mov    -0x20(%rbp),%rax
lea    0xebc(%rip),%rcx
movslq (%rcx,%rax,4),%rax
add    %rcx,%rax
jmp    *%rax
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0x80,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xc0,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xe0,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xf0,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xf8,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xfc,%ecx
mov    %cl,(%rax)
jmp    11d4 <mask_addr+0xd4>
mov    -0x18(%rbp),%rax
movzbl (%rax),%ecx
and    $0xfe,%ecx
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x18(%rbp)
mov    -0xc(%rbp),%eax
sub    $0x8,%eax
mov    %eax,-0xc(%rbp)
mov    -0x10(%rbp),%eax
sub    $0x8,%eax
mov    %eax,-0x10(%rbp)
jmp    111a <mask_addr+0x1a>
jmp    11fc <mask_addr+0xfc>
cmpl   $0x0,-0x10(%rbp)
je     1227 <mask_addr+0x127>
mov    -0x18(%rbp),%rax
movb   $0x0,(%rax)
mov    -0x18(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x18(%rbp)
mov    -0x10(%rbp),%eax
sub    $0x8,%eax
mov    %eax,-0x10(%rbp)
jmp    11fc <mask_addr+0xfc>
pop    %rbp
ret

x86 assembly (clang, -O2):
<mask_addr>:
push   %rax
test   %esi,%esi
jle    1147 <mask_addr+0x37>
mov    $0x78,%edx
nopw   0x0(%rax,%rax,1)
lea    (%rsi,%rdx,1),%eax
add    $0xffffff87,%eax
cmp    $0x6,%eax
jbe    114e <mask_addr+0x3e>
add    $0x1,%rdi
mov    %edx,%eax
add    $0xfffffff8,%edx
add    %esi,%eax
add    $0xffffff88,%eax
cmp    $0x8,%eax
ja     1120 <mask_addr+0x10>
add    $0x8,%edx
test   %edx,%edx
jne    1170 <mask_addr+0x60>
pop    %rax
ret
mov    $0x80,%edx
jmp    1170 <mask_addr+0x60>
add    %edx,%esi
shl    $0x3,%esi
add    $0x38,%sil
movabs $0xfefcf8f0e0c080,%rax
mov    %esi,%ecx
shr    %cl,%rax
and    %al,(%rdi)
add    $0x1,%rdi
test   %edx,%edx
je     1145 <mask_addr+0x35>
add    $0xfffffff8,%edx
shr    $0x3,%edx
add    $0x1,%edx
xor    %esi,%esi
call   1030 <memset@plt>
pop    %rax
ret

LLVM IR (-O0):
%struct.in6_addr = type opaque
define void @mask_addr(%struct.in6_addr* %0, i32 %1) {
%3 = alloca %struct.in6_addr*
%4 = alloca i32
%5 = alloca i32
%6 = alloca i8*
store %struct.in6_addr* %0, %struct.in6_addr** %3
store i32 %1, i32* %4
store i32 128, i32* %5
%7 = load %struct.in6_addr*, %struct.in6_addr** %3
%8 = bitcast %struct.in6_addr* %7 to i8*
store i8* %8, i8** %6
br label %9
9: ; preds = %56, %2
%10 = load i32, i32* %4
%11 = icmp sgt i32 %10, 0
br i1 %11, label %12, label %63
12: ; preds = %9
%13 = load i32, i32* %4
switch i32 %13, label %56 [
i32 1, label %14
i32 2, label %20
i32 3, label %26
i32 4, label %32
i32 5, label %38
i32 6, label %44
i32 7, label %50
]
14: ; preds = %12
%15 = load i8*, i8** %6
%16 = load i8, i8* %15
%17 = zext i8 %16 to i32
%18 = and i32 %17, 128
%19 = trunc i32 %18 to i8
store i8 %19, i8* %15
br label %56
20: ; preds = %12
%21 = load i8*, i8** %6
%22 = load i8, i8* %21
%23 = zext i8 %22 to i32
%24 = and i32 %23, 192
%25 = trunc i32 %24 to i8
store i8 %25, i8* %21
br label %56
26: ; preds = %12
%27 = load i8*, i8** %6
%28 = load i8, i8* %27
%29 = zext i8 %28 to i32
%30 = and i32 %29, 224
%31 = trunc i32 %30 to i8
store i8 %31, i8* %27
br label %56
32: ; preds = %12
%33 = load i8*, i8** %6
%34 = load i8, i8* %33
%35 = zext i8 %34 to i32
%36 = and i32 %35, 240
%37 = trunc i32 %36 to i8
store i8 %37, i8* %33
br label %56
38: ; preds = %12
%39 = load i8*, i8** %6
%40 = load i8, i8* %39
%41 = zext i8 %40 to i32
%42 = and i32 %41, 248
%43 = trunc i32 %42 to i8
store i8 %43, i8* %39
br label %56
44: ; preds = %12
%45 = load i8*, i8** %6
%46 = load i8, i8* %45
%47 = zext i8 %46 to i32
%48 = and i32 %47, 252
%49 = trunc i32 %48 to i8
store i8 %49, i8* %45
br label %56
50: ; preds = %12
%51 = load i8*, i8** %6
%52 = load i8, i8* %51
%53 = zext i8 %52 to i32
%54 = and i32 %53, 254
%55 = trunc i32 %54 to i8
store i8 %55, i8* %51
br label %56
56: ; preds = %12, %50, %44, %38, %32, %26, %20, %14
%57 = load i8*, i8** %6
%58 = getelementptr inbounds i8, i8* %57, i32 1
store i8* %58, i8** %6
%59 = load i32, i32* %4
%60 = sub nsw i32 %59, 8
store i32 %60, i32* %4
%61 = load i32, i32* %5
%62 = sub nsw i32 %61, 8
store i32 %62, i32* %5
br label %9
63: ; preds = %9
br label %64
64: ; preds = %67, %63
%65 = load i32, i32* %5
%66 = icmp ne i32 %65, 0
br i1 %66, label %67, label %73
67: ; preds = %64
%68 = load i8*, i8** %6
store i8 0, i8* %68
%69 = load i8*, i8** %6
%70 = getelementptr inbounds i8, i8* %69, i32 1
store i8* %70, i8** %6
%71 = load i32, i32* %5
%72 = sub nsw i32 %71, 8
store i32 %72, i32* %5
br label %64
73: ; preds = %64
ret void
}

LLVM IR (-O2):
%struct.in6_addr = type opaque
define void @mask_addr(%struct.in6_addr* nocapture %0, i32 %1) {
%3 = bitcast %struct.in6_addr* %0 to i8*
%4 = icmp sgt i32 %1, 0
br i1 %4, label %16, label %9
5: ; preds = %31, %22
%6 = phi i32 [ %30, %22 ], [ %34, %31 ]
%7 = phi i8* [ %29, %22 ], [ %32, %31 ]
%8 = icmp eq i32 %6, 0
br i1 %8, label %36, label %9
9: ; preds = %2, %5
%10 = phi i8* [ %7, %5 ], [ %3, %2 ]
%11 = phi i32 [ %6, %5 ], [ 128, %2 ]
%12 = add nsw i32 %11, -8
%13 = lshr i32 %12, 3
%14 = add nuw nsw i32 %13, 1
%15 = zext i32 %14 to i64
br label %36
16: ; preds = %2, %31
%17 = phi i8* [ %32, %31 ], [ %3, %2 ]
%18 = phi i32 [ %34, %31 ], [ 128, %2 ]
%19 = phi i32 [ %33, %31 ], [ %1, %2 ]
%20 = add i32 %19, -1
%21 = icmp ult i32 %20, 7
br i1 %21, label %22, label %31
22: ; preds = %16
%23 = zext i32 %20 to i56
%24 = shl nuw nsw i56 %23, 3
%25 = lshr i56 -284803830071168, %24
%26 = trunc i56 %25 to i8
%27 = load i8, i8* %17
%28 = and i8 %27, %26
store i8 %28, i8* %17
%29 = getelementptr inbounds i8, i8* %17, i64 1
%30 = add nsw i32 %18, -8
br label %5
31: ; preds = %16
%32 = getelementptr inbounds i8, i8* %17, i64 1
%33 = add nsw i32 %19, -8
%34 = add nsw i32 %18, -8
%35 = icmp ugt i32 %19, 8
br i1 %35, label %16, label %5
36: ; preds = %9, %5
ret void
}