Skip to content

Commit 22c091f

Browse files
committedNov 15, 2018
[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 llvm-svn: 346937
1 parent 553ac56 commit 22c091f

File tree

6 files changed

+149
-89
lines changed

6 files changed

+149
-89
lines changed
 

‎llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

+16-72
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "MCTargetDesc/RISCVMCTargetDesc.h"
1313
#include "MCTargetDesc/RISCVTargetStreamer.h"
1414
#include "Utils/RISCVBaseInfo.h"
15+
#include "Utils/RISCVMatInt.h"
1516
#include "llvm/ADT/STLExtras.h"
1617
#include "llvm/ADT/StringSwitch.h"
1718
#include "llvm/MC/MCAssembler.h"
@@ -1348,80 +1349,23 @@ void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) {
13481349

13491350
void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
13501351
MCStreamer &Out) {
1351-
if (isInt<32>(Value)) {
1352-
// Emits the MC instructions for loading a 32-bit constant into a register.
1353-
//
1354-
// Depending on the active bits in the immediate Value v, the following
1355-
// instruction sequences are emitted:
1356-
//
1357-
// v == 0 : ADDI(W)
1358-
// v[0,12) != 0 && v[12,32) == 0 : ADDI(W)
1359-
// v[0,12) == 0 && v[12,32) != 0 : LUI
1360-
// v[0,32) != 0 : LUI+ADDI(W)
1361-
//
1362-
int64_t Hi20 = ((Value + 0x800) >> 12) & 0xFFFFF;
1363-
int64_t Lo12 = SignExtend64<12>(Value);
1364-
unsigned SrcReg = RISCV::X0;
1365-
1366-
if (Hi20) {
1367-
emitToStreamer(Out,
1368-
MCInstBuilder(RISCV::LUI).addReg(DestReg).addImm(Hi20));
1369-
SrcReg = DestReg;
1352+
RISCVMatInt::InstSeq Seq;
1353+
RISCVMatInt::generateInstSeq(Value, isRV64(), Seq);
1354+
1355+
unsigned SrcReg = RISCV::X0;
1356+
for (RISCVMatInt::Inst &Inst : Seq) {
1357+
if (Inst.Opc == RISCV::LUI) {
1358+
emitToStreamer(
1359+
Out, MCInstBuilder(RISCV::LUI).addReg(DestReg).addImm(Inst.Imm));
1360+
} else {
1361+
emitToStreamer(
1362+
Out, MCInstBuilder(Inst.Opc).addReg(DestReg).addReg(SrcReg).addImm(
1363+
Inst.Imm));
13701364
}
13711365

1372-
if (Lo12 || Hi20 == 0) {
1373-
unsigned AddiOpcode =
1374-
STI->hasFeature(RISCV::Feature64Bit) ? RISCV::ADDIW : RISCV::ADDI;
1375-
emitToStreamer(Out, MCInstBuilder(AddiOpcode)
1376-
.addReg(DestReg)
1377-
.addReg(SrcReg)
1378-
.addImm(Lo12));
1379-
}
1380-
return;
1381-
}
1382-
assert(STI->hasFeature(RISCV::Feature64Bit) &&
1383-
"Target must be 64-bit to support a >32-bit constant");
1384-
1385-
// In the worst case, for a full 64-bit constant, a sequence of 8 instructions
1386-
// (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
1387-
// that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
1388-
// while the following ADDI instructions contribute up to 12 bits each.
1389-
//
1390-
// On the first glance, implementing this seems to be possible by simply
1391-
// emitting the most significant 32 bits (LUI+ADDIW) followed by as many left
1392-
// shift (SLLI) and immediate additions (ADDI) as needed. However, due to the
1393-
// fact that ADDI performs a sign extended addition, doing it like that would
1394-
// only be possible when at most 11 bits of the ADDI instructions are used.
1395-
// Using all 12 bits of the ADDI instructions, like done by GAS, actually
1396-
// requires that the constant is processed starting with the least significant
1397-
// bit.
1398-
//
1399-
// In the following, constants are processed from LSB to MSB but instruction
1400-
// emission is performed from MSB to LSB by recursively calling
1401-
// emitLoadImm. In each recursion, first the lowest 12 bits are removed
1402-
// from the constant and the optimal shift amount, which can be greater than
1403-
// 12 bits if the constant is sparse, is determined. Then, the shifted
1404-
// remaining constant is processed recursively and gets emitted as soon as it
1405-
// fits into 32 bits. The emission of the shifts and additions is subsequently
1406-
// performed when the recursion returns.
1407-
//
1408-
int64_t Lo12 = SignExtend64<12>(Value);
1409-
int64_t Hi52 = (Value + 0x800) >> 12;
1410-
int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52);
1411-
Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
1412-
1413-
emitLoadImm(DestReg, Hi52, Out);
1414-
1415-
emitToStreamer(Out, MCInstBuilder(RISCV::SLLI)
1416-
.addReg(DestReg)
1417-
.addReg(DestReg)
1418-
.addImm(ShiftAmount));
1419-
1420-
if (Lo12)
1421-
emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
1422-
.addReg(DestReg)
1423-
.addReg(DestReg)
1424-
.addImm(Lo12));
1366+
// Only the first instruction has X0 as its source.
1367+
SrcReg = DestReg;
1368+
}
14251369
}
14261370

14271371
void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
add_llvm_library(LLVMRISCVUtils
22
RISCVBaseInfo.cpp
3+
RISCVMatInt.cpp
34
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===- RISCVMatInt.cpp - Immediate materialisation -------------*- C++ -*--===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "RISCVMatInt.h"
11+
#include "MCTargetDesc/RISCVMCTargetDesc.h"
12+
#include "llvm/ADT/SmallVector.h"
13+
#include "llvm/Support/MachineValueType.h"
14+
#include "llvm/Support/MathExtras.h"
15+
#include <cstdint>
16+
17+
namespace llvm {
18+
19+
namespace RISCVMatInt {
20+
void generateInstSeq(int64_t Val, bool Is64Bit, InstSeq &Res) {
21+
if (isInt<32>(Val)) {
22+
// Depending on the active bits in the immediate Value v, the following
23+
// instruction sequences are emitted:
24+
//
25+
// v == 0 : ADDI
26+
// v[0,12) != 0 && v[12,32) == 0 : ADDI
27+
// v[0,12) == 0 && v[12,32) != 0 : LUI
28+
// v[0,32) != 0 : LUI+ADDI(W)
29+
int64_t Hi20 = ((Val + 0x800) >> 12) & 0xFFFFF;
30+
int64_t Lo12 = SignExtend64<12>(Val);
31+
32+
if (Hi20)
33+
Res.push_back(Inst(RISCV::LUI, Hi20));
34+
35+
if (Lo12 || Hi20 == 0) {
36+
unsigned AddiOpc = (Is64Bit && Hi20) ? RISCV::ADDIW : RISCV::ADDI;
37+
Res.push_back(Inst(AddiOpc, Lo12));
38+
}
39+
return;
40+
}
41+
42+
assert(Is64Bit && "Can't emit >32-bit imm for non-RV64 target");
43+
44+
// In the worst case, for a full 64-bit constant, a sequence of 8 instructions
45+
// (i.e., LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI) has to be emmitted. Note
46+
// that the first two instructions (LUI+ADDIW) can contribute up to 32 bits
47+
// while the following ADDI instructions contribute up to 12 bits each.
48+
//
49+
// On the first glance, implementing this seems to be possible by simply
50+
// emitting the most significant 32 bits (LUI+ADDIW) followed by as many left
51+
// shift (SLLI) and immediate additions (ADDI) as needed. However, due to the
52+
// fact that ADDI performs a sign extended addition, doing it like that would
53+
// only be possible when at most 11 bits of the ADDI instructions are used.
54+
// Using all 12 bits of the ADDI instructions, like done by GAS, actually
55+
// requires that the constant is processed starting with the least significant
56+
// bit.
57+
//
58+
// In the following, constants are processed from LSB to MSB but instruction
59+
// emission is performed from MSB to LSB by recursively calling
60+
// generateInstSeq. In each recursion, first the lowest 12 bits are removed
61+
// from the constant and the optimal shift amount, which can be greater than
62+
// 12 bits if the constant is sparse, is determined. Then, the shifted
63+
// remaining constant is processed recursively and gets emitted as soon as it
64+
// fits into 32 bits. The emission of the shifts and additions is subsequently
65+
// performed when the recursion returns.
66+
67+
int64_t Lo12 = SignExtend64<12>(Val);
68+
int64_t Hi52 = (Val + 0x800) >> 12;
69+
int ShiftAmount = 12 + findFirstSet((uint64_t)Hi52);
70+
Hi52 = SignExtend64(Hi52 >> (ShiftAmount - 12), 64 - ShiftAmount);
71+
72+
generateInstSeq(Hi52, Is64Bit, Res);
73+
74+
Res.push_back(Inst(RISCV::SLLI, ShiftAmount));
75+
if (Lo12)
76+
Res.push_back(Inst(RISCV::ADDI, Lo12));
77+
}
78+
} // namespace RISCVMatInt
79+
} // namespace llvm
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- RISCVMatInt.h - Immediate materialisation ---------------*- C++ -*--===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_LIB_TARGET_RISCV_MATINT_H
11+
#define LLVM_LIB_TARGET_RISCV_MATINT_H
12+
13+
#include "llvm/ADT/SmallVector.h"
14+
#include "llvm/Support/MachineValueType.h"
15+
#include <cstdint>
16+
17+
namespace llvm {
18+
19+
namespace RISCVMatInt {
20+
struct Inst {
21+
unsigned Opc;
22+
int64_t Imm;
23+
24+
Inst(unsigned Opc, int64_t Imm) : Opc(Opc), Imm(Imm) {}
25+
};
26+
using InstSeq = SmallVector<Inst, 8>;
27+
28+
// Helper to generate an instruction sequence that will materialise the given
29+
// immediate value into a register. A sequence of instructions represented by
30+
// a simple struct produced rather than directly emitting the instructions in
31+
// order to allow this helper to be used from both the MC layer and during
32+
// instruction selection.
33+
void generateInstSeq(int64_t Val, bool IsRV64, InstSeq &Res);
34+
} // namespace RISCVMatInt
35+
} // namespace llvm
36+
#endif

‎llvm/test/MC/RISCV/rv64c-aliases-valid.s

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ li x10, 0
1414
li x10, 1
1515
# CHECK-EXPAND: c.li a0, -1
1616
li x10, -1
17-
# CHECK-EXPAND: addiw a0, zero, 2047
17+
# CHECK-EXPAND: addi a0, zero, 2047
1818
li x10, 2047
19-
# CHECK-EXPAND: addiw a0, zero, -2047
19+
# CHECK-EXPAND: addi a0, zero, -2047
2020
li x10, -2047
2121
# CHECK-EXPAND: c.lui a1, 1
2222
# CHECK-EXPAND: addiw a1, a1, -2048
2323
li x11, 2048
24-
# CHECK-EXPAND: addiw a1, zero, -2048
24+
# CHECK-EXPAND: addi a1, zero, -2048
2525
li x11, -2048
2626
# CHECK-EXPAND: c.lui a1, 1
2727
# CHECK-EXPAND: addiw a1, a1, -2047

‎llvm/test/MC/RISCV/rv64i-aliases-valid.s

+14-14
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,21 @@
1717
# TODO ld
1818
# TODO sd
1919

20-
# CHECK-INST: addiw a0, zero, 0
21-
# CHECK-ALIAS: sext.w a0, zero
20+
# CHECK-INST: addi a0, zero, 0
21+
# CHECK-ALIAS: mv a0, zero
2222
li x10, 0
23-
# CHECK-EXPAND: addiw a0, zero, 1
23+
# CHECK-EXPAND: addi a0, zero, 1
2424
li x10, 1
25-
# CHECK-EXPAND: addiw a0, zero, -1
25+
# CHECK-EXPAND: addi a0, zero, -1
2626
li x10, -1
27-
# CHECK-EXPAND: addiw a0, zero, 2047
27+
# CHECK-EXPAND: addi a0, zero, 2047
2828
li x10, 2047
29-
# CHECK-EXPAND: addiw a0, zero, -2047
29+
# CHECK-EXPAND: addi a0, zero, -2047
3030
li x10, -2047
3131
# CHECK-EXPAND: lui a1, 1
3232
# CHECK-EXPAND: addiw a1, a1, -2048
3333
li x11, 2048
34-
# CHECK-EXPAND: addiw a1, zero, -2048
34+
# CHECK-EXPAND: addi a1, zero, -2048
3535
li x11, -2048
3636
# CHECK-EXPAND: lui a1, 1
3737
# CHECK-EXPAND: addiw a1, a1, -2047
@@ -66,28 +66,28 @@ li x12, -2147483648
6666
# CHECK-EXPAND: lui a2, 524288
6767
li x12, -0x80000000
6868

69-
# CHECK-EXPAND: addiw a2, zero, 1
69+
# CHECK-EXPAND: addi a2, zero, 1
7070
# CHECK-EXPAND: slli a2, a2, 31
7171
li x12, 0x80000000
72-
# CHECK-EXPAND: addiw a2, zero, 1
72+
# CHECK-EXPAND: addi a2, zero, 1
7373
# CHECK-EXPAND: slli a2, a2, 32
7474
# CHECK-EXPAND: addi a2, a2, -1
7575
li x12, 0xFFFFFFFF
7676

77-
# CHECK-EXPAND: addiw t0, zero, 1
77+
# CHECK-EXPAND: addi t0, zero, 1
7878
# CHECK-EXPAND: slli t0, t0, 32
7979
li t0, 0x100000000
80-
# CHECK-EXPAND: addiw t1, zero, -1
80+
# CHECK-EXPAND: addi t1, zero, -1
8181
# CHECK-EXPAND: slli t1, t1, 63
8282
li t1, 0x8000000000000000
83-
# CHECK-EXPAND: addiw t1, zero, -1
83+
# CHECK-EXPAND: addi t1, zero, -1
8484
# CHECK-EXPAND: slli t1, t1, 63
8585
li t1, -0x8000000000000000
8686
# CHECK-EXPAND: lui t2, 9321
8787
# CHECK-EXPAND: addiw t2, t2, -1329
8888
# CHECK-EXPAND: slli t2, t2, 35
8989
li t2, 0x1234567800000000
90-
# CHECK-EXPAND: addiw t3, zero, 7
90+
# CHECK-EXPAND: addi t3, zero, 7
9191
# CHECK-EXPAND: slli t3, t3, 36
9292
# CHECK-EXPAND: addi t3, t3, 11
9393
# CHECK-EXPAND: slli t3, t3, 24
@@ -102,7 +102,7 @@ li t3, 0x700000000B00000F
102102
# CHECK-EXPAND: slli t4, t4, 13
103103
# CHECK-EXPAND: addi t4, t4, -272
104104
li t4, 0x123456789abcdef0
105-
# CHECK-EXPAND: addiw t5, zero, -1
105+
# CHECK-EXPAND: addi t5, zero, -1
106106
li t5, 0xFFFFFFFFFFFFFFFF
107107

108108
# CHECK-INST: subw t6, zero, ra

0 commit comments

Comments
 (0)
Please sign in to comment.