LLVM 19.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"
16
17using namespace llvm;
18using namespace llvm::dxil;
19
20namespace {
21
22// Classifies the type of the value passed in by walking the value's users to
23// find a typed instruction to materialize a type from.
24Type *classifyPointerType(const Value *V, PointerTypeMap &Map) {
25 assert(V->getType()->isPointerTy() &&
26 "classifyPointerType called with non-pointer");
27 auto It = Map.find(V);
28 if (It != Map.end())
29 return It->second;
30
31 Type *PointeeTy = nullptr;
32 if (auto *Inst = dyn_cast<GetElementPtrInst>(V)) {
33 if (!Inst->getResultElementType()->isPointerTy())
34 PointeeTy = Inst->getResultElementType();
35 } else if (auto *Inst = dyn_cast<AllocaInst>(V)) {
36 PointeeTy = Inst->getAllocatedType();
37 } else if (auto *GV = dyn_cast<GlobalVariable>(V)) {
38 PointeeTy = GV->getValueType();
39 }
40
41 for (const auto *User : V->users()) {
42 Type *NewPointeeTy = nullptr;
43 if (const auto *Inst = dyn_cast<LoadInst>(User)) {
44 NewPointeeTy = Inst->getType();
45 } else if (const auto *Inst = dyn_cast<StoreInst>(User)) {
46 NewPointeeTy = Inst->getValueOperand()->getType();
47 // When store value is ptr type, cannot get more type info.
48 if (NewPointeeTy->isPointerTy())
49 continue;
50 } else if (const auto *Inst = dyn_cast<GetElementPtrInst>(User)) {
51 NewPointeeTy = Inst->getSourceElementType();
52 }
53 if (NewPointeeTy) {
54 // HLSL doesn't support pointers, so it is unlikely to get more than one
55 // or two levels of indirection in the IR. Because of this, recursion is
56 // pretty safe.
57 if (NewPointeeTy->isPointerTy()) {
58 PointeeTy = classifyPointerType(User, Map);
59 break;
60 }
61 if (!PointeeTy)
62 PointeeTy = NewPointeeTy;
63 else if (PointeeTy != NewPointeeTy)
64 PointeeTy = Type::getInt8Ty(V->getContext());
65 }
66 }
67 // If we were unable to determine the pointee type, set to i8
68 if (!PointeeTy)
69 PointeeTy = Type::getInt8Ty(V->getContext());
70 auto *TypedPtrTy =
71 TypedPointerType::get(PointeeTy, V->getType()->getPointerAddressSpace());
72
73 Map[V] = TypedPtrTy;
74 return TypedPtrTy;
75}
76
77// This function constructs a function type accepting typed pointers. It only
78// handles function arguments and return types, and assigns the function type to
79// the function's value in the type map.
80Type *classifyFunctionType(const Function &F, PointerTypeMap &Map) {
81 auto It = Map.find(&F);
82 if (It != Map.end())
83 return It->second;
84
86 Type *RetTy = F.getReturnType();
87 LLVMContext &Ctx = F.getContext();
88 if (RetTy->isPointerTy()) {
89 RetTy = nullptr;
90 for (const auto &B : F) {
91 const auto *RetInst = dyn_cast_or_null<ReturnInst>(B.getTerminator());
92 if (!RetInst)
93 continue;
94
95 Type *NewRetTy = classifyPointerType(RetInst->getReturnValue(), Map);
96 if (!RetTy)
97 RetTy = NewRetTy;
98 else if (RetTy != NewRetTy)
100 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
101 }
102 // For function decl.
103 if (!RetTy)
105 Type::getInt8Ty(Ctx), F.getReturnType()->getPointerAddressSpace());
106 }
107 for (auto &A : F.args()) {
108 Type *ArgTy = A.getType();
109 if (ArgTy->isPointerTy())
110 ArgTy = classifyPointerType(&A, Map);
111 NewArgs.push_back(ArgTy);
112 }
113 auto *TypedPtrTy =
114 TypedPointerType::get(FunctionType::get(RetTy, NewArgs, false), 0);
115 Map[&F] = TypedPtrTy;
116 return TypedPtrTy;
117}
118} // anonymous namespace
119
121 PointerTypeMap &Map) {
122 // FIXME: support ConstantPointerNull which could map to more than one
123 // TypedPointerType.
124 // See https://github.com/llvm/llvm-project/issues/57942.
125 if (isa<ConstantPointerNull>(C))
126 return TypedPointerType::get(Type::getInt8Ty(C->getContext()),
127 C->getType()->getPointerAddressSpace());
128
129 // Skip ConstantData which cannot have opaque ptr.
130 if (isa<ConstantData>(C))
131 return C->getType();
132
133 auto It = Map.find(C);
134 if (It != Map.end())
135 return It->second;
136
137 if (const auto *F = dyn_cast<Function>(C))
138 return classifyFunctionType(*F, Map);
139
140 Type *Ty = C->getType();
141 Type *TargetTy = nullptr;
142 if (auto *CS = dyn_cast<ConstantStruct>(C)) {
143 SmallVector<Type *> EltTys;
144 for (unsigned int I = 0; I < CS->getNumOperands(); ++I) {
145 const Constant *Elt = C->getAggregateElement(I);
146 Type *EltTy = classifyConstantWithOpaquePtr(Elt, Map);
147 EltTys.emplace_back(EltTy);
148 }
149 TargetTy = StructType::get(C->getContext(), EltTys);
150 } else if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
151
152 Type *TargetEltTy = nullptr;
153 for (auto &Elt : CA->operands()) {
154 Type *EltTy = classifyConstantWithOpaquePtr(cast<Constant>(&Elt), Map);
155 assert(TargetEltTy == EltTy || TargetEltTy == nullptr);
156 TargetEltTy = EltTy;
157 }
158
159 if (auto *AT = dyn_cast<ArrayType>(Ty)) {
160 TargetTy = ArrayType::get(TargetEltTy, AT->getNumElements());
161 } else {
162 // Not struct, not array, must be vector here.
163 auto *VT = cast<VectorType>(Ty);
164 TargetTy = VectorType::get(TargetEltTy, VT);
165 }
166 }
167 // Must have a target ty when map.
168 assert(TargetTy && "PointerTypeAnalyisis failed to identify target type");
169
170 // Same type, no need to map.
171 if (TargetTy == Ty)
172 return Ty;
173
174 Map[C] = TargetTy;
175 return TargetTy;
176}
177
179 PointerTypeMap &Map) {
180 const auto *CA = cast<ConstantArray>(GV.getInitializer());
181 // Type for global ctor should be array of { i32, void ()*, i8* }.
182 Type *CtorArrayTy = classifyConstantWithOpaquePtr(CA, Map);
183
184 // Map the global type.
185 Map[&GV] = TypedPointerType::get(CtorArrayTy,
187}
188
190 PointerTypeMap Map;
191 for (auto &G : M.globals()) {
192 if (G.getType()->isPointerTy())
193 classifyPointerType(&G, Map);
194 if (G.getName() == "llvm.global_ctors")
196 }
197
198 for (auto &F : M) {
199 classifyFunctionType(F, Map);
200
201 for (const auto &B : F) {
202 for (const auto &I : B) {
203 if (I.getType()->isPointerTy())
204 classifyPointerType(&I, Map);
205 }
206 }
207 }
208 return Map;
209}
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
#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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This is an important base class in LLVM.
Definition: Constant.h:41
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:294
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:67
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:950
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
static 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:373
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:255
unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static IntegerType * getInt8Ty(LLVMContext &C)
static 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:74
@ 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