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"
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
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:275
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:328
@ 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