LLVM 22.0.0git
RISCVPromoteConstant.cpp
Go to the documentation of this file.
1//==- RISCVPromoteConstant.cpp - Promote constant fp to global for RISC-V --==//
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 "RISCV.h"
10#include "RISCVSubtarget.h"
11#include "llvm/ADT/DenseMap.h"
13#include "llvm/ADT/Statistic.h"
16#include "llvm/IR/BasicBlock.h"
17#include "llvm/IR/Constant.h"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/GlobalValue.h"
22#include "llvm/IR/IRBuilder.h"
24#include "llvm/IR/Instruction.h"
27#include "llvm/IR/Module.h"
28#include "llvm/IR/Type.h"
30#include "llvm/Pass.h"
32#include "llvm/Support/Debug.h"
33
34using namespace llvm;
35
36#define DEBUG_TYPE "riscv-promote-const"
37#define RISCV_PROMOTE_CONSTANT_NAME "RISC-V Promote Constants"
38
39STATISTIC(NumPromoted, "Number of constant literals promoted to globals");
40STATISTIC(NumPromotedUses, "Number of uses of promoted literal constants");
41
42namespace {
43
44class RISCVPromoteConstant : public ModulePass {
45public:
46 static char ID;
47 RISCVPromoteConstant() : ModulePass(ID) {}
48
49 StringRef getPassName() const override { return RISCV_PROMOTE_CONSTANT_NAME; }
50
51 void getAnalysisUsage(AnalysisUsage &AU) const override {
52 AU.addRequired<TargetPassConfig>();
53 AU.setPreservesCFG();
54 }
55
56 /// Iterate over the functions and promote the double fp constants that
57 /// would otherwise go into the constant pool to a constant array.
58 bool runOnModule(Module &M) override {
59 if (skipModule(M))
60 return false;
61 // TargetMachine and Subtarget are needed to query isFPImmlegal.
62 const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
63 const TargetMachine &TM = TPC.getTM<TargetMachine>();
64 bool Changed = false;
65 for (Function &F : M) {
66 const RISCVSubtarget &ST = TM.getSubtarget<RISCVSubtarget>(F);
67 const RISCVTargetLowering *TLI = ST.getTargetLowering();
68 Changed |= runOnFunction(F, TLI);
69 }
70 return Changed;
71 }
72
73private:
74 bool runOnFunction(Function &F, const RISCVTargetLowering *TLI);
75};
76} // end anonymous namespace
77
78char RISCVPromoteConstant::ID = 0;
79
81 false, false)
82
84 return new RISCVPromoteConstant();
85}
86
87bool RISCVPromoteConstant::runOnFunction(Function &F,
88 const RISCVTargetLowering *TLI) {
89 if (F.hasOptNone() || F.hasOptSize())
90 return false;
91
92 // Bail out and make no transformation if the target doesn't support
93 // doubles, or if we're not targeting RV64 as we currently see some
94 // regressions for those targets.
95 if (!TLI->isTypeLegal(MVT::f64) || !TLI->isTypeLegal(MVT::i64))
96 return false;
97
98 // Collect all unique double constants and their uses in the function. Use
99 // MapVector to preserve insertion order.
100 MapVector<ConstantFP *, SmallVector<Use *, 8>> ConstUsesMap;
101
102 for (Instruction &I : instructions(F)) {
103 for (Use &U : I.operands()) {
104 auto *C = dyn_cast<ConstantFP>(U.get());
105 if (!C || !C->getType()->isDoubleTy())
106 continue;
107 // Do not promote if it wouldn't be loaded from the constant pool.
108 if (TLI->isFPImmLegal(C->getValueAPF(), MVT::f64,
109 /*ForCodeSize=*/false))
110 continue;
111 // Do not promote a constant if it is used as an immediate argument
112 // for an intrinsic.
113 if (auto *II = dyn_cast<IntrinsicInst>(U.getUser())) {
114 Function *IntrinsicFunc = II->getFunction();
115 unsigned OperandIdx = U.getOperandNo();
116 if (IntrinsicFunc && IntrinsicFunc->getAttributes().hasParamAttr(
117 OperandIdx, Attribute::ImmArg)) {
118 LLVM_DEBUG(dbgs() << "Skipping promotion of constant in: " << *II
119 << " because operand " << OperandIdx
120 << " must be an immediate.\n");
121 continue;
122 }
123 }
124 // Note: FP args to inline asm would be problematic if we had a
125 // constraint that required an immediate floating point operand. At the
126 // time of writing LLVM doesn't recognise such a constraint.
127 ConstUsesMap[C].push_back(&U);
128 }
129 }
130
131 int PromotableConstants = ConstUsesMap.size();
132 LLVM_DEBUG(dbgs() << "Found " << PromotableConstants
133 << " promotable constants in " << F.getName() << "\n");
134 // Bail out if no promotable constants found, or if only one is found.
135 if (PromotableConstants < 2) {
136 LLVM_DEBUG(dbgs() << "Performing no promotions as insufficient promotable "
137 "constants found\n");
138 return false;
139 }
140
141 NumPromoted += PromotableConstants;
142
143 // Create a global array containing the promoted constants.
144 Module *M = F.getParent();
145 Type *DoubleTy = Type::getDoubleTy(M->getContext());
146
147 SmallVector<Constant *, 16> ConstantVector;
148 for (auto const &Pair : ConstUsesMap)
149 ConstantVector.push_back(Pair.first);
150
151 ArrayType *ArrayTy = ArrayType::get(DoubleTy, ConstantVector.size());
152 Constant *GlobalArrayInitializer =
153 ConstantArray::get(ArrayTy, ConstantVector);
154
155 auto *GlobalArray = new GlobalVariable(
156 *M, ArrayTy,
157 /*isConstant=*/true, GlobalValue::InternalLinkage, GlobalArrayInitializer,
158 ".promoted_doubles." + F.getName());
159
160 // A cache to hold the loaded value for a given constant within a basic block.
161 DenseMap<std::pair<ConstantFP *, BasicBlock *>, Value *> LocalLoads;
162
163 // Replace all uses with the loaded value.
164 unsigned Idx = 0;
165 for (auto const &Pair : ConstUsesMap) {
166 ConstantFP *Const = Pair.first;
167 const SmallVector<Use *, 8> &Uses = Pair.second;
168
169 for (Use *U : Uses) {
170 Instruction *UserInst = cast<Instruction>(U->getUser());
171 BasicBlock *InsertionBB;
172
173 // If the user is a PHI node, we must insert the load in the
174 // corresponding predecessor basic block. Otherwise, it's inserted into
175 // the same block as the use.
176 if (auto *PN = dyn_cast<PHINode>(UserInst))
177 InsertionBB = PN->getIncomingBlock(*U);
178 else
179 InsertionBB = UserInst->getParent();
180
181 if (isa<CatchSwitchInst>(InsertionBB->getTerminator())) {
182 LLVM_DEBUG(dbgs() << "Bailing out: catchswitch means thre is no valid "
183 "insertion point.\n");
184 return false;
185 }
186
187 auto CacheKey = std::make_pair(Const, InsertionBB);
188 Value *LoadedVal = nullptr;
189
190 // Re-use a load if it exists in the insertion block.
191 if (LocalLoads.count(CacheKey)) {
192 LoadedVal = LocalLoads.at(CacheKey);
193 } else {
194 // Otherwise, create a new GEP and Load at the correct insertion point.
195 // It is always safe to insert in the first insertion point in the BB,
196 // so do that and let other passes reorder.
197 IRBuilder<> Builder(InsertionBB, InsertionBB->getFirstInsertionPt());
198 Value *ElementPtr = Builder.CreateConstInBoundsGEP2_64(
199 GlobalArray->getValueType(), GlobalArray, 0, Idx, "double.addr");
200 LoadedVal = Builder.CreateLoad(DoubleTy, ElementPtr, "double.val");
201
202 // Cache the newly created load for this block.
203 LocalLoads[CacheKey] = LoadedVal;
204 }
205
206 U->set(LoadedVal);
207 ++NumPromotedUses;
208 }
209 ++Idx;
210 }
211
212 return true;
213}
Expand Atomic instructions
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
Machine Check Debug Module
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define RISCV_PROMOTE_CONSTANT_NAME
Remove Loads Into Fake Uses
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:114
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition BasicBlock.h:233
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition DenseMap.h:174
const ValueT & at(const_arg_type_t< KeyT > Val) const
at - Return the entry for the specified key, or abort if no such entry exists.
Definition DenseMap.h:224
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:352
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
size_type size() const
Definition MapVector.h:56
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override
Returns true if the target can instruction select the specified FP immediate natively.
void push_back(const T &Elt)
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
TMC & getTM() const
Get the right type of TargetMachine for this target.
const ParentTy * getParent() const
Definition ilist_node.h:34
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
ModulePass * createRISCVPromoteConstantPass()
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559