]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | //===-- NVPTXLowerStructArgs.cpp - Copy struct args to local memory =====--===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // Copy struct args to local memory. This is needed for kernel functions only. | |
11 | // This is a preparation for handling cases like | |
12 | // | |
13 | // kernel void foo(struct A arg, ...) | |
14 | // { | |
15 | // struct A *p = &arg; | |
16 | // ... | |
17 | // ... = p->filed1 ... (this is no generic address for .param) | |
18 | // p->filed2 = ... (this is no write access to .param) | |
19 | // } | |
20 | // | |
21 | //===----------------------------------------------------------------------===// | |
22 | ||
23 | #include "NVPTX.h" | |
24 | #include "NVPTXUtilities.h" | |
25 | #include "llvm/IR/Function.h" | |
26 | #include "llvm/IR/Instructions.h" | |
27 | #include "llvm/IR/IntrinsicInst.h" | |
28 | #include "llvm/IR/Module.h" | |
29 | #include "llvm/IR/Type.h" | |
30 | #include "llvm/Pass.h" | |
31 | ||
32 | using namespace llvm; | |
33 | ||
34 | namespace llvm { | |
35 | void initializeNVPTXLowerStructArgsPass(PassRegistry &); | |
36 | } | |
37 | ||
38 | class LLVM_LIBRARY_VISIBILITY NVPTXLowerStructArgs : public FunctionPass { | |
39 | bool runOnFunction(Function &F) override; | |
40 | ||
41 | void handleStructPtrArgs(Function &); | |
42 | void handleParam(Argument *); | |
43 | ||
44 | public: | |
45 | static char ID; // Pass identification, replacement for typeid | |
46 | NVPTXLowerStructArgs() : FunctionPass(ID) {} | |
47 | const char *getPassName() const override { | |
48 | return "Copy structure (byval *) arguments to stack"; | |
49 | } | |
50 | }; | |
51 | ||
52 | char NVPTXLowerStructArgs::ID = 1; | |
53 | ||
54 | INITIALIZE_PASS(NVPTXLowerStructArgs, "nvptx-lower-struct-args", | |
55 | "Lower structure arguments (NVPTX)", false, false) | |
56 | ||
57 | void NVPTXLowerStructArgs::handleParam(Argument *Arg) { | |
58 | Function *Func = Arg->getParent(); | |
59 | Instruction *FirstInst = &(Func->getEntryBlock().front()); | |
60 | PointerType *PType = dyn_cast<PointerType>(Arg->getType()); | |
61 | ||
62 | assert(PType && "Expecting pointer type in handleParam"); | |
63 | ||
64 | Type *StructType = PType->getElementType(); | |
65 | AllocaInst *AllocA = new AllocaInst(StructType, Arg->getName(), FirstInst); | |
66 | ||
67 | /* Set the alignment to alignment of the byval parameter. This is because, | |
68 | * later load/stores assume that alignment, and we are going to replace | |
69 | * the use of the byval parameter with this alloca instruction. | |
70 | */ | |
71 | AllocA->setAlignment(Func->getParamAlignment(Arg->getArgNo() + 1)); | |
72 | ||
73 | Arg->replaceAllUsesWith(AllocA); | |
74 | ||
75 | // Get the cvt.gen.to.param intrinsic | |
76 | Type *CvtTypes[] = { | |
77 | Type::getInt8PtrTy(Func->getParent()->getContext(), ADDRESS_SPACE_PARAM), | |
78 | Type::getInt8PtrTy(Func->getParent()->getContext(), | |
79 | ADDRESS_SPACE_GENERIC)}; | |
80 | Function *CvtFunc = Intrinsic::getDeclaration( | |
81 | Func->getParent(), Intrinsic::nvvm_ptr_gen_to_param, CvtTypes); | |
82 | ||
83 | Value *BitcastArgs[] = { | |
84 | new BitCastInst(Arg, Type::getInt8PtrTy(Func->getParent()->getContext(), | |
85 | ADDRESS_SPACE_GENERIC), | |
86 | Arg->getName(), FirstInst)}; | |
87 | CallInst *CallCVT = | |
88 | CallInst::Create(CvtFunc, BitcastArgs, "cvt_to_param", FirstInst); | |
89 | ||
90 | BitCastInst *BitCast = new BitCastInst( | |
91 | CallCVT, PointerType::get(StructType, ADDRESS_SPACE_PARAM), | |
92 | Arg->getName(), FirstInst); | |
93 | LoadInst *LI = new LoadInst(BitCast, Arg->getName(), FirstInst); | |
94 | new StoreInst(LI, AllocA, FirstInst); | |
95 | } | |
96 | ||
97 | // ============================================================================= | |
98 | // If the function had a struct ptr arg, say foo(%struct.x *byval %d), then | |
99 | // add the following instructions to the first basic block : | |
100 | // | |
101 | // %temp = alloca %struct.x, align 8 | |
102 | // %tt1 = bitcast %struct.x * %d to i8 * | |
103 | // %tt2 = llvm.nvvm.cvt.gen.to.param %tt2 | |
104 | // %tempd = bitcast i8 addrspace(101) * to %struct.x addrspace(101) * | |
105 | // %tv = load %struct.x addrspace(101) * %tempd | |
106 | // store %struct.x %tv, %struct.x * %temp, align 8 | |
107 | // | |
108 | // The above code allocates some space in the stack and copies the incoming | |
109 | // struct from param space to local space. | |
110 | // Then replace all occurences of %d by %temp. | |
111 | // ============================================================================= | |
112 | void NVPTXLowerStructArgs::handleStructPtrArgs(Function &F) { | |
113 | for (Argument &Arg : F.args()) { | |
114 | if (Arg.getType()->isPointerTy() && Arg.hasByValAttr()) { | |
115 | handleParam(&Arg); | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | // ============================================================================= | |
121 | // Main function for this pass. | |
122 | // ============================================================================= | |
123 | bool NVPTXLowerStructArgs::runOnFunction(Function &F) { | |
124 | // Skip non-kernels. See the comments at the top of this file. | |
125 | if (!isKernelFunction(F)) | |
126 | return false; | |
127 | ||
128 | handleStructPtrArgs(F); | |
129 | return true; | |
130 | } | |
131 | ||
132 | FunctionPass *llvm::createNVPTXLowerStructArgsPass() { | |
133 | return new NVPTXLowerStructArgs(); | |
134 | } |