[llvm] r346937 - [RISCV] Introduce the RISCVMatInt::generateInstSeq helper

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 15 02:11:31 PST 2018


Author: asb
Date: Thu Nov 15 02:11:31 2018
New Revision: 346937

URL: http://llvm.org/viewvc/llvm-project?rev=346937&view=rev
Log:
[RISCV] Introduce the RISCVMatInt::generateInstSeq helper

Logic to load 32-bit and 64-bit immediates is currently present in
RISCVAsmParser::emitLoadImm in order to support the li pseudoinstruction. With
the introduction of RV64 codegen, there is a greater benefit of sharing
immediate materialisation logic between the MC layer and codegen. The
generateInstSeq helper allows this by producing a vector of simple structs
representing the chosen instructions. This can then be consumed in the MC
layer to produce MCInsts or at instruction selection time to produce
appropriate SelectionDAG node. Sharing this logic means that both the li
pseudoinstruction and codegen can benefit from future optimisations, and
that this logic can be used for materialising constants during RV64 codegen.

This patch does contain a behaviour change: addi will now be produced on RV64
when no lui is necessary to materialise the constant. In that case addiw takes
x0 as the source register, so is semantically identical to addi.

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

Added:
    llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.cpp
    llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.h
Modified:
    llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
    llvm/trunk/lib/Target/RISCV/Utils/CMakeLists.txt
    llvm/trunk/test/MC/RISCV/rv64c-aliases-valid.s
    llvm/trunk/test/MC/RISCV/rv64i-aliases-valid.s

Modified: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp?rev=346937&r1=346936&r2=346937&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp Thu Nov 15 02:11:31 2018
@@ -12,6 +12,7 @@
 #include "MCTargetDesc/RISCVMCTargetDesc.h"
 #include "MCTargetDesc/RISCVTargetStreamer.h"
 #include "Utils/RISCVBaseInfo.h"
+#include "Utils/RISCVMatInt.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/MC/MCAssembler.h"
@@ -1348,80 +1349,23 @@ void RISCVAsmParser::emitToStreamer(MCSt
 
 void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
                                  MCStreamer &Out) {
-  if (isInt<32>(Value)) {
-    // Emits the MC instructions for loading a 32-bit constant into a register.
-    //
-    // Depending on the active bits in the immediate Value v, the following
-    // instruction sequences are emitted:
-    //
-    // v == 0                        : ADDI(W)
-    // v[0,12) != 0 && v[12,32) == 0 : ADDI(W)
-    // v[0,12) == 0 && v[12,32) != 0 : LUI
-    // v[0,32) != 0                  : LUI+ADDI(W)
-    //
-    int64_t Hi20 = ((Value + 0x800) >> 12) & 0xFFFFF;
-    int64_t Lo12 = SignExtend64<12>(Value);
-    unsigned SrcReg = RISCV::X0;
-
-    if (Hi20) {
-      emitToStreamer(Out,
-                     MCInstBuilder(RISCV::LUI).addReg(DestReg).addImm(Hi20));
-      SrcReg = DestReg;
-    }
+  RISCVMatInt::InstSeq Seq;
+  RISCVMatInt::generateInstSeq(Value, isRV64(), Seq);
 
-    if (Lo12 || Hi20 == 0) {
-      unsigned AddiOpcode =
-          STI->hasFeature(RISCV::Feature64Bit) ? RISCV::ADDIW : RISCV::ADDI;
-      emitToStreamer(Out, MCInstBuilder(AddiOpcode)
-                              .addReg(DestReg)
-                              .addReg(SrcReg)
-                              .addImm(Lo12));
+  unsigned SrcReg = RISCV::X0;
+  for (RISCVMatInt::Inst &Inst : Seq) {
+    if (Inst.Opc == RISCV::LUI) {
+      emitToStreamer(
+          Out, MCInstBuilder(RISCV::LUI).addReg(DestReg).addImm(Inst.Imm));
+    } else {
+      emitToStreamer(
+          Out, MCInstBuilder(Inst.Opc).addReg(DestReg).addReg(SrcReg).addImm(
+                   Inst.Imm));
     }
-    return;
-  }
-  assert(STI->hasFeature(RISCV::Feature64Bit) &&
-         "Target must be 64-bit to support a >32-bit constant");
 
-  // In the worst case, for a full 64-bit constant, a sequence of 8 instructions
-  // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
-  // that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
-  // while the following ADDI instructions contribute up to 12 bits each.
-  //
-  // On the first glance, implementing this seems to be possible by simply
-  // emitting the most significant 32 bits (LUI+ADDIW) followed by as many left
-  // shift (SLLI) and immediate additions (ADDI) as needed. However, due to the
-  // fact that ADDI performs a sign extended addition, doing it like that would
-  // only be possible when at most 11 bits of the ADDI instructions are used.
-  // Using all 12 bits of the ADDI instructions, like done by GAS, actually
-  // requires that the constant is processed starting with the least significant
-  // bit.
-  //
-  // In the following, constants are processed from LSB to MSB but instruction
-  // emission is performed from MSB to LSB by recursively calling
-  // emitLoadImm. In each recursion, first the lowest 12 bits are removed
-  // from the constant and the optimal shift amount, which can be greater than
-  // 12 bits if the constant is sparse, is determined. Then, the shifted
-  // remaining constant is processed recursively and gets emitted as soon as it
-  // fits into 32 bits. The emission of the shifts and additions is subsequently
-  // performed when the recursion returns.
-  //
-  int64_t Lo12 = SignExtend64<12>(Value);
-  int64_t Hi52 = (Value + 0x800) >> 12;
-  int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52);
-  Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
-
-  emitLoadImm(DestReg, Hi52, Out);
-
-  emitToStreamer(Out, MCInstBuilder(RISCV::SLLI)
-                          .addReg(DestReg)
-                          .addReg(DestReg)
-                          .addImm(ShiftAmount));
-
-  if (Lo12)
-    emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
-                            .addReg(DestReg)
-                            .addReg(DestReg)
-                            .addImm(Lo12));
+    // Only the first instruction has X0 as its source.
+    SrcReg = DestReg;
+  }
 }
 
 void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,

Modified: llvm/trunk/lib/Target/RISCV/Utils/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/Utils/CMakeLists.txt?rev=346937&r1=346936&r2=346937&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/Utils/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/RISCV/Utils/CMakeLists.txt Thu Nov 15 02:11:31 2018
@@ -1,3 +1,4 @@
 add_llvm_library(LLVMRISCVUtils
   RISCVBaseInfo.cpp
+  RISCVMatInt.cpp
   )

Added: llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.cpp?rev=346937&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.cpp (added)
+++ llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.cpp Thu Nov 15 02:11:31 2018
@@ -0,0 +1,79 @@
+//===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCVMatInt.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MachineValueType.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+
+namespace llvm {
+
+namespace RISCVMatInt {
+void generateInstSeq(int64_t Val, bool Is64Bit, InstSeq &Res) {
+  if (isInt<32>(Val)) {
+    // Depending on the active bits in the immediate Value v, the following
+    // instruction sequences are emitted:
+    //
+    // v == 0                        : ADDI
+    // v[0,12) != 0 && v[12,32) == 0 : ADDI
+    // v[0,12) == 0 && v[12,32) != 0 : LUI
+    // v[0,32) != 0                  : LUI+ADDI(W)
+    int64_t Hi20 = ((Val + 0x800) >> 12) & 0xFFFFF;
+    int64_t Lo12 = SignExtend64<12>(Val);
+
+    if (Hi20)
+      Res.push_back(Inst(RISCV::LUI, Hi20));
+
+    if (Lo12 || Hi20 == 0) {
+      unsigned AddiOpc = (Is64Bit && Hi20) ? RISCV::ADDIW : RISCV::ADDI;
+      Res.push_back(Inst(AddiOpc, Lo12));
+    }
+    return;
+  }
+
+  assert(Is64Bit && "Can't emit >32-bit imm for non-RV64 target");
+
+  // In the worst case, for a full 64-bit constant, a sequence of 8 instructions
+  // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
+  // that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
+  // while the following ADDI instructions contribute up to 12 bits each.
+  //
+  // On the first glance, implementing this seems to be possible by simply
+  // emitting the most significant 32 bits (LUI+ADDIW) followed by as many left
+  // shift (SLLI) and immediate additions (ADDI) as needed. However, due to the
+  // fact that ADDI performs a sign extended addition, doing it like that would
+  // only be possible when at most 11 bits of the ADDI instructions are used.
+  // Using all 12 bits of the ADDI instructions, like done by GAS, actually
+  // requires that the constant is processed starting with the least significant
+  // bit.
+  //
+  // In the following, constants are processed from LSB to MSB but instruction
+  // emission is performed from MSB to LSB by recursively calling
+  // generateInstSeq. In each recursion, first the lowest 12 bits are removed
+  // from the constant and the optimal shift amount, which can be greater than
+  // 12 bits if the constant is sparse, is determined. Then, the shifted
+  // remaining constant is processed recursively and gets emitted as soon as it
+  // fits into 32 bits. The emission of the shifts and additions is subsequently
+  // performed when the recursion returns.
+
+  int64_t Lo12 = SignExtend64<12>(Val);
+  int64_t Hi52 = (Val + 0x800) >> 12;
+  int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52);
+  Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
+
+  generateInstSeq(Hi52, Is64Bit, Res);
+
+  Res.push_back(Inst(RISCV::SLLI, ShiftAmount));
+  if (Lo12)
+    Res.push_back(Inst(RISCV::ADDI, Lo12));
+}
+} // namespace RISCVMatInt
+} // namespace llvm

Added: llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.h?rev=346937&view=auto
==============================================================================
--- llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.h (added)
+++ llvm/trunk/lib/Target/RISCV/Utils/RISCVMatInt.h Thu Nov 15 02:11:31 2018
@@ -0,0 +1,36 @@
+//===- RISCVMatInt.h - Immediate materialisation ---------------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_RISCV_MATINT_H
+#define LLVM_LIB_TARGET_RISCV_MATINT_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MachineValueType.h"
+#include <cstdint>
+
+namespace llvm {
+
+namespace RISCVMatInt {
+struct Inst {
+  unsigned Opc;
+  int64_t Imm;
+
+  Inst(unsigned Opc, int64_t Imm) : Opc(Opc), Imm(Imm) {}
+};
+using InstSeq = SmallVector<Inst, 8>;
+
+// Helper to generate an instruction sequence that will materialise the given
+// immediate value into a register. A sequence of instructions represented by
+// a simple struct produced rather than directly emitting the instructions in
+// order to allow this helper to be used from both the MC layer and during
+// instruction selection.
+void generateInstSeq(int64_t Val, bool IsRV64, InstSeq &Res);
+} // namespace RISCVMatInt
+} // namespace llvm
+#endif

Modified: llvm/trunk/test/MC/RISCV/rv64c-aliases-valid.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv64c-aliases-valid.s?rev=346937&r1=346936&r2=346937&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv64c-aliases-valid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv64c-aliases-valid.s Thu Nov 15 02:11:31 2018
@@ -14,14 +14,14 @@ li x10, 0
 li x10, 1
 # CHECK-EXPAND: c.li a0, -1
 li x10, -1
-# CHECK-EXPAND: addiw a0, zero, 2047
+# CHECK-EXPAND: addi a0, zero, 2047
 li x10, 2047
-# CHECK-EXPAND: addiw a0, zero, -2047
+# CHECK-EXPAND: addi a0, zero, -2047
 li x10, -2047
 # CHECK-EXPAND: c.lui a1, 1
 # CHECK-EXPAND: addiw a1, a1, -2048
 li x11, 2048
-# CHECK-EXPAND: addiw a1, zero, -2048
+# CHECK-EXPAND: addi a1, zero, -2048
 li x11, -2048
 # CHECK-EXPAND: c.lui a1, 1
 # CHECK-EXPAND: addiw a1, a1, -2047

Modified: llvm/trunk/test/MC/RISCV/rv64i-aliases-valid.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/RISCV/rv64i-aliases-valid.s?rev=346937&r1=346936&r2=346937&view=diff
==============================================================================
--- llvm/trunk/test/MC/RISCV/rv64i-aliases-valid.s (original)
+++ llvm/trunk/test/MC/RISCV/rv64i-aliases-valid.s Thu Nov 15 02:11:31 2018
@@ -17,21 +17,21 @@
 # TODO ld
 # TODO sd
 
-# CHECK-INST: addiw a0, zero, 0
-# CHECK-ALIAS: sext.w a0, zero
+# CHECK-INST: addi a0, zero, 0
+# CHECK-ALIAS: mv a0, zero
 li x10, 0
-# CHECK-EXPAND: addiw a0, zero, 1
+# CHECK-EXPAND: addi a0, zero, 1
 li x10, 1
-# CHECK-EXPAND: addiw a0, zero, -1
+# CHECK-EXPAND: addi a0, zero, -1
 li x10, -1
-# CHECK-EXPAND: addiw a0, zero, 2047
+# CHECK-EXPAND: addi a0, zero, 2047
 li x10, 2047
-# CHECK-EXPAND: addiw a0, zero, -2047
+# CHECK-EXPAND: addi a0, zero, -2047
 li x10, -2047
 # CHECK-EXPAND: lui a1, 1
 # CHECK-EXPAND: addiw a1, a1, -2048
 li x11, 2048
-# CHECK-EXPAND: addiw a1, zero, -2048
+# CHECK-EXPAND: addi a1, zero, -2048
 li x11, -2048
 # CHECK-EXPAND: lui a1, 1
 # CHECK-EXPAND: addiw a1, a1, -2047
@@ -66,28 +66,28 @@ li x12, -2147483648
 # CHECK-EXPAND: lui a2, 524288
 li x12, -0x80000000
 
-# CHECK-EXPAND: addiw a2, zero, 1
+# CHECK-EXPAND: addi a2, zero, 1
 # CHECK-EXPAND: slli a2, a2, 31
 li x12, 0x80000000
-# CHECK-EXPAND: addiw a2, zero, 1
+# CHECK-EXPAND: addi a2, zero, 1
 # CHECK-EXPAND: slli a2, a2, 32
 # CHECK-EXPAND: addi a2, a2, -1
 li x12, 0xFFFFFFFF
 
-# CHECK-EXPAND: addiw t0, zero, 1
+# CHECK-EXPAND: addi t0, zero, 1
 # CHECK-EXPAND: slli t0, t0, 32
 li t0, 0x100000000
-# CHECK-EXPAND: addiw t1, zero, -1
+# CHECK-EXPAND: addi t1, zero, -1
 # CHECK-EXPAND: slli t1, t1, 63
 li t1, 0x8000000000000000
-# CHECK-EXPAND: addiw t1, zero, -1
+# CHECK-EXPAND: addi t1, zero, -1
 # CHECK-EXPAND: slli t1, t1, 63
 li t1, -0x8000000000000000
 # CHECK-EXPAND: lui t2, 9321
 # CHECK-EXPAND: addiw t2, t2, -1329
 # CHECK-EXPAND: slli t2, t2, 35
 li t2, 0x1234567800000000
-# CHECK-EXPAND: addiw t3, zero, 7
+# CHECK-EXPAND: addi t3, zero, 7
 # CHECK-EXPAND: slli t3, t3, 36
 # CHECK-EXPAND: addi t3, t3, 11
 # CHECK-EXPAND: slli t3, t3, 24
@@ -102,7 +102,7 @@ li t3, 0x700000000B00000F
 # CHECK-EXPAND: slli t4, t4, 13
 # CHECK-EXPAND: addi t4, t4, -272
 li t4, 0x123456789abcdef0
-# CHECK-EXPAND: addiw t5, zero, -1
+# CHECK-EXPAND: addi t5, zero, -1
 li t5, 0xFFFFFFFFFFFFFFFF
 
 # CHECK-INST: subw t6, zero, ra




More information about the llvm-commits mailing list