| ; 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 |
| } |