diff --git a/llvm/lib/Transforms/Scalar/Scalarizer.cpp b/llvm/lib/Transforms/Scalar/Scalarizer.cpp --- a/llvm/lib/Transforms/Scalar/Scalarizer.cpp +++ b/llvm/lib/Transforms/Scalar/Scalarizer.cpp @@ -200,7 +200,7 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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/llvm/test/Transforms/Scalarizer/basic.ll b/llvm/test/Transforms/Scalarizer/basic.ll --- a/llvm/test/Transforms/Scalarizer/basic.ll +++ b/llvm/test/Transforms/Scalarizer/basic.ll @@ -506,6 +506,59 @@ 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 }