1 //===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "RISCVMatInt.h"
10 #include "MCTargetDesc/RISCVMCTargetDesc.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/Support/MachineValueType.h"
13 #include "llvm/Support/MathExtras.h"
14 #include <cstdint>
15 
16 namespace llvm {
17 
18 namespace RISCVMatInt {
generateInstSeq(int64_t Val,bool IsRV64,InstSeq & Res)19 void generateInstSeq(int64_t Val, bool IsRV64, InstSeq &Res) {
20   if (isInt<32>(Val)) {
21     // Depending on the active bits in the immediate Value v, the following
22     // instruction sequences are emitted:
23     //
24     // v == 0                        : ADDI
25     // v[0,12) != 0 && v[12,32) == 0 : ADDI
26     // v[0,12) == 0 && v[12,32) != 0 : LUI
27     // v[0,32) != 0                  : LUI+ADDI(W)
28     int64_t Hi20 = ((Val + 0x800) >> 12) & 0xFFFFF;
29     int64_t Lo12 = SignExtend64<12>(Val);
30 
31     if (Hi20)
32       Res.push_back(Inst(RISCV::LUI, Hi20));
33 
34     if (Lo12 || Hi20 == 0) {
35       unsigned AddiOpc = (IsRV64 && Hi20) ? RISCV::ADDIW : RISCV::ADDI;
36       Res.push_back(Inst(AddiOpc, Lo12));
37     }
38     return;
39   }
40 
41   assert(IsRV64 && "Can't emit >32-bit imm for non-RV64 target");
42 
43   // In the worst case, for a full 64-bit constant, a sequence of 8 instructions
44   // (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
45   // that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
46   // while the following ADDI instructions contribute up to 12 bits each.
47   //
48   // On the first glance, implementing this seems to be possible by simply
49   // emitting the most significant 32 bits (LUI+ADDIW) followed by as many left
50   // shift (SLLI) and immediate additions (ADDI) as needed. However, due to the
51   // fact that ADDI performs a sign extended addition, doing it like that would
52   // only be possible when at most 11 bits of the ADDI instructions are used.
53   // Using all 12 bits of the ADDI instructions, like done by GAS, actually
54   // requires that the constant is processed starting with the least significant
55   // bit.
56   //
57   // In the following, constants are processed from LSB to MSB but instruction
58   // emission is performed from MSB to LSB by recursively calling
59   // generateInstSeq. In each recursion, first the lowest 12 bits are removed
60   // from the constant and the optimal shift amount, which can be greater than
61   // 12 bits if the constant is sparse, is determined. Then, the shifted
62   // remaining constant is processed recursively and gets emitted as soon as it
63   // fits into 32 bits. The emission of the shifts and additions is subsequently
64   // performed when the recursion returns.
65 
66   int64_t Lo12 = SignExtend64<12>(Val);
67   int64_t Hi52 = ((uint64_t)Val + 0x800ull) >> 12;
68   int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52);
69   Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
70 
71   generateInstSeq(Hi52, IsRV64, Res);
72 
73   Res.push_back(Inst(RISCV::SLLI, ShiftAmount));
74   if (Lo12)
75     Res.push_back(Inst(RISCV::ADDI, Lo12));
76 }
77 
getIntMatCost(const APInt & Val,unsigned Size,bool IsRV64)78 int getIntMatCost(const APInt &Val, unsigned Size, bool IsRV64) {
79   int PlatRegSize = IsRV64 ? 64 : 32;
80 
81   // Split the constant into platform register sized chunks, and calculate cost
82   // of each chunk.
83   int Cost = 0;
84   for (unsigned ShiftVal = 0; ShiftVal < Size; ShiftVal += PlatRegSize) {
85     APInt Chunk = Val.ashr(ShiftVal).sextOrTrunc(PlatRegSize);
86     InstSeq MatSeq;
87     generateInstSeq(Chunk.getSExtValue(), IsRV64, MatSeq);
88     Cost += MatSeq.size();
89   }
90   return std::max(1, Cost);
91 }
92 } // namespace RISCVMatInt
93 } // namespace llvm
94