Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -11,6 +11,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/MCContext.h" @@ -1307,80 +1308,23 @@ 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); + + 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)); } - if (Lo12 || Hi20 == 0) { - unsigned AddiOpcode = - STI->hasFeature(RISCV::Feature64Bit) ? RISCV::ADDIW : RISCV::ADDI; - emitToStreamer(Out, MCInstBuilder(AddiOpcode) - .addReg(DestReg) - .addReg(SrcReg) - .addImm(Lo12)); - } - 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, Index: lib/Target/RISCV/Utils/CMakeLists.txt =================================================================== --- lib/Target/RISCV/Utils/CMakeLists.txt +++ lib/Target/RISCV/Utils/CMakeLists.txt @@ -1,3 +1,4 @@ add_llvm_library(LLVMRISCVUtils RISCVBaseInfo.cpp + RISCVMatInt.cpp ) Index: lib/Target/RISCV/Utils/RISCVMatInt.h =================================================================== --- /dev/null +++ lib/Target/RISCV/Utils/RISCVMatInt.h @@ -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 + +namespace llvm { + +namespace RISCVMatInt { +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. 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 Index: lib/Target/RISCV/Utils/RISCVMatInt.cpp =================================================================== --- /dev/null +++ lib/Target/RISCV/Utils/RISCVMatInt.cpp @@ -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 + +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 Index: test/MC/RISCV/rv64c-aliases-valid.s =================================================================== --- test/MC/RISCV/rv64c-aliases-valid.s +++ test/MC/RISCV/rv64c-aliases-valid.s @@ -14,14 +14,14 @@ 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 Index: test/MC/RISCV/rv64i-aliases-valid.s =================================================================== --- test/MC/RISCV/rv64i-aliases-valid.s +++ test/MC/RISCV/rv64i-aliases-valid.s @@ -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 @@ # 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 @@ # 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