Alex Bradbury 8687f7cd66
[RISCV] Support constant hoisting of immediate store values (#96073)
Previously getIntImmInstCost only calculated the cost of materialising
the argument of a store if it was the address. This means
ConstantHoisting's transformation wouldn't kick in for cases like
storing two values that require multiple instructions to materialise but
where one can be cheaply generated from the other (e.g. by an addition).

Two key changes were needed to avoid regressions when enabling this:
* Allowing constant materialisation cost to be calculated assuming
zeroes are free (as might happen if you had a 2*XLEN constant and one
half is zero).
* Avoiding constant hoisting if we have a misaligned store that's going
to be a legalised to a sequence of narrower stores. I'm seeing cases
where hoisting the constant ends up with worse codegen in that case.

Out of caution and so as not to unexpectedly degrade other existing hoisting logic, FreeZeroes is used only for the new cost calculations for the load instruction. It would likely make sense to revisit this later.
2024-07-17 15:19:31 +01:00

84 lines
3.2 KiB
C++

//===- RISCVMatInt.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_RISCV_MCTARGETDESC_MATINT_H
#define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_MATINT_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCRegister.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include <cstdint>
namespace llvm {
class APInt;
namespace RISCVMatInt {
enum OpndKind {
RegImm, // ADDI/ADDIW/SLLI/SRLI/BSETI/BCLRI
Imm, // LUI
RegReg, // SH1ADD/SH2ADD/SH3ADD
RegX0, // ADD_UW
};
class Inst {
unsigned Opc;
int32_t Imm; // The largest value we need to store is 20 bits.
public:
Inst(unsigned Opc, int64_t I) : Opc(Opc), Imm(I) {
assert(I == Imm && "truncated");
}
unsigned getOpcode() const { return Opc; }
int64_t getImm() const { return Imm; }
OpndKind getOpndKind() const;
};
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 is 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.
InstSeq generateInstSeq(int64_t Val, const MCSubtargetInfo &STI);
// Helper to generate the generateInstSeq instruction sequence using MCInsts
void generateMCInstSeq(int64_t Val, const MCSubtargetInfo &STI,
MCRegister DestReg, SmallVectorImpl<MCInst> &Insts);
// Helper to generate an instruction sequence that can materialize the given
// immediate value into a register using an additional temporary register. This
// handles cases where the constant can be generated by (ADD (SLLI X, C), X) or
// (ADD_UW (SLLI X, C) X). The sequence to generate X is returned. ShiftAmt is
// provides the SLLI and AddOpc indicates ADD or ADD_UW.
InstSeq generateTwoRegInstSeq(int64_t Val, const MCSubtargetInfo &STI,
unsigned &ShiftAmt, unsigned &AddOpc);
// Helper to estimate the number of instructions required to materialise the
// given immediate value into a register. This estimate does not account for
// `Val` possibly fitting into an immediate, and so may over-estimate.
//
// This will attempt to produce instructions to materialise `Val` as an
// `Size`-bit immediate.
//
// If CompressionCost is true it will use a different cost calculation if RVC is
// enabled. This should be used to compare two different sequences to determine
// which is more compressible.
//
// If FreeZeroes is true, it will be assumed free to materialize any
// XLen-sized chunks that are 0. This is appropriate to use in instances when
// the zero register can be used, e.g. when estimating the cost of
// materializing a value used by a particular operation.
int getIntMatCost(const APInt &Val, unsigned Size, const MCSubtargetInfo &STI,
bool CompressionCost = false, bool FreeZeroes = false);
} // namespace RISCVMatInt
} // namespace llvm
#endif