From 1d0c845d9dce577c2ef14cd7d5fcf0b9c17f9ed2 Mon Sep 17 00:00:00 2001 From: Cameron McInally Date: Sun, 5 May 2019 16:07:09 +0000 Subject: [PATCH] Add FNeg IR constant folding support llvm-svn: 359982 --- llvm/include/llvm/Analysis/ConstantFolding.h | 6 +++ llvm/lib/Analysis/ConstantFolding.cpp | 11 +++- llvm/lib/IR/ConstantFold.cpp | 46 ++++++++++++++++ llvm/lib/IR/ConstantFold.h | 1 + llvm/lib/IR/Constants.cpp | 10 ++-- llvm/test/Analysis/ConstantFolding/fneg.ll | 42 +++++++++++++++ llvm/test/Transforms/InstCombine/fneg.ll | 53 ++----------------- llvm/test/Transforms/InstCombine/fsub.ll | 6 +-- .../Transforms/InstCombine/inselt-binop.ll | 2 +- llvm/test/Transforms/Reassociate/crash2.ll | 2 +- llvm/unittests/IR/ConstantsTest.cpp | 2 +- 11 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 llvm/test/Analysis/ConstantFolding/fneg.ll diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h index 43a2df0d853e..2385b6f09c40 100644 --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -71,6 +71,12 @@ ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS, Constant *RHS, const DataLayout &DL, const TargetLibraryInfo *TLI = nullptr); +/// Attempt to constant fold a unary operation with the specified +/// operand. If it fails, it returns a constant expression of the specified +/// operands. +Constant *ConstantFoldUnaryOpOperand(unsigned Opcode, Constant *Op, + const DataLayout &DL); + /// Attempt to constant fold a binary operation with the specified /// operands. If it fails, it returns a constant expression of the specified /// operands. diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 74468e8dd72c..2ea1e7dea829 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -999,7 +999,9 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode, const TargetLibraryInfo *TLI) { Type *DestTy = InstOrCE->getType(); - // Handle easy binops first. + if (Instruction::isUnaryOp(Opcode)) + return ConstantFoldUnaryOpOperand(Opcode, Ops[0], DL); + if (Instruction::isBinaryOp(Opcode)) return ConstantFoldBinaryOpOperands(Opcode, Ops[0], Ops[1], DL); @@ -1262,6 +1264,13 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned Predicate, return ConstantExpr::getCompare(Predicate, Ops0, Ops1); } +Constant *llvm::ConstantFoldUnaryOpOperand(unsigned Opcode, Constant *Op, + const DataLayout &DL) { + assert(Instruction::isUnaryOp(Opcode)); + + return ConstantExpr::get(Opcode, Op); +} + Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS, Constant *RHS, const DataLayout &DL) { diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index 1dfd5284a97f..835fbb3443b8 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -918,6 +918,52 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg, return ConstantVector::get(Result); } +Constant *llvm::ConstantFoldUnaryInstruction(unsigned Opcode, Constant *C) { + assert(Instruction::isUnaryOp(Opcode) && "Non-unary instruction detected"); + + // Handle scalar UndefValue. Vectors are always evaluated per element. + bool HasScalarUndef = !C->getType()->isVectorTy() && isa(C); + + if (HasScalarUndef) { + switch (static_cast(Opcode)) { + case Instruction::FNeg: + return C; // -undef -> undef + case Instruction::UnaryOpsEnd: + llvm_unreachable("Invalid UnaryOp"); + } + } + + // Constant should not be UndefValue, unless these are vector constants. + assert(!HasScalarUndef && "Unexpected UndefValue"); + // We only have FP UnaryOps right now. + assert(!isa(C) && "Unexpected Integer UnaryOp"); + + if (ConstantFP *CFP = dyn_cast(C)) { + const APFloat &CV = CFP->getValueAPF(); + switch (Opcode) { + default: + break; + case Instruction::FNeg: + return ConstantFP::get(C->getContext(), neg(CV)); + } + } else if (VectorType *VTy = dyn_cast(C->getType())) { + // Fold each element and create a vector constant from those constants. + SmallVector Result; + Type *Ty = IntegerType::get(VTy->getContext(), 32); + for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) { + Constant *ExtractIdx = ConstantInt::get(Ty, i); + Constant *Elt = ConstantExpr::getExtractElement(C, ExtractIdx); + + Result.push_back(ConstantExpr::get(Opcode, Elt)); + } + + return ConstantVector::get(Result); + } + + // We don't know how to fold this. + return nullptr; +} + Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, Constant *C2) { assert(Instruction::isBinaryOp(Opcode) && "Non-binary instruction detected"); diff --git a/llvm/lib/IR/ConstantFold.h b/llvm/lib/IR/ConstantFold.h index b57153bf00b0..9ad6e14e9e40 100644 --- a/llvm/lib/IR/ConstantFold.h +++ b/llvm/lib/IR/ConstantFold.h @@ -43,6 +43,7 @@ template class ArrayRef; ArrayRef Idxs); Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef Idxs); + Constant *ConstantFoldUnaryInstruction(unsigned Opcode, Constant *V); Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1, Constant *V2); Constant *ConstantFoldCompareInstruction(unsigned short predicate, diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index 00c722651ed8..5545eb46686e 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -1830,7 +1830,8 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C, unsigned Flags, } #endif - // TODO: Try to constant fold operation. + if (Constant *FC = ConstantFoldUnaryInstruction(Opcode, C)) + return FC; if (OnlyIfReducedTy == C->getType()) return nullptr; @@ -1909,7 +1910,7 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2, #endif if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2)) - return FC; // Fold a few common cases. + return FC; if (OnlyIfReducedTy == C1->getType()) return nullptr; @@ -2235,7 +2236,7 @@ Constant *ConstantExpr::getNeg(Constant *C, bool HasNUW, bool HasNSW) { Constant *ConstantExpr::getFNeg(Constant *C) { assert(C->getType()->isFPOrFPVectorTy() && "Cannot FNEG a non-floating-point value!"); - return getFSub(ConstantFP::getZeroValueForNegation(C->getType()), C); + return get(Instruction::FNeg, C); } Constant *ConstantExpr::getNot(Constant *C) { @@ -3024,7 +3025,8 @@ Instruction *ConstantExpr::getAsInstruction() { case Instruction::FCmp: return CmpInst::Create((Instruction::OtherOps)getOpcode(), (CmpInst::Predicate)getPredicate(), Ops[0], Ops[1]); - + case Instruction::FNeg: + return UnaryOperator::Create((Instruction::UnaryOps)getOpcode(), Ops[0]); default: assert(getNumOperands() == 2 && "Must be binary operator?"); BinaryOperator *BO = diff --git a/llvm/test/Analysis/ConstantFolding/fneg.ll b/llvm/test/Analysis/ConstantFolding/fneg.ll new file mode 100644 index 000000000000..70a2fe2a4bdd --- /dev/null +++ b/llvm/test/Analysis/ConstantFolding/fneg.ll @@ -0,0 +1,42 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -constprop -S | FileCheck %s + +define float @fneg_constant() { +; CHECK-LABEL: @fneg_constant( +; CHECK-NEXT: ret float 0.000000e+00 +; + %r = fneg float -0.0 + ret float %r +} + +define float @fneg_undef() { +; CHECK-LABEL: @fneg_undef( +; CHECK-NEXT: ret float undef +; + %r = fneg float undef + ret float %r +} + +define <4 x float> @fneg_constant_elts_v4f32() { +; CHECK-LABEL: @fneg_constant_elts_v4f32( +; CHECK-NEXT: ret <4 x float> +; + %r = fneg <4 x float> + ret <4 x float> %r +} + +define <4 x float> @fneg_constant_undef_elts_v4f32() { +; CHECK-LABEL: @fneg_constant_undef_elts_v4f32( +; CHECK-NEXT: ret <4 x float> +; + %r = fneg <4 x float> + ret <4 x float> %r +} + +define <4 x float> @fneg_constant_all_undef_elts_v4f32() { +; CHECK-LABEL: @fneg_constant_all_undef_elts_v4f32( +; CHECK-NEXT: ret <4 x float> undef +; + %r = fneg <4 x float> + ret <4 x float> %r +} diff --git a/llvm/test/Transforms/InstCombine/fneg.ll b/llvm/test/Transforms/InstCombine/fneg.ll index 84cc981566f3..889bb022541e 100644 --- a/llvm/test/Transforms/InstCombine/fneg.ll +++ b/llvm/test/Transforms/InstCombine/fneg.ll @@ -46,7 +46,7 @@ define float @fmul_fneg_extra_use(float %x) { define <4 x double> @fmul_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fmul_fneg_vec( -; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], ; CHECK-NEXT: ret <4 x double> [[R]] ; %m = fmul <4 x double> %x, @@ -97,7 +97,7 @@ define float @fdiv_op1_constant_fneg_extra_use(float %x) { define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fdiv_op1_constant_fneg_vec( -; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], ; CHECK-NEXT: ret <4 x double> [[R]] ; %d = fdiv <4 x double> %x, @@ -148,57 +148,10 @@ define float @fdiv_op0_constant_fneg_extra_use(float %x) { define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_vec( -; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> , [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> , [[X:%.*]] ; CHECK-NEXT: ret <4 x double> [[R]] ; %d = fdiv <4 x double> , %x %r = fsub <4 x double> , %d ret <4 x double> %r } - -; Actual fneg instructions. - -define float @fneg_constant() { -; CHECK-LABEL: @fneg_constant( -; CHECK-NEXT: [[R:%.*]] = fneg float -0.000000e+00 -; CHECK-NEXT: ret float [[R]] -; - %r = fneg float -0.0 - ret float %r -} - -define float @fneg_undef() { -; CHECK-LABEL: @fneg_undef( -; CHECK-NEXT: [[R:%.*]] = fneg float undef -; CHECK-NEXT: ret float [[R]] -; - %r = fneg float undef - ret float %r -} - -define <4 x float> @fneg_constant_elts_v4f32() { -; CHECK-LABEL: @fneg_constant_elts_v4f32( -; CHECK-NEXT: [[R:%.*]] = fneg <4 x float> -; CHECK-NEXT: ret <4 x float> [[R]] -; - %r = fneg <4 x float> - ret <4 x float> %r -} - -define <4 x float> @fneg_constant_undef_elts_v4f32() { -; CHECK-LABEL: @fneg_constant_undef_elts_v4f32( -; CHECK-NEXT: [[R:%.*]] = fneg <4 x float> -; CHECK-NEXT: ret <4 x float> [[R]] -; - %r = fneg <4 x float> - ret <4 x float> %r -} - -define <4 x float> @fneg_constant_all_undef_elts_v4f32() { -; CHECK-LABEL: @fneg_constant_all_undef_elts_v4f32( -; CHECK-NEXT: [[R:%.*]] = fneg <4 x float> undef -; CHECK-NEXT: ret <4 x float> [[R]] -; - %r = fneg <4 x float> - ret <4 x float> %r -} diff --git a/llvm/test/Transforms/InstCombine/fsub.ll b/llvm/test/Transforms/InstCombine/fsub.ll index 4868ece222d3..189bc4ca850f 100644 --- a/llvm/test/Transforms/InstCombine/fsub.ll +++ b/llvm/test/Transforms/InstCombine/fsub.ll @@ -64,8 +64,8 @@ define float @sub_sub_nsz(float %x, float %y, float %z) { define float @sub_add_neg_x(float %x, float %y) { ; CHECK-LABEL: @sub_add_neg_x( -; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00 -; CHECK-NEXT: ret float [[TMP1]] +; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00 +; CHECK-NEXT: ret float [[R]] ; %mul = fmul float %x, 5.000000e+00 %add = fadd float %mul, %y @@ -121,7 +121,7 @@ define <2 x float> @constant_op1_vec(<2 x float> %x, <2 x float> %y) { define <2 x float> @constant_op1_vec_undef(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @constant_op1_vec_undef( -; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], ; CHECK-NEXT: ret <2 x float> [[R]] ; %r = fsub <2 x float> %x, diff --git a/llvm/test/Transforms/InstCombine/inselt-binop.ll b/llvm/test/Transforms/InstCombine/inselt-binop.ll index 882a1318c689..64296c9fd5ad 100644 --- a/llvm/test/Transforms/InstCombine/inselt-binop.ll +++ b/llvm/test/Transforms/InstCombine/inselt-binop.ll @@ -504,7 +504,7 @@ define <2 x float> @fsub_constant_op0_not_undef_lane(float %x) { define <2 x float> @fsub_constant_op1(float %x) { ; CHECK-LABEL: @fsub_constant_op1( ; CHECK-NEXT: [[INS:%.*]] = insertelement <2 x float> undef, float [[X:%.*]], i32 1 -; CHECK-NEXT: [[BO:%.*]] = fadd <2 x float> [[INS]], +; CHECK-NEXT: [[BO:%.*]] = fadd <2 x float> [[INS]], ; CHECK-NEXT: ret <2 x float> [[BO]] ; %ins = insertelement <2 x float> undef, float %x, i32 1 diff --git a/llvm/test/Transforms/Reassociate/crash2.ll b/llvm/test/Transforms/Reassociate/crash2.ll index 7e4a3278c9ed..0da5bde2b31d 100644 --- a/llvm/test/Transforms/Reassociate/crash2.ll +++ b/llvm/test/Transforms/Reassociate/crash2.ll @@ -7,7 +7,7 @@ define float @undef1() { ; CHECK-LABEL: @undef1( -; CHECK-NEXT: ret float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float fsub (float -0.000000e+00, float bitcast (i32 ptrtoint (i32* @g to i32) to float)), float fsub (float -0.000000e+00, float bitcast (i32 ptrtoint (i32* @g to i32) to float))))) +; CHECK-NEXT: ret float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float bitcast (i32 ptrtoint (i32* @g to i32) to float), float fadd (float fneg (float bitcast (i32 ptrtoint (i32* @g to i32) to float)), float fneg (float bitcast (i32 ptrtoint (i32* @g to i32) to float))))) ; %t0 = fadd fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), bitcast (i32 ptrtoint (i32* @g to i32) to float) %t1 = fsub fast float bitcast (i32 ptrtoint (i32* @g to i32) to float), %t0 diff --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp index a07862213d22..6c3497a6c841 100644 --- a/llvm/unittests/IR/ConstantsTest.cpp +++ b/llvm/unittests/IR/ConstantsTest.cpp @@ -229,7 +229,7 @@ TEST(ConstantsTest, AsInstructionsTest) { #define P6STR "bitcast (i32 ptrtoint (i32** @dummy2 to i32) to <2 x i16>)" CHECK(ConstantExpr::getNeg(P0), "sub i32 0, " P0STR); - CHECK(ConstantExpr::getFNeg(P1), "fsub float -0.000000e+00, " P1STR); + CHECK(ConstantExpr::getFNeg(P1), "fneg float " P1STR); CHECK(ConstantExpr::getNot(P0), "xor i32 " P0STR ", -1"); CHECK(ConstantExpr::getAdd(P0, P0), "add i32 " P0STR ", " P0STR); CHECK(ConstantExpr::getAdd(P0, P0, false, true), "add nsw i32 " P0STR ", "