1 //===- SPIRVFunction.cpp � Class to represent a SPIR-V Function --*- C++ -*-===//
2 //
3 // The LLVM/SPIRV Translator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements Function class for SPIRV.
11 //
12 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal with the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimers.
23 // Redistributions in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimers in the documentation
25 // and/or other materials provided with the distribution.
26 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
27 // contributors may be used to endorse or promote products derived from this
28 // Software without specific prior written permission.
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
35 // THE SOFTWARE.
36 //
37 //===----------------------------------------------------------------------===//
38
39 #include "SPIRVEntry.h"
40 #include "SPIRVFunction.h"
41 #include "SPIRVBasicBlock.h"
42 #include "SPIRVInstruction.h"
43 #include "SPIRVStream.h"
44
45 #include <functional>
46 #include <algorithm>
47 using namespace SPIRV;
48
SPIRVFunctionParameter(SPIRVType * TheType,SPIRVId TheId,SPIRVFunction * TheParent,unsigned TheArgNo)49 SPIRVFunctionParameter::SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId,
50 SPIRVFunction *TheParent, unsigned TheArgNo):
51 SPIRVValue(TheParent->getModule(), 3, OpFunctionParameter,
52 TheType, TheId),
53 ParentFunc(TheParent),
54 ArgNo(TheArgNo){
55 validate();
56 }
57
58 void
foreachAttr(std::function<void (SPIRVFuncParamAttrKind)> Func)59 SPIRVFunctionParameter::foreachAttr(
60 std::function<void(SPIRVFuncParamAttrKind)>Func){
61 auto Locs = Decorates.equal_range(DecorationFuncParamAttr);
62 for (auto I = Locs.first, E = Locs.second; I != E; ++I){
63 auto Attr = static_cast<SPIRVFuncParamAttrKind>(
64 I->second->getLiteral(0));
65 assert(isValid(Attr));
66 Func(Attr);
67 }
68 }
69
70 SPIRVDecoder
getDecoder(std::istream & IS)71 SPIRVFunction::getDecoder(std::istream &IS) {
72 return SPIRVDecoder(IS, *this);
73 }
74
75 void
encode(spv_ostream & O) const76 SPIRVFunction::encode(spv_ostream &O) const {
77 getEncoder(O) << Type << Id << FCtrlMask << FuncType;
78 }
79
80 void
encodeChildren(spv_ostream & O) const81 SPIRVFunction::encodeChildren(spv_ostream &O) const {
82 O << SPIRVNL();
83 for (auto &I:Parameters)
84 O << *I;
85 O << SPIRVNL();
86 for (auto &I:BBVec)
87 O << *I;
88 O << SPIRVFunctionEnd();
89 }
90
91 void
encodeExecutionModes(spv_ostream & O) const92 SPIRVFunction::encodeExecutionModes(spv_ostream &O)const {
93 for (auto &I:ExecModes)
94 O << *I.second;
95 }
96
97 void
decode(std::istream & I)98 SPIRVFunction::decode(std::istream &I) {
99 SPIRVDecoder Decoder = getDecoder(I);
100 Decoder >> Type >> Id >> FCtrlMask >> FuncType;
101 Module->addFunction(this);
102 SPIRVDBG(spvdbgs() << "Decode function: " << Id << '\n');
103
104 Decoder.getWordCountAndOpCode();
105 while (!I.eof()) {
106 if (Decoder.OpCode == OpFunctionEnd)
107 break;
108
109 switch(Decoder.OpCode) {
110 case OpFunctionParameter: {
111 auto Param = static_cast<SPIRVFunctionParameter *>(Decoder.getEntry());
112 assert(Param);
113 Param->setParent(this);
114 Parameters.push_back(Param);
115 Decoder.getWordCountAndOpCode();
116 continue;
117 break;
118 }
119 case OpLabel: {
120 decodeBB(Decoder);
121 break;
122 }
123 default:
124 assert (0 && "Invalid SPIRV format");
125 }
126 }
127 }
128
129 /// Decode basic block and contained instructions.
130 /// Do it here instead of in BB:decode to avoid back track in input stream.
131 void
decodeBB(SPIRVDecoder & Decoder)132 SPIRVFunction::decodeBB(SPIRVDecoder &Decoder) {
133 SPIRVBasicBlock *BB = static_cast<SPIRVBasicBlock*>(Decoder.getEntry());
134 assert(BB);
135 addBasicBlock(BB);
136 SPIRVDBG(spvdbgs() << "Decode BB: " << BB->getId() << '\n');
137
138 Decoder.setScope(BB);
139 while(Decoder.getWordCountAndOpCode()) {
140 if (Decoder.OpCode == OpFunctionEnd ||
141 Decoder.OpCode == OpLabel) {
142 break;
143 }
144
145 if (Decoder.OpCode == OpName ||
146 Decoder.OpCode == OpDecorate) {
147 Decoder.getEntry();
148 continue;
149 }
150
151 SPIRVInstruction *Inst = static_cast<SPIRVInstruction *>(Decoder.getEntry());
152 assert(Inst);
153 BB->addInstruction(Inst);
154 }
155 Decoder.setScope(this);
156 }
157
158 void
foreachReturnValueAttr(std::function<void (SPIRVFuncParamAttrKind)> Func)159 SPIRVFunction::foreachReturnValueAttr(
160 std::function<void(SPIRVFuncParamAttrKind)>Func){
161 auto Locs = Decorates.equal_range(DecorationFuncParamAttr);
162 for (auto I = Locs.first, E = Locs.second; I != E; ++I){
163 auto Attr = static_cast<SPIRVFuncParamAttrKind>(
164 I->second->getLiteral(0));
165 assert(isValid(Attr));
166 Func(Attr);
167 }
168 }
169