blob: bcdf22c109743805f7e951da03757c19664bd364 [file]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
; The offsets of a GEP are computed in the pointer index type. With a 16 bit
; index type, a stride or struct member offset that does not fit in 15 bits is
; negative there, so a non-negative index does not imply a non-negative offset
; and nuw must not be added.
target datalayout = "p:16:16"
%S.big = type { [40000 x i8], i8 }
%S.small = type { i16, i8 }
; The stride 40000 is negative as an i16, so the offset for a positive index is
; negative and the GEP may wrap in the unsigned sense.
define ptr @gep_no_nuw_stride_negative_in_index_type(ptr %p, i16 %i, i16 %j) {
; CHECK-LABEL: define ptr @gep_no_nuw_stride_negative_in_index_type(
; CHECK-SAME: ptr [[P:%.*]], i16 [[I:%.*]], i16 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i16 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i16 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw [40000 x i8], ptr [[P]], i16 [[I]]
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i16 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i16 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw [40000 x i8], ptr %p, i16 %i
ret ptr %gep
exit:
ret ptr null
}
; Same for the offset of a struct member, which is 40000 for the second field.
define ptr @gep_no_nuw_struct_offset_negative_in_index_type(ptr %p, i16 %i, i16 %j) {
; CHECK-LABEL: define ptr @gep_no_nuw_struct_offset_negative_in_index_type(
; CHECK-SAME: ptr [[P:%.*]], i16 [[I:%.*]], i16 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i16 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i16 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw [[S_BIG:%.*]], ptr [[P]], i16 [[I]], i32 1
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i16 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i16 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw %S.big, ptr %p, i16 %i, i32 1
ret ptr %gep
exit:
ret ptr null
}
; The stride of the outer array is 160000, which is 28928 and thus non-negative
; as an i16, but the stride of the inner array is negative.
define ptr @gep_no_nuw_inner_stride_negative_in_index_type(ptr %p, i16 %i, i16 %j) {
; CHECK-LABEL: define ptr @gep_no_nuw_inner_stride_negative_in_index_type(
; CHECK-SAME: ptr [[P:%.*]], i16 [[I:%.*]], i16 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i16 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i16 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw [4 x [40000 x i8]], ptr [[P]], i16 [[I]], i16 [[J]]
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i16 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i16 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw [4 x [40000 x i8]], ptr %p, i16 %i, i16 %j
ret ptr %gep
exit:
ret ptr null
}
; The stride fits in the index type, so nuw can be added.
define ptr @gep_nuw_stride_fits_index_type(ptr %p, i16 %i, i16 %j) {
; CHECK-LABEL: define ptr @gep_nuw_stride_fits_index_type(
; CHECK-SAME: ptr [[P:%.*]], i16 [[I:%.*]], i16 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i16 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i16 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw i16, ptr [[P]], i16 [[I]]
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i16 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i16 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw i16, ptr %p, i16 %i
ret ptr %gep
exit:
ret ptr null
}
; The struct member offset fits in the index type, so nuw can be added.
define ptr @gep_nuw_struct_offset_fits_index_type(ptr %p, i16 %i, i16 %j) {
; CHECK-LABEL: define ptr @gep_nuw_struct_offset_fits_index_type(
; CHECK-SAME: ptr [[P:%.*]], i16 [[I:%.*]], i16 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i16 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i16 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw [[S_SMALL:%.*]], ptr [[P]], i16 [[I]], i32 1
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i16 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i16 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw %S.small, ptr %p, i16 %i, i32 1
ret ptr %gep
exit:
ret ptr null
}
; An index wider than the index type is truncated. nusw guarantees the
; truncation preserves the signed value, which together with the index being
; non-negative means it also preserves the unsigned value.
define ptr @gep_nuw_index_wider_than_index_type(ptr %p, i64 %i, i64 %j) {
; CHECK-LABEL: define ptr @gep_nuw_index_wider_than_index_type(
; CHECK-SAME: ptr [[P:%.*]], i64 [[I:%.*]], i64 [[J:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[C_0:%.*]] = icmp sgt i64 [[I]], [[J]]
; CHECK-NEXT: br i1 [[C_0]], label %[[BB_1:.*]], label %[[EXIT:.*]]
; CHECK: [[BB_1]]:
; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i64 [[J]], 0
; CHECK-NEXT: br i1 [[C_1]], label %[[BB_2:.*]], label %[[EXIT]]
; CHECK: [[BB_2]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nusw i16, ptr [[P]], i64 [[I]]
; CHECK-NEXT: ret ptr [[GEP]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret ptr null
;
entry:
%c.0 = icmp sgt i64 %i, %j
br i1 %c.0, label %bb.1, label %exit
bb.1:
%c.1 = icmp sgt i64 %j, 0
br i1 %c.1, label %bb.2, label %exit
bb.2:
%gep = getelementptr nusw i16, ptr %p, i64 %i
ret ptr %gep
exit:
ret ptr null
}