Skip to content

Commit

Permalink
[Mips] Optimize or (and $src1, mask), (shl $src2, shift) to ins (#…
Browse files Browse the repository at this point in the history
…103017)

Optimize `$dst = or (and $src1, (2**size0 - 1)), (shl $src2, size0)` to
`ins $src1, $src2, pos, size`,
where `pos = size0, size = 32 - pos`.

Fix #90325
  • Loading branch information
yingopq authored Sep 12, 2024
1 parent 7353507 commit 1ad84d7
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 18 deletions.
79 changes: 61 additions & 18 deletions llvm/lib/Target/Mips/MipsISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,38 +880,81 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const MipsSubtarget &Subtarget) {
// Pattern match INS.
// $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1),
// where mask1 = (2**size - 1) << pos, mask0 = ~mask1
// => ins $dst, $src, size, pos, $src1
if (DCI.isBeforeLegalizeOps() || !Subtarget.hasExtractInsert())
return SDValue();

SDValue And0 = N->getOperand(0), And1 = N->getOperand(1);
SDValue FirstOperand = N->getOperand(0), SecondOperand = N->getOperand(1);
unsigned SMPos0, SMSize0, SMPos1, SMSize1;
ConstantSDNode *CN, *CN1;

if ((FirstOperand.getOpcode() == ISD::AND &&
SecondOperand.getOpcode() == ISD::SHL) ||
(FirstOperand.getOpcode() == ISD::SHL &&
SecondOperand.getOpcode() == ISD::AND)) {
// Pattern match INS.
// $dst = or (and $src1, (2**size0 - 1)), (shl $src2, size0)
// ==> ins $src1, $src2, pos, size, pos = size0, size = 32 - pos;
// Or:
// $dst = or (shl $src2, size0), (and $src1, (2**size0 - 1))
// ==> ins $src1, $src2, pos, size, pos = size0, size = 32 - pos;
SDValue AndOperand0 = FirstOperand.getOpcode() == ISD::AND
? FirstOperand.getOperand(0)
: SecondOperand.getOperand(0);
SDValue ShlOperand0 = FirstOperand.getOpcode() == ISD::AND
? SecondOperand.getOperand(0)
: FirstOperand.getOperand(0);
SDValue AndMask = FirstOperand.getOpcode() == ISD::AND
? FirstOperand.getOperand(1)
: SecondOperand.getOperand(1);
if (!(CN = dyn_cast<ConstantSDNode>(AndMask)) ||
!isShiftedMask_64(CN->getZExtValue(), SMPos0, SMSize0))
return SDValue();

SDValue ShlShift = FirstOperand.getOpcode() == ISD::AND
? SecondOperand.getOperand(1)
: FirstOperand.getOperand(1);
if (!(CN = dyn_cast<ConstantSDNode>(ShlShift)))
return SDValue();
uint64_t ShlShiftValue = CN->getZExtValue();

if (SMPos0 != 0 || SMSize0 != ShlShiftValue)
return SDValue();

SDLoc DL(N);
EVT ValTy = N->getValueType(0);
SMPos1 = ShlShiftValue;
assert(SMPos1 < ValTy.getSizeInBits());
SMSize1 = (ValTy == MVT::i64 ? 64 : 32) - SMPos1;
return DAG.getNode(MipsISD::Ins, DL, ValTy, ShlOperand0,
DAG.getConstant(SMPos1, DL, MVT::i32),
DAG.getConstant(SMSize1, DL, MVT::i32), AndOperand0);
}

// See if Op's first operand matches (and $src1 , mask0).
if (And0.getOpcode() != ISD::AND)
if (FirstOperand.getOpcode() != ISD::AND)
return SDValue();

if (!(CN = dyn_cast<ConstantSDNode>(And0.getOperand(1))) ||
// Pattern match INS.
// $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1),
// where mask1 = (2**size - 1) << pos, mask0 = ~mask1
// => ins $dst, $src, size, pos, $src1
if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
!isShiftedMask_64(~CN->getSExtValue(), SMPos0, SMSize0))
return SDValue();

// See if Op's second operand matches (and (shl $src, pos), mask1).
if (And1.getOpcode() == ISD::AND &&
And1.getOperand(0).getOpcode() == ISD::SHL) {
if (SecondOperand.getOpcode() == ISD::AND &&
SecondOperand.getOperand(0).getOpcode() == ISD::SHL) {

if (!(CN = dyn_cast<ConstantSDNode>(And1.getOperand(1))) ||
if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand.getOperand(1))) ||
!isShiftedMask_64(CN->getZExtValue(), SMPos1, SMSize1))
return SDValue();

// The shift masks must have the same position and size.
if (SMPos0 != SMPos1 || SMSize0 != SMSize1)
return SDValue();

SDValue Shl = And1.getOperand(0);
SDValue Shl = SecondOperand.getOperand(0);

if (!(CN = dyn_cast<ConstantSDNode>(Shl.getOperand(1))))
return SDValue();
Expand All @@ -928,7 +971,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
return DAG.getNode(MipsISD::Ins, DL, ValTy, Shl.getOperand(0),
DAG.getConstant(SMPos0, DL, MVT::i32),
DAG.getConstant(SMSize0, DL, MVT::i32),
And0.getOperand(0));
FirstOperand.getOperand(0));
} else {
// Pattern match DINS.
// $dst = or (and $src, mask0), mask1
Expand All @@ -938,9 +981,9 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
((SMSize0 + SMPos0 <= 64 && Subtarget.hasMips64r2()) ||
(SMSize0 + SMPos0 <= 32))) {
// Check if AND instruction has constant as argument
bool isConstCase = And1.getOpcode() != ISD::AND;
if (And1.getOpcode() == ISD::AND) {
if (!(CN1 = dyn_cast<ConstantSDNode>(And1->getOperand(1))))
bool isConstCase = SecondOperand.getOpcode() != ISD::AND;
if (SecondOperand.getOpcode() == ISD::AND) {
if (!(CN1 = dyn_cast<ConstantSDNode>(SecondOperand->getOperand(1))))
return SDValue();
} else {
if (!(CN1 = dyn_cast<ConstantSDNode>(N->getOperand(1))))
Expand All @@ -957,7 +1000,8 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
SDValue SrlX;
if (!isConstCase) {
Const1 = DAG.getConstant(SMPos0, DL, MVT::i32);
SrlX = DAG.getNode(ISD::SRL, DL, And1->getValueType(0), And1, Const1);
SrlX = DAG.getNode(ISD::SRL, DL, SecondOperand->getValueType(0),
SecondOperand, Const1);
}
return DAG.getNode(
MipsISD::Ins, DL, N->getValueType(0),
Expand All @@ -968,8 +1012,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
DAG.getConstant(ValTy.getSizeInBits() / 8 < 8 ? SMSize0 & 31
: SMSize0,
DL, MVT::i32),
And0->getOperand(0));

FirstOperand->getOperand(0));
}
return SDValue();
}
Expand Down
60 changes: 60 additions & 0 deletions llvm/test/CodeGen/Mips/ins.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
; RUN: llc -O3 -mcpu=mips32r2 -mtriple=mipsel-linux-gnu < %s -o - \
; RUN: | FileCheck %s --check-prefixes=MIPS32R2
; RUN: llc -O3 -mcpu=mips64r2 -march=mips64el < %s \
; RUN: | FileCheck %s --check-prefixes=MIPS64R2

define i32 @or_and_shl(i32 %a, i32 %b) {
; MIPS32R2-LABEL: or_and_shl:
; MIPS32R2: # %bb.0: # %entry
; MIPS32R2-NEXT: ins $4, $5, 31, 1
; MIPS32R2-NEXT: jr $ra
; MIPS32R2-NEXT: move $2, $4

entry:
%shl = shl i32 %b, 31
%and = and i32 %a, 2147483647
%or = or i32 %and, %shl
ret i32 %or
}

define i32 @or_shl_and(i32 %a, i32 %b) {
; MIPS32R2-LABEL: or_shl_and:
; MIPS32R2: # %bb.0: # %entry
; MIPS32R2-NEXT: ins $4, $5, 31, 1
; MIPS32R2-NEXT: jr $ra
; MIPS32R2-NEXT: move $2, $4

entry:
%shl = shl i32 %b, 31
%and = and i32 %a, 2147483647
%or = or i32 %shl, %and
ret i32 %or
}

define i64 @dinsm(i64 %a, i64 %b) {
; MIPS64R2-LABEL: dinsm:
; MIPS64R2: # %bb.0: # %entry
; MIPS64R2-NEXT: dinsm $4, $5, 17, 47
; MIPS64R2-NEXT: jr $ra
; MIPS64R2-NEXT: move $2, $4

entry:
%shl = shl i64 %b, 17
%and = and i64 %a, 131071
%or = or i64 %shl, %and
ret i64 %or
}

define i64 @dinsu(i64 %a, i64 %b) {
; MIPS64R2-LABEL: dinsu:
; MIPS64R2: # %bb.0: # %entry
; MIPS64R2-NEXT: dinsu $4, $5, 35, 29
; MIPS64R2-NEXT: jr $ra
; MIPS64R2-NEXT: move $2, $4

entry:
%shl = shl i64 %b, 35
%and = and i64 %a, 34359738367
%or = or i64 %shl, %and
ret i64 %or
}

0 comments on commit 1ad84d7

Please sign in to comment.