[llvm] f35cb7b - [LoongArch] Add codegen support for bswap

Weining Lu via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 8 22:51:31 PDT 2022


Author: WANG Xuerui
Date: 2022-08-09T13:42:03+08:00
New Revision: f35cb7ba344b4de654c78f8a8d63a455e52588aa

URL: https://github.com/llvm/llvm-project/commit/f35cb7ba344b4de654c78f8a8d63a455e52588aa
DIFF: https://github.com/llvm/llvm-project/commit/f35cb7ba344b4de654c78f8a8d63a455e52588aa.diff

LOG: [LoongArch] Add codegen support for bswap

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

Added: 
    llvm/test/CodeGen/LoongArch/bswap.ll

Modified: 
    llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchISelLowering.h
    llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 08833d7c5b22..a4641e61ae83 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -69,6 +69,14 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
       setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
   }
 
+  // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
+  // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
+  // and i32 could still be byte-swapped relatively cheaply.
+  setOperationAction(ISD::BSWAP, MVT::i16, Custom);
+  if (Subtarget.is64Bit()) {
+    setOperationAction(ISD::BSWAP, MVT::i32, Custom);
+  }
+
   static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE,
                                                ISD::SETUGT, ISD::SETUGE};
 
@@ -131,6 +139,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
     assert(Op.getOperand(1).getValueType() == MVT::i32 && Subtarget.is64Bit() &&
            "Unexpected custom legalisation");
     return SDValue();
+  case ISD::BSWAP:
+    return SDValue();
   case ISD::ConstantPool:
     return lowerConstantPool(Op, DAG);
   case ISD::FP_TO_SINT:
@@ -418,6 +428,29 @@ void LoongArchTargetLowering::ReplaceNodeResults(
     Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
     break;
   }
+  case ISD::BSWAP: {
+    SDValue Src = N->getOperand(0);
+    EVT VT = N->getValueType(0);
+    assert((VT == MVT::i16 || VT == MVT::i32) &&
+           "Unexpected custom legalization");
+    MVT GRLenVT = Subtarget.getGRLenVT();
+    SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
+    SDValue Tmp;
+    switch (VT.getSizeInBits()) {
+    default:
+      llvm_unreachable("Unexpected operand width");
+    case 16:
+      Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
+      break;
+    case 32:
+      // Only LA64 will get to here due to the size mismatch between VT and
+      // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
+      Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
+      break;
+    }
+    Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
+    break;
+  }
   }
 }
 
@@ -847,6 +880,8 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
     NODE_NAME_CASE(MOVGR2FR_W_LA64)
     NODE_NAME_CASE(MOVFR2GR_S_LA64)
     NODE_NAME_CASE(FTINT)
+    NODE_NAME_CASE(REVB_2H)
+    NODE_NAME_CASE(REVB_2W)
   }
 #undef NODE_NAME_CASE
   return nullptr;

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 5589bf6a0f5c..9ab567713c2f 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -44,6 +44,9 @@ enum NodeType : unsigned {
   BSTRINS,
   BSTRPICK,
 
+  // Byte swapping operations
+  REVB_2H,
+  REVB_2W,
 };
 } // end namespace LoongArchISD
 

diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index faffe95c1e77..41df630b6b33 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -55,6 +55,8 @@ def loongarch_bstrins
     : SDNode<"LoongArchISD::BSTRINS", SDT_LoongArchBStrIns>;
 def loongarch_bstrpick
     : SDNode<"LoongArchISD::BSTRPICK", SDT_LoongArchBStrPick>;
+def loongarch_revb_2h : SDNode<"LoongArchISD::REVB_2H", SDTUnaryOp>;
+def loongarch_revb_2w : SDNode<"LoongArchISD::REVB_2W", SDTUnaryOp>;
 
 //===----------------------------------------------------------------------===//
 // Operand and SDNode transformation definitions.
@@ -816,6 +818,19 @@ def : Pat<(loongarch_bstrpick GPR:$rj, uimm6:$msbd, uimm6:$lsbd),
           (BSTRPICK_D GPR:$rj, uimm6:$msbd, uimm6:$lsbd)>;
 } // Predicates = [IsLA64]
 
+/// Byte-swapping
+
+def : Pat<(loongarch_revb_2h GPR:$rj), (REVB_2H GPR:$rj)>;
+
+let Predicates = [IsLA32] in {
+def : Pat<(bswap GPR:$rj), (ROTRI_W (REVB_2H GPR:$rj), 16)>;
+} // Predicates = [IsLA32]
+
+let Predicates = [IsLA64] in {
+def : Pat<(loongarch_revb_2w GPR:$rj), (REVB_2W GPR:$rj)>;
+def : Pat<(bswap GPR:$rj), (REVB_D GPR:$rj)>;
+} // Predicates = [IsLA64]
+
 /// Loads
 
 multiclass LdPat<PatFrag LoadOp, LAInst Inst, ValueType vt = GRLenVT> {

diff  --git a/llvm/test/CodeGen/LoongArch/bswap.ll b/llvm/test/CodeGen/LoongArch/bswap.ll
new file mode 100644
index 000000000000..1d2b0c3e9be2
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/bswap.ll
@@ -0,0 +1,151 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=loongarch32 --verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32
+; RUN: llc -mtriple=loongarch64 --verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64
+
+declare i16 @llvm.bswap.i16(i16)
+declare i32 @llvm.bswap.i32(i32)
+declare i48 @llvm.bswap.i48(i48)
+declare i64 @llvm.bswap.i64(i64)
+declare i80 @llvm.bswap.i80(i80)
+declare i128 @llvm.bswap.i128(i128)
+
+define i16 @test_bswap_i16(i16 %a) nounwind {
+; LA32-LABEL: test_bswap_i16:
+; LA32:       # %bb.0:
+; LA32-NEXT:    revb.2h $a0, $a0
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i16:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.2h $a0, $a0
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i16 @llvm.bswap.i16(i16 %a)
+  ret i16 %tmp
+}
+
+define i32 @test_bswap_i32(i32 %a) nounwind {
+; LA32-LABEL: test_bswap_i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    revb.2h $a0, $a0
+; LA32-NEXT:    rotri.w $a0, $a0, 16
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.2w $a0, $a0
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i32 @llvm.bswap.i32(i32 %a)
+  ret i32 %tmp
+}
+
+define i64 @test_bswap_i64(i64 %a) nounwind {
+; LA32-LABEL: test_bswap_i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    revb.2h $a1, $a1
+; LA32-NEXT:    rotri.w $a2, $a1, 16
+; LA32-NEXT:    revb.2h $a0, $a0
+; LA32-NEXT:    rotri.w $a1, $a0, 16
+; LA32-NEXT:    move $a0, $a2
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.d $a0, $a0
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i64 @llvm.bswap.i64(i64 %a)
+  ret i64 %tmp
+}
+
+;; Bswap on non-native integer widths.
+
+define i48 @test_bswap_i48(i48 %a) nounwind {
+; LA32-LABEL: test_bswap_i48:
+; LA32:       # %bb.0:
+; LA32-NEXT:    revb.2h $a1, $a1
+; LA32-NEXT:    rotri.w $a1, $a1, 16
+; LA32-NEXT:    srli.w $a1, $a1, 16
+; LA32-NEXT:    revb.2h $a0, $a0
+; LA32-NEXT:    rotri.w $a2, $a0, 16
+; LA32-NEXT:    slli.w $a0, $a2, 16
+; LA32-NEXT:    or $a0, $a1, $a0
+; LA32-NEXT:    srli.w $a1, $a2, 16
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i48:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.d $a0, $a0
+; LA64-NEXT:    srli.d $a0, $a0, 16
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i48 @llvm.bswap.i48(i48 %a)
+  ret i48 %tmp
+}
+
+define i80 @test_bswap_i80(i80 %a) nounwind {
+; LA32-LABEL: test_bswap_i80:
+; LA32:       # %bb.0:
+; LA32-NEXT:    ld.w $a2, $a1, 0
+; LA32-NEXT:    revb.2h $a2, $a2
+; LA32-NEXT:    rotri.w $a2, $a2, 16
+; LA32-NEXT:    ld.w $a3, $a1, 4
+; LA32-NEXT:    revb.2h $a3, $a3
+; LA32-NEXT:    rotri.w $a3, $a3, 16
+; LA32-NEXT:    srli.w $a4, $a3, 16
+; LA32-NEXT:    slli.w $a5, $a2, 16
+; LA32-NEXT:    or $a4, $a5, $a4
+; LA32-NEXT:    srli.w $a2, $a2, 16
+; LA32-NEXT:    st.h $a2, $a0, 8
+; LA32-NEXT:    st.w $a4, $a0, 4
+; LA32-NEXT:    slli.w $a2, $a3, 16
+; LA32-NEXT:    ld.w $a1, $a1, 8
+; LA32-NEXT:    revb.2h $a1, $a1
+; LA32-NEXT:    rotri.w $a1, $a1, 16
+; LA32-NEXT:    srli.w $a1, $a1, 16
+; LA32-NEXT:    or $a1, $a1, $a2
+; LA32-NEXT:    st.w $a1, $a0, 0
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i80:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.d $a1, $a1
+; LA64-NEXT:    srli.d $a1, $a1, 48
+; LA64-NEXT:    revb.d $a2, $a0
+; LA64-NEXT:    slli.d $a0, $a2, 16
+; LA64-NEXT:    or $a0, $a1, $a0
+; LA64-NEXT:    srli.d $a1, $a2, 48
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i80 @llvm.bswap.i80(i80 %a)
+  ret i80 %tmp
+}
+
+define i128 @test_bswap_i128(i128 %a) nounwind {
+; LA32-LABEL: test_bswap_i128:
+; LA32:       # %bb.0:
+; LA32-NEXT:    ld.w $a2, $a1, 0
+; LA32-NEXT:    revb.2h $a2, $a2
+; LA32-NEXT:    rotri.w $a2, $a2, 16
+; LA32-NEXT:    st.w $a2, $a0, 12
+; LA32-NEXT:    ld.w $a2, $a1, 4
+; LA32-NEXT:    revb.2h $a2, $a2
+; LA32-NEXT:    rotri.w $a2, $a2, 16
+; LA32-NEXT:    st.w $a2, $a0, 8
+; LA32-NEXT:    ld.w $a2, $a1, 8
+; LA32-NEXT:    revb.2h $a2, $a2
+; LA32-NEXT:    rotri.w $a2, $a2, 16
+; LA32-NEXT:    st.w $a2, $a0, 4
+; LA32-NEXT:    ld.w $a1, $a1, 12
+; LA32-NEXT:    revb.2h $a1, $a1
+; LA32-NEXT:    rotri.w $a1, $a1, 16
+; LA32-NEXT:    st.w $a1, $a0, 0
+; LA32-NEXT:    jirl $zero, $ra, 0
+;
+; LA64-LABEL: test_bswap_i128:
+; LA64:       # %bb.0:
+; LA64-NEXT:    revb.d $a2, $a1
+; LA64-NEXT:    revb.d $a1, $a0
+; LA64-NEXT:    move $a0, $a2
+; LA64-NEXT:    jirl $zero, $ra, 0
+  %tmp = call i128 @llvm.bswap.i128(i128 %a)
+  ret i128 %tmp
+}


        


More information about the llvm-commits mailing list