From: Artur Pilipenko Date: Mon, 2 Nov 2015 17:53:51 +0000 (+0000) Subject: Preserve load alignment and dereferenceable metadata during some transformations X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=bf7f89f1326c4c8c00932d15d42d3bd42027b981;p=oota-llvm.git Preserve load alignment and dereferenceable metadata during some transformations Reviewed By: hfinkel Differential Revision: http://reviews.llvm.org/D13953 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251809 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 26302109ff0..8805cec1471 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -964,6 +964,8 @@ public: static MDNode *getMostGenericFPMath(MDNode *A, MDNode *B); static MDNode *getMostGenericRange(MDNode *A, MDNode *B); static MDNode *getMostGenericAliasScope(MDNode *A, MDNode *B); + static MDNode *getMostGenericAlignmentOrDereferenceable(MDNode *A, MDNode *B); + }; /// \brief Tuple of metadata. diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index 7d8c3523743..80f18daa79b 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -953,6 +953,17 @@ MDNode *MDNode::getMostGenericRange(MDNode *A, MDNode *B) { return MDNode::get(A->getContext(), MDs); } +MDNode *MDNode::getMostGenericAlignmentOrDereferenceable(MDNode *A, MDNode *B) { + if (!A || !B) + return nullptr; + + ConstantInt *AVal = mdconst::extract(A->getOperand(0)); + ConstantInt *BVal = mdconst::extract(B->getOperand(0)); + if (AVal->getZExtValue() < BVal->getZExtValue()) + return A; + return B; +} + //===----------------------------------------------------------------------===// // NamedMDNode implementation. // diff --git a/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 4fba7f95797..933849f460b 100644 --- a/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -367,7 +367,13 @@ static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewT MDB.createRange(NonNullInt, NullInt)); } break; - + case LLVMContext::MD_align: + case LLVMContext::MD_dereferenceable: + case LLVMContext::MD_dereferenceable_or_null: + // These only directly apply if the new type is also a pointer. + if (NewTy->isPointerTy()) + NewLoad->setMetadata(ID, N); + break; case LLVMContext::MD_range: // FIXME: It would be nice to propagate this in some way, but the type // conversions make it hard. If the new type is a pointer, we could @@ -418,6 +424,9 @@ static StoreInst *combineStoreToNewValue(InstCombiner &IC, StoreInst &SI, Value case LLVMContext::MD_invariant_load: case LLVMContext::MD_nonnull: case LLVMContext::MD_range: + case LLVMContext::MD_align: + case LLVMContext::MD_dereferenceable: + case LLVMContext::MD_dereferenceable_or_null: // These don't apply for stores. break; } @@ -755,10 +764,12 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { DefMaxInstsToScan, AA, &AATags)) { if (LoadInst *NLI = dyn_cast(AvailableVal)) { unsigned KnownIDs[] = { - LLVMContext::MD_tbaa, LLVMContext::MD_alias_scope, - LLVMContext::MD_noalias, LLVMContext::MD_range, - LLVMContext::MD_invariant_load, LLVMContext::MD_nonnull, - LLVMContext::MD_invariant_group}; + LLVMContext::MD_tbaa, LLVMContext::MD_alias_scope, + LLVMContext::MD_noalias, LLVMContext::MD_range, + LLVMContext::MD_invariant_load, LLVMContext::MD_nonnull, + LLVMContext::MD_invariant_group, LLVMContext::MD_align, + LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null}; combineMetadata(NLI, &LI, KnownIDs); }; diff --git a/lib/Transforms/InstCombine/InstCombinePHI.cpp b/lib/Transforms/InstCombine/InstCombinePHI.cpp index 6c67fd38882..1d3b837f124 100644 --- a/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -358,7 +358,10 @@ Instruction *InstCombiner::FoldPHIArgLoadIntoPHI(PHINode &PN) { LLVMContext::MD_invariant_load, LLVMContext::MD_alias_scope, LLVMContext::MD_noalias, - LLVMContext::MD_nonnull + LLVMContext::MD_nonnull, + LLVMContext::MD_align, + LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null, }; for (unsigned ID : KnownIDs) diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index b6080f29faa..0bd5fa9f877 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -1430,6 +1430,15 @@ void llvm::combineMetadata(Instruction *K, const Instruction *J, case LLVMContext::MD_invariant_group: // Preserve !invariant.group in K. break; + case LLVMContext::MD_align: + K->setMetadata(Kind, + MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD)); + break; + case LLVMContext::MD_dereferenceable: + case LLVMContext::MD_dereferenceable_or_null: + K->setMetadata(Kind, + MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD)); + break; } } // Set !invariant.group from J if J has it. If both instructions have it diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index e44a04aaba6..f9d5d2d4d36 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1097,7 +1097,9 @@ static bool HoistThenElseCodeToIf(BranchInst *BI, unsigned KnownIDs[] = { LLVMContext::MD_tbaa, LLVMContext::MD_range, LLVMContext::MD_fpmath, LLVMContext::MD_invariant_load, - LLVMContext::MD_nonnull, LLVMContext::MD_invariant_group}; + LLVMContext::MD_nonnull, LLVMContext::MD_invariant_group, + LLVMContext::MD_align, LLVMContext::MD_dereferenceable, + LLVMContext::MD_dereferenceable_or_null}; combineMetadata(I1, I2, KnownIDs); I2->eraseFromParent(); Changed = true; diff --git a/test/Transforms/InstCombine/load-combine-metadata-2.ll b/test/Transforms/InstCombine/load-combine-metadata-2.ll new file mode 100644 index 00000000000..bec0d7d2c36 --- /dev/null +++ b/test/Transforms/InstCombine/load-combine-metadata-2.ll @@ -0,0 +1,20 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @test_load_load_combine_metadata( +; Check that align metadata is combined +; CHECK: load i32*, i32** %0 +; CHECK-SAME: !align ![[ALIGN:[0-9]+]] +define void @test_load_load_combine_metadata(i32**, i32**, i32**) { + %a = load i32*, i32** %0, !align !0 + %b = load i32*, i32** %0, !align !1 + store i32 0, i32* %a + store i32 0, i32* %b + ret void +} + +; CHECK: ![[ALIGN]] = !{i64 4} + +!0 = !{i64 4} +!1 = !{i64 8} \ No newline at end of file diff --git a/test/Transforms/InstCombine/load-combine-metadata-3.ll b/test/Transforms/InstCombine/load-combine-metadata-3.ll new file mode 100644 index 00000000000..bad4bb24059 --- /dev/null +++ b/test/Transforms/InstCombine/load-combine-metadata-3.ll @@ -0,0 +1,20 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @test_load_load_combine_metadata( +; Check that dereferenceable metadata is combined +; CHECK: load i32*, i32** %0 +; CHECK-SAME: !dereferenceable ![[DEREF:[0-9]+]] +define void @test_load_load_combine_metadata(i32**, i32**, i32**) { + %a = load i32*, i32** %0, !dereferenceable !0 + %b = load i32*, i32** %0, !dereferenceable !1 + store i32 0, i32* %a + store i32 0, i32* %b + ret void +} + +; CHECK: ![[DEREF]] = !{i64 4} + +!0 = !{i64 4} +!1 = !{i64 8} \ No newline at end of file diff --git a/test/Transforms/InstCombine/load-combine-metadata-4.ll b/test/Transforms/InstCombine/load-combine-metadata-4.ll new file mode 100644 index 00000000000..2a1ffcd0605 --- /dev/null +++ b/test/Transforms/InstCombine/load-combine-metadata-4.ll @@ -0,0 +1,20 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @test_load_load_combine_metadata( +; Check that dereferenceable_or_null metadata is combined +; CHECK: load i32*, i32** %0 +; CHECK-SAME: !dereferenceable_or_null ![[DEREF:[0-9]+]] +define void @test_load_load_combine_metadata(i32**, i32**, i32**) { + %a = load i32*, i32** %0, !dereferenceable_or_null !0 + %b = load i32*, i32** %0, !dereferenceable_or_null !1 + store i32 0, i32* %a + store i32 0, i32* %b + ret void +} + +; CHECK: ![[DEREF]] = !{i64 4} + +!0 = !{i64 4} +!1 = !{i64 8} diff --git a/test/Transforms/InstCombine/loadstore-metadata.ll b/test/Transforms/InstCombine/loadstore-metadata.ll index a30c0bc852e..f72e36a7ea3 100644 --- a/test/Transforms/InstCombine/loadstore-metadata.ll +++ b/test/Transforms/InstCombine/loadstore-metadata.ll @@ -31,7 +31,7 @@ define float @test_load_cast_combine_range(i32* %ptr) { ; CHECK-NOT: !range ; CHECK: ret float entry: - %l = load i32, i32* %ptr, !range !5 + %l = load i32, i32* %ptr, !range !6 %c = bitcast i32 %l to float ret float %c } @@ -57,6 +57,39 @@ entry: ret i32 %c } +define i8* @test_load_cast_combine_align(i32** %ptr) { +; Ensure (cast (load (...))) -> (load (cast (...))) preserves align +; metadata. +; CHECK-LABEL: @test_load_cast_combine_align( +; CHECK: load i8*, i8** %{{.*}}, !align !5 +entry: + %l = load i32*, i32** %ptr, !align !5 + %c = bitcast i32* %l to i8* + ret i8* %c +} + +define i8* @test_load_cast_combine_deref(i32** %ptr) { +; Ensure (cast (load (...))) -> (load (cast (...))) preserves dereferenceable +; metadata. +; CHECK-LABEL: @test_load_cast_combine_deref( +; CHECK: load i8*, i8** %{{.*}}, !dereferenceable !5 +entry: + %l = load i32*, i32** %ptr, !dereferenceable !5 + %c = bitcast i32* %l to i8* + ret i8* %c +} + +define i8* @test_load_cast_combine_deref_or_null(i32** %ptr) { +; Ensure (cast (load (...))) -> (load (cast (...))) preserves +; dereferenceable_or_null metadata. +; CHECK-LABEL: @test_load_cast_combine_deref_or_null( +; CHECK: load i8*, i8** %{{.*}}, !dereferenceable_or_null !5 +entry: + %l = load i32*, i32** %ptr, !dereferenceable_or_null !5 + %c = bitcast i32* %l to i8* + ret i8* %c +} + define void @test_load_cast_combine_loop(float* %src, i32* %dst, i32 %n) { ; Ensure (cast (load (...))) -> (load (cast (...))) preserves loop access ; metadata. @@ -110,4 +143,5 @@ entry: !2 = !{ !2, !1 } !3 = !{ } !4 = !{ i32 1 } -!5 = !{ i32 0, i32 42 } +!5 = !{ i64 8 } +!6 = !{ i32 0, i32 42 } diff --git a/test/Transforms/InstCombine/phi-load-metadata-2.ll b/test/Transforms/InstCombine/phi-load-metadata-2.ll new file mode 100644 index 00000000000..cfbf2dea8a7 --- /dev/null +++ b/test/Transforms/InstCombine/phi-load-metadata-2.ll @@ -0,0 +1,30 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +declare void @bar() +declare void @baz() + +; Check that dereferenceable metadata is combined +; CHECK-LABEL: cont: +; CHECK: load i32*, i32** +; CHECK-SAME: !dereferenceable ![[DEREF:[0-9]+]] +define i32* @test_phi_combine_load_metadata(i1 %c, i32** dereferenceable(8) %p1, i32** dereferenceable(8) %p2) { + br i1 %c, label %t, label %f +t: + call void @bar() + %v1 = load i32*, i32** %p1, align 8, !dereferenceable !0 + br label %cont + +f: + call void @baz() + %v2 = load i32*, i32** %p2, align 8, !dereferenceable !1 + br label %cont + +cont: + %res = phi i32* [ %v1, %t ], [ %v2, %f ] + ret i32* %res +} + +; CHECK: ![[DEREF]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16} diff --git a/test/Transforms/InstCombine/phi-load-metadata-3.ll b/test/Transforms/InstCombine/phi-load-metadata-3.ll new file mode 100644 index 00000000000..39049c9c718 --- /dev/null +++ b/test/Transforms/InstCombine/phi-load-metadata-3.ll @@ -0,0 +1,30 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +declare void @bar() +declare void @baz() + +; Check that dereferenceable_or_null metadata is combined +; CHECK-LABEL: cont: +; CHECK: load i32*, i32** +; CHECK-SAME: !dereferenceable_or_null ![[DEREF:[0-9]+]] +define i32* @test_phi_combine_load_metadata(i1 %c, i32** dereferenceable(8) %p1, i32** dereferenceable(8) %p2) { + br i1 %c, label %t, label %f +t: + call void @bar() + %v1 = load i32*, i32** %p1, align 8, !dereferenceable_or_null !0 + br label %cont + +f: + call void @baz() + %v2 = load i32*, i32** %p2, align 8, !dereferenceable_or_null !1 + br label %cont + +cont: + %res = phi i32* [ %v1, %t ], [ %v2, %f ] + ret i32* %res +} + +; CHECK: ![[DEREF]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16} diff --git a/test/Transforms/InstCombine/phi-load-metadata.ll b/test/Transforms/InstCombine/phi-load-metadata.ll new file mode 100644 index 00000000000..004a355ca44 --- /dev/null +++ b/test/Transforms/InstCombine/phi-load-metadata.ll @@ -0,0 +1,30 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +declare void @bar() +declare void @baz() + +; Check that align metadata is combined +; CHECK-LABEL: cont: +; CHECK: load i32*, i32** +; CHECK-SAME: !align ![[ALIGN:[0-9]+]] +define i32* @test_phi_combine_load_metadata(i1 %c, i32** dereferenceable(8) %p1, i32** dereferenceable(8) %p2) { + br i1 %c, label %t, label %f +t: + call void @bar() + %v1 = load i32*, i32** %p1, align 8, !align !0 + br label %cont + +f: + call void @baz() + %v2 = load i32*, i32** %p2, align 8, !align !1 + br label %cont + +cont: + %res = phi i32* [ %v1, %t ], [ %v2, %f ] + ret i32* %res +} + +; CHECK: ![[ALIGN]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16} diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll new file mode 100644 index 00000000000..94d3565ce98 --- /dev/null +++ b/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll @@ -0,0 +1,32 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +declare void @bar(i32*) +declare void @baz(i32*) + +; CHECK-LABEL: @test_load_combine_metadata( +; Check that dereferenceable metadata is combined +; CHECK: load i32*, i32** %p +; CHECK-SAME: !dereferenceable ![[DEREF:[0-9]+]] +; CHECK: t: +; CHECK: f: +define void @test_load_combine_metadata(i1 %c, i32** %p) { + br i1 %c, label %t, label %f + +t: + %v1 = load i32*, i32** %p, !dereferenceable !0 + call void @bar(i32* %v1) + br label %cont + +f: + %v2 = load i32*, i32** %p, !dereferenceable !1 + call void @baz(i32* %v2) + br label %cont + +cont: + ret void +} + +; CHECK: ![[DEREF]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16} diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll new file mode 100644 index 00000000000..92bdf6ec5c1 --- /dev/null +++ b/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll @@ -0,0 +1,32 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +declare void @bar(i32*) +declare void @baz(i32*) + +; CHECK-LABEL: @test_load_combine_metadata( +; Check that dereferenceable_or_null metadata is combined +; CHECK: load i32*, i32** %p +; CHECK-SAME: !dereferenceable_or_null ![[DEREF:[0-9]+]] +; CHECK: t: +; CHECK: f: +define void @test_load_combine_metadata(i1 %c, i32** %p) { + br i1 %c, label %t, label %f + +t: + %v1 = load i32*, i32** %p, !dereferenceable_or_null !0 + call void @bar(i32* %v1) + br label %cont + +f: + %v2 = load i32*, i32** %p, !dereferenceable_or_null !1 + call void @baz(i32* %v2) + br label %cont + +cont: + ret void +} + +; CHECK: ![[DEREF]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16} diff --git a/test/Transforms/SimplifyCFG/preserve-load-metadata.ll b/test/Transforms/SimplifyCFG/preserve-load-metadata.ll new file mode 100644 index 00000000000..89815c84315 --- /dev/null +++ b/test/Transforms/SimplifyCFG/preserve-load-metadata.ll @@ -0,0 +1,32 @@ +; RUN: opt < %s -simplifycfg -S | FileCheck %s + +declare void @bar(i32*) +declare void @baz(i32*) + +; CHECK-LABEL: @test_load_combine_metadata( +; Check that align metadata is combined +; CHECK: load i32*, i32** %p +; CHECK-SAME: !align ![[ALIGN:[0-9]+]] +; CHECK: t: +; CHECK: f: +define void @test_load_combine_metadata(i1 %c, i32** %p) { + br i1 %c, label %t, label %f + +t: + %v1 = load i32*, i32** %p, !align !0 + call void @bar(i32* %v1) + br label %cont + +f: + %v2 = load i32*, i32** %p, !align !1 + call void @baz(i32* %v2) + br label %cont + +cont: + ret void +} + +; CHECK: ![[ALIGN]] = !{i64 8} + +!0 = !{i64 8} +!1 = !{i64 16}