282 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			LLVM
		
	
	
	
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 | 
						|
; RUN: opt -constraint-elimination -S %s | FileCheck %s
 | 
						|
 | 
						|
; Tests for using inbounds information from GEPs where the GEP only causes UB in the use blocks.
 | 
						|
 | 
						|
declare void @noundef(i32* noundef) willreturn nounwind
 | 
						|
declare void @noundef2(i32* noundef)
 | 
						|
 | 
						|
declare void @use(i1)
 | 
						|
 | 
						|
; %start + %n.ext is guaranteed to not overflow (due to inbounds).
 | 
						|
; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
 | 
						|
define i1 @inbounds_poison_is_ub_in_use_block_1(i32* %src, i32 %n, i32 %idx) {
 | 
						|
; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_1(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 | 
						|
 | 
						|
define i1 @inbounds_poison_is_ub_in_use_block_2(i32* %src, i32 %n, i32 %idx, i1 %c) {
 | 
						|
; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_2(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 | 
						|
 | 
						|
declare void @llvm.assume(i1)
 | 
						|
 | 
						|
; %start + %n.ext is guaranteed to not overflow (due to inbounds).
 | 
						|
; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
 | 
						|
define i1 @inbounds_poison_is_ub_in_use_block_by_assume(i32* %src, i32 %n, i32 %idx) {
 | 
						|
; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_by_assume(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    [[CMP_NE:%.*]] = icmp ule i32* null, [[UPPER]]
 | 
						|
; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_NE]])
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  %cmp.ne = icmp ule i32* null, %upper
 | 
						|
  call void @llvm.assume(i1 %cmp.ne)
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
; %start + %n.ext is guaranteed to not overflow (due to inbounds).
 | 
						|
; %start + %idx.ext does not overflow if %idx.ext <= %n.ext.
 | 
						|
define i1 @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(i32* %src, i32 %n, i32 %idx, i1 %c) {
 | 
						|
; CHECK-LABEL: @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[C:%.*]], label [[CHECK_BB:%.*]], label [[EXIT:%.*]]
 | 
						|
; CHECK:       check.bb:
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
; CHECK:       exit:
 | 
						|
; CHECK-NEXT:    ret i1 false
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  br i1 %c, label %check.bb, label %exit
 | 
						|
 | 
						|
check.bb:
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
 | 
						|
exit:
 | 
						|
  ret i1 false
 | 
						|
}
 | 
						|
 | 
						|
define i1 @may_exit_before_ub_is_caused(i32* %src, i32 %n, i32 %idx) {
 | 
						|
; CHECK-LABEL: @may_exit_before_ub_is_caused(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    call void @use(i1 [[CMP_UPPER_1]])
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  call void @use(i1 %cmp.upper.1);
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 | 
						|
 | 
						|
define i1 @only_UB_in_false_block(i32* %src, i32 %n, i32 %idx) {
 | 
						|
; CHECK-LABEL: @only_UB_in_false_block(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    call void @noundef(i32* [[UPPER]])
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  call void @noundef(i32* %upper)
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 | 
						|
 | 
						|
define i1 @only_ub_by_assume_in_false_block(i32* %src, i32 %n, i32 %idx) {
 | 
						|
; CHECK-LABEL: @only_ub_by_assume_in_false_block(
 | 
						|
; CHECK-NEXT:  entry:
 | 
						|
; CHECK-NEXT:    [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64
 | 
						|
; CHECK-NEXT:    [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]]
 | 
						|
; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]]
 | 
						|
; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64
 | 
						|
; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]]
 | 
						|
; CHECK-NEXT:    br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]]
 | 
						|
; CHECK:       then:
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_1]]
 | 
						|
; CHECK:       else:
 | 
						|
; CHECK-NEXT:    [[CMP_NE:%.*]] = icmp ule i32* null, [[UPPER]]
 | 
						|
; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_NE]])
 | 
						|
; CHECK-NEXT:    [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]]
 | 
						|
; CHECK-NEXT:    ret i1 [[CMP_UPPER_2]]
 | 
						|
;
 | 
						|
entry:
 | 
						|
  %n.ext = zext i32 %n to i64
 | 
						|
  %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext
 | 
						|
  %cmp.idx = icmp ult i32 %idx, %n
 | 
						|
  %idx.ext = zext i32 %idx to i64
 | 
						|
  %src.idx = getelementptr i32, i32* %src, i64 %idx.ext
 | 
						|
  br i1 %cmp.idx, label %then, label %else
 | 
						|
 | 
						|
then:
 | 
						|
  %cmp.upper.1 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.1
 | 
						|
 | 
						|
else:
 | 
						|
  %cmp.ne = icmp ule i32* null, %upper
 | 
						|
  call void @llvm.assume(i1 %cmp.ne)
 | 
						|
  %cmp.upper.2 = icmp ule i32* %src.idx, %upper
 | 
						|
  ret i1 %cmp.upper.2
 | 
						|
}
 |