llvm.org GIT mirror llvm / c2f24d9
Implement strip.invariant.group Summary: This patch introduce new intrinsic - strip.invariant.group that was described in the RFC: Devirtualization v2 Reviewers: rsmith, hfinkel, nlopes, sanjoy, amharc, kuhar Subscribers: arsenm, nhaehnle, JDevlieghere, hiraditya, xbolva00, llvm-commits Differential Revision: https://reviews.llvm.org/D47103 Co-authored-by: Krzysztof Pszeniczny <krzysztof.pszeniczny@gmail.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336073 91177308-0d34-0410-b5e6-96231b3b80d8 Piotr Padlewski 1 year, 2 months ago
23 changed file(s) with 465 addition(s) and 217 deletion(s). Raw diff Collapse all Expand all
1334913349 """""""""
1335013350
1335113351 The '``llvm.launder.invariant.group``' intrinsic can be used when an invariant
13352 established by invariant.group metadata no longer holds, to obtain a new pointer
13353 value that does not carry the invariant information. It is an experimental
13354 intrinsic, which means that its semantics might change in the future.
13355
13356
13357 Arguments:
13358 """"""""""
13359
13360 The ``llvm.launder.invariant.group`` takes only one argument, which is
13361 the pointer to the memory for which the ``invariant.group`` no longer holds.
13352 established by ``invariant.group`` metadata no longer holds, to obtain a new
13353 pointer value that carries fresh invariant group information. It is an
13354 experimental intrinsic, which means that its semantics might change in the
13355 future.
13356
13357
13358 Arguments:
13359 """"""""""
13360
13361 The ``llvm.launder.invariant.group`` takes only one argument, which is a pointer
13362 to the memory.
1336213363
1336313364 Semantics:
1336413365 """"""""""
1336613367 Returns another pointer that aliases its argument but which is considered different
1336713368 for the purposes of ``load``/``store`` ``invariant.group`` metadata.
1336813369 It does not read any accessible memory and the execution can be speculated.
13370
13371 '``llvm.strip.invariant.group``' Intrinsic
13372 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13373
13374 Syntax:
13375 """""""
13376 This is an overloaded intrinsic. The memory object can belong to any address
13377 space. The returned pointer must belong to the same address space as the
13378 argument.
13379
13380 ::
13381
13382 declare i8* @llvm.strip.invariant.group.p0i8(i8* )
13383
13384 Overview:
13385 """""""""
13386
13387 The '``llvm.strip.invariant.group``' intrinsic can be used when an invariant
13388 established by ``invariant.group`` metadata no longer holds, to obtain a new pointer
13389 value that does not carry the invariant information. It is an experimental
13390 intrinsic, which means that its semantics might change in the future.
13391
13392
13393 Arguments:
13394 """"""""""
13395
13396 The ``llvm.strip.invariant.group`` takes only one argument, which is a pointer
13397 to the memory.
13398
13399 Semantics:
13400 """"""""""
13401
13402 Returns another pointer that aliases its argument but which has no associated
13403 ``invariant.group`` metadata.
13404 It does not read any memory and can be speculated.
13405
13406
1336913407
1337013408 .. _constrainedfp:
1337113409
20212021 Value *CreateLaunderInvariantGroup(Value *Ptr) {
20222022 assert(isa(Ptr->getType()) &&
20232023 "launder.invariant.group only applies to pointers.");
2024 // FIXME: we could potentially avoid casts to/from i8*.
20242025 auto *PtrType = Ptr->getType();
20252026 auto *Int8PtrTy = getInt8PtrTy(PtrType->getPointerAddressSpace());
20262027 if (PtrType != Int8PtrTy)
20352036 "LaunderInvariantGroup should take and return the same type");
20362037
20372038 CallInst *Fn = CreateCall(FnLaunderInvariantGroup, {Ptr});
2039
2040 if (PtrType != Int8PtrTy)
2041 return CreateBitCast(Fn, PtrType);
2042 return Fn;
2043 }
2044
2045 /// \brief Create a strip.invariant.group intrinsic call. If Ptr type is
2046 /// different from pointer to i8, it's casted to pointer to i8 in the same
2047 /// address space before call and casted back to Ptr type after call.
2048 Value *CreateStripInvariantGroup(Value *Ptr) {
2049 assert(isa(Ptr->getType()) &&
2050 "strip.invariant.group only applies to pointers.");
2051
2052 // FIXME: we could potentially avoid casts to/from i8*.
2053 auto *PtrType = Ptr->getType();
2054 auto *Int8PtrTy = getInt8PtrTy(PtrType->getPointerAddressSpace());
2055 if (PtrType != Int8PtrTy)
2056 Ptr = CreateBitCast(Ptr, Int8PtrTy);
2057 Module *M = BB->getParent()->getParent();
2058 Function *FnStripInvariantGroup = Intrinsic::getDeclaration(
2059 M, Intrinsic::strip_invariant_group, {Int8PtrTy});
2060
2061 assert(FnStripInvariantGroup->getReturnType() == Int8PtrTy &&
2062 FnStripInvariantGroup->getFunctionType()->getParamType(0) ==
2063 Int8PtrTy &&
2064 "StripInvariantGroup should take and return the same type");
2065
2066 CallInst *Fn = CreateCall(FnStripInvariantGroup, {Ptr});
20382067
20392068 if (PtrType != Int8PtrTy)
20402069 return CreateBitCast(Fn, PtrType);
726726 def int_launder_invariant_group : Intrinsic<[llvm_anyptr_ty],
727727 [LLVMMatchType<0>],
728728 [IntrInaccessibleMemOnly, IntrSpeculatable]>;
729
730
731 def int_strip_invariant_group : Intrinsic<[llvm_anyptr_ty],
732 [LLVMMatchType<0>],
733 [IntrSpeculatable, IntrNoMem]>;
729734
730735 //===------------------------ Stackmap Intrinsics -------------------------===//
731736 //
430430 const GEPOperator *GEPOp = dyn_cast(Op);
431431 if (!GEPOp) {
432432 if (auto CS = ImmutableCallSite(V)) {
433 // Note: getArgumentAliasingToReturnedPointer keeps it in sync with
434 // CaptureTracking, which is needed for correctness. This is because
435 // some intrinsics like launder.invariant.group returns pointers that
436 // are aliasing it's argument, which is known to CaptureTracking.
437 // If AliasAnalysis does not use the same information, it could assume
438 // that pointer returned from launder does not alias it's argument
439 // because launder could not return it if the pointer was not captured.
433 // CaptureTracking can know about special capturing properties of some
434 // intrinsics like launder.invariant.group, that can't be expressed with
435 // the attributes, but have properties like returning aliasing pointer.
436 // Because some analysis may assume that nocaptured pointer is not
437 // returned from some special intrinsic (because function would have to
438 // be marked with returns attribute), it is crucial to use this function
439 // because it should be in sync with CaptureTracking. Not using it may
440 // cause weird miscompilations where 2 aliasing pointers are assumed to
441 // noalias.
440442 if (auto *RP = getArgumentAliasingToReturnedPointer(CS)) {
441443 V = RP;
442444 continue;
13921392 case Intrinsic::fmuladd:
13931393 case Intrinsic::copysign:
13941394 case Intrinsic::launder_invariant_group:
1395 case Intrinsic::strip_invariant_group:
13951396 case Intrinsic::round:
13961397 case Intrinsic::masked_load:
13971398 case Intrinsic::sadd_with_overflow:
15951596 return Constant::getNullValue(Ty);
15961597 if (IntrinsicID == Intrinsic::bswap ||
15971598 IntrinsicID == Intrinsic::bitreverse ||
1598 IntrinsicID == Intrinsic::launder_invariant_group)
1599 IntrinsicID == Intrinsic::launder_invariant_group ||
1600 IntrinsicID == Intrinsic::strip_invariant_group)
15991601 return Operands[0];
16001602 }
16011603
16021604 if (isa(Operands[0]) &&
16031605 Operands[0]->getType()->getPointerAddressSpace() == 0) {
1604 // launder(null) == null iff in addrspace 0
1605 if (IntrinsicID == Intrinsic::launder_invariant_group)
1606 // launder(null) == null == strip(null) iff in addrspace 0
1607 if (IntrinsicID == Intrinsic::launder_invariant_group ||
1608 IntrinsicID == Intrinsic::strip_invariant_group)
16061609 return Operands[0];
16071610 return nullptr;
16081611 }
34033403 }
34043404
34053405 bool llvm::isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
3406 ImmutableCallSite CS) {
3407 return CS.getIntrinsicID() == Intrinsic::launder_invariant_group;
3406 ImmutableCallSite CS) {
3407 return CS.getIntrinsicID() == Intrinsic::launder_invariant_group ||
3408 CS.getIntrinsicID() == Intrinsic::strip_invariant_group;
34083409 }
34093410
34103411 /// \p PN defines a loop-variant pointer to an object. Check if the
34533454 return V;
34543455 } else {
34553456 if (auto CS = CallSite(V)) {
3456 // Note: getArgumentAliasingToReturnedPointer keeps it in sync with
3457 // CaptureTracking, which is needed for correctness. This is because
3458 // some intrinsics like launder.invariant.group returns pointers that
3459 // are aliasing it's argument, which is known to CaptureTracking.
3460 // If AliasAnalysis does not use the same information, it could assume
3461 // that pointer returned from launder does not alias it's argument
3462 // because launder could not return it if the pointer was not captured.
3457 // CaptureTracking can know about special capturing properties of some
3458 // intrinsics like launder.invariant.group, that can't be expressed with
3459 // the attributes, but have properties like returning aliasing pointer.
3460 // Because some analysis may assume that nocaptured pointer is not
3461 // returned from some special intrinsic (because function would have to
3462 // be marked with returns attribute), it is crucial to use this function
3463 // because it should be in sync with CaptureTracking. Not using it may
3464 // cause weird miscompilations where 2 aliasing pointers are assumed to
3465 // noalias.
34633466 if (auto *RP = getArgumentAliasingToReturnedPointer(CS)) {
34643467 V = RP;
34653468 continue;
17011701 return true;
17021702 }
17031703 case Intrinsic::launder_invariant_group:
1704 case Intrinsic::strip_invariant_group:
17041705 II->replaceAllUsesWith(II->getArgOperand(0));
17051706 II->eraseFromParent();
17061707 return true;
14361436 return true;
14371437 }
14381438 case Intrinsic::launder_invariant_group:
1439 case Intrinsic::strip_invariant_group:
14391440 case Intrinsic::expect: {
14401441 unsigned ResultReg = getRegForValue(II->getArgOperand(0));
14411442 if (!ResultReg)
57675767 case Intrinsic::annotation:
57685768 case Intrinsic::ptr_annotation:
57695769 case Intrinsic::launder_invariant_group:
5770 case Intrinsic::strip_invariant_group:
57705771 // Drop the intrinsic, but forward the value
57715772 setValue(&I, getValue(I.getOperand(0)));
57725773 return nullptr;
520520 // but it can't be marked with returned attribute, that's why it needs
521521 // special case.
522522 if (StripKind == PSK_ZeroIndicesAndAliasesAndInvariantGroups &&
523 CS.getIntrinsicID() == Intrinsic::launder_invariant_group) {
523 (CS.getIntrinsicID() == Intrinsic::launder_invariant_group ||
524 CS.getIntrinsicID() == Intrinsic::strip_invariant_group)) {
524525 V = CS.getArgOperand(0);
525526 continue;
526527 }
456456 case Intrinsic::invariant_start:
457457 case Intrinsic::invariant_end:
458458 case Intrinsic::launder_invariant_group:
459 case Intrinsic::strip_invariant_group:
459460 case Intrinsic::objectsize:
460461 return true;
461462 default:
881882 case Intrinsic::invariant_start:
882883 case Intrinsic::invariant_end:
883884 case Intrinsic::launder_invariant_group:
885 case Intrinsic::strip_invariant_group:
884886 Intr->eraseFromParent();
885887 // FIXME: I think the invariant marker should still theoretically apply,
886888 // but the intrinsics need to be changed to accept pointers with any
0 ; RUN: opt -S -instsimplify -instcombine < %s | FileCheck %s
11
2 ; CHECK-LABEL: define void @checkNonnull()
3 define void @checkNonnull() {
2 ; CHECK-LABEL: define void @checkNonnullLaunder()
3 define void @checkNonnullLaunder() {
44 ; CHECK: %p = call i8* @llvm.launder.invariant.group.p0i8(i8* nonnull %0)
55 ; CHECK: %p2 = call i8* @llvm.launder.invariant.group.p0i8(i8* nonnull %p)
66 ; CHECK: call void @use(i8* nonnull %p2)
1414 ret void
1515 }
1616
17 ; CHECK-LABEL: define void @checkNonnullStrip()
18 define void @checkNonnullStrip() {
19 ; CHECK: %p = call i8* @llvm.strip.invariant.group.p0i8(i8* nonnull %0)
20 ; CHECK: %p2 = call i8* @llvm.strip.invariant.group.p0i8(i8* nonnull %p)
21 ; CHECK: call void @use(i8* nonnull %p2)
22 entry:
23 %0 = alloca i8, align 8
24
25 %p = call i8* @llvm.strip.invariant.group.p0i8(i8* %0)
26 %p2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
27 call void @use(i8* %p2)
28
29 ret void
30 }
31
1732 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
33 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
34
1835 declare void @use(i8*)
4040
4141 declare i8* @llvm.launder.invariant.group(i8*)
4242
43 define i8* @barrier(i8* %p) {
43 define i8* @launder(i8* %p) {
4444 %q = call i8* @llvm.launder.invariant.group(i8* %p)
4545 ret i8* %q
4646 }
47
48 declare i8* @llvm.strip.invariant.group(i8*)
49
50 define i8* @strip(i8* %p) {
51 %q = call i8* @llvm.strip.invariant.group(i8* %p)
52 ret i8* %q
53 }
54
4755
4856 ; sideeffect
4957
0 ; RUN: opt -S -early-cse < %s | FileCheck %s
1 ; RUN: opt -S -gvn < %s | FileCheck %s
2 ; RUN: opt -S -newgvn < %s | FileCheck %s
3 ; RUN: opt -S -O3 < %s | FileCheck %s
4
5 ; These tests checks if passes with CSE functionality can do CSE on
6 ; launder.invariant.group, that is prohibited if there is a memory clobber
7 ; between barriers call.
8
9 ; CHECK-LABEL: define i8 @optimizable()
10 define i8 @optimizable() {
11 entry:
12 %ptr = alloca i8
13 store i8 42, i8* %ptr, !invariant.group !0
14 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
15 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
16 ; FIXME: This one could be CSE
17 ; CHECK: call i8* @llvm.launder.invariant.group
18 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
19 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
20 call void @clobber(i8* %ptr)
21
22 ; CHECK: call void @use(i8* {{.*}}%ptr2)
23 call void @use(i8* %ptr2)
24 ; CHECK: call void @use(i8* {{.*}}%ptr3)
25 call void @use(i8* %ptr3)
26 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
27 %v = load i8, i8* %ptr3, !invariant.group !0
28
29 ret i8 %v
30 }
31
32 ; CHECK-LABEL: define i8 @unoptimizable()
33 define i8 @unoptimizable() {
34 entry:
35 %ptr = alloca i8
36 store i8 42, i8* %ptr, !invariant.group !0
37 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
38 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
39 call void @clobber(i8* %ptr)
40 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
41 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
42 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
43 call void @clobber(i8* %ptr)
44 ; CHECK: call void @use(i8* {{.*}}%ptr2)
45 call void @use(i8* %ptr2)
46 ; CHECK: call void @use(i8* {{.*}}%ptr3)
47 call void @use(i8* %ptr3)
48 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
49 %v = load i8, i8* %ptr3, !invariant.group !0
50
51 ret i8 %v
52 }
53
54 ; CHECK-LABEL: define i8 @unoptimizable2()
55 define i8 @unoptimizable2() {
56 %ptr = alloca i8
57 store i8 42, i8* %ptr, !invariant.group !0
58 ; CHECK: call i8* @llvm.launder.invariant.group
59 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
60 store i8 43, i8* %ptr
61 ; CHECK: call i8* @llvm.launder.invariant.group
62 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
63 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
64 call void @clobber(i8* %ptr)
65 ; CHECK: call void @use(i8* {{.*}}%ptr2)
66 call void @use(i8* %ptr2)
67 ; CHECK: call void @use(i8* {{.*}}%ptr3)
68 call void @use(i8* %ptr3)
69 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
70 %v = load i8, i8* %ptr3, !invariant.group !0
71 ret i8 %v
72 }
73
74 ; This test check if optimizer is not proving equality based on mustalias
75 ; CHECK-LABEL: define void @dontProveEquality(i8* %a)
76 define void @dontProveEquality(i8* %a) {
77 %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
78 %r = icmp eq i8* %b, %a
79 ; CHECK: call void @useBool(i1 %r)
80 call void @useBool(i1 %r)
81
82 %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
83 %r2 = icmp eq i8* %b2, %a
84 ; CHECK: call void @useBool(i1 %r2)
85 call void @useBool(i1 %r2)
86
87 ret void
88 }
89
90 declare void @use(i8* readonly)
91 declare void @useBool(i1)
92
93 declare void @clobber(i8*)
94 ; CHECK: Function Attrs: inaccessiblememonly nounwind speculatable{{$}}
95 ; CHECK-NEXT: declare i8* @llvm.launder.invariant.group.p0i8(i8*)
96 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
97
98 ; CHECK: Function Attrs: nounwind readnone speculatable{{$}}
99 ; CHECK-NEXT: declare i8* @llvm.strip.invariant.group.p0i8(i8*)
100 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
101
102
103 !0 = !{}
+0
-94
test/Other/launder.invariant.group.ll less more
None ; RUN: opt -S -early-cse < %s | FileCheck %s
1 ; RUN: opt -S -gvn < %s | FileCheck %s
2 ; RUN: opt -S -newgvn < %s | FileCheck %s
3 ; RUN: opt -S -O3 < %s | FileCheck %s
4
5 ; These tests checks if passes with CSE functionality can do CSE on
6 ; launder.invariant.group, that is prohibited if there is a memory clobber
7 ; between barriers call.
8
9 ; CHECK-LABEL: define i8 @optimizable()
10 define i8 @optimizable() {
11 entry:
12 %ptr = alloca i8
13 store i8 42, i8* %ptr, !invariant.group !0
14 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
15 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
16 ; FIXME: This one could be CSE
17 ; CHECK: call i8* @llvm.launder.invariant.group
18 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
19 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
20 call void @clobber(i8* %ptr)
21
22 ; CHECK: call void @use(i8* {{.*}}%ptr2)
23 call void @use(i8* %ptr2)
24 ; CHECK: call void @use(i8* {{.*}}%ptr3)
25 call void @use(i8* %ptr3)
26 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
27 %v = load i8, i8* %ptr3, !invariant.group !0
28
29 ret i8 %v
30 }
31
32 ; CHECK-LABEL: define i8 @unoptimizable()
33 define i8 @unoptimizable() {
34 entry:
35 %ptr = alloca i8
36 store i8 42, i8* %ptr, !invariant.group !0
37 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
38 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
39 call void @clobber(i8* %ptr)
40 ; CHECK: call i8* @llvm.launder.invariant.group.p0i8
41 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
42 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
43 call void @clobber(i8* %ptr)
44 ; CHECK: call void @use(i8* {{.*}}%ptr2)
45 call void @use(i8* %ptr2)
46 ; CHECK: call void @use(i8* {{.*}}%ptr3)
47 call void @use(i8* %ptr3)
48 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
49 %v = load i8, i8* %ptr3, !invariant.group !0
50
51 ret i8 %v
52 }
53
54 ; CHECK-LABEL: define i8 @unoptimizable2()
55 define i8 @unoptimizable2() {
56 %ptr = alloca i8
57 store i8 42, i8* %ptr, !invariant.group !0
58 ; CHECK: call i8* @llvm.launder.invariant.group
59 %ptr2 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
60 store i8 43, i8* %ptr
61 ; CHECK: call i8* @llvm.launder.invariant.group
62 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr)
63 ; CHECK: call void @clobber(i8* {{.*}}%ptr)
64 call void @clobber(i8* %ptr)
65 ; CHECK: call void @use(i8* {{.*}}%ptr2)
66 call void @use(i8* %ptr2)
67 ; CHECK: call void @use(i8* {{.*}}%ptr3)
68 call void @use(i8* %ptr3)
69 ; CHECK: load i8, i8* %ptr3, {{.*}}!invariant.group
70 %v = load i8, i8* %ptr3, !invariant.group !0
71 ret i8 %v
72 }
73
74 ; This test check if optimizer is not proving equality based on mustalias
75 ; CHECK-LABEL: define void @dontProveEquality(i8* %a)
76 define void @dontProveEquality(i8* %a) {
77 %b = call i8* @llvm.launder.invariant.group.p0i8(i8* %a)
78 %r = icmp eq i8* %b, %a
79 ;CHECK: call void @useBool(i1 %r)
80 call void @useBool(i1 %r)
81 ret void
82 }
83
84 declare void @use(i8* readonly)
85 declare void @useBool(i1)
86
87 declare void @clobber(i8*)
88 ; CHECK: Function Attrs: inaccessiblememonly nounwind speculatable{{$}}
89 ; CHECK-NEXT: declare i8* @llvm.launder.invariant.group.p0i8(i8*)
90 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
91
92 !0 = !{}
93
66 enter:
77 ; CHECK-NOT: !invariant.group
88 ; CHECK-NOT: @llvm.launder.invariant.group.p0i8(
9 ; CHECK: %val = load i8, i8* @tmp, !tbaa
10 %val = load i8, i8* @tmp, !invariant.group !0, !tbaa !{!1, !1, i64 0}
9 ; CHECK: %val = load i8, i8* @tmp{{$}}
10 %val = load i8, i8* @tmp, !invariant.group !0
1111 %ptr = call i8* @llvm.launder.invariant.group.p0i8(i8* @tmp)
1212
1313 ; CHECK: store i8 42, i8* @tmp{{$}}
1717 }
1818 ; CHECK-LABEL: }
1919
20 ; CHECK-LABEL: define void @foo2() {
21 define void @foo2() {
22 enter:
23 ; CHECK-NOT: !invariant.group
24 ; CHECK-NOT: @llvm.strip.invariant.group.p0i8(
25 ; CHECK: %val = load i8, i8* @tmp{{$}}
26 %val = load i8, i8* @tmp, !invariant.group !0
27 %ptr = call i8* @llvm.strip.invariant.group.p0i8(i8* @tmp)
28
29 ; CHECK: store i8 42, i8* @tmp{{$}}
30 store i8 42, i8* %ptr, !invariant.group !0
31
32 ret void
33 }
34 ; CHECK-LABEL: }
35
36
2037 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
21
38 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
2239 !0 = !{}
23 !1 = !{!"x", !0}
2626 ret void
2727 }
2828
29 ; CHECK-LABEL: void @skip3Barriers(i8* %ptr)
30 define void @skip3Barriers(i8* %ptr) {
31 ; CHECK-NOT: store i8 42
32 store i8 42, i8* %ptr
33 ; CHECK: %ptr2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr)
34 %ptr2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr)
35 ; CHECK-NOT: store i8 43
36 store i8 43, i8* %ptr2
37 %ptr3 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr2)
38 %ptr4 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr3)
39
40 ; CHECK: store i8 44
41 store i8 44, i8* %ptr4
42 ret void
43 }
44
45 ; CHECK-LABEL: void @skip4Barriers(i8* %ptr)
46 define void @skip4Barriers(i8* %ptr) {
47 ; CHECK-NOT: store i8 42
48 store i8 42, i8* %ptr
49 ; CHECK: %ptr2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr)
50 %ptr2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr)
51 ; CHECK-NOT: store i8 43
52 store i8 43, i8* %ptr2
53 %ptr3 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr2)
54 %ptr4 = call i8* @llvm.strip.invariant.group.p0i8(i8* %ptr3)
55 %ptr5 = call i8* @llvm.launder.invariant.group.p0i8(i8* %ptr3)
56
57 ; CHECK: store i8 44
58 store i8 44, i8* %ptr5
59 ret void
60 }
61
62
2963 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
64 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
236236 ret void
237237 }
238238
239 ; CHECK: @nocaptureStrip(i8* nocapture %p)
240 define void @nocaptureStrip(i8* %p) {
241 entry:
242 %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
243 store i8 42, i8* %b
244 ret void
245 }
246
247 @g3 = global i8* null
248 ; CHECK: define void @captureStrip(i8* %p)
249 define void @captureStrip(i8* %p) {
250 %b = call i8* @llvm.strip.invariant.group.p0i8(i8* %p)
251 store i8* %b, i8** @g3
252 ret void
253 }
254
239255 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
256 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
5050 ret i8 %b
5151 }
5252
53 ; CHECK-LABEL: define i1 @proveEqualityForStrip(
54 define i1 @proveEqualityForStrip(i8* %a) {
55 ; FIXME: The first call could be also removed by GVN. Right now
56 ; DCE removes it. The second call is CSE'd with the first one.
57 ; CHECK: %b1 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
58 %b1 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
59 ; CHECK-NOT: llvm.strip.invariant.group
60 %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
61 %r = icmp eq i8* %b1, %b2
62 ; CHECK: ret i1 true
63 ret i1 %r
64 }
5365 ; CHECK-LABEL: define i8 @unoptimizable1() {
5466 define i8 @unoptimizable1() {
5567 entry:
436448 declare void @fooBit(i1*, i1)
437449
438450 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
439
440 ; Function Attrs: nounwind
441 declare void @llvm.assume(i1 %cmp.vtables) #0
442
443
444 attributes #0 = { nounwind }
451 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
452
453
454 declare void @llvm.assume(i1 %cmp.vtables)
455
456
445457 !0 = !{}
+0
-79
test/Transforms/GlobalOpt/invariant.group.barrier.ll less more
None ; RUN: opt -S -globalopt < %s | FileCheck %s
1
2 ; This test is hint, what could globalOpt optimize and what it can't
3 ; FIXME: @tmp and @tmp2 can be safely set to 42
4 ; CHECK: @tmp = local_unnamed_addr global i32 0
5 ; CHECK: @tmp2 = local_unnamed_addr global i32 0
6 ; CHECK: @tmp3 = global i32 0
7
8 @tmp = global i32 0
9 @tmp2 = global i32 0
10 @tmp3 = global i32 0
11 @ptrToTmp3 = global i32* null
12
13 @llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
14
15 define i32 @TheAnswerToLifeTheUniverseAndEverything() {
16 ret i32 42
17 }
18
19 define void @_GLOBAL__I_a() {
20 enter:
21 call void @_optimizable()
22 call void @_not_optimizable()
23 ret void
24 }
25
26 define void @_optimizable() {
27 enter:
28 %valptr = alloca i32
29
30 %val = call i32 @TheAnswerToLifeTheUniverseAndEverything()
31 store i32 %val, i32* @tmp
32 store i32 %val, i32* %valptr
33
34 %0 = bitcast i32* %valptr to i8*
35 %barr = call i8* @llvm.launder.invariant.group(i8* %0)
36 %1 = bitcast i8* %barr to i32*
37
38 %val2 = load i32, i32* %1
39 store i32 %val2, i32* @tmp2
40 ret void
41 }
42
43 ; We can't step through launder.invariant.group here, because that would change
44 ; this load in @usage_of_globals()
45 ; val = load i32, i32* %ptrVal, !invariant.group !0
46 ; into
47 ; %val = load i32, i32* @tmp3, !invariant.group !0
48 ; and then we could assume that %val and %val2 to be the same, which coud be
49 ; false, because @changeTmp3ValAndCallBarrierInside() may change the value
50 ; of @tmp3.
51 define void @_not_optimizable() {
52 enter:
53 store i32 13, i32* @tmp3, !invariant.group !0
54
55 %0 = bitcast i32* @tmp3 to i8*
56 %barr = call i8* @llvm.launder.invariant.group(i8* %0)
57 %1 = bitcast i8* %barr to i32*
58
59 store i32* %1, i32** @ptrToTmp3
60 store i32 42, i32* %1, !invariant.group !0
61
62 ret void
63 }
64 define void @usage_of_globals() {
65 entry:
66 %ptrVal = load i32*, i32** @ptrToTmp3
67 %val = load i32, i32* %ptrVal, !invariant.group !0
68
69 call void @changeTmp3ValAndCallBarrierInside()
70 %val2 = load i32, i32* @tmp3, !invariant.group !0
71 ret void;
72 }
73
74 declare void @changeTmp3ValAndCallBarrierInside()
75
76 declare i8* @llvm.launder.invariant.group(i8*)
77
78 !0 = !{}
0 ; RUN: opt -S -globalopt < %s | FileCheck %s
1
2 ; This test is hint, what could globalOpt optimize and what it can't
3 ; FIXME: @tmp and @tmp2 can be safely set to 42
4 ; CHECK: @tmp = local_unnamed_addr global i32 0
5 ; CHECK: @tmp2 = local_unnamed_addr global i32 0
6 ; CHECK: @tmp3 = global i32 0
7
8 @tmp = global i32 0
9 @tmp2 = global i32 0
10 @tmp3 = global i32 0
11 @ptrToTmp3 = global i32* null
12
13 @llvm.global_ctors = appending global [1 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }]
14
15 define i32 @TheAnswerToLifeTheUniverseAndEverything() {
16 ret i32 42
17 }
18
19 define void @_GLOBAL__I_a() {
20 enter:
21 call void @_optimizable()
22 call void @_not_optimizable()
23 ret void
24 }
25
26 define void @_optimizable() {
27 enter:
28 %valptr = alloca i32
29
30 %val = call i32 @TheAnswerToLifeTheUniverseAndEverything()
31 store i32 %val, i32* @tmp
32 store i32 %val, i32* %valptr
33
34 %0 = bitcast i32* %valptr to i8*
35 %barr = call i8* @llvm.launder.invariant.group(i8* %0)
36 %1 = bitcast i8* %barr to i32*
37
38 %val2 = load i32, i32* %1
39 store i32 %val2, i32* @tmp2
40 ret void
41 }
42
43 ; We can't step through launder.invariant.group here, because that would change
44 ; this load in @usage_of_globals()
45 ; val = load i32, i32* %ptrVal, !invariant.group !0
46 ; into
47 ; %val = load i32, i32* @tmp3, !invariant.group !0
48 ; and then we could assume that %val and %val2 to be the same, which coud be
49 ; false, because @changeTmp3ValAndCallBarrierInside() may change the value
50 ; of @tmp3.
51 define void @_not_optimizable() {
52 enter:
53 store i32 13, i32* @tmp3, !invariant.group !0
54
55 %0 = bitcast i32* @tmp3 to i8*
56 %barr = call i8* @llvm.launder.invariant.group(i8* %0)
57 %1 = bitcast i8* %barr to i32*
58
59 store i32* %1, i32** @ptrToTmp3
60 store i32 42, i32* %1, !invariant.group !0
61
62 ret void
63 }
64 define void @usage_of_globals() {
65 entry:
66 %ptrVal = load i32*, i32** @ptrToTmp3
67 %val = load i32, i32* %ptrVal, !invariant.group !0
68
69 call void @changeTmp3ValAndCallBarrierInside()
70 %val2 = load i32, i32* @tmp3, !invariant.group !0
71 ret void;
72 }
73
74 declare void @changeTmp3ValAndCallBarrierInside()
75
76 declare i8* @llvm.launder.invariant.group(i8*)
77
78 !0 = !{}
0 ; RUN: opt -instcombine -S < %s | FileCheck %s
1
12
23 ; CHECK-LABEL: define i8* @simplifyNullLaunder()
34 define i8* @simplifyNullLaunder() {
2829 ret i8 addrspace(42)* %b2
2930 }
3031
31
3232 declare i8* @llvm.launder.invariant.group.p0i8(i8*)
3333 declare i8 addrspace(42)* @llvm.launder.invariant.group.p42i8(i8 addrspace(42)*)
34
35
36 ; CHECK-LABEL: define i8* @simplifyNullStrip()
37 define i8* @simplifyNullStrip() {
38 ; CHECK-NEXT: ret i8* null
39 %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* null)
40 ret i8* %b2
41 }
42
43 ; CHECK-LABEL: define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace()
44 define i8 addrspace(42)* @dontsimplifyNullStripForDifferentAddrspace() {
45 ; CHECK: %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* null)
46 ; CHECK: ret i8 addrspace(42)* %b2
47 %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* null)
48 ret i8 addrspace(42)* %b2
49 }
50
51 ; CHECK-LABEL: define i8* @simplifyUndefStrip()
52 define i8* @simplifyUndefStrip() {
53 ; CHECK-NEXT: ret i8* undef
54 %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* undef)
55 ret i8* %b2
56 }
57
58 ; CHECK-LABEL: define i8 addrspace(42)* @simplifyUndefStrip2()
59 define i8 addrspace(42)* @simplifyUndefStrip2() {
60 ; CHECK-NEXT: ret i8 addrspace(42)* undef
61 %b2 = call i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)* undef)
62 ret i8 addrspace(42)* %b2
63 }
64
65 declare i8* @llvm.strip.invariant.group.p0i8(i8*)
66 declare i8 addrspace(42)* @llvm.strip.invariant.group.p42i8(i8 addrspace(42)*)
67
4949
5050 ; CHECK: ret i8 42
5151 ret i8 %b
52 }
53
54 ; CHECK-LABEL: define i1 @proveEqualityForStrip(
55 define i1 @proveEqualityForStrip(i8* %a) {
56 ; FIXME: The first call could be also removed by GVN. Right now
57 ; DCE removes it. The second call is CSE'd with the first one.
58 ; CHECK: %b1 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
59 %b1 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
60 ; CHECK-NOT: llvm.strip.invariant.group
61 %b2 = call i8* @llvm.strip.invariant.group.p0i8(i8* %a)
62 %r = icmp eq i8* %b1, %b2
63 ; CHECK: ret i1 true
64 ret i1 %r
5265 }
5366
5467 ; CHECK-LABEL: define i8 @unoptimizable1() {