1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=instcombine < %s | FileCheck %s 3 4define i16 @foo(i16 %x) { 5; CHECK-LABEL: @foo( 6; CHECK-NEXT: [[T1:%.*]] = and i16 [[X:%.*]], 255 7; CHECK-NEXT: ret i16 [[T1]] 8; 9 %t1 = and i16 %x, 255 10 %t2 = zext i16 %t1 to i32 11 %t3 = icmp ult i32 %t2, 255 12 %t4 = select i1 %t3, i32 %t2, i32 255 13 %t5 = trunc i32 %t4 to i16 14 %t6 = and i16 %t5, 255 15 ret i16 %t6 16} 17 18; This contains a min/max pair to clamp a value to 12 bits. 19; By analyzing the clamp pattern, we can tell the add doesn't have signed overflow. 20define i16 @min_max_clamp(i16 %x) { 21; CHECK-LABEL: @min_max_clamp( 22; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048) 23; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047) 24; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D]], 1 25; CHECK-NEXT: ret i16 [[E]] 26; 27 %a = icmp sgt i16 %x, -2048 28 %b = select i1 %a, i16 %x, i16 -2048 29 %c = icmp slt i16 %b, 2047 30 %d = select i1 %c, i16 %b, i16 2047 31 %e = add i16 %d, 1 32 ret i16 %e 33} 34 35; Same as above with min/max reversed. 36define i16 @min_max_clamp_2(i16 %x) { 37; CHECK-LABEL: @min_max_clamp_2( 38; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) 39; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048) 40; CHECK-NEXT: [[E:%.*]] = add nsw i16 [[D]], 1 41; CHECK-NEXT: ret i16 [[E]] 42; 43 %a = icmp slt i16 %x, 2047 44 %b = select i1 %a, i16 %x, i16 2047 45 %c = icmp sgt i16 %b, -2048 46 %d = select i1 %c, i16 %b, i16 -2048 47 %e = add i16 %d, 1 48 ret i16 %e 49} 50 51; This contains a min/max pair to clamp a value to 12 bits. 52; By analyzing the clamp pattern, we can tell that the second add doesn't 53; overflow the original type and can be moved before the extend. 54define i32 @min_max_clamp_3(i16 %x) { 55; CHECK-LABEL: @min_max_clamp_3( 56; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048) 57; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047) 58; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[D]] to i32 59; CHECK-NEXT: ret i32 [[TMP1]] 60; 61 %a = icmp sgt i16 %x, -2048 62 %b = select i1 %a, i16 %x, i16 -2048 63 %c = icmp slt i16 %b, 2047 64 %d = select i1 %c, i16 %b, i16 2047 65 %e = add i16 %d, 1 66 %f = sext i16 %e to i32 67 %g = add i32 %f, -1 68 ret i32 %g 69} 70 71; Same as above with min/max order reversed 72define i32 @min_max_clamp_4(i16 %x) { 73; CHECK-LABEL: @min_max_clamp_4( 74; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) 75; CHECK-NEXT: [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048) 76; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[D]] to i32 77; CHECK-NEXT: ret i32 [[TMP1]] 78; 79 %a = icmp slt i16 %x, 2047 80 %b = select i1 %a, i16 %x, i16 2047 81 %c = icmp sgt i16 %b, -2048 82 %d = select i1 %c, i16 %b, i16 -2048 83 %e = add i16 %d, 1 84 %f = sext i16 %e to i32 85 %g = add i32 %f, -1 86 ret i32 %g 87} 88 89; Intrinsic versions of the above tests. 90 91declare i16 @llvm.smin.i16(i16, i16) 92declare i16 @llvm.smax.i16(i16, i16) 93 94define i16 @min_max_clamp_intrinsic(i16 %x) { 95; CHECK-LABEL: @min_max_clamp_intrinsic( 96; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048) 97; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[A]], i16 2047) 98; CHECK-NEXT: [[C:%.*]] = add nsw i16 [[B]], 1 99; CHECK-NEXT: ret i16 [[C]] 100; 101 %a = call i16 @llvm.smax.i16(i16 %x, i16 -2048) 102 %b = call i16 @llvm.smin.i16(i16 %a, i16 2047) 103 %c = add i16 %b, 1 104 ret i16 %c 105} 106 107define i16 @min_max_clamp_intrinsic_2(i16 %x) { 108; CHECK-LABEL: @min_max_clamp_intrinsic_2( 109; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) 110; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048) 111; CHECK-NEXT: [[C:%.*]] = add nsw i16 [[B]], 1 112; CHECK-NEXT: ret i16 [[C]] 113; 114 %a = call i16 @llvm.smin.i16(i16 %x, i16 2047) 115 %b = call i16 @llvm.smax.i16(i16 %a, i16 -2048) 116 %c = add i16 %b, 1 117 ret i16 %c 118} 119 120define i32 @min_max_clamp_intrinsic_3(i16 %x) { 121; CHECK-LABEL: @min_max_clamp_intrinsic_3( 122; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048) 123; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[A]], i16 2047) 124; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[B]] to i32 125; CHECK-NEXT: ret i32 [[TMP1]] 126; 127 %a = call i16 @llvm.smax.i16(i16 %x, i16 -2048) 128 %b = call i16 @llvm.smin.i16(i16 %a, i16 2047) 129 %c = add i16 %b, 1 130 %d = sext i16 %c to i32 131 %e = add i32 %d, -1 132 ret i32 %e 133} 134 135define i32 @min_max_clamp_intrinsic_4(i16 %x) { 136; CHECK-LABEL: @min_max_clamp_intrinsic_4( 137; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) 138; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048) 139; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[B]] to i32 140; CHECK-NEXT: ret i32 [[TMP1]] 141; 142 %a = call i16 @llvm.smin.i16(i16 %x, i16 2047) 143 %b = call i16 @llvm.smax.i16(i16 %a, i16 -2048) 144 %c = add i16 %b, 1 145 %d = sext i16 %c to i32 146 %e = add i32 %d, -1 147 ret i32 %e 148} 149