void threshold(unsigned char *src, int width, int height, int min, int max) {
  int i;
  int val;
  int size = width * height;
  for (i = 0; i < size; i++) {
    val = *(src + i);
    if (val > max)
      val = 255;
    else if (val < min)
      val = 0;
    *(src + i) = val;
  }
}


x86 assembly (clang, -O0):
<threshold>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %edx,-0x10(%rbp)
mov    %ecx,-0x14(%rbp)
mov    %r8d,-0x18(%rbp)
mov    -0xc(%rbp),%eax
imul   -0x10(%rbp),%eax
mov    %eax,-0x24(%rbp)
movl   $0x0,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    118f <threshold+0x8f>
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
cmp    -0x18(%rbp),%eax
jle    1159 <threshold+0x59>
movl   $0xff,-0x20(%rbp)
jmp    1171 <threshold+0x71>
mov    -0x20(%rbp),%eax
cmp    -0x14(%rbp),%eax
jge    116c <threshold+0x6c>
movl   $0x0,-0x20(%rbp)
jmp    1171 <threshold+0x71>
mov    -0x20(%rbp),%eax
mov    %al,%dl
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    1126 <threshold+0x26>
pop    %rbp
ret

x86 assembly (clang, -O2):
<threshold>:
imul   %edx,%esi
test   %esi,%esi
jle    140f <threshold+0x30f>
mov    %esi,%r11d
xor    %r9d,%r9d
cmp    $0x8,%esi
jae    111d <threshold+0x1d>
xor    %esi,%esi
jmp    13dc <threshold+0x2dc>
movd   %r8d,%xmm8
movd   %ecx,%xmm9
cmp    $0x10,%esi
jae    11bd <threshold+0xbd>
xor    %esi,%esi
mov    %rsi,%rax
mov    %r11d,%esi
and    $0xfffffff8,%esi
pshufd $0x0,%xmm8,%xmm0
pshufd $0x0,%xmm9,%xmm1
pxor   %xmm2,%xmm2
nopl   0x0(%rax,%rax,1)
movq   (%rdi,%rax,1),%xmm3
movdqa %xmm3,%xmm4
punpcklbw %xmm2,%xmm4
movdqa %xmm4,%xmm5
punpcklwd %xmm2,%xmm5
punpckhwd %xmm2,%xmm4
movdqa %xmm1,%xmm6
pcmpgtd %xmm4,%xmm6
pcmpgtd %xmm0,%xmm4
movdqa %xmm1,%xmm7
pcmpgtd %xmm5,%xmm7
pcmpgtd %xmm0,%xmm5
packssdw %xmm4,%xmm5
packsswb %xmm5,%xmm5
packssdw %xmm6,%xmm7
packsswb %xmm7,%xmm7
pandn  %xmm3,%xmm7
movdqa %xmm5,%xmm3
pandn  %xmm7,%xmm3
por    %xmm5,%xmm3
movq   %xmm3,(%rdi,%rax,1)
add    $0x8,%rax
cmp    %rax,%rsi
jne    1150 <threshold+0x50>
cmp    %r11,%rsi
jne    13dc <threshold+0x2dc>
jmp    140f <threshold+0x30f>
mov    %r11d,%esi
and    $0xfffffff0,%esi
pshufd $0x0,%xmm8,%xmm12
pshufd $0x0,%xmm9,%xmm11
lea    -0x10(%rsi),%rax
mov    %rax,%r10
shr    $0x4,%r10
add    $0x1,%r10
test   %rax,%rax
je     1410 <threshold+0x310>
mov    %r10,%rax
and    $0xfffffffffffffffe,%rax
xor    %edx,%edx
pxor   %xmm13,%xmm13
cs nopw 0x0(%rax,%rax,1)
nop
movdqu (%rdi,%rdx,1),%xmm1
movdqu 0x10(%rdi,%rdx,1),%xmm10
movdqa %xmm1,%xmm6
punpcklbw %xmm13,%xmm6
movdqa %xmm6,%xmm7
punpcklwd %xmm13,%xmm7
punpckhwd %xmm13,%xmm6
movdqa %xmm1,%xmm0
punpckhbw %xmm13,%xmm0
movdqa %xmm0,%xmm5
punpcklwd %xmm13,%xmm5
punpckhwd %xmm13,%xmm0
movdqa %xmm11,%xmm2
pcmpgtd %xmm0,%xmm2
pcmpgtd %xmm12,%xmm0
movdqa %xmm11,%xmm3
pcmpgtd %xmm5,%xmm3
pcmpgtd %xmm12,%xmm5
packssdw %xmm0,%xmm5
movdqa %xmm11,%xmm0
pcmpgtd %xmm6,%xmm0
pcmpgtd %xmm12,%xmm6
movdqa %xmm11,%xmm4
pcmpgtd %xmm7,%xmm4
pcmpgtd %xmm12,%xmm7
packssdw %xmm6,%xmm7
packsswb %xmm5,%xmm7
packssdw %xmm2,%xmm3
packssdw %xmm0,%xmm4
packsswb %xmm3,%xmm4
pandn  %xmm1,%xmm4
por    %xmm7,%xmm4
movdqu %xmm4,(%rdi,%rdx,1)
movdqa %xmm10,%xmm0
punpcklbw %xmm13,%xmm0
movdqa %xmm0,%xmm6
punpcklwd %xmm13,%xmm6
punpckhwd %xmm13,%xmm0
movdqa %xmm10,%xmm1
punpckhbw %xmm13,%xmm1
movdqa %xmm1,%xmm2
punpcklwd %xmm13,%xmm2
punpckhwd %xmm13,%xmm1
movdqa %xmm11,%xmm3
pcmpgtd %xmm1,%xmm3
pcmpgtd %xmm12,%xmm1
movdqa %xmm11,%xmm4
pcmpgtd %xmm2,%xmm4
pcmpgtd %xmm12,%xmm2
packssdw %xmm1,%xmm2
movdqa %xmm11,%xmm1
pcmpgtd %xmm0,%xmm1
pcmpgtd %xmm12,%xmm0
movdqa %xmm11,%xmm5
pcmpgtd %xmm6,%xmm5
pcmpgtd %xmm12,%xmm6
packssdw %xmm0,%xmm6
packsswb %xmm2,%xmm6
packssdw %xmm3,%xmm4
packssdw %xmm1,%xmm5
packsswb %xmm4,%xmm5
pandn  %xmm10,%xmm5
por    %xmm6,%xmm5
movdqu %xmm5,0x10(%rdi,%rdx,1)
add    $0x20,%rdx
add    $0xfffffffffffffffe,%rax
jne    1200 <threshold+0x100>
test   $0x1,%r10b
je     13cd <threshold+0x2cd>
movdqu (%rdi,%rdx,1),%xmm4
pxor   %xmm0,%xmm0
movdqa %xmm4,%xmm1
punpcklbw %xmm0,%xmm1
movdqa %xmm1,%xmm5
punpcklwd %xmm0,%xmm5
punpckhwd %xmm0,%xmm1
movdqa %xmm4,%xmm2
punpckhbw %xmm0,%xmm2
movdqa %xmm2,%xmm3
punpcklwd %xmm0,%xmm3
punpckhwd %xmm0,%xmm2
movdqa %xmm11,%xmm0
pcmpgtd %xmm2,%xmm0
pcmpgtd %xmm12,%xmm2
movdqa %xmm11,%xmm6
pcmpgtd %xmm3,%xmm6
pcmpgtd %xmm12,%xmm3
packssdw %xmm2,%xmm3
movdqa %xmm11,%xmm2
pcmpgtd %xmm1,%xmm2
pcmpgtd %xmm12,%xmm1
pcmpgtd %xmm5,%xmm11
pcmpgtd %xmm12,%xmm5
packssdw %xmm1,%xmm5
packsswb %xmm3,%xmm5
packssdw %xmm0,%xmm6
packssdw %xmm2,%xmm11
packsswb %xmm6,%xmm11
pandn  %xmm4,%xmm11
por    %xmm5,%xmm11
movdqu %xmm11,(%rdi,%rdx,1)
cmp    %r11,%rsi
je     140f <threshold+0x30f>
test   $0x8,%r11b
jne    1132 <threshold+0x32>
mov    $0xff,%r10d
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movzbl (%rdi,%rsi,1),%eax
cmp    %ecx,%eax
mov    %eax,%edx
cmovl  %r9d,%edx
cmp    %r8d,%eax
cmovg  %r10d,%edx
mov    %dl,(%rdi,%rsi,1)
add    $0x1,%rsi
cmp    %rsi,%r11
jne    13f0 <threshold+0x2f0>
ret
xor    %edx,%edx
test   $0x1,%r10b
jne    133e <threshold+0x23e>
jmp    13cd <threshold+0x2cd>

LLVM IR (-O0):
define void @threshold(i8* %0, i32 %1, i32 %2, i32 %3, i32 %4) {
%6 = alloca i8*
%7 = alloca i32
%8 = alloca i32
%9 = alloca i32
%10 = alloca i32
%11 = alloca i32
%12 = alloca i32
%13 = alloca i32
store i8* %0, i8** %6
store i32 %1, i32* %7
store i32 %2, i32* %8
store i32 %3, i32* %9
store i32 %4, i32* %10
%14 = load i32, i32* %7
%15 = load i32, i32* %8
%16 = mul nsw i32 %14, %15
store i32 %16, i32* %13
store i32 0, i32* %11
br label %17
17: ; preds = %45, %5
%18 = load i32, i32* %11
%19 = load i32, i32* %13
%20 = icmp slt i32 %18, %19
br i1 %20, label %21, label %48
21: ; preds = %17
%22 = load i8*, i8** %6
%23 = load i32, i32* %11
%24 = sext i32 %23 to i64
%25 = getelementptr inbounds i8, i8* %22, i64 %24
%26 = load i8, i8* %25
%27 = zext i8 %26 to i32
store i32 %27, i32* %12
%28 = load i32, i32* %12
%29 = load i32, i32* %10
%30 = icmp sgt i32 %28, %29
br i1 %30, label %31, label %32
31: ; preds = %21
store i32 255, i32* %12
br label %38
32: ; preds = %21
%33 = load i32, i32* %12
%34 = load i32, i32* %9
%35 = icmp slt i32 %33, %34
br i1 %35, label %36, label %37
36: ; preds = %32
store i32 0, i32* %12
br label %37
37: ; preds = %36, %32
br label %38
38: ; preds = %37, %31
%39 = load i32, i32* %12
%40 = trunc i32 %39 to i8
%41 = load i8*, i8** %6
%42 = load i32, i32* %11
%43 = sext i32 %42 to i64
%44 = getelementptr inbounds i8, i8* %41, i64 %43
store i8 %40, i8* %44
br label %45
45: ; preds = %38
%46 = load i32, i32* %11
%47 = add nsw i32 %46, 1
store i32 %47, i32* %11
br label %17
48: ; preds = %17
ret void
}

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