Skip to content

Commit

Permalink
[Reassociate] Handle unary FNeg in the Reassociate pass
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D63445

llvm-svn: 363813
  • Loading branch information
mcinally committed Jun 19, 2019
1 parent d4754ca commit a027cf4
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 19 deletions.
43 changes: 28 additions & 15 deletions llvm/lib/Transforms/Scalar/Reassociate.cpp
Expand Up @@ -266,12 +266,20 @@ static BinaryOperator *CreateNeg(Value *S1, const Twine &Name,

/// Replace 0-X with X*-1.
static BinaryOperator *LowerNegateToMultiply(Instruction *Neg) {
assert((isa<UnaryOperator>(Neg) || isa<BinaryOperator>(Neg)) &&
"Expected a Negate!");
// It's not safe to lower a unary FNeg into a FMul by -1.0. However,
// we can only reach this function with fast flags set, so it's
// safe to do with nnan.
assert((!isa<FPMathOperator>(Neg) || Neg->isFast()) &&
"Expecting FastMathFlags!");
unsigned OpNo = isa<BinaryOperator>(Neg) ? 1 : 0;
Type *Ty = Neg->getType();
Constant *NegOne = Ty->isIntOrIntVectorTy() ?
ConstantInt::getAllOnesValue(Ty) : ConstantFP::get(Ty, -1.0);

BinaryOperator *Res = CreateMul(Neg->getOperand(1), NegOne, "", Neg, Neg);
Neg->setOperand(1, Constant::getNullValue(Ty)); // Drop use of op.
BinaryOperator *Res = CreateMul(Neg->getOperand(OpNo), NegOne, "", Neg, Neg);
Neg->setOperand(OpNo, Constant::getNullValue(Ty)); // Drop use of op.
Res->takeName(Neg);
Neg->replaceAllUsesWith(Res);
Res->setDebugLoc(Neg->getDebugLoc());
Expand Down Expand Up @@ -444,8 +452,10 @@ using RepeatedValue = std::pair<Value*, APInt>;
/// that have all uses inside the expression (i.e. only used by non-leaf nodes
/// of the expression) if it can turn them into binary operators of the right
/// type and thus make the expression bigger.
static bool LinearizeExprTree(BinaryOperator *I,
static bool LinearizeExprTree(Instruction *I,
SmallVectorImpl<RepeatedValue> &Ops) {
assert((isa<UnaryOperator>(I) || isa<BinaryOperator>(I)) &&
"Expected a UnaryOperator or BinaryOperator!");
LLVM_DEBUG(dbgs() << "LINEARIZE: " << *I << '\n');
unsigned Bitwidth = I->getType()->getScalarType()->getPrimitiveSizeInBits();
unsigned Opcode = I->getOpcode();
Expand All @@ -462,7 +472,7 @@ static bool LinearizeExprTree(BinaryOperator *I,
// with their weights, representing a certain number of paths to the operator.
// If an operator occurs in the worklist multiple times then we found multiple
// ways to get to it.
SmallVector<std::pair<BinaryOperator*, APInt>, 8> Worklist; // (Op, Weight)
SmallVector<std::pair<Instruction*, APInt>, 8> Worklist; // (Op, Weight)
Worklist.push_back(std::make_pair(I, APInt(Bitwidth, 1)));
bool Changed = false;

Expand All @@ -489,10 +499,10 @@ static bool LinearizeExprTree(BinaryOperator *I,
SmallPtrSet<Value *, 8> Visited; // For sanity checking the iteration scheme.
#endif
while (!Worklist.empty()) {
std::pair<BinaryOperator*, APInt> P = Worklist.pop_back_val();
std::pair<Instruction*, APInt> P = Worklist.pop_back_val();
I = P.first; // We examine the operands of this binary operator.

for (unsigned OpIdx = 0; OpIdx < 2; ++OpIdx) { // Visit operands.
for (unsigned OpIdx = 0; OpIdx < I->getNumOperands(); ++OpIdx) { // Visit operands.
Value *Op = I->getOperand(OpIdx);
APInt Weight = P.second; // Number of paths to this operand.
LLVM_DEBUG(dbgs() << "OPERAND: " << *Op << " (" << Weight << ")\n");
Expand Down Expand Up @@ -572,14 +582,14 @@ static bool LinearizeExprTree(BinaryOperator *I,

// If this is a multiply expression, turn any internal negations into
// multiplies by -1 so they can be reassociated.
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Op))
if ((Opcode == Instruction::Mul && match(BO, m_Neg(m_Value()))) ||
(Opcode == Instruction::FMul && match(BO, m_FNeg(m_Value())))) {
if (Instruction *Tmp = dyn_cast<Instruction>(Op))
if ((Opcode == Instruction::Mul && match(Tmp, m_Neg(m_Value()))) ||
(Opcode == Instruction::FMul && match(Tmp, m_FNeg(m_Value())))) {
LLVM_DEBUG(dbgs()
<< "MORPH LEAF: " << *Op << " (" << Weight << ") TO ");
BO = LowerNegateToMultiply(BO);
LLVM_DEBUG(dbgs() << *BO << '\n');
Worklist.push_back(std::make_pair(BO, Weight));
Tmp = LowerNegateToMultiply(Tmp);
LLVM_DEBUG(dbgs() << *Tmp << '\n');
Worklist.push_back(std::make_pair(Tmp, Weight));
Changed = true;
continue;
}
Expand Down Expand Up @@ -2020,7 +2030,7 @@ Instruction *ReassociatePass::canonicalizeNegConstExpr(Instruction *I) {
/// instructions is not allowed.
void ReassociatePass::OptimizeInst(Instruction *I) {
// Only consider operations that we understand.
if (!isa<BinaryOperator>(I))
if (!isa<UnaryOperator>(I) && !isa<BinaryOperator>(I))
return;

if (I->getOpcode() == Instruction::Shl && isa<ConstantInt>(I->getOperand(1)))
Expand Down Expand Up @@ -2085,7 +2095,8 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
I = NI;
}
}
} else if (I->getOpcode() == Instruction::FSub) {
} else if (I->getOpcode() == Instruction::FNeg ||
I->getOpcode() == Instruction::FSub) {
if (ShouldBreakUpSubtract(I)) {
Instruction *NI = BreakUpSubtract(I, RedoInsts);
RedoInsts.insert(I);
Expand All @@ -2094,7 +2105,9 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
} else if (match(I, m_FNeg(m_Value()))) {
// Otherwise, this is a negation. See if the operand is a multiply tree
// and if this is not an inner node of a multiply tree.
if (isReassociableOp(I->getOperand(1), Instruction::FMul) &&
Value *Op = isa<BinaryOperator>(I) ? I->getOperand(1) :
I->getOperand(0);
if (isReassociableOp(Op, Instruction::FMul) &&
(!I->hasOneUse() ||
!isReassociableOp(I->user_back(), Instruction::FMul))) {
// If the negate was simplified, revisit the users to see if we can
Expand Down
21 changes: 17 additions & 4 deletions llvm/test/Transforms/Reassociate/fast-basictest.ll
Expand Up @@ -586,12 +586,10 @@ define float @test18(float %a, float %b, float %z) {
ret float %f
}

; FIXME: This reassociation is not working.
define float @test18_unary_fneg(float %a, float %b, float %z) {
; CHECK-LABEL: @test18_unary_fneg(
; CHECK-NEXT: [[C:%.*]] = fmul fast float [[Z:%.*]], -4.000000e+01
; CHECK-NEXT: [[E:%.*]] = fmul fast float [[C]], [[A:%.*]]
; CHECK-NEXT: [[F:%.*]] = fneg fast float [[E]]
; CHECK-NEXT: [[E:%.*]] = fmul fast float [[A:%.*]], 4.000000e+01
; CHECK-NEXT: [[F:%.*]] = fmul fast float [[E]], [[Z:%.*]]
; CHECK-NEXT: ret float [[F]]
;
%d = fmul fast float %z, 4.000000e+01
Expand All @@ -616,6 +614,21 @@ define float @test18_reassoc(float %a, float %b, float %z) {
ret float %f
}

; It is not safe to reassociate unary fneg without nnan.
define float @test18_reassoc_unary_fneg(float %a, float %b, float %z) {
; CHECK-LABEL: @test18_reassoc_unary_fneg(
; CHECK-NEXT: [[C:%.*]] = fmul reassoc float [[Z:%.*]], -4.000000e+01
; CHECK-NEXT: [[E:%.*]] = fmul reassoc float [[C]], [[A:%.*]]
; CHECK-NEXT: [[F:%.*]] = fneg reassoc float [[E]]
; CHECK-NEXT: ret float [[F]]
;
%d = fmul reassoc float %z, 4.000000e+01
%c = fneg reassoc float %d
%e = fmul reassoc float %a, %c
%f = fneg reassoc float %e
ret float %f
}

; With sub reassociation, constant folding can eliminate the 12 and -12 constants.
define float @test19(float %A, float %B) {
; CHECK-LABEL: @test19(
Expand Down

0 comments on commit a027cf4

Please sign in to comment.