; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6 ; RUN: llubi --verbose < %s 2>&1 | FileCheck %s target datalayout = "e-p:64:64:64:32" %struct = type { i64, [2 x i32], i64 } define ptr @dead_stack_object() { %alloc = alloca i32 ret ptr %alloc } define void @main() { %alloc = alloca i32 %alloc_struct = alloca %struct %gep = getelementptr i8, ptr %alloc, i64 3 %gep_poison_base = getelementptr i8, ptr poison, i64 1 %gep_poison_idx = getelementptr i8, ptr %alloc, i64 poison ; The indices are first converted to offsets in the pointer’s index type. ; The index itself is sign-extended or truncated, and then multiplied by the type allocation size %gep_trunc_idx = getelementptr i32, ptr %alloc, i128 18446744073709551616 %gep_sext_idx = getelementptr i32, ptr %alloc, i8 -1 ; The offsets are then added to the low bits of the base address up to the index type width, ; with silently-wrapping two’s complement arithmetic. %large_address = inttoptr i64 -1 to ptr %gep_update_idx_bits = getelementptr i32, ptr %large_address, i64 1 %gep_struct = getelementptr %struct, ptr %alloc_struct, i64 0, i32 1, i32 1 %gep_scalable_vec = getelementptr , ptr null, i64 4 %gep_vec_idx = getelementptr [2 x i32], ptr %alloc, i64 1, <2 x i64> %ptr_vec_insert = insertelement <2 x ptr> poison, ptr %alloc, i32 0 %ptr_vec_splat = shufflevector <2 x ptr> %ptr_vec_insert, <2 x ptr> poison, <2 x i32> zeroinitializer %gep_vec_ptr = getelementptr i32, <2 x ptr> %ptr_vec_splat, i64 1 %gep_vec_ptr_vec_idx = getelementptr i32, <2 x ptr> %ptr_vec_splat, <2 x i64> ; Note that getelementptr with all-zero indices is always considered to be inbounds, even if the base ; pointer does not point to an allocated object. As a corollary, the only pointer in bounds of the null ; pointer in the default address space is the null pointer itself. %gep_inbounds_valid_null = getelementptr inbounds i8, ptr null, i64 0 %gep_inbounds_invalid_null = getelementptr inbounds i8, ptr null, i64 1 ; The base pointer has an in bounds address of the allocated object that it is based on. ; This means that it points into that allocated object, or to its end. %gep_inbounds_valid1 = getelementptr inbounds i8, ptr %alloc, i64 3 %gep_inbounds_valid2 = getelementptr inbounds i8, ptr %alloc, i64 4 %gep_inbounds_invalid1 = getelementptr inbounds i8, ptr %alloc, i64 -1 %gep_inbounds_invalid2 = getelementptr inbounds i8, ptr %alloc, i64 5 ; During the successive addition of offsets to the address, the resulting pointer ; must remain in bounds of the allocated object at each step. %gep_inbounds_invalid3 = getelementptr inbounds %struct, ptr %alloc_struct, i64 1, i32 1, i32 -2 %dead_stack_ptr = call ptr @dead_stack_object() ; The object does not have to be live anymore; being in-bounds of a deallocated object is sufficient. %gep_inbounds_valid4 = getelementptr inbounds i8, ptr %dead_stack_ptr, i64 4 %gep_inbounds_invalid4 = getelementptr inbounds i8, ptr %dead_stack_ptr, i64 5 ; If the type of an index is larger than the pointer index type, the truncation to the pointer index ; type preserves the signed value (trunc nsw). %gep_nusw_valid1 = getelementptr nusw i8, ptr %alloc, i64 -1 %gep_nusw_invalid1 = getelementptr nusw i8, ptr %large_address, i64 -2147483649 ; The multiplication of an index by the type size does not wrap the pointer index type in a signed sense (mul nsw). %gep_nusw_valid2 = getelementptr nusw i32, ptr null, i32 536870911 %gep_nusw_invalid2 = getelementptr nusw i32, ptr null, i32 536870912 ; The successive addition of each offset (without adding the base address) does not wrap the pointer ; index type in a signed sense (add nsw). %gep_nusw_valid3 = getelementptr nusw [2 x i16], ptr null, i32 536870911, i32 1 %gep_nusw_invalid3 = getelementptr nusw [2 x i16], ptr null, i32 536870911, i32 2 ; The successive addition of the current address, truncated to the pointer index type and interpreted as an unsigned ; number, and each offset, interpreted as a signed number, does not wrap the pointer index type. %large_address2 = inttoptr i64 -4 to ptr %gep_nusw_valid4 = getelementptr nusw i8, ptr %large_address2, i64 3 %gep_nusw_invalid4 = getelementptr nusw i8, ptr %large_address2, i64 4 %gep_nusw_valid5 = getelementptr nusw i8, ptr %large_address2, i64 -4 %gep_nusw_invalid5 = getelementptr nusw i8, ptr %alloc, i64 -16 ; If the type of an index is larger than the pointer index type, ; the truncation to the pointer index type preserves the unsigned value (trunc nuw). %gep_nuw_valid1 = getelementptr nuw i8, ptr null, i64 2147483647 %gep_nuw_invalid1 = getelementptr nuw i8, ptr null, i64 -1 ; The multiplication of an index by the type size does not wrap ; the pointer index type in an unsigned sense (mul nuw). %gep_nuw_valid2 = getelementptr nuw i32, ptr null, i32 1073741823 %gep_nuw_invalid2 = getelementptr nuw i32, ptr null, i32 1073741824 ; The successive addition of each offset (without adding the base address) does not ; wrap the pointer index type in an unsigned sense (add nuw). %gep_nuw_valid3 = getelementptr nuw [2 x i16], ptr null, i32 1073741823, i32 1 %gep_nuw_invalid3 = getelementptr nuw [2 x i16], ptr null, i32 1073741823, i32 2 ; The successive addition of the current address, truncated to the pointer index type and interpreted ; as an unsigned number, and each offset, also interpreted as an unsigned number, does not wrap the ; pointer index type (add nuw). %gep_nuw_valid4 = getelementptr nuw i32, ptr %alloc, i64 1073741821 %gep_nuw_invalid4 = getelementptr nuw i32, ptr %alloc, i64 1073741822 ret void } ; CHECK: Entering function: main ; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x8 [alloc] ; CHECK-NEXT: %alloc_struct = alloca %struct, align 8 => ptr 0x10 [alloc_struct] ; CHECK-NEXT: %gep = getelementptr i8, ptr %alloc, i64 3 => ptr 0xB [alloc + 3] ; CHECK-NEXT: %gep_poison_base = getelementptr i8, ptr poison, i64 1 => poison ; CHECK-NEXT: %gep_poison_idx = getelementptr i8, ptr %alloc, i64 poison => poison ; CHECK-NEXT: %gep_trunc_idx = getelementptr i32, ptr %alloc, i128 18446744073709551616 => ptr 0x8 [alloc] ; CHECK-NEXT: %gep_sext_idx = getelementptr i32, ptr %alloc, i8 -1 => ptr 0x4 [alloc + -4] ; CHECK-NEXT: %large_address = inttoptr i64 -1 to ptr => ptr 0xFFFFFFFFFFFFFFFF [nullary] ; CHECK-NEXT: %gep_update_idx_bits = getelementptr i32, ptr %large_address, i64 1 => ptr 0xFFFFFFFF00000003 [nullary] ; CHECK-NEXT: %gep_struct = getelementptr %struct, ptr %alloc_struct, i64 0, i32 1, i32 1 => ptr 0x1C [alloc_struct + 12] ; CHECK-NEXT: %gep_scalable_vec = getelementptr , ptr null, i64 4 => ptr 0x100 [nullary] ; CHECK-NEXT: %gep_vec_idx = getelementptr [2 x i32], ptr %alloc, i64 1, <2 x i64> => { ptr 0x10 [alloc + 8], ptr 0x18 [alloc + 16] } ; CHECK-NEXT: %ptr_vec_insert = insertelement <2 x ptr> poison, ptr %alloc, i32 0 => { ptr 0x8 [alloc], poison } ; CHECK-NEXT: %ptr_vec_splat = shufflevector <2 x ptr> %ptr_vec_insert, <2 x ptr> poison, <2 x i32> zeroinitializer => { ptr 0x8 [alloc], ptr 0x8 [alloc] } ; CHECK-NEXT: %gep_vec_ptr = getelementptr i32, <2 x ptr> %ptr_vec_splat, i64 1 => { ptr 0xC [alloc + 4], ptr 0xC [alloc + 4] } ; CHECK-NEXT: %gep_vec_ptr_vec_idx = getelementptr i32, <2 x ptr> %ptr_vec_splat, <2 x i64> => { ptr 0x8 [alloc], ptr 0x10 [alloc + 8] } ; CHECK-NEXT: %gep_inbounds_valid_null = getelementptr inbounds i8, ptr null, i64 0 => ptr 0x0 [nullary] ; CHECK-NEXT: %gep_inbounds_invalid_null = getelementptr inbounds i8, ptr null, i64 1 => poison ; CHECK-NEXT: %gep_inbounds_valid1 = getelementptr inbounds i8, ptr %alloc, i64 3 => ptr 0xB [alloc + 3] ; CHECK-NEXT: %gep_inbounds_valid2 = getelementptr inbounds i8, ptr %alloc, i64 4 => ptr 0xC [alloc + 4] ; CHECK-NEXT: %gep_inbounds_invalid1 = getelementptr inbounds i8, ptr %alloc, i64 -1 => poison ; CHECK-NEXT: %gep_inbounds_invalid2 = getelementptr inbounds i8, ptr %alloc, i64 5 => poison ; CHECK-NEXT: %gep_inbounds_invalid3 = getelementptr inbounds %struct, ptr %alloc_struct, i64 1, i32 1, i32 -2 => poison ; CHECK-NEXT: Entering function: dead_stack_object ; CHECK-NEXT: %alloc = alloca i32, align 4 => ptr 0x28 [alloc] ; CHECK-NEXT: ret ptr %alloc ; CHECK-NEXT: Exiting function: dead_stack_object ; CHECK-NEXT: %dead_stack_ptr = call ptr @dead_stack_object() => ptr 0x28 [alloc (dangling)] ; CHECK-NEXT: %gep_inbounds_valid4 = getelementptr inbounds i8, ptr %dead_stack_ptr, i64 4 => ptr 0x2C [alloc + 4 (dangling)] ; CHECK-NEXT: %gep_inbounds_invalid4 = getelementptr inbounds i8, ptr %dead_stack_ptr, i64 5 => poison ; CHECK-NEXT: %gep_nusw_valid1 = getelementptr nusw i8, ptr %alloc, i64 -1 => ptr 0x7 [alloc + -1] ; CHECK-NEXT: %gep_nusw_invalid1 = getelementptr nusw i8, ptr %large_address, i64 -2147483649 => poison ; CHECK-NEXT: %gep_nusw_valid2 = getelementptr nusw i32, ptr null, i32 536870911 => ptr 0x7FFFFFFC [nullary] ; CHECK-NEXT: %gep_nusw_invalid2 = getelementptr nusw i32, ptr null, i32 536870912 => poison ; CHECK-NEXT: %gep_nusw_valid3 = getelementptr nusw [2 x i16], ptr null, i32 536870911, i32 1 => ptr 0x7FFFFFFE [nullary] ; CHECK-NEXT: %gep_nusw_invalid3 = getelementptr nusw [2 x i16], ptr null, i32 536870911, i32 2 => poison ; CHECK-NEXT: %large_address2 = inttoptr i64 -4 to ptr => ptr 0xFFFFFFFFFFFFFFFC [nullary] ; CHECK-NEXT: %gep_nusw_valid4 = getelementptr nusw i8, ptr %large_address2, i64 3 => ptr 0xFFFFFFFFFFFFFFFF [nullary] ; CHECK-NEXT: %gep_nusw_invalid4 = getelementptr nusw i8, ptr %large_address2, i64 4 => poison ; CHECK-NEXT: %gep_nusw_valid5 = getelementptr nusw i8, ptr %large_address2, i64 -4 => ptr 0xFFFFFFFFFFFFFFF8 [nullary] ; CHECK-NEXT: %gep_nusw_invalid5 = getelementptr nusw i8, ptr %alloc, i64 -16 => poison ; CHECK-NEXT: %gep_nuw_valid1 = getelementptr nuw i8, ptr null, i64 2147483647 => ptr 0x7FFFFFFF [nullary] ; CHECK-NEXT: %gep_nuw_invalid1 = getelementptr nuw i8, ptr null, i64 -1 => poison ; CHECK-NEXT: %gep_nuw_valid2 = getelementptr nuw i32, ptr null, i32 1073741823 => ptr 0xFFFFFFFC [nullary] ; CHECK-NEXT: %gep_nuw_invalid2 = getelementptr nuw i32, ptr null, i32 1073741824 => poison ; CHECK-NEXT: %gep_nuw_valid3 = getelementptr nuw [2 x i16], ptr null, i32 1073741823, i32 1 => ptr 0xFFFFFFFE [nullary] ; CHECK-NEXT: %gep_nuw_invalid3 = getelementptr nuw [2 x i16], ptr null, i32 1073741823, i32 2 => poison ; CHECK-NEXT: %gep_nuw_valid4 = getelementptr nuw i32, ptr %alloc, i64 1073741821 => ptr 0xFFFFFFFC [alloc + 4294967284] ; CHECK-NEXT: %gep_nuw_invalid4 = getelementptr nuw i32, ptr %alloc, i64 1073741822 => poison ; CHECK-NEXT: ret void ; CHECK-NEXT: Exiting function: main