From 55a0dcdf87645b605a3f63bdbd885b29f7b9710f Mon Sep 17 00:00:00 2001 From: Jay Foad Date: Fri, 21 Jun 2019 14:10:18 +0000 Subject: [PATCH] [Scalarizer] Propagate IR flags Summary: The motivation for this was to propagate fast-math flags like nnan and ninf on vector floating point operations to the corresponding scalar operations to take advantage of follow-on optimizations. But I think the same argument applies to all of our IR flags: if they apply to the vector operation then they also apply to all the individual scalar operations, and they might enable follow-on optimizations. Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D63593 llvm-svn: 364051 --- lib/Transforms/Scalar/Scalarizer.cpp | 10 +++--- test/Transforms/Scalarizer/basic.ll | 53 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/Transforms/Scalar/Scalarizer.cpp b/lib/Transforms/Scalar/Scalarizer.cpp index 515a6482773..2ee1a3a95f2 100644 --- a/lib/Transforms/Scalar/Scalarizer.cpp +++ b/lib/Transforms/Scalar/Scalarizer.cpp @@ -200,7 +200,7 @@ private: Scatterer scatter(Instruction *Point, Value *V); void gather(Instruction *Op, const ValueVector &CV); bool canTransferMetadata(unsigned Kind); - void transferMetadata(Instruction *Op, const ValueVector &CV); + void transferMetadataAndIRFlags(Instruction *Op, const ValueVector &CV); bool getVectorLayout(Type *Ty, unsigned Alignment, VectorLayout &Layout, const DataLayout &DL); bool finish(); @@ -361,7 +361,7 @@ void ScalarizerVisitor::gather(Instruction *Op, const ValueVector &CV) { for (unsigned I = 0, E = Op->getNumOperands(); I != E; ++I) Op->setOperand(I, UndefValue::get(Op->getOperand(I)->getType())); - transferMetadata(Op, CV); + transferMetadataAndIRFlags(Op, CV); // If we already have a scattered form of Op (created from ExtractElements // of Op itself), replace them with the new form. @@ -397,7 +397,8 @@ bool ScalarizerVisitor::canTransferMetadata(unsigned Tag) { // Transfer metadata from Op to the instructions in CV if it is known // to be safe to do so. -void ScalarizerVisitor::transferMetadata(Instruction *Op, const ValueVector &CV) { +void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *Op, + const ValueVector &CV) { SmallVector, 4> MDs; Op->getAllMetadataOtherThanDebugLoc(MDs); for (unsigned I = 0, E = CV.size(); I != E; ++I) { @@ -405,6 +406,7 @@ void ScalarizerVisitor::transferMetadata(Instruction *Op, const ValueVector &CV) for (const auto &MD : MDs) if (canTransferMetadata(MD.first)) New->setMetadata(MD.first, MD.second); + New->copyIRFlags(Op); if (Op->getDebugLoc() && !New->getDebugLoc()) New->setDebugLoc(Op->getDebugLoc()); } @@ -809,7 +811,7 @@ bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) { unsigned Align = Layout.getElemAlign(I); Stores[I] = Builder.CreateAlignedStore(Val[I], Ptr[I], Align); } - transferMetadata(&SI, Stores); + transferMetadataAndIRFlags(&SI, Stores); return true; } diff --git a/test/Transforms/Scalarizer/basic.ll b/test/Transforms/Scalarizer/basic.ll index 577f0b19bb1..ba6aa933aa8 100644 --- a/test/Transforms/Scalarizer/basic.ll +++ b/test/Transforms/Scalarizer/basic.ll @@ -506,6 +506,59 @@ exit: ret void } +; Check that IR flags are preserved. +define <2 x i32> @f16(<2 x i32> %i, <2 x i32> %j) { +; CHECK-LABEL: @f16( +; CHECK: %res.i0 = add nuw nsw i32 +; CHECK: %res.i1 = add nuw nsw i32 + %res = add nuw nsw <2 x i32> %i, %j + ret <2 x i32> %res +} +define <2 x i32> @f17(<2 x i32> %i, <2 x i32> %j) { +; CHECK-LABEL: @f17( +; CHECK: %res.i0 = sdiv exact i32 +; CHECK: %res.i1 = sdiv exact i32 + %res = sdiv exact <2 x i32> %i, %j + ret <2 x i32> %res +} +define <2 x float> @f18(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @f18( +; CHECK: %res.i0 = fadd fast float +; CHECK: %res.i1 = fadd fast float + %res = fadd fast <2 x float> %x, %y + ret <2 x float> %res +} +define <2 x float> @f19(<2 x float> %x) { +; CHECK-LABEL: @f19( +; CHECK: %res.i0 = fneg fast float +; CHECK: %res.i1 = fneg fast float + %res = fneg fast <2 x float> %x + ret <2 x float> %res +} +define <2 x i1> @f20(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @f20( +; CHECK: %res.i0 = fcmp fast ogt float +; CHECK: %res.i1 = fcmp fast ogt float + %res = fcmp fast ogt <2 x float> %x, %y + ret <2 x i1> %res +} +declare <2 x float> @llvm.sqrt.v2f32(<2 x float>) +define <2 x float> @f21(<2 x float> %x) { +; CHECK-LABEL: @f21( +; CHECK: %res.i0 = call fast float @llvm.sqrt.f32 +; CHECK: %res.i1 = call fast float @llvm.sqrt.f32 + %res = call fast <2 x float> @llvm.sqrt.v2f32(<2 x float> %x) + ret <2 x float> %res +} +declare <2 x float> @llvm.fma.v2f32(<2 x float>, <2 x float>, <2 x float>) +define <2 x float> @f22(<2 x float> %x, <2 x float> %y, <2 x float> %z) { +; CHECK-LABEL: @f22( +; CHECK: %res.i0 = call fast float @llvm.fma.f32 +; CHECK: %res.i1 = call fast float @llvm.fma.f32 + %res = call fast <2 x float> @llvm.fma.v2f32(<2 x float> %x, <2 x float> %y, <2 x float> %z) + ret <2 x float> %res +} + !0 = !{ !"root" } !1 = !{ !"set1", !0 } !2 = !{ !"set2", !0 }