[LoongArch] Lower ANY_EXTEND to ZERO_EXTEND under LASX to avoid scalarization (#201099)

Some integer/floating-point conversion will generate ANY_EXTEND under
LASX, lowering it to ZERO_EXTEND to avoid scalarization.
This commit is contained in:
lrzlin 2026-07-08 16:55:51 +08:00 committed by GitHub
parent f02b48182b
commit 063ac503e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 12 deletions

View file

@ -491,6 +491,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
for (MVT VT : {MVT::v4i64, MVT::v8i32, MVT::v16i16}) {
setOperationAction(ISD::SIGN_EXTEND, VT, Legal);
setOperationAction(ISD::ZERO_EXTEND, VT, Legal);
setOperationAction(ISD::ANY_EXTEND, VT, Custom);
}
for (MVT VT :
{MVT::v2i64, MVT::v4i32, MVT::v4i64, MVT::v8i16, MVT::v8i32}) {
@ -678,6 +679,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return lowerSIGN_EXTEND_VECTOR_INREG(Op, DAG);
case ISD::DYNAMIC_STACKALLOC:
return lowerDYNAMIC_STACKALLOC(Op, DAG);
case ISD::ANY_EXTEND:
return lowerANY_EXTEND(Op, DAG);
}
return SDValue();
}
@ -1027,6 +1030,16 @@ SDValue LoongArchTargetLowering::lowerSIGN_EXTEND_VECTOR_INREG(
return SDValue();
}
// ANY_EXTEND can be replaced by ZERO_EXTEND when LASX is enabled.
SDValue LoongArchTargetLowering::lowerANY_EXTEND(SDValue Op,
SelectionDAG &DAG) const {
assert(Subtarget.hasExtLASX());
// We don't have corresponding instrunction for ANY_EXTEND, lowering it to
// ZERO_EXTEND won't break its semantics, while avoid scalar extract/insert.
return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), Op.getValueType(),
Op.getOperand(0));
}
// Lower vecreduce_add using vhaddw instructions.
// For Example:
// call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %a)

View file

@ -262,6 +262,7 @@ private:
SDValue lowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerSIGN_EXTEND_VECTOR_INREG(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerANY_EXTEND(SDValue Op, SelectionDAG &DAG) const;
bool isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const override;

View file

@ -0,0 +1,48 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA32
; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA64
define void @shuffle_any_ext_8i16_to_8i32(ptr %ptr, ptr %dst) nounwind {
; CHECK-LABEL: shuffle_any_ext_8i16_to_8i32:
; CHECK: # %bb.0:
; CHECK-NEXT: vld $vr0, $a0, 0
; CHECK-NEXT: vext2xv.wu.hu $xr0, $xr0
; CHECK-NEXT: xvst $xr0, $a1, 0
; CHECK-NEXT: ret
%x = load <8 x i16>, ptr %ptr
%y = shufflevector <8 x i16> %x, <8 x i16> poison, <16 x i32> <i32 0, i32 15, i32 1, i32 15, i32 2, i32 13, i32 3, i32 12, i32 4, i32 11, i32 5, i32 10, i32 6, i32 9, i32 7, i32 8>
%r = bitcast <16 x i16> %y to <8 x i32>
store <8 x i32> %r, ptr %dst
ret void
}
define void @shuffle_any_ext_16i8_to_16i16(ptr %ptr, ptr %dst) nounwind {
; CHECK-LABEL: shuffle_any_ext_16i8_to_16i16:
; CHECK: # %bb.0:
; CHECK-NEXT: vld $vr0, $a0, 0
; CHECK-NEXT: vext2xv.hu.bu $xr0, $xr0
; CHECK-NEXT: xvst $xr0, $a1, 0
; CHECK-NEXT: ret
%x = load <16 x i8>, ptr %ptr
%y = shufflevector <16 x i8> %x, <16 x i8> poison, <32 x i32> <i32 0, i32 31, i32 1, i32 31, i32 2, i32 29, i32 3, i32 28, i32 4, i32 27, i32 5, i32 26, i32 6, i32 25, i32 7, i32 24, i32 8, i32 23, i32 9, i32 22, i32 10, i32 21, i32 11, i32 20, i32 12, i32 19, i32 13, i32 18, i32 14, i32 17, i32 15, i32 16>
%r = bitcast <32 x i8> %y to <16 x i16>
store <16 x i16> %r, ptr %dst
ret void
}
define void @shuffle_any_ext_4i32_to_4i64(ptr %ptr, ptr %dst) nounwind {
; CHECK-LABEL: shuffle_any_ext_4i32_to_4i64:
; CHECK: # %bb.0:
; CHECK-NEXT: vld $vr0, $a0, 0
; CHECK-NEXT: vext2xv.du.wu $xr0, $xr0
; CHECK-NEXT: xvst $xr0, $a1, 0
; CHECK-NEXT: ret
%x = load <4 x i32>, ptr %ptr
%y = shufflevector <4 x i32> %x, <4 x i32> poison, <8 x i32> <i32 0, i32 7, i32 1, i32 6, i32 2, i32 5, i32 3, i32 4>
%r = bitcast <8 x i32> %y to <4 x i64>
store <4 x i64> %r, ptr %dst
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; LA32: {{.*}}
; LA64: {{.*}}

View file

@ -12,10 +12,7 @@ define void @xor_zext_masks_v4i64(ptr %res, ptr %a, ptr %b) nounwind {
; LA32-NEXT: xvpermi.d $xr0, $xr0, 216
; LA32-NEXT: vldi $vr1, -1777
; LA32-NEXT: vxor.v $vr0, $vr0, $vr1
; LA32-NEXT: vextrins.w $vr1, $vr0, 2
; LA32-NEXT: vextrins.w $vr1, $vr0, 35
; LA32-NEXT: vextrins.w $vr0, $vr0, 33
; LA32-NEXT: xvpermi.q $xr0, $xr1, 2
; LA32-NEXT: vext2xv.du.wu $xr0, $xr0
; LA32-NEXT: xvrepli.d $xr1, 1
; LA32-NEXT: xvand.v $xr0, $xr0, $xr1
; LA32-NEXT: xvst $xr0, $a0, 0
@ -173,10 +170,7 @@ define void @or_zext_masks_v4i64(ptr %res, ptr %a, ptr %b) nounwind {
; LA32-NEXT: xvpermi.d $xr0, $xr0, 216
; LA32-NEXT: vldi $vr1, -1777
; LA32-NEXT: vor.v $vr0, $vr0, $vr1
; LA32-NEXT: vextrins.w $vr1, $vr0, 2
; LA32-NEXT: vextrins.w $vr1, $vr0, 35
; LA32-NEXT: vextrins.w $vr0, $vr0, 33
; LA32-NEXT: xvpermi.q $xr0, $xr1, 2
; LA32-NEXT: vext2xv.du.wu $xr0, $xr0
; LA32-NEXT: xvrepli.d $xr1, 1
; LA32-NEXT: xvand.v $xr0, $xr0, $xr1
; LA32-NEXT: xvst $xr0, $a0, 0
@ -331,10 +325,7 @@ define void @and_zext_masks_v4i64(ptr %res, ptr %a, ptr %b) nounwind {
; LA32-NEXT: xvpermi.d $xr0, $xr0, 216
; LA32-NEXT: vldi $vr1, -1777
; LA32-NEXT: vand.v $vr0, $vr0, $vr1
; LA32-NEXT: vextrins.w $vr1, $vr0, 2
; LA32-NEXT: vextrins.w $vr1, $vr0, 35
; LA32-NEXT: vextrins.w $vr0, $vr0, 33
; LA32-NEXT: xvpermi.q $xr0, $xr1, 2
; LA32-NEXT: vext2xv.du.wu $xr0, $xr0
; LA32-NEXT: xvrepli.d $xr1, 1
; LA32-NEXT: xvand.v $xr0, $xr0, $xr1
; LA32-NEXT: xvst $xr0, $a0, 0