LLVM_FALLTHROUGH;
case Instruction::Add: {
// `add` is negatible if both of its operands are negatible.
- Value *NegOp0 = negate(I->getOperand(0), Depth + 1);
- if (!NegOp0) // Early return.
- return nullptr;
- Value *NegOp1 = negate(I->getOperand(1), Depth + 1);
- if (!NegOp1)
+ SmallVector<Value *, 2> NegatedOps, NonNegatedOps;
+ for (Value *Op : I->operands()) {
+ // Can we sink the negation into this operand?
+ if (Value *NegOp = negate(Op, Depth + 1)) {
+ NegatedOps.emplace_back(NegOp); // Successfully negated operand!
+ continue;
+ }
+ // Failed to sink negation into this operand. IFF we started from negation
+ // and we manage to sink negation into one operand, we can still do this.
+ if (!IsTrulyNegation)
+ return nullptr;
+ NonNegatedOps.emplace_back(Op); // Just record which operand that was.
+ }
+ assert((NegatedOps.size() + NonNegatedOps.size()) == 2 &&
+ "Internal consistency sanity check.");
+ // Did we manage to sink negation into both of the operands?
+ if (NegatedOps.size() == 2) // Then we get to keep the `add`!
+ return Builder.CreateAdd(NegatedOps[0], NegatedOps[1],
+ I->getName() + ".neg");
+ assert(IsTrulyNegation && "We should have early-exited then.");
+ // Completely failed to sink negation?
+ if (NonNegatedOps.size() == 2)
return nullptr;
- return Builder.CreateAdd(NegOp0, NegOp1, I->getName() + ".neg");
+ // 0-(a+b) --> (-a)-b
+ return Builder.CreateSub(NegatedOps[0], NonNegatedOps[0],
+ I->getName() + ".neg");
}
case Instruction::Xor:
// `xor` is negatible if one of its operands is invertible.
; `add` with single negatible operand is still negatible
define i8 @negate_add_with_single_negatible_operand(i8 %x, i8 %y) {
; CHECK-LABEL: @negate_add_with_single_negatible_operand(
-; CHECK-NEXT: [[T0:%.*]] = add i8 [[X:%.*]], 42
-; CHECK-NEXT: [[T1:%.*]] = sub i8 0, [[T0]]
-; CHECK-NEXT: ret i8 [[T1]]
+; CHECK-NEXT: [[T0_NEG:%.*]] = sub i8 -42, [[X:%.*]]
+; CHECK-NEXT: ret i8 [[T0_NEG]]
;
%t0 = add i8 %x, 42
%t1 = sub i8 0, %t0
%t1 = sub i8 0, %t0
ret i8 %t1
}
+; But don't do this if that means just sinking the negation.
define i8 @negate_add_with_single_negatible_operand_non_negation(i8 %x, i8 %y) {
; CHECK-LABEL: @negate_add_with_single_negatible_operand_non_negation(
; CHECK-NEXT: [[T0:%.*]] = add i8 [[X:%.*]], 42
define i64 @test30(i8* %foo, i64 %i, i64 %j) {
; CHECK-LABEL: @test30(
-; CHECK-NEXT: [[GEP1_IDX_NEG:%.*]] = mul i64 [[I:%.*]], -4
-; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[GEP1_IDX_NEG]], [[J:%.*]]
-; CHECK-NEXT: [[DIFF_NEG:%.*]] = sub i64 0, [[TMP1]]
-; CHECK-NEXT: ret i64 [[DIFF_NEG]]
+; CHECK-NEXT: [[GEP1_IDX_NEG_NEG:%.*]] = shl i64 [[I:%.*]], 2
+; CHECK-NEXT: [[DOTNEG:%.*]] = sub i64 [[GEP1_IDX_NEG_NEG]], [[J:%.*]]
+; CHECK-NEXT: ret i64 [[DOTNEG]]
;
%bit = bitcast i8* %foo to i32*
%gep1 = getelementptr inbounds i32, i32* %bit, i64 %i
define i16 @test30_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) {
; CHECK-LABEL: @test30_as1(
-; CHECK-NEXT: [[GEP1_IDX_NEG:%.*]] = mul i16 [[I:%.*]], -4
-; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[GEP1_IDX_NEG]], [[J:%.*]]
-; CHECK-NEXT: [[DIFF_NEG:%.*]] = sub i16 0, [[TMP1]]
-; CHECK-NEXT: ret i16 [[DIFF_NEG]]
+; CHECK-NEXT: [[GEP1_IDX_NEG_NEG:%.*]] = shl i16 [[I:%.*]], 2
+; CHECK-NEXT: [[DOTNEG:%.*]] = sub i16 [[GEP1_IDX_NEG_NEG]], [[J:%.*]]
+; CHECK-NEXT: ret i16 [[DOTNEG]]
;
%bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
%gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i16 %i