LLVM 22.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.
40 if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
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 *GEP = dyn_cast<GEPOperator>(User)) {
67 NewPointeeTy = GEP->getSourceElementType();
68 }
69 if (NewPointeeTy) {
70 // HLSL doesn't support pointers, so it is unlikely to get more than one
71 // or two levels of indirection in the IR. Because of this, recursion is
72 // pretty safe.
73 if (NewPointeeTy->isPointerTy()) {
74 PointeeTy = classifyPointerType(User, Map);
75 break;
76 }
77 if (!PointeeTy)
78 PointeeTy = NewPointeeTy;
79 else if (PointeeTy != NewPointeeTy)
80 PointeeTy = Type::getInt8Ty(V->getContext());
81 }
82 }
83 // If we were unable to determine the pointee type, set to i8
84 if (!PointeeTy)
85 PointeeTy = Type::getInt8Ty(V->getContext());
86 auto *TypedPtrTy =
87 TypedPointerType::get(PointeeTy, V->getType()->getPointerAddressSpace());
88
89 Map[V] = TypedPtrTy;
90 return TypedPtrTy;
91}
92
93// This function constructs a function type accepting typed pointers. It only
94// handles function arguments and return types, and assigns the function type to
95// the function's value in the type map.
96Type *classifyFunctionType(const Function &F, PointerTypeMap &Map) {
97 auto It = Map.find(&F);
98 if (It != Map.end())
99 return It->second;
100
102 Type *RetTy = F.getReturnType();
103 LLVMContext &Ctx = F.getContext();
104 if (RetTy->isPointerTy()) {
105 RetTy = nullptr;
106 for (const auto &B : F) {
107 const auto *RetInst = dyn_cast_or_null<ReturnInst>(B.getTerminator());
108 if (!RetInst)
109 continue;
110
111 Type *NewRetTy = classifyPointerType(RetInst->getReturnValue(), Map);
112 if (!RetTy)
113 RetTy = NewRetTy;
114 else if (RetTy != NewRetTy)
116 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
117 }
118 // For function decl.
119 if (!RetTy)
121 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
122 }
123 for (auto &A : F.args()) {
124 Type *ArgTy = A.getType();
125 if (ArgTy->isPointerTy())
126 ArgTy = classifyPointerType(&A, Map);
127 NewArgs.push_back(ArgTy);
128 }
129 auto *TypedPtrTy =
130 TypedPointerType::get(FunctionType::get(RetTy, NewArgs, false), 0);
131 Map[&F] = TypedPtrTy;
132 return TypedPtrTy;
133}
134} // anonymous namespace
135
137 PointerTypeMap &Map) {
138 // FIXME: support ConstantPointerNull which could map to more than one
139 // TypedPointerType.
140 // See https://github.com/llvm/llvm-project/issues/57942.
141 if (isa<ConstantPointerNull>(C))
142 return TypedPointerType::get(Type::getInt8Ty(C->getContext()),
143 C->getType()->getPointerAddressSpace());
144
145 // Skip ConstantData which cannot have opaque ptr.
146 if (isa<ConstantData>(C))
147 return C->getType();
148
149 auto It = Map.find(C);
150 if (It != Map.end())
151 return It->second;
152
153 if (const auto *F = dyn_cast<Function>(C))
154 return classifyFunctionType(*F, Map);
155
156 Type *Ty = C->getType();
157 Type *TargetTy = nullptr;
158 if (auto *CS = dyn_cast<ConstantStruct>(C)) {
159 SmallVector<Type *> EltTys;
160 for (unsigned int I = 0; I < CS->getNumOperands(); ++I) {
161 const Constant *Elt = C->getAggregateElement(I);
162 Type *EltTy = classifyConstantWithOpaquePtr(Elt, Map);
163 EltTys.emplace_back(EltTy);
164 }
165 TargetTy = StructType::get(C->getContext(), EltTys);
166 } else if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
167
168 Type *TargetEltTy = nullptr;
169 for (auto &Elt : CA->operands()) {
170 Type *EltTy = classifyConstantWithOpaquePtr(cast<Constant>(&Elt), Map);
171 assert(TargetEltTy == EltTy || TargetEltTy == nullptr);
172 TargetEltTy = EltTy;
173 }
174
175 if (auto *AT = dyn_cast<ArrayType>(Ty)) {
176 TargetTy = ArrayType::get(TargetEltTy, AT->getNumElements());
177 } else {
178 // Not struct, not array, must be vector here.
179 auto *VT = cast<VectorType>(Ty);
180 TargetTy = VectorType::get(TargetEltTy, VT);
181 }
182 }
183 // Must have a target ty when map.
184 assert(TargetTy && "PointerTypeAnalyisis failed to identify target type");
185
186 // Same type, no need to map.
187 if (TargetTy == Ty)
188 return Ty;
189
190 Map[C] = TargetTy;
191 return TargetTy;
192}
193
195 PointerTypeMap &Map) {
196 const auto *CA = cast<ConstantArray>(GV.getInitializer());
197 // Type for global ctor should be array of { i32, void ()*, i8* }.
198 Type *CtorArrayTy = classifyConstantWithOpaquePtr(CA, Map);
199
200 // Map the global type.
201 Map[&GV] = TypedPointerType::get(CtorArrayTy,
203}
204
206 PointerTypeMap Map;
207 for (auto &G : M.globals()) {
208 if (G.getType()->isPointerTy())
209 classifyPointerType(&G, Map);
210 if (G.getName() == "llvm.global_ctors")
212 }
213
214 for (auto &F : M) {
215 classifyFunctionType(F, Map);
216
217 for (const auto &B : F) {
218 for (const auto &I : B) {
219 if (I.getType()->isPointerTy())
220 classifyPointerType(&I, Map);
221 for (const auto &O : I.operands())
222 if (O.get()->getType()->isPointerTy())
223 classifyPointerType(O.get(), Map);
224 }
225 }
226 }
227 return Map;
228}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
return RetTy
Hexagon Common GEP
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
#define G(x, y, z)
Definition: MD5.cpp:56
static Type * classifyConstantWithOpaquePtr(const Constant *C, PointerTypeMap &Map)
static void classifyGlobalCtorPointerType(const GlobalVariable &GV, PointerTypeMap &Map)
This is an important base class in LLVM.
Definition: Constant.h:43
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:296
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:67
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:938
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
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:414
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:267
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
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
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18