Index: llvm/trunk/include/llvm/IR/Metadata.h =================================================================== --- llvm/trunk/include/llvm/IR/Metadata.h +++ llvm/trunk/include/llvm/IR/Metadata.h @@ -964,6 +964,8 @@ 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. Index: llvm/trunk/lib/IR/Metadata.cpp =================================================================== --- llvm/trunk/lib/IR/Metadata.cpp +++ llvm/trunk/lib/IR/Metadata.cpp @@ -953,6 +953,17 @@ 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. // Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -367,7 +367,13 @@ 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 @@ 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 @@ 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); }; Index: llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -358,7 +358,10 @@ 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) Index: llvm/trunk/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/Local.cpp +++ llvm/trunk/lib/Transforms/Utils/Local.cpp @@ -1430,6 +1430,15 @@ 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 Index: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp +++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1097,7 +1097,9 @@ 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; Index: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-2.ll +++ llvm/trunk/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 Index: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-3.ll +++ llvm/trunk/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 Index: llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/load-combine-metadata-4.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll +++ llvm/trunk/test/Transforms/InstCombine/loadstore-metadata.ll @@ -31,7 +31,7 @@ ; 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 @@ 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 @@ !2 = !{ !2, !1 } !3 = !{ } !4 = !{ i32 1 } -!5 = !{ i32 0, i32 42 } +!5 = !{ i64 8 } +!6 = !{ i32 0, i32 42 } Index: llvm/trunk/test/Transforms/InstCombine/phi-load-metadata-2.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/phi-load-metadata-2.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/InstCombine/phi-load-metadata-3.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/phi-load-metadata-3.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/InstCombine/phi-load-metadata.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/phi-load-metadata.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll =================================================================== --- llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata-2.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll =================================================================== --- llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata-3.ll +++ llvm/trunk/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} Index: llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata.ll =================================================================== --- llvm/trunk/test/Transforms/SimplifyCFG/preserve-load-metadata.ll +++ llvm/trunk/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}