source: src/Validate/ImplementEnumFunc.cpp@ 38093ae

Last change on this file since 38093ae was 38093ae, checked in by JiadaL <j82liang@…>, 18 months ago

Resolve conflict

  • Property mode set to 100644
File size: 19.4 KB
Line 
1#include "AST/Create.hpp"
2#include "AST/Pass.hpp"
3#include "AST/TranslationUnit.hpp"
4#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.h" // for isAssignment, isCopyConstructor
6namespace Validate {
7
8namespace {
9class EnumAttrFuncGenerator {
10 const ast::EnumDecl* decl;
11 const ast::EnumInstType* instType;
12 // const ast::EnumAttrType* attrType;
13 unsigned int functionNesting;
14 ast::Linkage::Spec proto_linkage;
15
16 public:
17 std::list<ast::ptr<ast::Decl>> forwards;
18 std::list<ast::ptr<ast::Decl>> definitions;
19
20 void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
21
22 EnumAttrFuncGenerator(const ast::EnumDecl* decl,
23 const ast::EnumInstType* instType,
24 // const ast::EnumAttrType* enumAttrType,
25 unsigned int functionNesting)
26 : decl(decl),
27 instType{instType},
28 // attrType{enumAttrType},
29 functionNesting{functionNesting},
30 proto_linkage{ast::Linkage::Cforall} {}
31
32 void genAttrFunctions();
33 void genSuccPredPosn();
34 void genSuccPredDecl();
35
36 void appendReturnThis(ast::FunctionDecl* decl) {
37 assert(1 <= decl->params.size());
38 assert(1 == decl->returns.size());
39 assert(decl->stmts);
40
41 const CodeLocation& location = (decl->stmts->kids.empty())
42 ? decl->stmts->location
43 : decl->stmts->kids.back()->location;
44 const ast::DeclWithType* thisParam = decl->params.front();
45 decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
46 location, new ast::VariableExpr(location, thisParam)));
47 }
48 void genAttrStandardFuncs() {
49 ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
50 const = {&EnumAttrFuncGenerator::genCtorProto,
51 &EnumAttrFuncGenerator::genCopyProto,
52 &EnumAttrFuncGenerator::genDtorProto,
53 &EnumAttrFuncGenerator::genAssignProto};
54 for (auto& generator : standardProtos) {
55 ast::FunctionDecl* decl = (this->*generator)();
56 produceForwardDecl(decl);
57 genFuncBody(decl);
58 if (CodeGen::isAssignment(decl->name)) {
59 appendReturnThis(decl);
60 }
61 produceDecl(decl);
62 }
63 }
64
65 private:
66 const CodeLocation& getLocation() const { return decl->location; }
67
68 ast::FunctionDecl* genProto(
69 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
70 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
71
72 void produceDecl(const ast::FunctionDecl* decl);
73 void produceForwardDecl(const ast::FunctionDecl* decl);
74
75 const ast::Decl* getDecl() const { return decl; }
76
77 ast::FunctionDecl* genPosnProto() const;
78 ast::FunctionDecl* genLabelProto() const;
79 ast::FunctionDecl* genValueProto() const;
80 ast::FunctionDecl* genSuccProto() const;
81 ast::FunctionDecl* genPredProto() const;
82
83 ast::FunctionDecl* genSuccPosProto() const;
84 ast::FunctionDecl* genPredPosProto() const;
85
86 // ---------------------------------------------------
87 // ast::FunctionDecl* genAttrCtorProto() const;
88 /// Changes the node inside a pointer so that it has the unused attribute.
89 void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
90 ast::DeclWithType* decl = declPtr.get_and_mutate();
91 decl->attributes.push_back(new ast::Attribute("unused"));
92 }
93
94 ast::ObjectDecl* dstParam() const {
95 return new ast::ObjectDecl(getLocation(), "_dst",
96 new ast::ReferenceType(new ast::EnumAttrType(
97 ast::deepCopy(instType))));
98 }
99
100 ast::ObjectDecl* srcParam() const {
101 return new ast::ObjectDecl(
102 getLocation(), "_src",
103 new ast::EnumAttrType(ast::deepCopy(instType)));
104 }
105
106 /// E = EnumAttrType<T>`
107 /// `void ?{}(E & _dst)`.
108 ast::FunctionDecl* genCtorProto() const {
109 return genProto("?{}", {dstParam()}, {});
110 }
111
112 /// void ?{}(E & _dst, E _src)`.
113 ast::FunctionDecl* genCopyProto() const {
114 return genProto("?{}", {dstParam(), srcParam()}, {});
115 }
116
117 ///`void ^?{}(E & _dst)`.
118 ast::FunctionDecl* genDtorProto() const {
119 // The destructor must be mutex on a concurrent type.
120 return genProto("^?{}", {dstParam()}, {});
121 }
122
123 /// `E ?{}(E & _dst, E _src)`.
124 ast::FunctionDecl* genAssignProto() const {
125 // Only the name is different, so just reuse the generation function.
126 auto retval = srcParam();
127 retval->name = "_ret";
128 return genProto("?=?", {dstParam(), srcParam()}, {retval});
129 }
130
131 void genFuncBody(ast::FunctionDecl* func) {
132 const CodeLocation& location = func->location;
133 auto& params = func->params;
134 if (InitTweak::isCopyConstructor(func) ||
135 InitTweak::isAssignment(func)) {
136 assert(2 == params.size());
137 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
138 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
139 func->stmts = genCopyBody(location, dstParam, srcParam);
140 } else {
141 assert(1 == params.size());
142 // Default constructor and destructor is empty.
143 func->stmts = new ast::CompoundStmt(location);
144 // Add unused attribute to parameter to silence warnings.
145 addUnusedAttribute(params.front());
146
147 // Just an extra step to make the forward and declaration match.
148 if (forwards.empty()) return;
149 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
150 forwards.back().get_and_mutate());
151 addUnusedAttribute(fwd->params.front());
152 }
153 }
154
155 const ast::CompoundStmt* genCopyBody(const CodeLocation& location,
156 const ast::ObjectDecl* dstParam,
157 const ast::ObjectDecl* srcParam) {
158 return new ast::CompoundStmt(
159 location,
160 {new ast::ExprStmt(
161 location,
162 new ast::UntypedExpr(
163 location, new ast::NameExpr(location, "__builtin_memcpy"),
164 {
165 new ast::AddressExpr(location, new ast::VariableExpr(
166 location, dstParam)),
167 new ast::AddressExpr(location, new ast::VariableExpr(
168 location, srcParam)),
169 new ast::SizeofExpr(location, srcParam->type),
170 }))});
171 }
172
173 void genDtorBody(ast::FunctionDecl* func) {
174 const CodeLocation& location = func->location;
175 auto& params = func->params;
176 assert(1 == params.size());
177 func->stmts = new ast::CompoundStmt(location);
178 addUnusedAttribute(params.front());
179
180 // Just an extra step to make the forward and declaration match.
181 if (forwards.empty()) return;
182 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
183 forwards.back().get_and_mutate());
184 addUnusedAttribute(fwd->params.front());
185 }
186
187 // ast::FunctionDecl*
188 // ----------------------------------------------------
189
190 ast::FunctionDecl* genSuccPredFunc(bool succ);
191
192 const ast::Init* getAutoInit(const ast::Init* prev) const;
193
194 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
195
196 std::vector<ast::ptr<ast::Init>> genValueInit() const;
197 ast::ObjectDecl* genAttrArrayProto(
198 const ast::EnumAttribute attr, const CodeLocation& location,
199 std::vector<ast::ptr<ast::Init>>& inits) const;
200 void genValueOrLabelBody(ast::FunctionDecl* func,
201 ast::ObjectDecl* arrDecl) const;
202 void genPosnBody(ast::FunctionDecl* func) const;
203 void genAttributesDecls(const ast::EnumAttribute attr);
204};
205
206std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
207 std::vector<ast::ptr<ast::Init>> inits;
208 for (size_t i = 0; i < decl->members.size(); i++) {
209 ast::ptr<ast::Decl> mem = decl->members.at(i);
210 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
211 assert(memAsObjectDecl);
212 inits.emplace_back(new ast::SingleInit(
213 mem->location,
214 ast::ConstantExpr::from_string(mem->location, mem->name)));
215 }
216 return inits;
217}
218
219std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
220 std::vector<ast::ptr<ast::Init>> inits;
221 for (size_t i = 0; i < decl->members.size(); i++) {
222 ast::ptr<ast::Decl> mem = decl->members.at(i);
223 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
224 assert(memAsObjectDecl);
225 if (memAsObjectDecl->init) {
226 inits.emplace_back(memAsObjectDecl->init);
227 } else {
228 const CodeLocation& location = mem->location;
229 if (i == 0) {
230 inits.emplace_back(new ast::SingleInit(
231 location, ast::ConstantExpr::from_int(mem->location, 0)));
232 } else {
233 inits.emplace_back(getAutoInit(inits.at(i - 1)));
234 }
235 }
236 }
237 return inits;
238}
239const ast::Init* EnumAttrFuncGenerator::getAutoInit(
240 const ast::Init* prev) const {
241 if (prev == nullptr) {
242 return new ast::SingleInit(
243 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
244 }
245 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
246 assert(prevInit);
247 auto prevInitExpr = prevInit->value;
248 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
249 // Assume no string literal for now
250 return new ast::SingleInit(
251 getLocation(), ast::ConstantExpr::from_int(
252 getLocation(), constInit->intValue() + 1));
253 } else {
254 auto untypedThisInit = new ast::UntypedExpr(
255 getLocation(), new ast::NameExpr(getLocation(), "?++"),
256 {prevInitExpr});
257 return new ast::SingleInit(getLocation(), untypedThisInit);
258 }
259}
260
261ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
262 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
263 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
264 ast::FunctionDecl* decl = new ast::FunctionDecl(
265 // Auto-generated routines use the type declaration's location.
266 getLocation(), std::move(name), {}, {}, std::move(params),
267 std::move(returns),
268 // Only a prototype, no body.
269 nullptr,
270 // Use static storage if we are at the top level.
271 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
272 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
273 // Auto-generated routines are inline to avoid conflicts.
274 ast::Function::Specs(ast::Function::Inline));
275 decl->fixUniqueId();
276 return decl;
277}
278
279void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
280 assert(nullptr != decl->stmts);
281
282 definitions.push_back(decl);
283}
284
285void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
286 if (0 != functionNesting) return;
287 ast::FunctionDecl* fwd =
288 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
289 fwd->fixUniqueId();
290 forwards.push_back(fwd);
291}
292
293ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
294 return genProto(
295 "posE",
296 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
297 {new ast::ObjectDecl(getLocation(), "_ret",
298 new ast::BasicType(ast::BasicType::UnsignedInt))});
299}
300
301ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
302 return genProto(
303 "labelE",
304 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
305 {new ast::ObjectDecl(
306 getLocation(), "_ret",
307 new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
308}
309
310ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
311 return genProto(
312 "valueE",
313 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
314 {new ast::ObjectDecl(getLocation(), "_ret",
315 ast::deepCopy(decl->base))});
316}
317
318ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
319 return genProto(
320 "succ",
321 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
322 {new ast::ObjectDecl(getLocation(), "_ret",
323 new ast::EnumInstType(decl))});
324}
325
326ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
327 return genProto(
328 "pred",
329 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
330 {new ast::ObjectDecl(getLocation(), "_ret",
331 new ast::EnumInstType(decl))});
332}
333
334inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
335 return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
336}
337
338ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
339 return genProto(
340 "_successor_",
341 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
342 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
343 );
344}
345
346ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
347 return genProto(
348 "_predessor_",
349 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
350 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
351 );
352}
353
354ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
355 const ast::EnumAttribute attr, const CodeLocation& location,
356 std::vector<ast::ptr<ast::Init>>& inits) const {
357 ast::ArrayType* arrT = new ast::ArrayType(
358 attr == ast::EnumAttribute::Value
359 ? decl->base
360 : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
361 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
362 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
363
364 ast::ObjectDecl* objDecl =
365 new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
366 arrT, new ast::ListInit(location, std::move(inits)),
367 ast::Storage::Static, ast::Linkage::AutoGen);
368
369 return objDecl;
370}
371
372void EnumAttrFuncGenerator::genValueOrLabelBody(
373 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
374 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
375 func->location, "?[?]",
376 {new ast::NameExpr(func->location, arrDecl->name),
377 new ast::CastExpr(
378 func->location,
379 new ast::VariableExpr(func->location, func->params.front()),
380 new ast::EnumAttrType(new ast::EnumInstType(decl),
381 ast::EnumAttribute::Posn))});
382 func->stmts = new ast::CompoundStmt(
383 func->location, {new ast::ReturnStmt(func->location, untyped)});
384}
385
386void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
387 auto castExpr = new ast::CastExpr(
388 func->location,
389 new ast::VariableExpr(func->location, func->params.front()),
390 new ast::EnumAttrType(new ast::EnumInstType(decl),
391 ast::EnumAttribute::Posn));
392 func->stmts = new ast::CompoundStmt(
393 func->location, {new ast::ReturnStmt(func->location, castExpr)});
394}
395
396void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
397 if (attr == ast::EnumAttribute::Value ||
398 attr == ast::EnumAttribute::Label) {
399 std::vector<ast::ptr<ast::Init>> inits =
400 attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
401 ast::ObjectDecl* arrayProto =
402 genAttrArrayProto(attr, getLocation(), inits);
403 forwards.push_back(arrayProto);
404
405 ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
406 ? genValueProto()
407 : genLabelProto();
408 produceForwardDecl(funcProto);
409 genValueOrLabelBody(funcProto, arrayProto);
410 produceDecl(funcProto);
411 } else {
412 ast::FunctionDecl* funcProto = genPosnProto();
413 produceForwardDecl(funcProto);
414 genPosnBody(funcProto);
415 produceDecl(funcProto);
416 }
417}
418
419ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
420 ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
421 produceForwardDecl(funcDecl);
422
423 const CodeLocation& location = getLocation();
424
425 auto& params = funcDecl->params;
426 assert(params.size() == 1);
427 auto param = params.front().strict_as<ast::ObjectDecl>();
428
429
430 auto rets = funcDecl->returns;
431 assert(params.size() == 1);
432 auto ret = rets.front().strict_as<ast::ObjectDecl>();
433 auto retType = ret->type.strict_as<ast::EnumAttrType>();
434
435 auto addOneExpr = ast::UntypedExpr::createCall( location,
436 succ? "?+?": "?-?",
437 {new ast::VariableExpr(location, param),
438 ast::ConstantExpr::from_int(location, 1)}
439 );
440
441 funcDecl->stmts = new ast::CompoundStmt(
442 location, {
443 new ast::ReturnStmt(
444 location,
445 new ast::CastExpr(location, addOneExpr, retType)
446 )
447 }
448 );
449
450 return funcDecl;
451}
452
453void EnumAttrFuncGenerator::genAttrFunctions() {
454 if (decl->base) {
455 genAttributesDecls(ast::EnumAttribute::Value);
456 genAttributesDecls(ast::EnumAttribute::Label);
457 genAttributesDecls(ast::EnumAttribute::Posn);
458 }
459}
460
461void EnumAttrFuncGenerator::genSuccPredDecl() {
462 if (decl->base) {
463 auto succProto = genSuccProto();
464 auto predProto = genPredProto();
465
466 produceForwardDecl(succProto);
467 produceForwardDecl(predProto);
468 }
469}
470
471void EnumAttrFuncGenerator::genSuccPredPosn() {
472 if (decl->base) {
473 ast::FunctionDecl* succ = genSuccPredFunc(true);
474 ast::FunctionDecl* pred = genSuccPredFunc(false);
475
476 produceDecl(succ);
477 produceDecl(pred);
478 }
479}
480
481void EnumAttrFuncGenerator::generateAndAppendFunctions(
482 std::list<ast::ptr<ast::Decl>>& decls) {
483 // Generate the functions (they go into forwards and definitions).
484 genAttrStandardFuncs();
485 genAttrFunctions();
486 genSuccPredDecl();
487 genSuccPredPosn(); // Posn
488 // Now export the lists contents.
489 decls.splice(decls.end(), forwards);
490 decls.splice(decls.end(), definitions);
491}
492
493// ---------------------------------------------------------
494
495struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
496 public ast::WithShortCircuiting {
497 void previsit(const ast::EnumDecl* enumDecl);
498 void previsit(const ast::FunctionDecl* functionDecl);
499 void postvisit(const ast::FunctionDecl* functionDecl);
500
501 private:
502 // Current level of nested functions.
503 unsigned int functionNesting = 0;
504};
505
506void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
507 if (!enumDecl->body) return;
508 if (!enumDecl->base) return;
509
510 ast::EnumInstType enumInst(enumDecl->name);
511 enumInst.base = enumDecl;
512
513 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
514 gen.generateAndAppendFunctions(declsToAddAfter);
515}
516
517void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
518 functionNesting += 1;
519}
520
521void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
522 functionNesting -= 1;
523}
524
525} // namespace
526
527void implementEnumFunc(ast::TranslationUnit& translationUnit) {
528 ast::Pass<ImplementEnumFunc>::run(translationUnit);
529}
530} // namespace Validate
Note: See TracBrowser for help on using the repository browser.