1 //===- subzero/src/IceGlobalInits.cpp - Global declarations ---------------===//
2 //
3 // The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Implements the notion of function declarations, global variable
12 /// declarations, and the corresponding variable initializers in Subzero.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "IceGlobalInits.h"
17
18 #include "IceDefs.h"
19 #include "IceGlobalContext.h"
20 #include "IceTypes.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/Value.h"
24
25 namespace {
hexdigit(unsigned X)26 char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
27
dumpLinkage(Ice::Ostream & Stream,llvm::GlobalValue::LinkageTypes Linkage)28 void dumpLinkage(Ice::Ostream &Stream,
29 llvm::GlobalValue::LinkageTypes Linkage) {
30 if (!Ice::BuildDefs::dump())
31 return;
32 switch (Linkage) {
33 case llvm::GlobalValue::ExternalLinkage:
34 Stream << "external";
35 return;
36 case llvm::GlobalValue::InternalLinkage:
37 Stream << "internal";
38 return;
39 default:
40 break;
41 }
42 std::string Buffer;
43 llvm::raw_string_ostream StrBuf(Buffer);
44 StrBuf << "Unknown linkage value: " << Linkage;
45 llvm::report_fatal_error(StrBuf.str());
46 }
47
dumpCallingConv(Ice::Ostream &,llvm::CallingConv::ID CallingConv)48 void dumpCallingConv(Ice::Ostream &, llvm::CallingConv::ID CallingConv) {
49 if (!Ice::BuildDefs::dump())
50 return;
51 if (CallingConv == llvm::CallingConv::C)
52 return;
53 std::string Buffer;
54 llvm::raw_string_ostream StrBuf(Buffer);
55 StrBuf << "Unknown calling convention: " << CallingConv;
56 llvm::report_fatal_error(StrBuf.str());
57 }
58
59 } // end of anonymous namespace
60
61 namespace Ice {
62
63 const Intrinsics::FullIntrinsicInfo *
getIntrinsicInfo(const GlobalContext * Ctx,bool * IsIntrinsic) const64 FunctionDeclaration::getIntrinsicInfo(const GlobalContext *Ctx,
65 bool *IsIntrinsic) const {
66 *IsIntrinsic = false;
67 if (!hasName())
68 return nullptr;
69 bool BadIntrinsic;
70 const Intrinsics::FullIntrinsicInfo *Info =
71 Ctx->getIntrinsicsInfo().find(getName(), BadIntrinsic);
72 *IsIntrinsic = Info || BadIntrinsic;
73 return Info;
74 }
75
validateRegularTypeSignature() const76 bool FunctionDeclaration::validateRegularTypeSignature() const {
77 for (SizeT i = 0; i < Signature.getNumArgs(); ++i) {
78 if (!isCallParameterType(Signature.getArgType(i)))
79 return false;
80 }
81 return isCallReturnType(Signature.getReturnType());
82 }
83
validateIntrinsicTypeSignature(const Intrinsics::FullIntrinsicInfo * Info) const84 bool FunctionDeclaration::validateIntrinsicTypeSignature(
85 const Intrinsics::FullIntrinsicInfo *Info) const {
86 if (Signature.getNumArgs() != Info->getNumArgs())
87 return false;
88 for (SizeT i = 0; i < Signature.getNumArgs(); ++i) {
89 if (Signature.getArgType(i) != Info->getArgType(i))
90 return false;
91 }
92 return Signature.getReturnType() == Info->getReturnType();
93 }
94
95 std::string
getTypeSignatureError(const GlobalContext * Ctx)96 FunctionDeclaration::getTypeSignatureError(const GlobalContext *Ctx) {
97 std::string Buffer;
98 llvm::raw_string_ostream StrBuf(Buffer);
99 StrBuf << "Invalid";
100 bool IsIntrinsic;
101 const Intrinsics::FullIntrinsicInfo *Info =
102 getIntrinsicInfo(Ctx, &IsIntrinsic);
103 if (IsIntrinsic && Info == nullptr) {
104 StrBuf << " intrinsic name: " << getName();
105 return StrBuf.str();
106 }
107 StrBuf << " type signature for";
108 if (IsIntrinsic)
109 StrBuf << " intrinsic";
110 StrBuf << " " << getName() << ": " << getSignature();
111 return StrBuf.str();
112 }
113
dumpType(Ostream & Stream) const114 void FunctionDeclaration::dumpType(Ostream &Stream) const {
115 if (!Ice::BuildDefs::dump())
116 return;
117 Stream << Signature;
118 }
119
dump(Ostream & Stream) const120 void FunctionDeclaration::dump(Ostream &Stream) const {
121 if (!Ice::BuildDefs::dump())
122 return;
123 if (IsProto)
124 Stream << "declare ";
125 ::dumpLinkage(Stream, Linkage);
126 ::dumpCallingConv(Stream, CallingConv);
127 Stream << Signature.getReturnType() << " @" << Name << "(";
128 bool IsFirst = true;
129 for (Type ArgTy : Signature.getArgList()) {
130 if (IsFirst)
131 IsFirst = false;
132 else
133 Stream << ", ";
134 Stream << ArgTy;
135 }
136 Stream << ")";
137 }
138
dumpType(Ostream & Stream) const139 void VariableDeclaration::dumpType(Ostream &Stream) const {
140 if (!Ice::BuildDefs::dump())
141 return;
142 if (Initializers.size() == 1) {
143 Initializers.front()->dumpType(Stream);
144 } else {
145 Stream << "<{ ";
146 bool IsFirst = true;
147 for (const auto *Init : Initializers) {
148 if (IsFirst) {
149 IsFirst = false;
150 } else {
151 Stream << ", ";
152 }
153 Init->dumpType(Stream);
154 }
155 Stream << " }>";
156 }
157 }
158
dump(Ostream & Stream) const159 void VariableDeclaration::dump(Ostream &Stream) const {
160 if (!Ice::BuildDefs::dump())
161 return;
162 Stream << "@" << Name << " = ";
163 ::dumpLinkage(Stream, Linkage);
164 Stream << " " << (IsConstant ? "constant" : "global") << " ";
165
166 // Add initializer.
167 if (Initializers.size() == 1) {
168 Initializers.front()->dump(Stream);
169 } else {
170 dumpType(Stream);
171 Stream << " <{ ";
172 bool IsFirst = true;
173 for (const auto *Init : Initializers) {
174 if (IsFirst) {
175 IsFirst = false;
176 } else {
177 Stream << ", ";
178 }
179 Init->dump(Stream);
180 }
181 Stream << " }>";
182 }
183
184 // Add alignment.
185 if (Alignment > 0)
186 Stream << ", align " << Alignment;
187 Stream << "\n";
188 }
189
dumpType(Ostream & Stream) const190 void VariableDeclaration::Initializer::dumpType(Ostream &Stream) const {
191 if (!Ice::BuildDefs::dump())
192 return;
193 Stream << "[" << getNumBytes() << " x " << Ice::IceType_i8 << "]";
194 }
195
dump(Ostream & Stream) const196 void VariableDeclaration::DataInitializer::dump(Ostream &Stream) const {
197 if (!Ice::BuildDefs::dump())
198 return;
199 dumpType(Stream);
200 Stream << " c\"";
201 // Code taken from PrintEscapedString() in AsmWriter.cpp. Keep the strings in
202 // the same format as the .ll file for practical diffing.
203 for (SizeT i = 0; i < ContentsSize; ++i) {
204 uint8_t C = Contents[i];
205 if (isprint(C) && C != '\\' && C != '"')
206 Stream << C;
207 else
208 Stream << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
209 }
210 Stream << "\"";
211 }
212
dump(Ostream & Stream) const213 void VariableDeclaration::ZeroInitializer::dump(Ostream &Stream) const {
214 if (!Ice::BuildDefs::dump())
215 return;
216 dumpType(Stream);
217 Stream << " zeroinitializer";
218 }
219
dumpType(Ostream & Stream) const220 void VariableDeclaration::RelocInitializer::dumpType(Ostream &Stream) const {
221 if (!Ice::BuildDefs::dump())
222 return;
223 Stream << Ice::IceType_i32;
224 }
225
dump(Ostream & Stream) const226 void VariableDeclaration::RelocInitializer::dump(Ostream &Stream) const {
227 if (!Ice::BuildDefs::dump())
228 return;
229 const RelocOffsetT Offset = getOffset();
230 if (Offset != 0) {
231 dumpType(Stream);
232 Stream << " add (";
233 }
234 dumpType(Stream);
235 Stream << " ptrtoint (";
236 Declaration->dumpType(Stream);
237 Stream << "* @" << Declaration->getName() << " to ";
238 dumpType(Stream);
239 Stream << ")";
240 if (Offset != 0) {
241 Stream << ", ";
242 dumpType(Stream);
243 Stream << " " << Offset << ")";
244 }
245 }
246
247 } // end of namespace Ice
248