source: src/Validate/ImplementEnumFunc.cpp @ 748c751

Last change on this file since 748c751 was 748c751, checked in by JiadaL <j82liang@…>, 3 months ago

Remove unnecessary implicit enum type conversion

  • 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::BasicType::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::BasicType::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.