From 407b613d7344a37662a9933d5684dd207917e577 Mon Sep 17 00:00:00 2001 From: wanglei Date: Fri, 15 Apr 2022 11:43:36 +0800 Subject: [PATCH] [LoongArch] Add support for selecting constant materializations. Integer materializing can generate LU12I_W, ORI, LU32I_D, LU52I_D and ADDI_W instructions. According to the sign-extended behavior of these instructions (except ORI), the generated instruction sequence can be improved. For example, load -1 into general register: The ADDI_W instruction performs the operation that the [31:0] bit data in the general register `rj` plus the 12-bit immediate `simm12` sign extension 32-bit data; the resultant [31:0] bit is sign extension, then written into the general register `rd`. Normal sequence: ``` lu12i.w $a0, -1 ori $a0, $a0, 2048 ``` Improved with sign-extended instruction: ``` addi.w $a0, $zero, -1 ``` Reviewed By: SixWeining, MaskRay Differential Revision: https://reviews.llvm.org/D123290 --- .../LoongArch/LoongArchISelDAGToDAG.cpp | 20 +++ .../LoongArch/MCTargetDesc/CMakeLists.txt | 1 + .../MCTargetDesc/LoongArchMatInt.cpp | 51 ++++++ .../LoongArch/MCTargetDesc/LoongArchMatInt.h | 30 ++++ llvm/test/CodeGen/LoongArch/imm.ll | 157 ++++++++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.cpp create mode 100644 llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h create mode 100644 llvm/test/CodeGen/LoongArch/imm.ll diff --git a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp index e754dabc002f..13d7218d3641 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp @@ -12,6 +12,7 @@ #include "LoongArchISelDAGToDAG.h" #include "MCTargetDesc/LoongArchMCTargetDesc.h" +#include "MCTargetDesc/LoongArchMatInt.h" using namespace llvm; @@ -28,11 +29,30 @@ void LoongArchDAGToDAGISel::Select(SDNode *Node) { // Instruction Selection not handled by the auto-generated tablegen selection // should be handled here. unsigned Opcode = Node->getOpcode(); + MVT GRLenVT = Subtarget->getGRLenVT(); SDLoc DL(Node); switch (Opcode) { default: break; + case ISD::Constant: { + int64_t Imm = cast(Node)->getSExtValue(); + SDNode *Result = nullptr; + SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT); + + // The instructions in the sequence are handled here. + for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) { + SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT); + if (Inst.Opc == LoongArch::LU12I_W) + Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm); + else + Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm); + SrcReg = SDValue(Result, 0); + } + + ReplaceNode(Node, Result); + return; + } // TODO: Add selection nodes needed later. } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt index a97a68b5838c..2e1ca69a3e56 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMLoongArchDesc LoongArchMCAsmInfo.cpp LoongArchMCTargetDesc.cpp LoongArchMCCodeEmitter.cpp + LoongArchMatInt.cpp LINK_COMPONENTS MC diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.cpp new file mode 100644 index 000000000000..1509c436c810 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.cpp @@ -0,0 +1,51 @@ +//===- LoongArchMatInt.cpp - Immediate materialisation ---------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LoongArchMatInt.h" +#include "MCTargetDesc/LoongArchMCTargetDesc.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +LoongArchMatInt::InstSeq LoongArchMatInt::generateInstSeq(int64_t Val) { + // Val: + // | hi32 | lo32 | + // +-----------+------------------+------------------+-----------+ + // | Highest12 | Higher20 | Hi20 | Lo12 | + // +-----------+------------------+------------------+-----------+ + // 63 52 51 32 31 12 11 0 + // + const int64_t Highest12 = Val >> 52 & 0xFFF; + const int64_t Higher20 = Val >> 32 & 0xFFFFF; + const int64_t Hi20 = Val >> 12 & 0xFFFFF; + const int64_t Lo12 = Val & 0xFFF; + InstSeq Insts; + + if (Highest12 != 0 && SignExtend64<52>(Val) == 0) { + Insts.push_back(Inst(LoongArch::LU52I_D, SignExtend64<12>(Highest12))); + return Insts; + } + + if (Hi20 == 0) + Insts.push_back(Inst(LoongArch::ORI, Lo12)); + else if (SignExtend32<1>(Lo12 >> 11) == SignExtend32<20>(Hi20)) + Insts.push_back(Inst(LoongArch::ADDI_W, SignExtend64<12>(Lo12))); + else { + Insts.push_back(Inst(LoongArch::LU12I_W, SignExtend64<20>(Hi20))); + if (Lo12 != 0) + Insts.push_back(Inst(LoongArch::ORI, Lo12)); + } + + if (SignExtend32<1>(Hi20 >> 19) != SignExtend32<20>(Higher20)) + Insts.push_back(Inst(LoongArch::LU32I_D, SignExtend64<20>(Higher20))); + + if (SignExtend32<1>(Higher20 >> 19) != SignExtend32<12>(Highest12)) + Insts.push_back(Inst(LoongArch::LU52I_D, SignExtend64<12>(Highest12))); + + return Insts; +} diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h new file mode 100644 index 000000000000..945aa91e40c0 --- /dev/null +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMatInt.h @@ -0,0 +1,30 @@ +//===- LoongArchMatInt.h - Immediate materialisation - --------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_MATINT_H +#define LLVM_LIB_TARGET_LOONGARCH_MCTARGETDESC_MATINT_H + +#include "llvm/ADT/SmallVector.h" +#include + +namespace llvm { +namespace LoongArchMatInt { +struct Inst { + unsigned Opc; + int64_t Imm; + Inst(unsigned Opc, int64_t Imm) : Opc(Opc), Imm(Imm) {} +}; +using InstSeq = SmallVector; + +// Helper to generate an instruction sequence that will materialise the given +// immediate value into a register. +InstSeq generateInstSeq(int64_t Val); +} // namespace LoongArchMatInt +} // namespace llvm + +#endif diff --git a/llvm/test/CodeGen/LoongArch/imm.ll b/llvm/test/CodeGen/LoongArch/imm.ll new file mode 100644 index 000000000000..3d6cfce3dabc --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/imm.ll @@ -0,0 +1,157 @@ +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s + +define i64 @imm7ff0000000000000() { +; CHECK-LABEL: imm7ff0000000000000: +; CHECK: # %bb.0: +; CHECK-NEXT: lu52i.d $a0, $zero, 2047 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 9218868437227405312 +} + +define i64 @imm0000000000000fff() { +; CHECK-LABEL: imm0000000000000fff: +; CHECK: # %bb.0: +; CHECK-NEXT: ori $a0, $zero, 4095 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 4095 +} + +define i64 @imm0007ffff00000800() { +; CHECK-LABEL: imm0007ffff00000800: +; CHECK: # %bb.0: +; CHECK-NEXT: ori $a0, $zero, 2048 +; CHECK-NEXT: lu32i.d $a0, 524287 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2251795518720000 +} + +define i64 @immfff0000000000fff() { +; CHECK-LABEL: immfff0000000000fff: +; CHECK: # %bb.0: +; CHECK-NEXT: ori $a0, $zero, 4095 +; CHECK-NEXT: lu52i.d $a0, $a0, -1 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 -4503599627366401 +} + +define i64 @imm0008000000000fff() { +; CHECK-LABEL: imm0008000000000fff: +; CHECK: # %bb.0: +; CHECK-NEXT: ori $a0, $zero, 4095 +; CHECK-NEXT: lu32i.d $a0, -524288 +; CHECK-NEXT: lu52i.d $a0, $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2251799813689343 +} + +define i64 @immfffffffffffff800() { +; CHECK-LABEL: immfffffffffffff800: +; CHECK: # %bb.0: +; CHECK-NEXT: addi.w $a0, $zero, -2048 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 -2048 +} + +define i64 @imm00000000fffff800() { +; CHECK-LABEL: imm00000000fffff800: +; CHECK: # %bb.0: +; CHECK-NEXT: addi.w $a0, $zero, -2048 +; CHECK-NEXT: lu32i.d $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 4294965248 +} + +define i64 @imm000ffffffffff800() { +; CHECK-LABEL: imm000ffffffffff800: +; CHECK: # %bb.0: +; CHECK-NEXT: addi.w $a0, $zero, -2048 +; CHECK-NEXT: lu52i.d $a0, $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 4503599627368448 +} + +define i64 @imm00080000fffff800() { +; CHECK-LABEL: imm00080000fffff800: +; CHECK: # %bb.0: +; CHECK-NEXT: addi.w $a0, $zero, -2048 +; CHECK-NEXT: lu32i.d $a0, -524288 +; CHECK-NEXT: lu52i.d $a0, $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2251804108650496 +} + +define i64 @imm000000007ffff000() { +; CHECK-LABEL: imm000000007ffff000: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, 524287 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2147479552 +} + +define i64 @imm0000000080000000() { +; CHECK-LABEL: imm0000000080000000: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -524288 +; CHECK-NEXT: lu32i.d $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2147483648 +} + +define i64 @imm000ffffffffff000() { +; CHECK-LABEL: imm000ffffffffff000: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -1 +; CHECK-NEXT: lu52i.d $a0, $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 4503599627366400 +} + +define i64 @imm7ff0000080000000() { +; CHECK-LABEL: imm7ff0000080000000: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -524288 +; CHECK-NEXT: lu32i.d $a0, 0 +; CHECK-NEXT: lu52i.d $a0, $a0, 2047 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 9218868439374888960 +} + +define i64 @immffffffff80000800() { +; CHECK-LABEL: immffffffff80000800: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -524288 +; CHECK-NEXT: ori $a0, $a0, 2048 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 -2147481600 +} + +define i64 @immffffffff7ffff800() { +; CHECK-LABEL: immffffffff7ffff800: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, 524287 +; CHECK-NEXT: ori $a0, $a0, 2048 +; CHECK-NEXT: lu32i.d $a0, -1 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 -2147485696 +} + +define i64 @imm7fffffff800007ff() { +; CHECK-LABEL: imm7fffffff800007ff: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -524288 +; CHECK-NEXT: ori $a0, $a0, 2047 +; CHECK-NEXT: lu52i.d $a0, $a0, 2047 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 9223372034707294207 +} + +define i64 @imm0008000080000800() { +; CHECK-LABEL: imm0008000080000800: +; CHECK: # %bb.0: +; CHECK-NEXT: lu12i.w $a0, -524288 +; CHECK-NEXT: ori $a0, $a0, 2048 +; CHECK-NEXT: lu32i.d $a0, -524288 +; CHECK-NEXT: lu52i.d $a0, $a0, 0 +; CHECK-NEXT: jirl $zero, $ra, 0 + ret i64 2251801961170944 +}