199 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 | |
| ; RUN: opt < %s -instcombine -S | FileCheck %s
 | |
| 
 | |
| target datalayout = "n32"
 | |
| 
 | |
| define i1 @is_rem2_neg_i8(i8 %x) {
 | |
| ; CHECK-LABEL: @is_rem2_neg_i8(
 | |
| ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -127
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], -127
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i8 %x, 2
 | |
|   %r = icmp slt i8 %s, 0
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| define <2 x i1> @is_rem2_pos_v2i8(<2 x i8> %x) {
 | |
| ; CHECK-LABEL: @is_rem2_pos_v2i8(
 | |
| ; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -127, i8 -127>
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 1, i8 1>
 | |
| ; CHECK-NEXT:    ret <2 x i1> [[R]]
 | |
| ;
 | |
|   %s = srem <2 x i8> %x, <i8 2, i8 2>
 | |
|   %r = icmp sgt <2 x i8> %s, zeroinitializer
 | |
|   ret <2 x i1> %r
 | |
| }
 | |
| 
 | |
| ; i8 -97 == 159 == 0b10011111
 | |
| 
 | |
| define i1 @is_rem32_pos_i8(i8 %x) {
 | |
| ; CHECK-LABEL: @is_rem32_pos_i8(
 | |
| ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -97
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], 0
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i8 %x, 32
 | |
|   %r = icmp sgt i8 %s, 0
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| ; i16 -32765 == 32771 == 0b1000000000000011
 | |
| 
 | |
| define i1 @is_rem4_neg_i16(i16 %x) {
 | |
| ; CHECK-LABEL: @is_rem4_neg_i16(
 | |
| ; CHECK-NEXT:    [[TMP1:%.*]] = and i16 [[X:%.*]], -32765
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i16 [[TMP1]], -32768
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i16 %x, 4
 | |
|   %r = icmp slt i16 %s, 0
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| declare void @use(i32)
 | |
| 
 | |
| ; TODO: This is still worth folding because srem is difficult?
 | |
| 
 | |
| define i1 @is_rem32_neg_i32_extra_use(i32 %x) {
 | |
| ; CHECK-LABEL: @is_rem32_neg_i32_extra_use(
 | |
| ; CHECK-NEXT:    [[S:%.*]] = srem i32 [[X:%.*]], 32
 | |
| ; CHECK-NEXT:    call void @use(i32 [[S]])
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[S]], 0
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i32 %x, 32
 | |
|   call void @use(i32 %s)
 | |
|   %r = icmp slt i32 %s, 0
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| ; Negative test - wrong compare constant
 | |
| 
 | |
| define i1 @is_rem8_nonneg_i16(i16 %x) {
 | |
| ; CHECK-LABEL: @is_rem8_nonneg_i16(
 | |
| ; CHECK-NEXT:    [[S:%.*]] = srem i16 [[X:%.*]], 8
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp sgt i16 [[S]], -1
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i16 %x, 8
 | |
|   %r = icmp sgt i16 %s, -1
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| ; Negative test - wrong remainder constant
 | |
| 
 | |
| define i1 @is_rem3_neg_i8(i8 %x) {
 | |
| ; CHECK-LABEL: @is_rem3_neg_i8(
 | |
| ; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 3
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[S]], 0
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i8 %x, 3
 | |
|   %r = icmp slt i8 %s, 0
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| ; Negative test - wrong compare constant
 | |
| 
 | |
| define i1 @is_rem16_something_i8(i8 %x) {
 | |
| ; CHECK-LABEL: @is_rem16_something_i8(
 | |
| ; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 16
 | |
| ; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[S]], 7
 | |
| ; CHECK-NEXT:    ret i1 [[R]]
 | |
| ;
 | |
|   %s = srem i8 %x, 16
 | |
|   %r = icmp slt i8 %s, 7
 | |
|   ret i1 %r
 | |
| }
 | |
| 
 | |
| ; PR30281 - https://llvm.org/bugs/show_bug.cgi?id=30281
 | |
| 
 | |
| ; All of these tests contain foldable division-by-constant instructions, but we
 | |
| ; can't assert that those folds have occurred before we process the later icmp.
 | |
| 
 | |
| define i32 @icmp_div(i16 %a, i16 %c) {
 | |
| ; CHECK-LABEL: @icmp_div(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
 | |
| ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
 | |
| ; CHECK:       then:
 | |
| ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
 | |
| ; CHECK-NEXT:    [[PHI_BO:%.*]] = sext i1 [[CMP]] to i32
 | |
| ; CHECK-NEXT:    br label [[EXIT]]
 | |
| ; CHECK:       exit:
 | |
| ; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHI_BO]], [[THEN]] ]
 | |
| ; CHECK-NEXT:    ret i32 [[PHI]]
 | |
| ;
 | |
| entry:
 | |
|   %tobool = icmp eq i16 %a, 0
 | |
|   br i1 %tobool, label %then, label %exit
 | |
| 
 | |
| then:
 | |
|   %div = sdiv i16 %c, -1
 | |
|   %cmp = icmp ne i16 %div, 0
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
 | |
|   %zext = zext i1 %phi to i32
 | |
|   %add = add nsw i32 %zext, -1
 | |
|   ret i32 %add
 | |
| }
 | |
| 
 | |
| define i32 @icmp_div2(i16 %a, i16 %c) {
 | |
| ; CHECK-LABEL: @icmp_div2(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
 | |
| ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
 | |
| ; CHECK:       then:
 | |
| ; CHECK-NEXT:    br label [[EXIT]]
 | |
| ; CHECK:       exit:
 | |
| ; CHECK-NEXT:    ret i32 -1
 | |
| ;
 | |
| entry:
 | |
|   %tobool = icmp eq i16 %a, 0
 | |
|   br i1 %tobool, label %then, label %exit
 | |
| 
 | |
| then:
 | |
|   %div = sdiv i16 %c, 0
 | |
|   %cmp = icmp ne i16 %div, 0
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
 | |
|   %zext = zext i1 %phi to i32
 | |
|   %add = add nsw i32 %zext, -1
 | |
|   ret i32 %add
 | |
| }
 | |
| 
 | |
| define i32 @icmp_div3(i16 %a, i16 %c) {
 | |
| ; CHECK-LABEL: @icmp_div3(
 | |
| ; CHECK-NEXT:  entry:
 | |
| ; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
 | |
| ; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
 | |
| ; CHECK:       then:
 | |
| ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
 | |
| ; CHECK-NEXT:    [[PHI_BO:%.*]] = sext i1 [[CMP]] to i32
 | |
| ; CHECK-NEXT:    br label [[EXIT]]
 | |
| ; CHECK:       exit:
 | |
| ; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHI_BO]], [[THEN]] ]
 | |
| ; CHECK-NEXT:    ret i32 [[PHI]]
 | |
| ;
 | |
| entry:
 | |
|   %tobool = icmp eq i16 %a, 0
 | |
|   br i1 %tobool, label %then, label %exit
 | |
| 
 | |
| then:
 | |
|   %div = sdiv i16 %c, 1
 | |
|   %cmp = icmp ne i16 %div, 0
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
 | |
|   %zext = zext i1 %phi to i32
 | |
|   %add = add nsw i32 %zext, -1
 | |
|   ret i32 %add
 | |
| }
 | |
| 
 |