| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s |
| |
| ; The ptrtoaddr folds are also valid for pointers that have external state. |
| target datalayout = "pe1:64:64:64:32" |
| |
| @g = external global i8 |
| @g2 = external global i8 |
| |
| @g.as1 = external addrspace(1) global i8 |
| @g2.as1 = external addrspace(1) global i8 |
| |
| define i64 @ptrtoaddr_inttoptr_arg(i64 %a) { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_arg( |
| ; CHECK-SAME: i64 [[A:%.*]]) { |
| ; CHECK-NEXT: ret i64 [[A]] |
| ; |
| %toptr = inttoptr i64 %a to ptr |
| %toaddr = ptrtoaddr ptr %toptr to i64 |
| ret i64 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_inttoptr_arg_addrsize(i32 %a) { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_arg_addrsize( |
| ; CHECK-SAME: i32 [[A:%.*]]) { |
| ; CHECK-NEXT: ret i32 [[A]] |
| ; |
| %toptr = inttoptr i32 %a to ptr addrspace(1) |
| %toaddr = ptrtoaddr ptr addrspace(1) %toptr to i32 |
| ret i32 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_inttoptr() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr() { |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| %toptr = inttoptr i32 -1 to ptr addrspace(1) |
| %toaddr = ptrtoaddr ptr addrspace(1) %toptr to i32 |
| ret i32 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_inttoptr_diff_size1() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_diff_size1() { |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| %toptr = inttoptr i64 -1 to ptr addrspace(1) |
| %toaddr = ptrtoaddr ptr addrspace(1) %toptr to i32 |
| ret i32 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_inttoptr_diff_size2() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_inttoptr_diff_size2() { |
| ; CHECK-NEXT: ret i32 65535 |
| ; |
| %toptr = inttoptr i16 -1 to ptr addrspace(1) |
| %toaddr = ptrtoaddr ptr addrspace(1) %toptr to i32 |
| ret i32 %toaddr |
| } |
| |
| define i64 @ptrtoaddr_inttoptr_noas1() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_noas1() { |
| ; CHECK-NEXT: ret i64 1 |
| ; |
| %toptr = getelementptr i8, ptr null, i64 1 |
| %toaddr = ptrtoaddr ptr %toptr to i64 |
| ret i64 %toaddr |
| } |
| |
| define i64 @ptr2addr2_inttoptr_noas2() { |
| ; CHECK-LABEL: define i64 @ptr2addr2_inttoptr_noas2() { |
| ; CHECK-NEXT: ret i64 123 |
| ; |
| %toptr = inttoptr i64 123 to ptr |
| %toaddr = ptrtoaddr ptr %toptr to i64 |
| ret i64 %toaddr |
| } |
| |
| define i64 @ptrtoaddr_inttoptr_noas_diff_size1() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_noas_diff_size1() { |
| ; CHECK-NEXT: ret i64 4294967295 |
| ; |
| %toptr = inttoptr i32 -1 to ptr |
| %toaddr = ptrtoaddr ptr %toptr to i64 |
| ret i64 %toaddr |
| } |
| |
| define i64 @ptrtoaddr_inttoptr_noas_diff_size2() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_inttoptr_noas_diff_size2() { |
| ; CHECK-NEXT: ret i64 -1 |
| ; |
| %toptr = inttoptr i128 -1 to ptr |
| %toaddr = ptrtoaddr ptr %toptr to i64 |
| ret i64 %toaddr |
| } |
| |
| define i64 @ptrtoaddr_gep_null() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_gep_null() { |
| ; CHECK-NEXT: ret i64 42 |
| ; |
| %toaddr = ptrtoaddr ptr getelementptr (i8, ptr null, i64 42) to i64 |
| ret i64 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_gep_null_addrsize() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_gep_null_addrsize() { |
| ; CHECK-NEXT: ret i32 42 |
| ; |
| %toaddr = ptrtoaddr ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i32 42) to i32 |
| ret i32 %toaddr |
| } |
| |
| define i64 @ptrtoaddr_gep_sub() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_gep_sub() { |
| ; CHECK-NEXT: ret i64 sub (i64 ptrtoaddr (ptr @g to i64), i64 ptrtoaddr (ptr @g2 to i64)) |
| ; |
| %toaddr = ptrtoaddr ptr getelementptr (i8, ptr @g, i64 sub (i64 0, i64 ptrtoaddr (ptr @g2 to i64))) to i64 |
| ret i64 %toaddr |
| } |
| |
| define i32 @ptrtoaddr_gep_sub_addrsize() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_gep_sub_addrsize() { |
| ; CHECK-NEXT: ret i32 sub (i32 ptrtoaddr (ptr addrspace(1) @g.as1 to i32), i32 ptrtoaddr (ptr addrspace(1) @g2.as1 to i32)) |
| ; |
| %toaddr = ptrtoaddr ptr addrspace(1) getelementptr (i8, ptr addrspace(1) @g.as1, i32 sub (i32 0, i32 ptrtoaddr (ptr addrspace(1) @g2.as1 to i32))) to i32 |
| ret i32 %toaddr |
| } |
| |
| ; Don't fold inttoptr of ptrtoaddr away. inttoptr will pick a previously |
| ; exposed provenance, which is not necessarily that of @g (especially as |
| ; ptrtoaddr does not expose the provenance.) |
| define ptr @inttoptr_of_ptrtoaddr() { |
| ; CHECK-LABEL: define ptr @inttoptr_of_ptrtoaddr() { |
| ; CHECK-NEXT: ret ptr inttoptr (i64 ptrtoaddr (ptr @g to i64) to ptr) |
| ; |
| %toptr = inttoptr i64 ptrtoaddr (ptr @g to i64) to ptr |
| ret ptr %toptr |
| } |
| |
| define i64 @ptrtoaddr_sub_consts_unrelated() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_sub_consts_unrelated() { |
| ; CHECK-NEXT: ret i64 sub (i64 ptrtoaddr (ptr @g to i64), i64 ptrtoaddr (ptr @g2 to i64)) |
| ; |
| %sub = sub i64 ptrtoaddr (ptr @g to i64), ptrtoaddr (ptr @g2 to i64) |
| ret i64 %sub |
| } |
| |
| define i64 @ptrtoaddr_sub_consts_offset() { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_sub_consts_offset() { |
| ; CHECK-NEXT: ret i64 42 |
| ; |
| %sub = sub i64 ptrtoaddr (ptr getelementptr (i8, ptr @g, i64 42) to i64), ptrtoaddr (ptr @g to i64) |
| ret i64 %sub |
| } |
| |
| define i32 @ptrtoaddr_sub_consts_offset_addrsize() { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_sub_consts_offset_addrsize() { |
| ; CHECK-NEXT: ret i32 42 |
| ; |
| %sub = sub i32 ptrtoaddr (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) @g.as1, i32 42) to i32), ptrtoaddr (ptr addrspace(1) @g.as1 to i32) |
| ret i32 %sub |
| } |
| |
| define i64 @ptrtoaddr_sub_known_offset(ptr %p) { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_sub_known_offset( |
| ; CHECK-SAME: ptr [[P:%.*]]) { |
| ; CHECK-NEXT: ret i64 42 |
| ; |
| %p2 = getelementptr inbounds i8, ptr %p, i64 42 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %p2.addr = ptrtoaddr ptr %p2 to i64 |
| %sub = sub i64 %p2.addr, %p.addr |
| ret i64 %sub |
| } |
| |
| define i32 @ptrtoaddr_sub_known_offset_addrsize(ptr addrspace(1) %p) { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_sub_known_offset_addrsize( |
| ; CHECK-SAME: ptr addrspace(1) [[P:%.*]]) { |
| ; CHECK-NEXT: ret i32 42 |
| ; |
| %p2 = getelementptr inbounds i8, ptr addrspace(1) %p, i32 42 |
| %p.addr = ptrtoaddr ptr addrspace(1) %p to i32 |
| %p2.addr = ptrtoaddr ptr addrspace(1) %p2 to i32 |
| %sub = sub i32 %p2.addr, %p.addr |
| ret i32 %sub |
| } |
| |
| define i64 @ptrtoaddr_of_ptradd_of_sub(i64 %x, ptr %p) { |
| ; CHECK-LABEL: define i64 @ptrtoaddr_of_ptradd_of_sub( |
| ; CHECK-SAME: i64 [[X:%.*]], ptr [[P:%.*]]) { |
| ; CHECK-NEXT: ret i64 [[X]] |
| ; |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %sub = sub i64 %x, %p.addr |
| %ptradd = getelementptr i8, ptr %p, i64 %sub |
| %ptradd.addr = ptrtoaddr ptr %ptradd to i64 |
| ret i64 %ptradd.addr |
| } |
| |
| define i32 @ptrtoaddr_of_ptradd_of_sub_addrsize(i32 %x, ptr addrspace(1) %p) { |
| ; CHECK-LABEL: define i32 @ptrtoaddr_of_ptradd_of_sub_addrsize( |
| ; CHECK-SAME: i32 [[X:%.*]], ptr addrspace(1) [[P:%.*]]) { |
| ; CHECK-NEXT: ret i32 [[X]] |
| ; |
| %p.addr = ptrtoaddr ptr addrspace(1) %p to i32 |
| %sub = sub i32 %x, %p.addr |
| %ptradd = getelementptr i8, ptr addrspace(1) %p, i32 %sub |
| %ptradd.addr = ptrtoaddr ptr addrspace(1) %ptradd to i32 |
| ret i32 %ptradd.addr |
| } |
| |
| define ptr @gep_of_sub_ptrtoaddr_unrelated_pointers(ptr %p, ptr %p2, i64 %x) { |
| ; CHECK-LABEL: define ptr @gep_of_sub_ptrtoaddr_unrelated_pointers( |
| ; CHECK-SAME: ptr [[P:%.*]], ptr [[P2:%.*]], i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[P2_ADDR:%.*]] = ptrtoaddr ptr [[P2]] to i64 |
| ; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr [[P]] to i64 |
| ; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[P2_ADDR]], [[P_ADDR]] |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[P]], i64 [[SUB]] |
| ; CHECK-NEXT: ret ptr [[GEP2]] |
| ; |
| %p2.addr = ptrtoaddr ptr %p2 to i64 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %sub = sub i64 %p2.addr, %p.addr |
| %gep2 = getelementptr i8, ptr %p, i64 %sub |
| ret ptr %gep2 |
| } |
| |
| define ptr @gep_of_sub_ptrtoaddr(ptr %p, i64 %x) { |
| ; CHECK-LABEL: define ptr @gep_of_sub_ptrtoaddr( |
| ; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] |
| ; CHECK-NEXT: ret ptr [[GEP1]] |
| ; |
| %gep1 = getelementptr i8, ptr %p, i64 %x |
| %gep1.addr = ptrtoaddr ptr %gep1 to i64 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %sub = sub i64 %gep1.addr, %p.addr |
| %gep2 = getelementptr i8, ptr %p, i64 %sub |
| ret ptr %gep2 |
| } |
| |
| define ptr addrspace(1) @gep_of_sub_ptrtoaddr_addrsize(ptr addrspace(1) %p, i32 %x) { |
| ; CHECK-LABEL: define ptr addrspace(1) @gep_of_sub_ptrtoaddr_addrsize( |
| ; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[X:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr addrspace(1) [[P]], i32 [[X]] |
| ; CHECK-NEXT: ret ptr addrspace(1) [[GEP1]] |
| ; |
| %gep1 = getelementptr i8, ptr addrspace(1) %p, i32 %x |
| %gep1.addr = ptrtoaddr ptr addrspace(1) %gep1 to i32 |
| %p.addr = ptrtoaddr ptr addrspace(1) %p to i32 |
| %sub = sub i32 %gep1.addr, %p.addr |
| %gep2 = getelementptr i8, ptr addrspace(1) %p, i32 %sub |
| ret ptr addrspace(1) %gep2 |
| } |
| |
| define ptr @gep_of_sub_ptrtoaddr_ashr(ptr %p, i64 %x) { |
| ; CHECK-LABEL: define ptr @gep_of_sub_ptrtoaddr_ashr( |
| ; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] |
| ; CHECK-NEXT: ret ptr [[GEP1]] |
| ; |
| %gep1 = getelementptr i8, ptr %p, i64 %x |
| %gep1.addr = ptrtoaddr ptr %gep1 to i64 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %sub = sub i64 %gep1.addr, %p.addr |
| %ashr = ashr i64 %sub, 1 |
| %gep2 = getelementptr i16, ptr %p, i64 %ashr |
| ret ptr %gep2 |
| } |
| |
| define ptr addrspace(1) @gep_of_sub_ptrtoaddr_ashr_addrsize(ptr addrspace(1) %p, i32 %x) { |
| ; CHECK-LABEL: define ptr addrspace(1) @gep_of_sub_ptrtoaddr_ashr_addrsize( |
| ; CHECK-SAME: ptr addrspace(1) [[P:%.*]], i32 [[X:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i8, ptr addrspace(1) [[P]], i32 [[X]] |
| ; CHECK-NEXT: ret ptr addrspace(1) [[GEP1]] |
| ; |
| %gep1 = getelementptr i8, ptr addrspace(1) %p, i32 %x |
| %gep1.addr = ptrtoaddr ptr addrspace(1) %gep1 to i32 |
| %p.addr = ptrtoaddr ptr addrspace(1) %p to i32 |
| %sub = sub i32 %gep1.addr, %p.addr |
| %sdiv = sdiv i32 %sub, 3 |
| %gep2 = getelementptr [3 x i8], ptr addrspace(1) %p, i32 %sdiv |
| ret ptr addrspace(1) %gep2 |
| } |
| |
| ; Not folding this to inttoptr(123), as this may have different provenance from |
| ; %p, and the use of ptrtoaddr implies that the provenance of %p may not be |
| ; exposed, such that inttoptr cannot recover it. |
| define ptr @gep_gep_neg_ptrtoaddr(ptr %p) { |
| ; CHECK-LABEL: define ptr @gep_gep_neg_ptrtoaddr( |
| ; CHECK-SAME: ptr [[P:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 123 |
| ; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr [[P]] to i64 |
| ; CHECK-NEXT: [[P_ADDR_NEG:%.*]] = sub i64 0, [[P_ADDR]] |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[GEP1]], i64 [[P_ADDR_NEG]] |
| ; CHECK-NEXT: ret ptr [[GEP2]] |
| ; |
| %gep1 = getelementptr inbounds i8, ptr %p, i64 123 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %p.addr.neg = sub i64 0, %p.addr |
| %gep2 = getelementptr i8, ptr %gep1, i64 %p.addr.neg |
| ret ptr %gep2 |
| } |
| |
| define ptr @gep_gep_inv_ptrtoaddr(ptr %p) { |
| ; CHECK-LABEL: define ptr @gep_gep_inv_ptrtoaddr( |
| ; CHECK-SAME: ptr [[P:%.*]]) { |
| ; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 123 |
| ; CHECK-NEXT: [[P_ADDR:%.*]] = ptrtoaddr ptr [[P]] to i64 |
| ; CHECK-NEXT: [[P_ADDR_INV:%.*]] = xor i64 [[P_ADDR]], -1 |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[GEP1]], i64 [[P_ADDR_INV]] |
| ; CHECK-NEXT: ret ptr [[GEP2]] |
| ; |
| %gep1 = getelementptr inbounds i8, ptr %p, i64 123 |
| %p.addr = ptrtoaddr ptr %p to i64 |
| %p.addr.inv = xor i64 %p.addr, -1 |
| %gep2 = getelementptr i8, ptr %gep1, i64 %p.addr.inv |
| ret ptr %gep2 |
| } |