Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 34 additions & 19 deletions llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,44 +113,59 @@ void LoongArchDAGToDAGISel::Select(SDNode *Node) {
APInt SplatValue, SplatUndef;
unsigned SplatBitSize;
bool HasAnyUndefs;
unsigned Op;
unsigned Op = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unnecessary to initialize it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without initialization, a warning will occur. I'm not sure why it didn't happen before.

[44/185] Building CXX object lib/Target/LoongArch/CMakeFiles/LLVMLoongArchCodeGen.dir/LoongArchISelDAGToDAG.cpp.o
/home/yangzhaoxin/workspace/flang-test/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp:131:7: warning: variable 'Op' is used uninitialized whenever switch default is taken [-Wsometimes-uninitialized]
  131 |       default:
      |       ^~~~~~~
/home/yangzhaoxin/workspace/flang-test/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp:150:36: note: uninitialized use occurs here
  150 |       Res = CurDAG->getMachineNode(Op, DL, ResTy, Imm);
      |                                    ^~
/home/yangzhaoxin/workspace/flang-test/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp:116:16: note: initialize the variable 'Op' to silence this warning
  116 |     unsigned Op;
      |                ^
      |                 = 0
1 warning generated.

EVT ResTy = BVN->getValueType(0);
bool Is128Vec = BVN->getValueType(0).is128BitVector();
bool Is256Vec = BVN->getValueType(0).is256BitVector();
SDNode *Res;

if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))
break;
if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
HasAnyUndefs, 8))
break;

switch (SplatBitSize) {
default:
break;
case 8:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
break;
case 16:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
break;
case 32:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
break;
case 64:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
break;
}

SDNode *Res;
// If we have a signed 10 bit integer, we can splat it directly.
if (SplatValue.isSignedIntN(10)) {
switch (SplatBitSize) {
default:
break;
case 8:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;
break;
case 16:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;
break;
case 32:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;
break;
case 64:
Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;
break;
}

EVT EleType = ResTy.getVectorElementType();
APInt Val = SplatValue.sextOrTrunc(EleType.getSizeInBits());
SDValue Imm = CurDAG->getTargetConstant(Val, DL, EleType);
Res = CurDAG->getMachineNode(Op, DL, ResTy, Imm);
ReplaceNode(Node, Res);
return;
}

// Select appropriate [x]vldi instructions for some special constant splats,
// where the immediate value `imm[12] == 1` for used [x]vldi instructions.
const auto &TLI =
*static_cast<const LoongArchTargetLowering *>(getTargetLowering());
std::pair<bool, uint64_t> ConvertVLDI =
TLI.isImmVLDILegalForMode1(SplatValue, SplatBitSize);
if (ConvertVLDI.first) {
Op = Is256Vec ? LoongArch::XVLDI : LoongArch::VLDI;
SDValue Imm = CurDAG->getSignedTargetConstant(
SignExtend32<13>(ConvertVLDI.second), DL, MVT::i32);
Res = CurDAG->getMachineNode(Op, DL, ResTy, Imm);
ReplaceNode(Node, Res);
return;
}
break;
}
}
Expand Down
86 changes: 84 additions & 2 deletions llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2815,9 +2815,10 @@ SDValue LoongArchTargetLowering::lowerBUILD_VECTOR(SDValue Op,

if (SplatBitSize == 64 && !Subtarget.is64Bit()) {
// We can only handle 64-bit elements that are within
// the signed 10-bit range on 32-bit targets.
// the signed 10-bit range or match vldi patterns on 32-bit targets.
// See the BUILD_VECTOR case in LoongArchDAGToDAGISel::Select().
if (!SplatValue.isSignedIntN(10))
if (!SplatValue.isSignedIntN(10) &&
!isImmVLDILegalForMode1(SplatValue, SplatBitSize).first)
return SDValue();
if ((Is128Vec && ResTy == MVT::v4i32) ||
(Is256Vec && ResTy == MVT::v8i32))
Expand Down Expand Up @@ -8507,6 +8508,87 @@ SDValue LoongArchTargetLowering::LowerReturn(
return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
}

// Check if a constant splat can be generated using [x]vldi, where imm[12] == 1.
// Note: The following prefixes are excluded:
// imm[11:8] == 4'b0000, 4'b0100, 4'b1000
// as they can be represented using [x]vrepli.[whb]
std::pair<bool, uint64_t> LoongArchTargetLowering::isImmVLDILegalForMode1(
const APInt &SplatValue, const unsigned SplatBitSize) const {
uint64_t RequiredImm = 0;
uint64_t V = SplatValue.getZExtValue();
if (SplatBitSize == 16 && !(V & 0x00FF)) {
// 4'b0101
RequiredImm = (0b10101 << 8) | (V >> 8);
return {true, RequiredImm};
} else if (SplatBitSize == 32) {
// 4'b0001
if (!(V & 0xFFFF00FF)) {
RequiredImm = (0b10001 << 8) | (V >> 8);
return {true, RequiredImm};
}
// 4'b0010
if (!(V & 0xFF00FFFF)) {
RequiredImm = (0b10010 << 8) | (V >> 16);
return {true, RequiredImm};
}
// 4'b0011
if (!(V & 0x00FFFFFF)) {
RequiredImm = (0b10011 << 8) | (V >> 24);
return {true, RequiredImm};
}
// 4'b0110
if ((V & 0xFFFF00FF) == 0xFF) {
RequiredImm = (0b10110 << 8) | (V >> 8);
return {true, RequiredImm};
}
// 4'b0111
if ((V & 0xFF00FFFF) == 0xFFFF) {
RequiredImm = (0b10111 << 8) | (V >> 16);
return {true, RequiredImm};
}
// 4'b1010
if ((V & 0x7E07FFFF) == 0x3E000000 || (V & 0x7E07FFFF) == 0x40000000) {
RequiredImm =
(0b11010 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
return {true, RequiredImm};
}
} else if (SplatBitSize == 64) {
// 4'b1011
if ((V & 0xFFFFFFFF7E07FFFFULL) == 0x3E000000ULL ||
(V & 0xFFFFFFFF7E07FFFFULL) == 0x40000000ULL) {
RequiredImm =
(0b11011 << 8) | (((V >> 24) & 0xC0) ^ 0x40) | ((V >> 19) & 0x3F);
return {true, RequiredImm};
}
// 4'b1100
if ((V & 0x7FC0FFFFFFFFFFFFULL) == 0x4000000000000000ULL ||
(V & 0x7FC0FFFFFFFFFFFFULL) == 0x3FC0000000000000ULL) {
RequiredImm =
(0b11100 << 8) | (((V >> 56) & 0xC0) ^ 0x40) | ((V >> 48) & 0x3F);
return {true, RequiredImm};
}
// 4'b1001
auto sameBitsPreByte = [](uint64_t x) -> std::pair<bool, uint8_t> {
uint8_t res = 0;
for (int i = 0; i < 8; ++i) {
uint8_t byte = x & 0xFF;
if (byte == 0 || byte == 0xFF)
res |= ((byte & 1) << i);
else
return {false, 0};
x >>= 8;
}
return {true, res};
};
auto [IsSame, Suffix] = sameBitsPreByte(V);
if (IsSame) {
RequiredImm = (0b11001 << 8) | Suffix;
return {true, RequiredImm};
}
}
return {false, RequiredImm};
}

bool LoongArchTargetLowering::isFPImmVLDILegal(const APFloat &Imm,
EVT VT) const {
if (!Subtarget.hasExtLSX())
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ class LoongArchTargetLowering : public TargetLowering {

bool shouldScalarizeBinop(SDValue VecOp) const override;

/// Check if a constant splat can be generated using [x]vldi, where imm[12]
/// is 1.
std::pair<bool, uint64_t>
isImmVLDILegalForMode1(const APInt &SplatValue,
const unsigned SplatBitSize) const;

private:
/// Target-specific function used to lower LoongArch calling conventions.
typedef bool LoongArchCCAssignFn(const DataLayout &DL, LoongArchABI::ABI ABI,
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ def vsplatf32_fpimm_eq_1
N = N->getOperand(0).getNode();

return selectVSplat(N, Imm, EltTy.getSizeInBits()) &&
Imm.getBitWidth() == 32 &&
Imm.getBitWidth() == EltTy.getSizeInBits() &&
Imm == APFloat(+1.0f).bitcastToAPInt();
}]>;
Expand Down
80 changes: 23 additions & 57 deletions llvm/test/CodeGen/LoongArch/lasx/build-vector.ll
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,7 @@ entry:
define void @buildvector_v8f32_const_splat(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_v8f32_const_splat:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: lu12i.w $a1, 260096
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -1424
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -207,19 +206,11 @@ entry:

;; Also check buildvector_const_splat_xvldi_1100.
define void @buildvector_v4f64_const_splat(ptr %dst) nounwind {
; LA32-LABEL: buildvector_v4f64_const_splat:
; LA32: # %bb.0: # %entry
; LA32-NEXT: pcalau12i $a1, %pc_hi20(.LCPI14_0)
; LA32-NEXT: xvld $xr0, $a1, %pc_lo12(.LCPI14_0)
; LA32-NEXT: xvst $xr0, $a0, 0
; LA32-NEXT: ret
;
; LA64-LABEL: buildvector_v4f64_const_splat:
; LA64: # %bb.0: # %entry
; LA64-NEXT: lu52i.d $a1, $zero, 1023
; LA64-NEXT: xvreplgr2vr.d $xr0, $a1
; LA64-NEXT: xvst $xr0, $a0, 0
; LA64-NEXT: ret
; CHECK-LABEL: buildvector_v4f64_const_splat:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: xvldi $xr0, -912
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
store <4 x double> <double 1.0, double 1.0, double 1.0, double 1.0>, ptr %dst
ret void
Expand All @@ -229,8 +220,7 @@ entry:
define void @buildvector_const_splat_xvldi_0001(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_const_splat_xvldi_0001:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: ori $a1, $zero, 768
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -3837
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -241,8 +231,7 @@ entry:
define void @buildvector_const_splat_xvldi_0010(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_const_splat_xvldi_0010:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: lu12i.w $a1, 16
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -3583
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -253,8 +242,7 @@ entry:
define void @buildvector_const_splat_xvldi_0011(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_const_splat_xvldi_0011:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: lu12i.w $a1, 4096
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -3327
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -265,8 +253,7 @@ entry:
define void @buildvector_const_splat_xvldi_0101(ptr %dst) {
; CHECK-LABEL: buildvector_const_splat_xvldi_0101:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: ori $a1, $zero, 768
; CHECK-NEXT: xvreplgr2vr.h $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -2813
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -277,8 +264,7 @@ entry:
define void @buildvector_const_splat_xvldi_0110(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_const_splat_xvldi_0110:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: ori $a1, $zero, 1023
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -2557
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -289,9 +275,7 @@ entry:
define void @buildvector_const_splat_xvldi_0111(ptr %dst) nounwind {
; CHECK-LABEL: buildvector_const_splat_xvldi_0111:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: lu12i.w $a1, 15
; CHECK-NEXT: ori $a1, $a1, 4095
; CHECK-NEXT: xvreplgr2vr.w $xr0, $a1
; CHECK-NEXT: xvldi $xr0, -2305
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
Expand All @@ -300,39 +284,22 @@ entry:
}

define void @buildvector_const_splat_xvldi_1001(ptr %dst) nounwind {
; LA32-LABEL: buildvector_const_splat_xvldi_1001:
; LA32: # %bb.0: # %entry
; LA32-NEXT: pcalau12i $a1, %pc_hi20(.LCPI21_0)
; LA32-NEXT: xvld $xr0, $a1, %pc_lo12(.LCPI21_0)
; LA32-NEXT: xvst $xr0, $a0, 0
; LA32-NEXT: ret
;
; LA64-LABEL: buildvector_const_splat_xvldi_1001:
; LA64: # %bb.0: # %entry
; LA64-NEXT: lu12i.w $a1, 15
; LA64-NEXT: ori $a1, $a1, 4095
; LA64-NEXT: xvreplgr2vr.d $xr0, $a1
; LA64-NEXT: xvst $xr0, $a0, 0
; LA64-NEXT: ret
; CHECK-LABEL: buildvector_const_splat_xvldi_1001:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: xvldi $xr0, -1789
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
store <8 x i32> <i32 65535, i32 0, i32 65535, i32 0, i32 65535, i32 0, i32 65535, i32 0>, ptr %dst
ret void
}

define void @buildvector_const_splat_xvldi_1011(ptr %dst) nounwind {
; LA32-LABEL: buildvector_const_splat_xvldi_1011:
; LA32: # %bb.0: # %entry
; LA32-NEXT: pcalau12i $a1, %pc_hi20(.LCPI22_0)
; LA32-NEXT: xvld $xr0, $a1, %pc_lo12(.LCPI22_0)
; LA32-NEXT: xvst $xr0, $a0, 0
; LA32-NEXT: ret
;
; LA64-LABEL: buildvector_const_splat_xvldi_1011:
; LA64: # %bb.0: # %entry
; LA64-NEXT: lu12i.w $a1, 262144
; LA64-NEXT: xvreplgr2vr.d $xr0, $a1
; LA64-NEXT: xvst $xr0, $a0, 0
; LA64-NEXT: ret
; CHECK-LABEL: buildvector_const_splat_xvldi_1011:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: xvldi $xr0, -1280
; CHECK-NEXT: xvst $xr0, $a0, 0
; CHECK-NEXT: ret
entry:
store <8 x float> <float 2.0, float 0.0, float 2.0, float 0.0, float 2.0, float 0.0, float 2.0, float 0.0>, ptr %dst
ret void
Expand Down Expand Up @@ -1626,8 +1593,7 @@ define void @buildvector_v8f32_with_constant(ptr %dst, float %a1, float %a2, flo
; CHECK-NEXT: # kill: def $f2 killed $f2 def $xr2
; CHECK-NEXT: # kill: def $f1 killed $f1 def $xr1
; CHECK-NEXT: # kill: def $f0 killed $f0 def $xr0
; CHECK-NEXT: lu12i.w $a1, 262144
; CHECK-NEXT: xvreplgr2vr.w $xr4, $a1
; CHECK-NEXT: xvldi $xr4, -3264
; CHECK-NEXT: xvinsve0.w $xr4, $xr0, 1
; CHECK-NEXT: xvinsve0.w $xr4, $xr1, 2
; CHECK-NEXT: xvinsve0.w $xr4, $xr2, 5
Expand Down
Loading