source: src/Validate/ImplementEnumFunc.cpp@ d02d223

Last change on this file since d02d223 was 0c327ce, checked in by JiadaL <j82liang@…>, 15 months ago
  1. Add bound check to Serial function: now compiler generates the unchecked functions in ImplementEnumFunc, and enum.hfa implements the bound check on top. Todo: Wrapped the checked version into a trait; 2. countof is now works on any type that implement Countof(). Because Countof() is implemented in enum.hfa for all CfaEnum, we can call countof on { T | CfaEnum(T) }
  • Property mode set to 100644
File size: 17.2 KB
Line 
1#include "AST/Create.hpp"
2#include "AST/Pass.hpp"
3#include "AST/TranslationUnit.hpp"
4#include "CodeGen/OperatorTable.hpp" // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.hpp" // for isAssignment, isCopyConstructor
6namespace Validate {
7
8namespace {
9class EnumAttrFuncGenerator {
10 const ast::EnumDecl* decl;
11 unsigned int functionNesting;
12 const ast::StructDecl* quasi_void_decl;
13 ast::Linkage::Spec proto_linkage;
14
15public:
16 std::list<ast::ptr<ast::Decl>> forwards;
17 std::list<ast::ptr<ast::Decl>> definitions;
18
19 void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
20
21 EnumAttrFuncGenerator(
22 const ast::EnumDecl* decl,
23 const ast::EnumInstType*,
24 unsigned int functionNesting )
25 : decl(decl),
26 functionNesting{functionNesting},
27 // quasi_void_decl(new ast::StructDecl(decl->location,
28 // "quasi_void", ast::AggregateDecl::Struct,
29 // {}, ast::Linkage::AutoGen)),
30 proto_linkage{ast::Linkage::Cforall} {}
31
32private:
33 const CodeLocation& getLocation() const { return decl->location; }
34
35 ast::FunctionDecl* genProto(
36 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
37 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
38
39 void produceDecl(const ast::FunctionDecl* decl);
40 void produceForwardDecl(const ast::FunctionDecl* decl);
41
42 const ast::Decl* getDecl() const { return decl; }
43
44 // Implement Bounded trait
45 void genBoundedFunctions();
46 ast::FunctionDecl* genBoundedProto(const char *) const;
47 void genBoundedBody(ast::FunctionDecl* func) const;
48
49 // Implement Serial trait
50 void genSerialTraitFuncs();
51 ast::FunctionDecl* genFromIntProto() const;
52 ast::FunctionDecl* genFromInstanceProto() const;
53 ast::FunctionDecl* genInstToInstFuncProto(const char* func) const;
54 void genFromIntBody(ast::FunctionDecl *) const;
55 void genFromInstanceBody(ast::FunctionDecl *) const;
56 void genSuccPredBody(ast::FunctionDecl *, const char *) const;
57
58 void genTypeNameFunc();
59
60 // Implement TypedEnum trait
61 void genTypedEnumFuncs();
62 void genTypedEnumFunction(const ast::EnumAttribute attr);
63 ast::FunctionDecl* genPosnProto() const;
64 ast::FunctionDecl* genLabelProto() const;
65 ast::FunctionDecl* genValueProto() const;
66 ast::FunctionDecl* genQuasiValueProto() const;
67 ast::FunctionDecl* genTypeNameProto() const;
68
69 void genValueOrLabelBody(
70 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
71 void genPosnBody(ast::FunctionDecl* func) const;
72 void genQuasiValueBody(ast::FunctionDecl* func) const;
73 void genTypeNameBody(ast::FunctionDecl* func) const;
74
75 // ----------------------------------------------------
76
77 const ast::Init* getAutoInit(const ast::Init* prev) const;
78
79 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
80
81 std::vector<ast::ptr<ast::Init>> genValueInit() const;
82 ast::ObjectDecl* genAttrArrayProto(
83 const ast::EnumAttribute attr, const CodeLocation& location,
84 std::vector<ast::ptr<ast::Init>>& inits) const;
85};
86
87std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
88 std::vector<ast::ptr<ast::Init>> inits;
89 for (size_t i = 0; i < decl->members.size(); i++) {
90 ast::ptr<ast::Decl> mem = decl->members.at(i);
91 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
92 assert(memAsObjectDecl);
93 inits.emplace_back(new ast::SingleInit(
94 mem->location,
95 ast::ConstantExpr::from_string(mem->location, mem->name)));
96 }
97 return inits;
98}
99
100std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
101 std::vector<ast::ptr<ast::Init>> inits;
102 for (size_t i = 0; i < decl->members.size(); i++) {
103 ast::ptr<ast::Decl> mem = decl->members.at(i);
104 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
105 assert(memAsObjectDecl);
106 if (auto& init = memAsObjectDecl->init) {
107 if ( auto singleInit = init.as<ast::SingleInit>() ) {
108 if ( auto nameExpr = singleInit->value.as<ast::NameExpr>() ) {
109 auto name = nameExpr->name;
110 if (auto it = std::find_if(decl->members.begin(), decl->members.end(),
111 [name](ast::ptr<ast::Decl> mem_decl) {
112 return (mem_decl->name == name);
113 }); it != std::end(decl->members)
114 ) {
115 auto index = std::distance( decl->members.begin(), it );
116 auto targetInit = inits.at(index).strict_as<ast::SingleInit>();
117 auto targetExpr = targetInit->value;
118 inits.push_back( new ast::SingleInit( targetExpr->location, targetExpr ) );
119 continue;
120 }
121 }
122 }
123 inits.emplace_back(memAsObjectDecl->init);
124 } else {
125 const CodeLocation& location = mem->location;
126 if (i == 0) {
127 inits.emplace_back(new ast::SingleInit(
128 location, ast::ConstantExpr::from_int(mem->location, 0)));
129 } else {
130 inits.emplace_back(getAutoInit(inits.at(i - 1)));
131 }
132 }
133 }
134 return inits;
135}
136
137const ast::Init* EnumAttrFuncGenerator::getAutoInit(
138 const ast::Init* prev) const {
139 if (prev == nullptr) {
140 return new ast::SingleInit(
141 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
142 }
143 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
144 assert(prevInit);
145 auto prevInitExpr = prevInit->value;
146 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
147 // Assume no string literal for now
148 return new ast::SingleInit(
149 getLocation(), ast::ConstantExpr::from_int(
150 getLocation(), constInit->intValue() + 1));
151 } else {
152 auto untypedThisInit = new ast::UntypedExpr(
153 getLocation(), new ast::NameExpr(getLocation(), "?++"),
154 {prevInitExpr});
155 return new ast::SingleInit(getLocation(), untypedThisInit);
156 }
157}
158
159ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
160 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
161 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
162 ast::FunctionDecl* decl = new ast::FunctionDecl(
163 // Auto-generated routines use the type declaration's location.
164 getLocation(), std::move(name), {}, {}, std::move(params),
165 std::move(returns),
166 // Only a prototype, no body.
167 nullptr,
168 // Use static storage if we are at the top level.
169 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
170 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
171 // Auto-generated routines are inline to avoid conflicts.
172 ast::Function::Specs(ast::Function::Inline));
173 decl->fixUniqueId();
174 return decl;
175}
176
177void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
178 assert(nullptr != decl->stmts);
179
180 definitions.push_back(decl);
181}
182
183void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
184 if (0 != functionNesting) return;
185 ast::FunctionDecl* fwd =
186 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
187 fwd->fixUniqueId();
188 forwards.push_back(fwd);
189}
190
191ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
192 return genProto(
193 "posn",
194 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
195 {new ast::ObjectDecl(getLocation(), "_ret",
196 new ast::BasicType(ast::BasicKind::UnsignedInt))});
197}
198
199ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
200 return genProto(
201 "label",
202 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
203 {new ast::ObjectDecl(
204 getLocation(), "_ret",
205 new ast::PointerType(
206 new ast::BasicType(ast::BasicKind::Char, ast::CV::Const)))});
207}
208
209ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
210 assert (decl->isTyped());
211 return genProto(
212 "value",
213 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
214 {new ast::ObjectDecl(getLocation(), "_ret",
215 ast::deepCopy(decl->base))});
216 // else
217 // return genQuasiValueProto();
218}
219
220// ast::FunctionDecl* EnumAttrFuncGenerator::genQuasiValueProto() const {
221// return genProto(
222// "value",
223// {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
224// {new ast::ObjectDecl(getLocation(), "_ret",
225// new ast::StructInstType(quasi_void_decl))});
226// }
227
228ast::FunctionDecl* EnumAttrFuncGenerator::genFromIntProto() const {
229 return genProto(
230 "fromInt_unsafe",
231 {new ast::ObjectDecl(getLocation(), "_i", new ast::BasicType(ast::BasicKind::UnsignedInt))},
232 {new ast::ObjectDecl(getLocation(), "_ret", new ast::EnumInstType(decl))}
233 );
234}
235
236ast::FunctionDecl* EnumAttrFuncGenerator::genFromInstanceProto() const {
237 return genProto(
238 "fromInstance",
239 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
240 {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
241 );
242}
243
244ast::FunctionDecl* EnumAttrFuncGenerator::genTypeNameProto() const {
245 return genProto(
246 "type_name",
247 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
248 {new ast::ObjectDecl(
249 getLocation(), "_ret",
250 new ast::PointerType(
251 new ast::BasicType(ast::BasicKind::Char, ast::CV::Const)))});
252}
253
254void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
255 auto params = func->params;
256 assert( params.size() == 1 );
257 auto param = params.front();
258 auto castExpr = new ast::CastExpr(
259 func->location,
260 new ast::VariableExpr(func->location, param),
261 new ast::EnumInstType(decl),
262 ast::GeneratedFlag::ExplicitCast
263 );
264 func->stmts = new ast::CompoundStmt(
265 func->location, {new ast::ReturnStmt(func->location, castExpr)}
266 );
267}
268
269void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
270 auto params = func->params;
271 assert( params.size() == 1 );
272 auto param = params.front();
273 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
274 func->location, "posn", { new ast::VariableExpr(func->location, param) });
275 func->stmts = new ast::CompoundStmt(
276 func->location, {new ast::ReturnStmt(func->location, untyped)}
277 );
278}
279
280void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
281 auto params = func->params;
282 assert( params.size() == 1 );
283 auto param = params.front();
284 auto enumToInt = new ast::CastExpr(
285 func->location,
286 new ast::VariableExpr(func->location, param),
287 new ast::BasicType(ast::BasicKind::UnsignedInt),
288 ast::GeneratedFlag::ExplicitCast
289 );
290 ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
291 opt,
292 {enumToInt,
293 ast::ConstantExpr::from_int(func->location, 1)}
294 );
295 auto intToEnum = new ast::CastExpr(
296 func->location,
297 addOneExpr,
298 new ast::EnumInstType( decl ),
299 ast::GeneratedFlag::ExplicitCast
300 );
301 func->stmts = new ast::CompoundStmt(
302 func->location, {
303 new ast::ReturnStmt(
304 func->location,
305 intToEnum
306 )
307 }
308 );
309}
310
311void EnumAttrFuncGenerator::genSerialTraitFuncs() {
312 ast::FunctionDecl * protos[4] = {
313 genFromIntProto(),
314 genFromInstanceProto(),
315 genInstToInstFuncProto("succ_unsafe"),
316 genInstToInstFuncProto("pred_unsafe")
317 };
318 for (auto& proto: protos) produceForwardDecl(proto);
319 genFromIntBody(protos[0]);
320 genFromInstanceBody(protos[1]);
321 genSuccPredBody(protos[2], "?+?");
322 genSuccPredBody(protos[3], "?-?");
323 for (auto& proto: protos) produceDecl(proto);
324}
325
326ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
327 return genProto(
328 func,
329 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
330 {new ast::ObjectDecl(getLocation(), "_ret",
331 new ast::EnumInstType(decl))});
332}
333
334ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
335 return genProto(func, {}, {
336 new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
337 });
338}
339
340void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
341 const CodeLocation & loc = func->location;
342 auto mem = func->name=="lowerBound"? decl->members.front() : decl->members.back();
343 // auto expr = new ast::NameExpr( loc, mem->name );
344 auto expr = new ast::QualifiedNameExpr( loc, decl->name, mem->name );
345 func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
346}
347
348void EnumAttrFuncGenerator::genBoundedFunctions() {
349 ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
350 for (auto & protos: boundedProtos) {
351 produceForwardDecl(protos);
352 genBoundedBody(protos);
353 produceDecl(protos);
354 }
355}
356
357ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
358 const ast::EnumAttribute attr, const CodeLocation& location,
359 std::vector<ast::ptr<ast::Init>>& inits) const {
360 ast::ArrayType* arrT = new ast::ArrayType(
361 attr == ast::EnumAttribute::Value
362 ? decl->base
363 : new ast::PointerType(
364 new ast::BasicType(ast::BasicKind::Char, ast::CV::Const)),
365 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
366 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
367
368 ast::ObjectDecl* objDecl =
369 new ast::ObjectDecl(
370 decl->location, decl->getUnmangeldArrayName( attr ),
371 arrT, new ast::ListInit( location, std::move( inits ) ),
372 ast::Storage::Static, ast::Linkage::AutoGen );
373
374 return objDecl;
375}
376
377void EnumAttrFuncGenerator::genValueOrLabelBody(
378 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
379 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
380 func->location, "?[?]",
381 {new ast::NameExpr(func->location, arrDecl->name),
382 new ast::CastExpr(
383 func->location,
384 new ast::VariableExpr( func->location, func->params.front() ),
385 new ast::BasicType( ast::BasicKind::UnsignedInt ),
386 ast::GeneratedFlag::ExplicitCast
387 )});
388 func->stmts = new ast::CompoundStmt(
389 func->location, {new ast::ReturnStmt(func->location, untyped)});
390}
391
392// void EnumAttrFuncGenerator::genQuasiValueBody(ast::FunctionDecl* func) const {
393// auto location = func->location;
394// const ast::ObjectDecl * objDecl = new ast::ObjectDecl(
395// location, "_out", new ast::StructInstType( quasi_void_decl ));
396// const ast::DeclStmt * declStmt = new ast::DeclStmt(location, objDecl);
397// const ast::VariableExpr * varExpr = new ast::VariableExpr(location, objDecl);
398// const ast::ReturnStmt * retStmt = new ast::ReturnStmt(location, varExpr);
399
400// func->stmts = new ast::CompoundStmt(
401// location, {declStmt, retStmt}
402// );
403// }
404
405void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
406 auto castExpr = new ast::CastExpr(
407 func->location,
408 new ast::VariableExpr(func->location, func->params.front()),
409 new ast::BasicType( ast::BasicKind::UnsignedInt ),
410 ast::GeneratedFlag::ExplicitCast);
411 func->stmts = new ast::CompoundStmt(
412 func->location, {new ast::ReturnStmt(func->location, castExpr)});
413}
414
415void EnumAttrFuncGenerator::genTypeNameBody(ast::FunctionDecl* func) const {
416 const ast::Expr * type_name = ast::ConstantExpr::from_string(func->location, decl->name);
417 func->stmts = new ast::CompoundStmt(
418 func->location, {new ast::ReturnStmt(func->location, type_name)}
419 );
420}
421
422void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
423 if (attr == ast::EnumAttribute::Value) {
424 if (decl->isTyped()) {
425 // TypedEnum's backing arrays
426 std::vector<ast::ptr<ast::Init>> inits = genValueInit();
427 ast::ObjectDecl* arrayProto =
428 genAttrArrayProto(attr, getLocation(), inits);
429 forwards.push_back(arrayProto);
430
431 ast::FunctionDecl* funcProto = genValueProto();
432 produceForwardDecl(funcProto);
433 genValueOrLabelBody(funcProto, arrayProto);
434 produceDecl(funcProto);
435 }
436 // else {
437 // ast::FunctionDecl* funcProto = genQuasiValueProto();
438 // produceForwardDecl(funcProto);
439 // // genQuasiValueBody(funcProto);
440 // produceDecl(funcProto);
441 // }
442 } else if (attr == ast::EnumAttribute::Label) {
443 std::vector<ast::ptr<ast::Init>> inits = genLabelInit();
444 ast::ObjectDecl* arrayProto =
445 genAttrArrayProto(attr, getLocation(), inits);
446 forwards.push_back(arrayProto);
447 ast::FunctionDecl* funcProto = genLabelProto();
448 produceForwardDecl(funcProto);
449 genValueOrLabelBody(funcProto, arrayProto);
450 produceDecl(funcProto);
451 } else {
452 ast::FunctionDecl* funcProto = genPosnProto();
453 produceForwardDecl(funcProto);
454 genPosnBody(funcProto);
455 produceDecl(funcProto);
456 }
457}
458
459void EnumAttrFuncGenerator::genTypedEnumFuncs() {
460 genTypedEnumFunction(ast::EnumAttribute::Value);
461 genTypedEnumFunction(ast::EnumAttribute::Label);
462 genTypedEnumFunction(ast::EnumAttribute::Posn);
463}
464
465void EnumAttrFuncGenerator::genTypeNameFunc() {
466 ast::FunctionDecl* funcProto = genTypeNameProto();
467 produceForwardDecl(funcProto);
468 genTypeNameBody(funcProto);
469 produceDecl(funcProto);
470}
471
472void EnumAttrFuncGenerator::generateAndAppendFunctions(
473 std::list<ast::ptr<ast::Decl>>& decls) {
474 // Generate the functions (they go into forwards and definitions).
475 genTypeNameFunc();
476 genTypedEnumFuncs();
477 genSerialTraitFuncs();
478 genBoundedFunctions();
479 // Now export the lists contents.
480 decls.splice(decls.end(), forwards);
481 decls.splice(decls.end(), definitions);
482}
483
484// ---------------------------------------------------------
485
486struct ImplementEnumFunc final :
487 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
488 void previsit(const ast::EnumDecl* enumDecl);
489 void previsit(const ast::FunctionDecl* functionDecl);
490 void postvisit(const ast::FunctionDecl* functionDecl);
491
492private:
493 // Current level of nested functions.
494 unsigned int functionNesting = 0;
495};
496
497void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
498 if (!enumDecl->body || !enumDecl->isCfa) return;
499 ast::EnumInstType enumInst(enumDecl->name);
500 enumInst.base = enumDecl;
501 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
502 gen.generateAndAppendFunctions(declsToAddAfter);
503}
504
505void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
506 functionNesting += 1;
507}
508
509void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
510 functionNesting -= 1;
511}
512
513} // namespace
514
515void implementEnumFunc(ast::TranslationUnit& translationUnit) {
516 ast::Pass<ImplementEnumFunc>::run(translationUnit);
517}
518
519} // namespace Validate
Note: See TracBrowser for help on using the repository browser.