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/Instructions.h"
15 
16 using namespace llvm;
17 using namespace llvm::dxil;
18 
19 namespace {
20 
21 // Classifies the type of the value passed in by walking the value's users to
22 // find a typed instruction to materialize a type from.
classifyPointerType(const Value * V)23 TypedPointerType *classifyPointerType(const Value *V) {
24   assert(V->getType()->isOpaquePointerTy() &&
25          "classifyPointerType called with non-opaque pointer");
26   Type *PointeeTy = nullptr;
27   if (auto *Inst = dyn_cast<GetElementPtrInst>(V)) {
28     if (!Inst->getResultElementType()->isOpaquePointerTy())
29       PointeeTy = Inst->getResultElementType();
30   } else if (auto *Inst = dyn_cast<AllocaInst>(V)) {
31     PointeeTy = Inst->getAllocatedType();
32   }
33   for (const auto *User : V->users()) {
34     Type *NewPointeeTy = nullptr;
35     if (const auto *Inst = dyn_cast<LoadInst>(User)) {
36       NewPointeeTy = Inst->getType();
37     } else if (const auto *Inst = dyn_cast<StoreInst>(User)) {
38       NewPointeeTy = Inst->getValueOperand()->getType();
39     } else if (const auto *Inst = dyn_cast<GetElementPtrInst>(User)) {
40       NewPointeeTy = Inst->getSourceElementType();
41     }
42     if (NewPointeeTy) {
43       // HLSL doesn't support pointers, so it is unlikely to get more than one
44       // or two levels of indirection in the IR. Because of this, recursion is
45       // pretty safe.
46       if (NewPointeeTy->isOpaquePointerTy())
47         return TypedPointerType::get(classifyPointerType(User),
48                                      V->getType()->getPointerAddressSpace());
49       if (!PointeeTy)
50         PointeeTy = NewPointeeTy;
51       else if (PointeeTy != NewPointeeTy)
52         PointeeTy = Type::getInt8Ty(V->getContext());
53     }
54   }
55   // If we were unable to determine the pointee type, set to i8
56   if (!PointeeTy)
57     PointeeTy = Type::getInt8Ty(V->getContext());
58   return TypedPointerType::get(PointeeTy,
59                                V->getType()->getPointerAddressSpace());
60 }
61 
62 // This function constructs a function type accepting typed pointers. It only
63 // handles function arguments and return types, and assigns the function type to
64 // the function's value in the type map.
classifyFunctionType(const Function & F,PointerTypeMap & Map)65 void classifyFunctionType(const Function &F, PointerTypeMap &Map) {
66   SmallVector<Type *, 8> NewArgs;
67   bool HasOpaqueTy = false;
68   Type *RetTy = F.getReturnType();
69   if (RetTy->isOpaquePointerTy()) {
70     RetTy = nullptr;
71     for (const auto &B : F) {
72       for (const auto &I : B) {
73         if (const auto *RetInst = dyn_cast_or_null<ReturnInst>(&I)) {
74           Type *NewRetTy = classifyPointerType(RetInst->getReturnValue());
75           if (!RetTy)
76             RetTy = NewRetTy;
77           else if (RetTy != NewRetTy)
78             RetTy = TypedPointerType::get(
79                 Type::getInt8Ty(I.getContext()),
80                 F.getReturnType()->getPointerAddressSpace());
81         }
82       }
83     }
84   }
85   for (auto &A : F.args()) {
86     Type *ArgTy = A.getType();
87     if (ArgTy->isOpaquePointerTy()) {
88       TypedPointerType *NewTy = classifyPointerType(&A);
89       Map[&A] = NewTy;
90       ArgTy = NewTy;
91       HasOpaqueTy = true;
92     }
93     NewArgs.push_back(ArgTy);
94   }
95   if (!HasOpaqueTy)
96     return;
97   Map[&F] = FunctionType::get(RetTy, NewArgs, false);
98 }
99 } // anonymous namespace
100 
run(const Module & M)101 PointerTypeMap PointerTypeAnalysis::run(const Module &M) {
102   PointerTypeMap Map;
103   for (auto &G : M.globals()) {
104     if (G.getType()->isOpaquePointerTy())
105       Map[&G] = classifyPointerType(&G);
106   }
107   for (auto &F : M) {
108     classifyFunctionType(F, Map);
109 
110     for (const auto &B : F) {
111       for (const auto &I : B) {
112         if (I.getType()->isOpaquePointerTy())
113           Map[&I] = classifyPointerType(&I);
114       }
115     }
116   }
117 
118   return Map;
119 }
120