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 if (F.isDeclaration())
66 continue;
67 const RISCVSubtarget &ST = TM.getSubtarget<RISCVSubtarget>(F);
68 const RISCVTargetLowering *TLI = ST.getTargetLowering();
69 Changed |= runOnFunction(F, TLI);
70 }
71 return Changed;
72 }
73
74private:
75 bool runOnFunction(Function &F, const RISCVTargetLowering *TLI);
76};
77} // end anonymous namespace
78
79char RISCVPromoteConstant::ID = 0;
80
82 false, false)
83
85 return new RISCVPromoteConstant();
86}
87
88bool RISCVPromoteConstant::runOnFunction(Function &F,
89 const RISCVTargetLowering *TLI) {
90 if (F.hasOptNone() || F.hasOptSize())
91 return false;
92
93 // Bail out and make no transformation if the target doesn't support
94 // doubles, or if we're not targeting RV64 as we currently see some
95 // regressions for those targets.
96 if (!TLI->isTypeLegal(MVT::f64) || !TLI->isTypeLegal(MVT::i64))
97 return false;
98
99 // Collect all unique double constants and their uses in the function. Use
100 // MapVector to preserve insertion order.
101 MapVector<ConstantFP *, SmallVector<Use *, 8>> ConstUsesMap;
102
103 for (Instruction &I : instructions(F)) {
104 for (Use &U : I.operands()) {
105 auto *C = dyn_cast<ConstantFP>(U.get());
106 if (!C || !C->getType()->isDoubleTy())
107 continue;
108 // Do not promote if it wouldn't be loaded from the constant pool.
109 if (TLI->isFPImmLegal(C->getValueAPF(), MVT::f64,
110 /*ForCodeSize=*/false))
111 continue;
112 // Do not promote a constant if it is used as an immediate argument
113 // for an intrinsic.
114 if (auto *II = dyn_cast<IntrinsicInst>(U.getUser())) {
115 Function *IntrinsicFunc = II->getFunction();
116 unsigned OperandIdx = U.getOperandNo();
117 if (IntrinsicFunc && IntrinsicFunc->getAttributes().hasParamAttr(
118 OperandIdx, Attribute::ImmArg)) {
119 LLVM_DEBUG(dbgs() << "Skipping promotion of constant in: " << *II
120 << " because operand " << OperandIdx
121 << " must be an immediate.\n");
122 continue;
123 }
124 }
125 // Note: FP args to inline asm would be problematic if we had a
126 // constraint that required an immediate floating point operand. At the
127 // time of writing LLVM doesn't recognise such a constraint.
128 ConstUsesMap[C].push_back(&U);
129 }
130 }
131
132 int PromotableConstants = ConstUsesMap.size();
133 LLVM_DEBUG(dbgs() << "Found " << PromotableConstants
134 << " promotable constants in " << F.getName() << "\n");
135 // Bail out if no promotable constants found, or if only one is found.
136 if (PromotableConstants < 2) {
137 LLVM_DEBUG(dbgs() << "Performing no promotions as insufficient promotable "
138 "constants found\n");
139 return false;
140 }
141
142 NumPromoted += PromotableConstants;
143
144 // Create a global array containing the promoted constants.
145 Module *M = F.getParent();
146 Type *DoubleTy = Type::getDoubleTy(M->getContext());
147
148 SmallVector<Constant *, 16> ConstantVector;
149 for (auto const &Pair : ConstUsesMap)
150 ConstantVector.push_back(Pair.first);
151
152 ArrayType *ArrayTy = ArrayType::get(DoubleTy, ConstantVector.size());
153 Constant *GlobalArrayInitializer =
154 ConstantArray::get(ArrayTy, ConstantVector);
155
156 auto *GlobalArray = new GlobalVariable(
157 *M, ArrayTy,
158 /*isConstant=*/true, GlobalValue::InternalLinkage, GlobalArrayInitializer,
159 ".promoted_doubles." + F.getName());
160
161 // A cache to hold the loaded value for a given constant within a basic block.
162 DenseMap<std::pair<ConstantFP *, BasicBlock *>, Value *> LocalLoads;
163
164 // Replace all uses with the loaded value.
165 unsigned Idx = 0;
166 for (auto const &Pair : ConstUsesMap) {
167 ConstantFP *Const = Pair.first;
168 const SmallVector<Use *, 8> &Uses = Pair.second;
169
170 for (Use *U : Uses) {
171 Instruction *UserInst = cast<Instruction>(U->getUser());
172 BasicBlock *InsertionBB;
173
174 // If the user is a PHI node, we must insert the load in the
175 // corresponding predecessor basic block. Otherwise, it's inserted into
176 // the same block as the use.
177 if (auto *PN = dyn_cast<PHINode>(UserInst))
178 InsertionBB = PN->getIncomingBlock(*U);
179 else
180 InsertionBB = UserInst->getParent();
181
182 if (isa<CatchSwitchInst>(InsertionBB->getTerminator())) {
183 LLVM_DEBUG(dbgs() << "Bailing out: catchswitch means thre is no valid "
184 "insertion point.\n");
185 return false;
186 }
187
188 auto CacheKey = std::make_pair(Const, InsertionBB);
189 Value *LoadedVal = nullptr;
190
191 // Re-use a load if it exists in the insertion block.
192 if (LocalLoads.count(CacheKey)) {
193 LoadedVal = LocalLoads.at(CacheKey);
194 } else {
195 // Otherwise, create a new GEP and Load at the correct insertion point.
196 // It is always safe to insert in the first insertion point in the BB,
197 // so do that and let other passes reorder.
198 IRBuilder<> Builder(InsertionBB, InsertionBB->getFirstInsertionPt());
199 Value *ElementPtr = Builder.CreateConstInBoundsGEP2_64(
200 GlobalArray->getValueType(), GlobalArray, 0, Idx, "double.addr");
201 LoadedVal = Builder.CreateLoad(DoubleTy, ElementPtr, "double.val");
202
203 // Cache the newly created load for this block.
204 LocalLoads[CacheKey] = LoadedVal;
205 }
206
207 U->set(LoadedVal);
208 ++NumPromotedUses;
209 }
210 ++Idx;
211 }
212
213 return true;
214}
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:303
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:254
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