1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[InstCombine] reassociate logic ops with constants separated by a zext

This is a partial implementation of a general fold for associative+commutative operators:
(op (cast (op X, C2)), C1) --> (cast (op X, op (C1, C2)))
(op (cast (op X, C2)), C1) --> (op (cast X), op (C1, C2))

There are 7 associative operators and 13 cast types, so this could potentially go a lot further.

Differential Revision: https://reviews.llvm.org/D22421

llvm-svn: 275684
This commit is contained in:
Sanjay Patel 2016-07-16 15:20:19 +00:00
parent 138dfcb551
commit 54d0ef2693
2 changed files with 59 additions and 15 deletions

View File

@ -162,6 +162,49 @@ static void ClearSubclassDataAfterReassociation(BinaryOperator &I) {
I.setFastMathFlags(FMF);
}
/// Combine constant operands of associative operations either before or after a
/// cast to eliminate one of the associative operations:
/// (op (cast (op X, C2)), C1) --> (cast (op X, op (C1, C2)))
/// (op (cast (op X, C2)), C1) --> (op (cast X), op (C1, C2))
static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1) {
auto *Cast = dyn_cast<CastInst>(BinOp1->getOperand(0));
if (!Cast || !Cast->hasOneUse())
return false;
// TODO: Enhance logic for other casts and remove this check.
auto CastOpcode = Cast->getOpcode();
if (CastOpcode != Instruction::ZExt)
return false;
// TODO: Enhance logic for other BinOps and remove this check.
auto AssocOpcode = BinOp1->getOpcode();
if (AssocOpcode != Instruction::Xor && AssocOpcode != Instruction::And &&
AssocOpcode != Instruction::Or)
return false;
auto *BinOp2 = dyn_cast<BinaryOperator>(Cast->getOperand(0));
if (!BinOp2 || !BinOp2->hasOneUse() || BinOp2->getOpcode() != AssocOpcode)
return false;
Constant *C1, *C2;
if (!match(BinOp1->getOperand(1), m_Constant(C1)) ||
!match(BinOp2->getOperand(1), m_Constant(C2)))
return false;
// TODO: This assumes a zext cast.
// Eg, if it was a trunc, we'd cast C1 to the source type because casting C2
// to the destination type might lose bits.
// Fold the constants together in the destination type:
// (op (cast (op X, C2)), C1) --> (op (cast X), FoldedC)
Type *DestTy = C1->getType();
Constant *CastC2 = ConstantExpr::getCast(CastOpcode, C2, DestTy);
Constant *FoldedC = ConstantExpr::get(AssocOpcode, C1, CastC2);
Cast->setOperand(0, BinOp2->getOperand(0));
BinOp1->setOperand(1, FoldedC);
return true;
}
/// This performs a few simplifications for operators that are associative or
/// commutative:
///
@ -249,6 +292,12 @@ bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
}
if (I.isAssociative() && I.isCommutative()) {
if (simplifyAssocCastAssoc(&I)) {
Changed = true;
++NumReassoc;
continue;
}
// Transform: "(A op B) op C" ==> "(C op A) op B" if "C op A" simplifies.
if (Op0 && Op0->getOpcode() == Opcode) {
Value *A = Op0->getOperand(0);

View File

@ -3,9 +3,8 @@
define i5 @XorZextXor(i3 %a) {
; CHECK-LABEL: @XorZextXor(
; CHECK-NEXT: [[OP1:%.*]] = xor i3 %a, 3
; CHECK-NEXT: [[CAST:%.*]] = zext i3 [[OP1]] to i5
; CHECK-NEXT: [[OP2:%.*]] = xor i5 [[CAST]], 12
; CHECK-NEXT: [[CAST:%.*]] = zext i3 %a to i5
; CHECK-NEXT: [[OP2:%.*]] = xor i5 [[CAST]], 15
; CHECK-NEXT: ret i5 [[OP2]]
;
%op1 = xor i3 %a, 3
@ -16,9 +15,8 @@ define i5 @XorZextXor(i3 %a) {
define <2 x i32> @XorZextXorVec(<2 x i1> %a) {
; CHECK-LABEL: @XorZextXorVec(
; CHECK-NEXT: [[OP1:%.*]] = xor <2 x i1> %a, <i1 true, i1 false>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i1> [[OP1]] to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = xor <2 x i32> [[CAST]], <i32 3, i32 1>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i1> %a to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = xor <2 x i32> [[CAST]], <i32 2, i32 1>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = xor <2 x i1> %a, <i1 true, i1 false>
@ -29,9 +27,8 @@ define <2 x i32> @XorZextXorVec(<2 x i1> %a) {
define i5 @OrZextOr(i3 %a) {
; CHECK-LABEL: @OrZextOr(
; CHECK-NEXT: [[OP1:%.*]] = or i3 %a, 3
; CHECK-NEXT: [[CAST:%.*]] = zext i3 [[OP1]] to i5
; CHECK-NEXT: [[OP2:%.*]] = or i5 [[CAST]], 8
; CHECK-NEXT: [[CAST:%.*]] = zext i3 %a to i5
; CHECK-NEXT: [[OP2:%.*]] = or i5 [[CAST]], 11
; CHECK-NEXT: ret i5 [[OP2]]
;
%op1 = or i3 %a, 3
@ -42,9 +39,8 @@ define i5 @OrZextOr(i3 %a) {
define <2 x i32> @OrZextOrVec(<2 x i2> %a) {
; CHECK-LABEL: @OrZextOrVec(
; CHECK-NEXT: [[OP1:%.*]] = or <2 x i2> %a, <i2 -2, i2 0>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i2> [[OP1]] to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = or <2 x i32> [[CAST]], <i32 1, i32 5>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i2> %a to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = or <2 x i32> [[CAST]], <i32 3, i32 5>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = or <2 x i2> %a, <i2 2, i2 0>
@ -69,9 +65,8 @@ define i5 @AndZextAnd(i3 %a) {
define <2 x i32> @AndZextAndVec(<2 x i8> %a) {
; CHECK-LABEL: @AndZextAndVec(
; CHECK-NEXT: [[OP1:%.*]] = and <2 x i8> %a, <i8 7, i8 0>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i8> [[OP1]] to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = and <2 x i32> [[CAST]], <i32 261, i32 1>
; CHECK-NEXT: [[CAST:%.*]] = zext <2 x i8> %a to <2 x i32>
; CHECK-NEXT: [[OP2:%.*]] = and <2 x i32> [[CAST]], <i32 5, i32 0>
; CHECK-NEXT: ret <2 x i32> [[OP2]]
;
%op1 = and <2 x i8> %a, <i8 7, i8 0>