LLVM 24.0.0git
PointerTypeAnalysis.cpp
Go to the documentation of this file.
1//===- Target/DirectX/PointerTypeAnalisis.cpp - PointerType analysis ------===//
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// Analysis pass to assign types to opaque pointers.
10//
11//===----------------------------------------------------------------------===//
12
13#include "PointerTypeAnalysis.h"
14#include "llvm/IR/Constants.h"
17#include "llvm/IR/Module.h"
18#include "llvm/IR/Operator.h"
19
20using namespace llvm;
21using namespace llvm::dxil;
22
23namespace {
24
25Type *classifyFunctionType(const Function &F, PointerTypeMap &Map);
26
27// Classifies the type of the value passed in by walking the value's users to
28// find a typed instruction to materialize a type from.
29Type *classifyPointerType(const Value *V, PointerTypeMap &Map) {
30 assert(V->getType()->isPointerTy() &&
31 "classifyPointerType called with non-pointer");
32
33 // A CallInst will trigger this case, and we want to classify its Function
34 // operand as a Function rather than a generic Value.
35 if (const Function *F = dyn_cast<Function>(V))
36 return classifyFunctionType(*F, Map);
37
38 // There can potentially be dead constants hanging off of the globals we do
39 // not want to deal with. So we remove them here.
41 GV->removeDeadConstantUsers();
42
43 auto It = Map.find(V);
44 if (It != Map.end())
45 return It->second;
46
47 Type *PointeeTy = nullptr;
48 if (auto *GEP = dyn_cast<GEPOperator>(V)) {
49 if (!GEP->getResultElementType()->isPointerTy())
50 PointeeTy = GEP->getResultElementType();
51 } else if (auto *Inst = dyn_cast<AllocaInst>(V)) {
52 PointeeTy = Inst->getAllocatedType();
53 } else if (auto *GV = dyn_cast<GlobalVariable>(V)) {
54 PointeeTy = GV->getValueType();
55 }
56
57 for (const auto *User : V->users()) {
58 Type *NewPointeeTy = nullptr;
59 if (const auto *Inst = dyn_cast<LoadInst>(User)) {
60 NewPointeeTy = Inst->getType();
61 } else if (const auto *Inst = dyn_cast<StoreInst>(User)) {
62 NewPointeeTy = Inst->getValueOperand()->getType();
63 // When store value is ptr type, cannot get more type info.
64 if (NewPointeeTy->isPointerTy())
65 continue;
66 } else if (const auto *Inst = dyn_cast<AtomicRMWInst>(User)) {
67 NewPointeeTy = Inst->getValOperand()->getType();
68 } else if (const auto *Inst = dyn_cast<AtomicCmpXchgInst>(User)) {
69 NewPointeeTy = Inst->getNewValOperand()->getType();
70 } else if (const auto *GEP = dyn_cast<GEPOperator>(User)) {
71 NewPointeeTy = GEP->getSourceElementType();
72 }
73 if (NewPointeeTy) {
74 // HLSL doesn't support pointers, so it is unlikely to get more than one
75 // or two levels of indirection in the IR. Because of this, recursion is
76 // pretty safe.
77 if (NewPointeeTy->isPointerTy()) {
78 PointeeTy = classifyPointerType(User, Map);
79 break;
80 }
81 if (!PointeeTy)
82 PointeeTy = NewPointeeTy;
83 else if (PointeeTy != NewPointeeTy)
84 PointeeTy = Type::getInt8Ty(V->getContext());
85 }
86 }
87 // If we were unable to determine the pointee type, set to i8
88 // If we were able to determine the pointee type as ptr, set to i8*
89 if (!PointeeTy)
90 PointeeTy = Type::getInt8Ty(V->getContext());
91 if (PointeeTy->isPointerTy())
92 PointeeTy = TypedPointerType::get(Type::getInt8Ty(V->getContext()),
93 PointeeTy->getPointerAddressSpace());
94 auto *TypedPtrTy =
95 TypedPointerType::get(PointeeTy, V->getType()->getPointerAddressSpace());
96
97 Map[V] = TypedPtrTy;
98 return TypedPtrTy;
99}
100
101// This function constructs a function type accepting typed pointers. It only
102// handles function arguments and return types, and assigns the function type to
103// the function's value in the type map.
104Type *classifyFunctionType(const Function &F, PointerTypeMap &Map) {
105 auto It = Map.find(&F);
106 if (It != Map.end())
107 return It->second;
108
110 Type *RetTy = F.getReturnType();
111 LLVMContext &Ctx = F.getContext();
112 if (RetTy->isPointerTy()) {
113 RetTy = nullptr;
114 for (const auto &B : F) {
115 const auto *RetInst = dyn_cast_or_null<ReturnInst>(B.getTerminator());
116 if (!RetInst)
117 continue;
118
119 Type *NewRetTy = classifyPointerType(RetInst->getReturnValue(), Map);
120 if (!RetTy)
121 RetTy = NewRetTy;
122 else if (RetTy != NewRetTy)
123 RetTy = TypedPointerType::get(
124 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
125 }
126 // For function decl.
127 if (!RetTy)
128 RetTy = TypedPointerType::get(
129 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
130 }
131 for (auto &A : F.args()) {
132 Type *ArgTy = A.getType();
133 if (ArgTy->isPointerTy())
134 ArgTy = classifyPointerType(&A, Map);
135 NewArgs.push_back(ArgTy);
136 }
137 auto *TypedPtrTy =
138 TypedPointerType::get(FunctionType::get(RetTy, NewArgs, false), 0);
139 Map[&F] = TypedPtrTy;
140 return TypedPtrTy;
141}
142} // anonymous namespace
143
145 PointerTypeMap &Map) {
146 // FIXME: support ConstantPointerNull and UndefValue which could map to more
147 // than one TypedPointerType. See
148 // https://github.com/llvm/llvm-project/issues/57942.
150 (isa<UndefValue>(C) && C->getType()->isPointerTy()))
151 return TypedPointerType::get(Type::getInt8Ty(C->getContext()),
152 C->getType()->getPointerAddressSpace());
153
154 // Skip ConstantData which cannot have opaque ptr.
155 if (isa<ConstantData>(C))
156 return C->getType();
157
158 auto It = Map.find(C);
159 if (It != Map.end())
160 return It->second;
161
162 if (const auto *F = dyn_cast<Function>(C))
163 return classifyFunctionType(*F, Map);
164
165 Type *Ty = C->getType();
166 Type *TargetTy = nullptr;
167 if (auto *CS = dyn_cast<ConstantStruct>(C)) {
168 SmallVector<Type *> EltTys;
169 for (unsigned int I = 0; I < CS->getNumOperands(); ++I) {
170 const Constant *Elt = C->getAggregateElement(I);
171 Type *EltTy = classifyConstantWithOpaquePtr(Elt, Map);
172 EltTys.emplace_back(EltTy);
173 }
174 TargetTy = StructType::get(C->getContext(), EltTys);
175 } else if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
176
177 Type *TargetEltTy = nullptr;
178 for (auto &Elt : CA->operands()) {
180 assert(TargetEltTy == EltTy || TargetEltTy == nullptr);
181 TargetEltTy = EltTy;
182 }
183
184 if (auto *AT = dyn_cast<ArrayType>(Ty)) {
185 TargetTy = ArrayType::get(TargetEltTy, AT->getNumElements());
186 } else {
187 // Not struct, not array, must be vector here.
188 auto *VT = cast<VectorType>(Ty);
189 TargetTy = VectorType::get(TargetEltTy, VT);
190 }
191 }
192 // Must have a target ty when map.
193 assert(TargetTy && "PointerTypeAnalyisis failed to identify target type");
194
195 // Same type, no need to map.
196 if (TargetTy == Ty)
197 return Ty;
198
199 Map[C] = TargetTy;
200 return TargetTy;
201}
202
204 PointerTypeMap &Map) {
205 const auto *CA = dyn_cast<ConstantArray>(GV.getInitializer());
206 if (!CA) {
207 // An empty global_ctors will be a zeroinitializer, so just skip it.
209 "global_ctors should be a ConstantArray or ConstantAggregateZero");
210 return;
211 }
212 // Type for global ctor should be array of { i32, void ()*, i8* }.
213 Type *CtorArrayTy = classifyConstantWithOpaquePtr(CA, Map);
214
215 // Map the global type.
216 Map[&GV] = TypedPointerType::get(CtorArrayTy,
218}
219
221 PointerTypeMap Map;
222 for (auto &G : M.globals()) {
223 if (G.getType()->isPointerTy())
224 classifyPointerType(&G, Map);
225 if (G.getName() == "llvm.global_ctors")
227 }
228
229 for (auto &F : M) {
230 classifyFunctionType(F, Map);
231
232 for (const auto &B : F) {
233 for (const auto &I : B) {
234 if (I.getType()->isPointerTy())
235 classifyPointerType(&I, Map);
236 for (const auto &O : I.operands())
237 if (O.get()->getType()->isPointerTy())
238 classifyPointerType(O.get(), Map);
239 }
240 }
241 }
242 return Map;
243}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Hexagon Common GEP
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
#define G(x, y, z)
Definition MD5.cpp:55
static Type * classifyConstantWithOpaquePtr(const Constant *C, PointerTypeMap &Map)
static void classifyGlobalCtorPointerType(const GlobalVariable &GV, PointerTypeMap &Map)
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
This is an important base class in LLVM.
Definition Constant.h:43
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
PointerType * getType() const
Global values are always pointers.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:467
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
LLVM Value Representation.
Definition Value.h:75
iterator_range< user_iterator > users()
Definition Value.h:428
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
DenseMap< const Value *, Type * > PointerTypeMap
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
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
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
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559