private:
void BuildRankMap(Function &F);
unsigned getRank(Value *V);
+ void canonicalizeOperands(Instruction *I);
void ReassociateExpression(BinaryOperator *I);
void RewriteExprTree(BinaryOperator *I, SmallVectorImpl<ValueEntry> &Ops);
Value *OptimizeExpression(BinaryOperator *I,
return ValueRankMap[I] = Rank;
}
+void Reassociate::canonicalizeOperands(Instruction *I) {
+ assert(isa<BinaryOperator>(I) && "Expected binary operator.");
+ assert(I->isCommutative() && "Expected commutative operator.");
+
+ Value *LHS = I->getOperand(0);
+ Value *RHS = I->getOperand(1);
+ unsigned LHSRank = getRank(LHS);
+ unsigned RHSRank = getRank(RHS);
+
+ // Canonicalize constants to RHS. Otherwise, sort the operands by rank.
+ if (isa<Constant>(LHS) || RHSRank < LHSRank)
+ cast<BinaryOperator>(I)->swapOperands();
+}
+
static BinaryOperator *CreateAdd(Value *S1, Value *S2, const Twine &Name,
Instruction *InsertBefore, Value *FlagsOp) {
if (S1->getType()->isIntegerTy())
// FAdd and FMul can be commuted.
unsigned Opcode = I->getOpcode();
- if (Opcode == Instruction::FMul || Opcode == Instruction::FAdd) {
- Value *LHS = I->getOperand(0);
- Value *RHS = I->getOperand(1);
- unsigned LHSRank = getRank(LHS);
- unsigned RHSRank = getRank(RHS);
-
- // Sort the operands by rank.
- if (RHSRank < LHSRank) {
- I->setOperand(0, RHS);
- I->setOperand(1, LHS);
- }
- }
+ if (Opcode == Instruction::FMul || Opcode == Instruction::FAdd)
+ canonicalizeOperands(I);
// FIXME: We should commute vector instructions as well. However, this
// requires further analysis to determine the effect on later passes.
define <4 x float> @test1() {
; CHECK-LABEL: test1
; CHECK-NEXT: %tmp1 = fsub <4 x float> zeroinitializer, zeroinitializer
-; CHECK-NEXT: %tmp2 = fmul <4 x float> zeroinitializer, %tmp1
+; CHECK-NEXT: %tmp2 = fmul <4 x float> %tmp1, zeroinitializer
; CHECK-NEXT: ret <4 x float> %tmp2
%tmp1 = fsub <4 x float> zeroinitializer, zeroinitializer
; (x + 0.1234 * y) * (x + -0.1234 * y) -> (x + 0.1234 * y) * (x - 0.1234 * y)
define double @test1(double %x, double %y) {
; CHECK-LABEL: @test1
-; CHECK-NEXT: fmul double 1.234000e-01, %y
+; CHECK-NEXT: fmul double %y, 1.234000e-01
; CHECK-NEXT: fadd double %x, %mul
; CHECK-NEXT: fsub double %x, %mul
; CHECK-NEXT: fmul double %add{{.*}}, %add{{.*}}
; Canonicalize (x - -0.1234 * y)
define double @test5(double %x, double %y) {
; CHECK-LABEL: @test5
-; CHECK-NEXT: fmul double 1.234000e-01, %y
+; CHECK-NEXT: fmul double %y, 1.234000e-01
; CHECK-NEXT: fadd double %x, %mul
; CHECK-NEXT: ret double
; Don't modify (-0.1234 * y - x)
define double @test6(double %x, double %y) {
; CHECK-LABEL: @test6
-; CHECK-NEXT: fmul double -1.234000e-01, %y
+; CHECK-NEXT: fmul double %y, -1.234000e-01
; CHECK-NEXT: fsub double %mul, %x
; CHECK-NEXT: ret double %sub
; Canonicalize (-0.1234 * y + x) -> (x - 0.1234 * y)
define double @test7(double %x, double %y) {
; CHECK-LABEL: @test7
-; CHECK-NEXT: fmul double 1.234000e-01, %y
+; CHECK-NEXT: fmul double %y, 1.234000e-01
; CHECK-NEXT: fsub double %x, %mul
; CHECK-NEXT: ret double %add
; RUN: opt < %s -reassociate -S | FileCheck %s
-; Don't handle floating point vector operations.
+; Canonicalize operands, but don't optimize floating point vector operations.
define <4 x float> @test1() {
; CHECK-LABEL: test1
; CHECK-NEXT: %tmp1 = fsub fast <4 x float> zeroinitializer, zeroinitializer
-; CHECK-NEXT: %tmp2 = fmul fast <4 x float> zeroinitializer, %tmp1
+; CHECK-NEXT: %tmp2 = fmul fast <4 x float> %tmp1, zeroinitializer
%tmp1 = fsub fast <4 x float> zeroinitializer, zeroinitializer
%tmp2 = fmul fast <4 x float> zeroinitializer, %tmp1