Skip to content

Commit 53141b2

Browse files
committed
[LoongArch] Add LSX intrinsic support
For handling intrinsics, our approach is not simply to match them one-to-one with instructions. Instead, we lower some intrinsics to common nodes and then perform matching. The advantage of this approach is that it allows us to fully utilize the passes available at the common layer for optimizing purposes. We perform error checks on the immediate operand of all intrinsics, rather than waiting until the end to throw exceptions. Reviewed By: SixWeining Differential Revision: https://reviews.llvm.org/D155829
1 parent d188916 commit 53141b2

File tree

8 files changed

+2359
-23
lines changed

8 files changed

+2359
-23
lines changed

llvm/include/llvm/IR/IntrinsicsLoongArch.td

Lines changed: 524 additions & 0 deletions
Large diffs are not rendered by default.

llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1616
#include "MCTargetDesc/LoongArchMatInt.h"
1717
#include "llvm/Support/KnownBits.h"
18+
#include "llvm/Support/raw_ostream.h"
1819

1920
using namespace llvm;
2021

@@ -75,7 +76,14 @@ void LoongArchDAGToDAGISel::Select(SDNode *Node) {
7576
ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
7677
return;
7778
}
78-
// TODO: Add selection nodes needed later.
79+
case ISD::BITCAST: {
80+
if (VT.is128BitVector() || VT.is512BitVector()) {
81+
ReplaceUses(SDValue(Node, 0), Node->getOperand(0));
82+
CurDAG->RemoveDeadNode(Node);
83+
return;
84+
}
85+
break;
86+
}
7987
}
8088

8189
// Select the default instruction.
@@ -262,6 +270,96 @@ bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
262270
return false;
263271
}
264272

273+
bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,
274+
unsigned MinSizeInBits) const {
275+
if (!Subtarget->hasExtLSX())
276+
return false;
277+
278+
BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);
279+
280+
if (!Node)
281+
return false;
282+
283+
APInt SplatValue, SplatUndef;
284+
unsigned SplatBitSize;
285+
bool HasAnyUndefs;
286+
287+
if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
288+
MinSizeInBits, /*IsBigEndian=*/false))
289+
return false;
290+
291+
Imm = SplatValue;
292+
293+
return true;
294+
}
295+
296+
template <unsigned ImmBitSize, bool IsSigned>
297+
bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {
298+
APInt ImmValue;
299+
EVT EltTy = N->getValueType(0).getVectorElementType();
300+
301+
if (N->getOpcode() == ISD::BITCAST)
302+
N = N->getOperand(0);
303+
304+
if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
305+
ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
306+
if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {
307+
SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),
308+
Subtarget->getGRLenVT());
309+
return true;
310+
}
311+
if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {
312+
SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),
313+
Subtarget->getGRLenVT());
314+
return true;
315+
}
316+
}
317+
318+
return false;
319+
}
320+
321+
bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,
322+
SDValue &SplatImm) const {
323+
APInt ImmValue;
324+
EVT EltTy = N->getValueType(0).getVectorElementType();
325+
326+
if (N->getOpcode() == ISD::BITCAST)
327+
N = N->getOperand(0);
328+
329+
if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
330+
ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
331+
int32_t Log2 = (~ImmValue).exactLogBase2();
332+
333+
if (Log2 != -1) {
334+
SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
335+
return true;
336+
}
337+
}
338+
339+
return false;
340+
}
341+
342+
bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,
343+
SDValue &SplatImm) const {
344+
APInt ImmValue;
345+
EVT EltTy = N->getValueType(0).getVectorElementType();
346+
347+
if (N->getOpcode() == ISD::BITCAST)
348+
N = N->getOperand(0);
349+
350+
if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&
351+
ImmValue.getBitWidth() == EltTy.getSizeInBits()) {
352+
int32_t Log2 = ImmValue.exactLogBase2();
353+
354+
if (Log2 != -1) {
355+
SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);
356+
return true;
357+
}
358+
}
359+
360+
return false;
361+
}
362+
265363
// This pass converts a legalized DAG into a LoongArch-specific DAG, ready
266364
// for instruction scheduling.
267365
FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {

llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ class LoongArchDAGToDAGISel : public SelectionDAGISel {
5656
bool selectSExti32(SDValue N, SDValue &Val);
5757
bool selectZExti32(SDValue N, SDValue &Val);
5858

59+
bool selectVSplat(SDNode *N, APInt &Imm, unsigned MinSizeInBits) const;
60+
61+
template <unsigned ImmSize, bool IsSigned = false>
62+
bool selectVSplatImm(SDValue N, SDValue &SplatVal);
63+
64+
bool selectVSplatUimmInvPow2(SDValue N, SDValue &SplatImm) const;
65+
bool selectVSplatUimmPow2(SDValue N, SDValue &SplatImm) const;
66+
5967
// Include the pieces autogenerated from the target description.
6068
#include "LoongArchGenDAGISel.inc"
6169
};

0 commit comments

Comments
 (0)