1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef _METADATA_H_
10 #define _METADATA_H_
11 
12 #include <optional>
13 #include <iostream>
14 
15 namespace vISA
16 {
17 
18 //
19 // A metadata is simply a collection of (<key>, <value>) pairs that may be attached to an IR object (BB, Inst, Declare, etc.)
20 // Metadata is completely optional; vISA optimizations and transformations are not obliged to preserve them, and dropping them should not affect correctness
21 // Metadata key is a string, and only one value is allowed per key for now.
22 // Metadata value is represented by an MDNode abstract class, each subclass provides the actual implementation of the metadata value
23 // Currently there are only two types of metadata: MDString and MDLocation.
24 // Metadata memory management is performed by IR_Builder through the various allocaeMD* methods.
25 // An MDNode may be shared among muitiple IR objects, it's the user's responsiblity to ensure correct ownership and sharing behaviors.
26 // Each object has its own unqiue metadata map, however.
27 // Currently only G4_INST supports metadata through the setMetaData/getMetadata interface.
28 // OPEN: use enum instead of string as metadata key. This would speed up lookup at the expense of some flexibility.
29 // OPEN: better management schemes for a MDNode's lifetime/ownership.
30 //
31 
32 enum class MDType
33 {
34     String,
35     SrcLoc,
36     TokenLoc
37 };
38 
39 // forward declaration so that the asMD*() calls can work
40 class MDString;
41 class MDLocation;
42 class MDTokenLocation;
43 
44 class MDNode
45 {
46 
47     const MDType nodeType;
48 
49 protected:
MDNode(MDType ty)50     MDNode(MDType ty) : nodeType(ty) {}
51 
52  public:
53 
54     MDNode(const MDNode& node) = delete;
55 
56     void operator=(const MDNode& node) = delete;
57 
new(size_t sz,Mem_Manager & m)58     void* operator new(size_t sz, Mem_Manager& m) { return m.alloc(sz); }
59 
~MDNode()60     virtual ~MDNode() {}
61 
isMDString()62     bool isMDString() const { return nodeType == MDType::String; }
isMDLocation()63     bool isMDLocation() const { return nodeType == MDType::SrcLoc; }
isMDTokenLocation()64     bool isMDTokenLocation() const { return nodeType == MDType::TokenLoc; }
65 
asMDString()66     const MDString* asMDString() const
67     {
68         return isMDString() ? reinterpret_cast<const MDString*>(this) : nullptr;
69     }
70 
asMDLocation()71     MDLocation* asMDLocation() const
72     {
73         return isMDLocation() ? reinterpret_cast<MDLocation*>(const_cast<MDNode*>(this)) : nullptr;
74     }
75 
asMDTokenLocation()76     MDTokenLocation* asMDTokenLocation() const
77     {
78         return isMDTokenLocation() ? reinterpret_cast<MDTokenLocation*>(const_cast<MDNode*>(this)) : nullptr;
79     }
80 
81     virtual void print(std::ostream& OS) const = 0;
dump()82     void dump() const
83     {
84         print(std::cerr);
85     }
86 };
87 
88 class MDString : public MDNode
89 {
90     const std::string data;
91 
92 public:
93 
MDString(const std::string & str)94     MDString(const std::string& str) : MDNode(MDType::String), data(str) {}
95 
96     MDString(const MDString& node) = delete;
97 
98     void operator=(const MDString& node) = delete;
99 
100     virtual ~MDString() = default;
101 
getData()102     std::string getData() const { return data; }
103 
print(std::ostream & OS)104     void print(std::ostream& OS) const
105     {
106         OS << "\"" << data << "\"";
107     }
108 };
109 
110 class MDLocation : public MDNode
111 {
112     int lineNo = -1;
113     const char* srcFilename = nullptr;
114 
115 public:
116 
MDLocation(int lineNo,const char * srcFilename)117     MDLocation(int lineNo, const char* srcFilename) :
118         MDNode(MDType::SrcLoc), lineNo(lineNo), srcFilename(srcFilename) {}
119 
120     MDLocation(const MDLocation& node) = delete;
121 
122     void operator=(const MDLocation& node) = delete;
123 
124     ~MDLocation() = default;
125 
new(size_t sz,Mem_Manager & m)126     void* operator new(size_t sz, Mem_Manager& m) { return m.alloc(sz); }
getLineNo()127     int getLineNo() const { return lineNo; }
getSrcFilename()128     const char* getSrcFilename() const { return srcFilename; }
129 
print(std::ostream & OS)130     void print(std::ostream& OS) const
131     {
132         OS << "\"" << srcFilename << ":" << lineNo << "\"";
133     }
134 };
135 
136 class MDTokenLocation : public MDNode
137 {
138     std::vector<unsigned short> token;
139     std::vector<unsigned> global_id;
140 
141 public:
142 
MDTokenLocation(unsigned short _token,unsigned globalID)143     MDTokenLocation(unsigned short _token, unsigned globalID) :
144         MDNode(MDType::TokenLoc)
145     {
146         token.push_back(_token);
147         global_id.push_back(globalID);
148     }
149 
150     MDTokenLocation(const MDTokenLocation& node) = delete;
151 
152     void operator=(const MDTokenLocation& node) = delete;
153 
154     ~MDTokenLocation() = default;
155 
new(size_t sz,Mem_Manager & m)156     void* operator new(size_t sz, Mem_Manager& m) { return m.alloc(sz); }
getTokenLocationNum()157     int getTokenLocationNum() const { return global_id.size(); }
getToken(int i)158     unsigned short getToken(int i) const { return token[i]; }
getTokenLocation(int i)159     unsigned getTokenLocation(int i) const { return global_id[i]; }
addTokenLocation(unsigned short _token,int globalID)160     void addTokenLocation(unsigned short _token, int globalID) { token.push_back(_token), global_id.push_back(globalID); }
161 
print(std::ostream & OS)162     void print(std::ostream& OS) const
163     {
164         OS << token.back() << "." << global_id.back();
165     }
166 };
167 
168 class Metadata
169 {
170 
171     std::unordered_map<std::string, MDNode*> MDMap;
172 
173 public:
Metadata()174     explicit Metadata() {}
175 
176     Metadata(const Metadata& md) = delete;
177 
~Metadata()178     virtual ~Metadata() {}
179 
new(size_t sz,Mem_Manager & m)180     void* operator new(size_t sz, Mem_Manager& m) { return m.alloc(sz); }
181 
182     // it simply overwrites existing value for key if it already exists
setMetadata(const std::string & key,MDNode * value)183     void setMetadata(const std::string& key, MDNode* value)
184     {
185         if (!value)
186         {
187             // do not allow nullptr value for now. ToDo: distinguish between nullptr value vs. metadata not set?
188             return;
189         }
190         MDMap[key] = value;
191     }
192 
getMetadata(const std::string & key)193     MDNode* getMetadata(const std::string& key)
194     {
195         auto iter = MDMap.find(key);
196         return iter != MDMap.end() ? iter->second : nullptr;
197     }
198 
isMetadataSet(const std::string & key)199     bool isMetadataSet(const std::string& key)
200     {
201         return MDMap.count(key);
202     }
203 
print(std::ostream & OS)204     void print(std::ostream& OS) const
205     {
206         for (auto&& iter : MDMap)
207         {
208             OS << "\"" << iter.first << "\" : ";
209             iter.second->print(OS);
210             OS << "\n";
211         }
212     }
213 
dump()214     void dump() const
215     {
216         print(std::cerr);
217     }
218 
219     // list the known keys here to avoid typos
220     inline static const std::string InstComment = "comment";
221     inline static const std::string InstLoc = "location";
222     inline static const std::string TokenLoc = "tokenlocation";
223 };
224 
225 }
226 
227 #endif
228