LLVM 24.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"
29#include "llvm/Pass.h"
31#include "llvm/Support/Debug.h"
32
33using namespace llvm;
34
35#define DEBUG_TYPE "riscv-promote-const"
36#define RISCV_PROMOTE_CONSTANT_NAME "RISC-V Promote Constants"
37
38STATISTIC(NumPromoted, "Number of constant literals promoted to globals");
39STATISTIC(NumPromotedUses, "Number of uses of promoted literal constants");
40
41namespace {
42
43class RISCVPromoteConstant : public ModulePass {
44public:
45 static char ID;
46 RISCVPromoteConstant() : ModulePass(ID) {}
47
48 StringRef getPassName() const override { return RISCV_PROMOTE_CONSTANT_NAME; }
49
50 void getAnalysisUsage(AnalysisUsage &AU) const override {
51 AU.addRequired<TargetPassConfig>();
52 AU.setPreservesCFG();
53 }
54
55 /// Iterate over the functions and promote the double fp constants that
56 /// would otherwise go into the constant pool to a constant array.
57 bool runOnModule(Module &M) override {
58 if (skipModule(M))
59 return false;
60 // TargetMachine and Subtarget are needed to query isFPImmlegal.
61 const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
62 const TargetMachine &TM = TPC.getTM<TargetMachine>();
63 bool Changed = false;
64 for (Function &F : M) {
65 const RISCVSubtarget &ST = TM.getSubtarget<RISCVSubtarget>(F);
66 const RISCVTargetLowering *TLI = ST.getTargetLowering();
67 Changed |= runOnFunction(F, TLI);
68 }
69 return Changed;
70 }
71
72private:
73 bool runOnFunction(Function &F, const RISCVTargetLowering *TLI);
74};
75} // end anonymous namespace
76
77char RISCVPromoteConstant::ID = 0;
78
80 false, false)
81
83 return new RISCVPromoteConstant();
84}
85
86bool RISCVPromoteConstant::runOnFunction(Function &F,
87 const RISCVTargetLowering *TLI) {
88 if (F.hasOptNone() || F.hasOptSize())
89 return false;
90
91 // Bail out and make no transformation if the target doesn't support
92 // doubles, or if we're not targeting RV64 as we currently see some
93 // regressions for those targets.
94 if (!TLI->isTypeLegal(MVT::f64) || !TLI->isTypeLegal(MVT::i64))
95 return false;
96
97 // Collect all unique double constants and their uses in the function. Use
98 // MapVector to preserve insertion order.
99 MapVector<ConstantFP *, SmallVector<Use *, 8>> ConstUsesMap;
100
101 for (Instruction &I : instructions(F)) {
102 for (Use &U : I.operands()) {
103 auto *C = dyn_cast<ConstantFP>(U.get());
104 if (!C || !C->getType()->isDoubleTy())
105 continue;
106 // Do not promote if it wouldn't be loaded from the constant pool.
107 if (TLI->isFPImmLegal(C->getValueAPF(), MVT::f64,
108 /*ForCodeSize=*/false))
109 continue;
110 // Do not promote a constant if it is used as an immediate argument
111 // for an intrinsic.
112 if (auto *II = dyn_cast<IntrinsicInst>(U.getUser())) {
113 Function *IntrinsicFunc = II->getFunction();
114 unsigned OperandIdx = U.getOperandNo();
115 if (IntrinsicFunc && IntrinsicFunc->getAttributes().hasParamAttr(
116 OperandIdx, Attribute::ImmArg)) {
117 LLVM_DEBUG(dbgs() << "Skipping promotion of constant in: " << *II
118 << " because operand " << OperandIdx
119 << " must be an immediate.\n");
120 continue;
121 }
122 }
123 // Note: FP args to inline asm would be problematic if we had a
124 // constraint that required an immediate floating point operand. At the
125 // time of writing LLVM doesn't recognise such a constraint.
126 ConstUsesMap[C].push_back(&U);
127 }
128 }
129
130 int PromotableConstants = ConstUsesMap.size();
131 LLVM_DEBUG(dbgs() << "Found " << PromotableConstants
132 << " promotable constants in " << F.getName() << "\n");
133 // Bail out if no promotable constants found, or if only one is found.
134 if (PromotableConstants < 2) {
135 LLVM_DEBUG(dbgs() << "Performing no promotions as insufficient promotable "
136 "constants found\n");
137 return false;
138 }
139
140 NumPromoted += PromotableConstants;
141
142 // Create a global array containing the promoted constants.
143 Module *M = F.getParent();
144 Type *DoubleTy = Type::getDoubleTy(M->getContext());
145
146 SmallVector<Constant *, 16> ConstantVector;
147 for (auto const &Pair : ConstUsesMap)
148 ConstantVector.push_back(Pair.first);
149
150 ArrayType *ArrayTy = ArrayType::get(DoubleTy, ConstantVector.size());
151 Constant *GlobalArrayInitializer =
152 ConstantArray::get(ArrayTy, ConstantVector);
153
154 auto *GlobalArray = new GlobalVariable(
155 *M, ArrayTy,
156 /*isConstant=*/true, GlobalValue::InternalLinkage, GlobalArrayInitializer,
157 ".promoted_doubles." + F.getName());
158
159 // A cache to hold the loaded value for a given constant within a basic block.
160 DenseMap<std::pair<ConstantFP *, BasicBlock *>, Value *> LocalLoads;
161
162 // Replace all uses with the loaded value.
163 unsigned Idx = 0;
164 for (auto const &Pair : ConstUsesMap) {
165 ConstantFP *Const = Pair.first;
166 const SmallVector<Use *, 8> &Uses = Pair.second;
167
168 for (Use *U : Uses) {
169 Instruction *UserInst = cast<Instruction>(U->getUser());
170 BasicBlock *InsertionBB;
171
172 // If the user is a PHI node, we must insert the load in the
173 // corresponding predecessor basic block. Otherwise, it's inserted into
174 // the same block as the use.
175 if (auto *PN = dyn_cast<PHINode>(UserInst))
176 InsertionBB = PN->getIncomingBlock(*U);
177 else
178 InsertionBB = UserInst->getParent();
179
180 if (isa<CatchSwitchInst>(InsertionBB->getTerminator())) {
181 LLVM_DEBUG(dbgs() << "Bailing out: catchswitch means thre is no valid "
182 "insertion point.\n");
183 return false;
184 }
185
186 auto CacheKey = std::make_pair(Const, InsertionBB);
187 Value *LoadedVal = nullptr;
188
189 // Re-use a load if it exists in the insertion block.
190 if (LocalLoads.count(CacheKey)) {
191 LoadedVal = LocalLoads.at(CacheKey);
192 } else {
193 // Otherwise, create a new GEP and Load at the correct insertion point.
194 // It is always safe to insert in the first insertion point in the BB,
195 // so do that and let other passes reorder.
196 IRBuilder<> Builder(InsertionBB, InsertionBB->getFirstInsertionPt());
197 Value *ElementPtr = Builder.CreateConstInBoundsGEP2_64(
198 GlobalArray->getValueType(), GlobalArray, 0, Idx, "double.addr");
199 LoadedVal = Builder.CreateLoad(DoubleTy, ElementPtr, "double.val");
200
201 // Cache the newly created load for this block.
202 LocalLoads[CacheKey] = LoadedVal;
203 }
204
205 U->set(LoadedVal);
206 ++NumPromotedUses;
207 }
208 ++Idx;
209 }
210
211 return true;
212}
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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:54
#define I(x, y, z)
Definition MD5.cpp:57
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:119
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:278
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; assumes that the block is well-formed.
Definition BasicBlock.h:237
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
ValueT & at(const_arg_type_t< KeyT > Val)
Return the entry for the specified key, or abort if no such entry exists.
Definition DenseMap.h:268
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:219
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:329
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
size_type size() const
Definition MapVector.h:58
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.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
TMC & getTM() const
Get the right type of TargetMachine for this target.
const ParentTy * getParent() const
Definition ilist_node.h:34
Changed
@ 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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
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