314 lines · plain
1; RUN: opt -passes=print-memderefs -S < %s -disable-output -use-dereferenceable-at-point-semantics=false 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL2; RUN: opt -passes=print-memderefs -S < %s -disable-output -use-dereferenceable-at-point-semantics 2>&1 | FileCheck %s --check-prefixes=CHECK,POINT3 4 5; Uses the print-deref (+ analyze to print) pass to run6; isDereferenceablePointer() on many load instruction operands7 8target datalayout = "e-i32:32:64"9 10%TypeOpaque = type opaque11 12declare zeroext i1 @return_i1()13 14declare ptr @foo()15@globalstr = global [6 x i8] c"hello\00"16@globali32ptr = external global ptr17 18%struct.A = type { [8 x i8], [5 x i8] }19@globalstruct = external global %struct.A20 21@globalptr.align1 = external global i8, align 122@globalptr.align16 = external global i8, align 1623 24; Loads from sret arguments25; CHECK-LABEL: 'test_sret'26; CHECK: %sret_gep{{.*}}(aligned)27; CHECK-NOT: %sret_gep_outside28define void @test_sret(ptr sret(%struct.A) %result, i1 %arg) {29 %sret_gep = getelementptr inbounds %struct.A, ptr %result, i64 0, i32 1, i64 230 load i8, ptr %sret_gep31 32 %sret_gep_outside = getelementptr %struct.A, ptr %result, i64 0, i32 1, i64 733 load i8, ptr %sret_gep_outside34 ret void35}36 37; CHECK-LABEL: 'test'38define void @test(ptr addrspace(1) dereferenceable(8) %dparam,39 ptr addrspace(1) dereferenceable(32) align 1 %dparam.align1,40 ptr addrspace(1) dereferenceable(32) align 16 %dparam.align16)41 gc "statepoint-example" {42; CHECK: The following are dereferenceable:43entry:44 call void @mayfree()45 46; GLOBAL: %dparam{{.*}}(unaligned)47; POINT-NOT: %dparam{{.*}}(unaligned)48 %load3 = load i32, ptr addrspace(1) %dparam49 50; GLOBAL: %relocate{{.*}}(unaligned)51; POINT-NOT: %relocate{{.*}}(unaligned)52 %tok = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %dparam)]53 %relocate = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 0, i32 0)54 %load4 = load i32, ptr addrspace(1) %relocate55 56; CHECK-NOT: %nparam57 %dpa = call ptr addrspace(1) @func1(ptr addrspace(1) %dparam)58 %nparam = getelementptr i32, ptr addrspace(1) %dpa, i32 559 %load5 = load i32, ptr addrspace(1) %nparam60 61 ; Load from a non-dereferenceable load62; CHECK-NOT: %nd_load63 %nd_load = load ptr, ptr @globali32ptr64 %load6 = load i32, ptr %nd_load65 66 ; Load from a dereferenceable load67; GLOBAL: %d4_load{{.*}}(unaligned)68; POINT-NOT: %d4_load{{.*}}(unaligned)69 %d4_load = load ptr, ptr @globali32ptr, !dereferenceable !070 %load7 = load i32, ptr %d4_load71 72 ; Load from an offset not covered by the dereferenceable portion73; CHECK-NOT: %d2_load74 %d2_load = load ptr, ptr @globali32ptr, !dereferenceable !175 %load8 = load i32, ptr %d2_load76 77 ; Load from a potentially null pointer with dereferenceable_or_null78; CHECK-NOT: %d_or_null_load79 %d_or_null_load = load ptr, ptr @globali32ptr, !dereferenceable_or_null !080 %load9 = load i32, ptr %d_or_null_load81 82 ; Load from a non-null pointer with dereferenceable_or_null83; GLOBAL: %d_or_null_non_null_load{{.*}}(unaligned)84; POINT-NOT: %d_or_null_non_null_load{{.*}}(unaligned)85 %d_or_null_non_null_load = load ptr, ptr @globali32ptr, !nonnull !2, !dereferenceable_or_null !086 %load10 = load i32, ptr %d_or_null_non_null_load87 88 ; Loads from aligned arguments89; GLOBAL: %dparam.align1{{.*}}(unaligned)90; POINT-NOT: %dparam.align1{{.*}}(unaligned)91; POINT-NOT: %dparam.align16{{.*}}(aligned)92; GLOBAL: %dparam.align16{{.*}}(aligned)93 %load15 = load i8, ptr addrspace(1) %dparam.align1, align 1694 %load16 = load i8, ptr addrspace(1) %dparam.align16, align 1695 96 ; Loads from GEPs97; GLOBAL: %gep.align1.offset1{{.*}}(unaligned)98; GLOBAL: %gep.align16.offset1{{.*}}(unaligned)99; GLOBAL: %gep.align1.offset16{{.*}}(unaligned)100; GLOBAL: %gep.align16.offset16{{.*}}(aligned)101; POINT-NOT: %gep.align1.offset1{{.*}}(unaligned)102; POINT-NOT: %gep.align16.offset1{{.*}}(unaligned)103; POINT-NOT: %gep.align1.offset16{{.*}}(unaligned)104; POINT-NOT: %gep.align16.offset16{{.*}}(aligned)105 %gep.align1.offset1 = getelementptr inbounds i8, ptr addrspace(1) %dparam.align1, i32 1106 %gep.align16.offset1 = getelementptr inbounds i8, ptr addrspace(1) %dparam.align16, i32 1107 %gep.align1.offset16 = getelementptr inbounds i8, ptr addrspace(1) %dparam.align1, i32 16108 %gep.align16.offset16 = getelementptr inbounds i8, ptr addrspace(1) %dparam.align16, i32 16109 %load19 = load i8, ptr addrspace(1) %gep.align1.offset1, align 16110 %load20 = load i8, ptr addrspace(1) %gep.align16.offset1, align 16111 %load21 = load i8, ptr addrspace(1) %gep.align1.offset16, align 16112 %load22 = load i8, ptr addrspace(1) %gep.align16.offset16, align 16113 114; CHECK-NOT: %no_deref_return115; GLOBAL: %deref_return{{.*}}(unaligned)116; GLOBAL: %deref_and_aligned_return{{.*}}(aligned)117; POINT-NOT: %deref_return{{.*}}(unaligned)118; POINT-NOT: %deref_and_aligned_return{{.*}}(aligned)119 %no_deref_return = call ptr @foo()120 %deref_return = call dereferenceable(32) ptr @foo()121 %deref_and_aligned_return = call dereferenceable(32) align 16 ptr @foo()122 %load23 = load i32, ptr %no_deref_return123 %load24 = load i32, ptr %deref_return, align 16124 %load25 = load i32, ptr %deref_and_aligned_return, align 16125 126 ; Load from a dereferenceable and aligned load127; GLOBAL: %d4_unaligned_load{{.*}}(unaligned)128; GLOBAL: %d4_aligned_load{{.*}}(aligned)129; POINT-NOT: %d4_unaligned_load{{.*}}(unaligned)130; POINT-NOT: %d4_aligned_load{{.*}}(aligned)131 %d4_unaligned_load = load ptr, ptr @globali32ptr, !dereferenceable !0132 %d4_aligned_load = load ptr, ptr @globali32ptr, !dereferenceable !0, !align !{i64 16}133 %load26 = load i32, ptr %d4_unaligned_load, align 16134 %load27 = load i32, ptr %d4_aligned_load, align 16135 ret void136}137 138; Loads from aligned allocas139; CHECK-LABEL: 'alloca_aligned'140; CHECK: %alloca.align1{{.*}}(unaligned)141; CHECK: %alloca.align16{{.*}}(aligned)142define void @alloca_aligned() {143 %alloca.align1 = alloca i1, align 1144 %alloca.align16 = alloca i1, align 16145 call void @mayfree()146 %load17 = load i1, ptr %alloca.align1, align 16147 %load18 = load i1, ptr %alloca.align16, align 16148 ret void149}150 151; CHECK-LABEL: 'alloca_basic'152; CHECK: %alloca{{.*}}(aligned)153define void @alloca_basic() {154 %alloca = alloca i1155 call void @mayfree()156 %load2 = load i1, ptr %alloca157 ret void158}159 160; Load from empty array alloca161; CHECK-LABEL: 'alloca_empty'162; CHECK-NOT: %empty_alloca163define void @alloca_empty() {164 %empty_alloca = alloca i8, i64 0165 call void @mayfree()166 %empty_load = load i8, ptr %empty_alloca167 ret void168}169 170; Alloca with no explicit alignment is aligned to preferred alignment of171; the type (specified by datalayout string).172; CHECK-LABEL: 'alloca_perfalign'173; CHECK: %alloca.noalign{{.*}}(aligned)174define void @alloca_perfalign() {175 %alloca.noalign = alloca i32176 call void @mayfree()177 %load28 = load i32, ptr %alloca.noalign, align 8178 ret void179}180 181; CHECK-LABEL: 'global'182; CHECK: @globalptr.align1{{.*}}(unaligned)183; CHECK: @globalptr.align16{{.*}}(aligned)184; CHECK: @globalstr{{.*}}(aligned)185define void @global() {186 %load13 = load i8, ptr @globalptr.align1, align 16187 %load14 = load i8, ptr @globalptr.align16, align 16188 189 %load1 = load i8, ptr @globalstr190 ret void191}192 193; It's OK to overrun static array size as long as we stay within underlying194; object size195; CHECK-LABEL: 'global_allocationsize'196; CHECK: %within_allocation{{.*}}(aligned)197; CHECK-NOT: %outside_allocation198define void @global_allocationsize() {199 %within_allocation = getelementptr inbounds %struct.A, ptr @globalstruct, i64 0, i32 0, i64 10200 %load11 = load i8, ptr %within_allocation201 202 %outside_allocation = getelementptr inbounds %struct.A, ptr @globalstruct, i64 0, i32 1, i64 10203 %load12 = load i8, ptr %outside_allocation204 ret void205}206 207; Loads from byval arguments208; CHECK-LABEL: 'byval'209; CHECK: %i8_byval{{.*}}(aligned)210; CHECK-NOT: %bad_byval_cast211; CHECK: %byval_gep{{.*}}(aligned)212; CHECK: %A_byval{{.*}}(unaligned)213define void @byval(ptr byval(i8) %i8_byval,214 ptr byval(%struct.A) %A_byval) {215 call void @mayfree()216 load i8, ptr %i8_byval217 218 load i32, ptr %i8_byval219 220 %byval_gep = getelementptr inbounds %struct.A, ptr %A_byval, i64 0, i32 1, i64 2221 load i8, ptr %byval_gep222 load i32, ptr %A_byval223 224 ret void225}226 227; CHECK-LABEL: 'f_0'228; GLOBAL: %ptr = inttoptr i32 %val to ptr, !dereferenceable !0229; POINT-NOT: %ptr = inttoptr i32 %val to ptr, !dereferenceable !0230define i32 @f_0(i32 %val) {231 %ptr = inttoptr i32 %val to ptr, !dereferenceable !0232 call void @mayfree()233 %load29 = load i32, ptr %ptr, align 8234 ret i32 %load29235}236 237 238; The most basic case showing the difference between legacy global deref239; attribute semantics and the new point-in-time semantics.240; CHECK-LABEL: 'negative'241; GLOBAL: %p242; POINT-NOT: %p243define void @negative(ptr dereferenceable(8) %p) {244 call void @mayfree()245 %v = load i32, ptr %p246 ret void247}248 249; CHECK-LABEL: 'infer_func_attrs1'250; CHECK: %p251define void @infer_func_attrs1(ptr dereferenceable(8) %p) nofree nosync {252 call void @mayfree()253 %v = load i32, ptr %p254 ret void255}256 257; CHECK-LABEL: 'infer_func_attrs2'258; GLOBAL: %p259; POINT-NOT: %p260; FIXME: Can be inferred from attributes261define void @infer_func_attrs2(ptr dereferenceable(8) %p) readonly {262 call void @mayfree()263 %v = load i32, ptr %p264 ret void265}266 267; CHECK-LABEL: 'infer_noalias1'268; GLOBAL: %p269; POINT-NOT: %p270; FIXME: Can be inferred from attributes271define void @infer_noalias1(ptr dereferenceable(8) noalias nofree %p) {272 call void @mayfree()273 %v = load i32, ptr %p274 ret void275}276 277; CHECK-LABEL: 'infer_noalias2'278; GLOBAL: %p279; POINT-NOT: %p280; FIXME: Can be inferred from attributes281define void @infer_noalias2(ptr dereferenceable(8) noalias readonly %p) nosync {282 call void @mayfree()283 %v = load i32, ptr %p284 ret void285}286 287 288; Just check that we don't crash.289; CHECK-LABEL: 'opaque_type_crasher'290define void @opaque_type_crasher(ptr dereferenceable(16) %a, i1 %arg) {291entry:292 %ptr8 = getelementptr inbounds i8, ptr %a, i32 8293 br i1 %arg, label %if.then, label %if.end294 295if.then:296 %res = load i32, ptr %ptr8, align 4297 br label %if.end298 299if.end:300 ret void301}302 303declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)304declare ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32)305 306declare ptr addrspace(1) @func1(ptr addrspace(1) returned) nounwind argmemonly307 308; Can free any object accessible in memory309declare void @mayfree()310 311!0 = !{i64 4}312!1 = !{i64 2}313!2 = !{}314