source: src/SymTab/GenImplicitCall.cpp @ 1e7a765

Last change on this file since 1e7a765 was 14c0f7b, checked in by Andrew Beach <ajbeach@…>, 15 months ago

Added invariant to check that referenced declarations are in scope. This one took a while, I don't remember why forall pointer decay is involved.

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[fb4dc28]1//
2// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// GenImplicitCall.hpp --
8//
9// Author           : Andrew Beach
10// Created On       : Fri Apr 14 14:38:00 2023
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Apr 14 14:46:00 2023
13// Update Count     : 0
14//
15
16#include "GenImplicitCall.hpp"
17
[14c0f7b]18#include "AST/Copy.hpp"                  // for deepCopy
[8913de4]19#include "AST/Decl.hpp"                  // for ObjectDecl
20#include "AST/Expr.hpp"                  // for ConstantExpr, UntypedExpr,...
21#include "AST/Init.hpp"                  // for SingleInit
[fb4dc28]22#include "AST/Inspect.hpp"               // for isUnnamedBitfield
[8913de4]23#include "AST/Stmt.hpp"                  // for ExprStmt
24#include "AST/Type.hpp"                  // for ArrayType, BasicType, ...
[fb4dc28]25#include "CodeGen/OperatorTable.h"       // for isCtorDtor
26#include "Common/UniqueName.h"           // for UniqueName
27
28namespace SymTab {
29
[8913de4]30namespace {
31
[fb4dc28]32template< typename OutIter >
33ast::ptr< ast::Stmt > genCall(
34        InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
35        const CodeLocation & loc, const std::string & fname, OutIter && out,
36        const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
37
38/// inserts into out a generated call expression to function fname with arguments dstParam and
39/// srcParam. Should only be called with non-array types.
40/// optionally returns a statement which must be inserted prior to the containing loop, if
41/// there is one
42template< typename OutIter >
43ast::ptr< ast::Stmt > genScalarCall(
44        InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
45        const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
46        const ast::Type * addCast = nullptr
47) {
48        bool isReferenceCtorDtor = false;
49        if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
50                // reference constructors are essentially application of the rebind operator.
51                // apply & to both arguments, do not need a cast
52                fname = "?=?";
53                dstParam = new ast::AddressExpr( dstParam );
54                addCast = nullptr;
55                isReferenceCtorDtor = true;
56        }
57
58        // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
59        // "?=?", "?{}", or "^?{}"
60        ast::UntypedExpr * fExpr = new ast::UntypedExpr( loc, new ast::NameExpr( loc, fname ) );
61
62        if ( addCast ) {
63                // cast to T& with qualifiers removed, so that qualified objects can be constructed and
64                // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
65                // is considered a qualifier - for AddressExpr to resolve, its argument must have an
66                // lvalue-qualified type, so remove all qualifiers except lvalue.
67                // xxx -- old code actually removed lvalue too...
68                ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
69                ast::ptr< ast::Type > castType = addCast;
70                ast::remove_qualifiers(
71                        castType,
72                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
73                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
74        }
75        fExpr->args.emplace_back( dstParam );
76
77        ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
78
79        // fetch next set of arguments
80        ++srcParam;
81
82        // return if adding reference fails -- will happen on default ctor and dtor
83        if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
84
85        std::vector< ast::ptr< ast::Expr > > args = *srcParam;
86        splice( fExpr->args, args );
87
88        *out++ = new ast::ExprStmt{ loc, fExpr };
89
90        srcParam.clearArrayIndices();
91
92        return listInit;
93}
94
95
96/// Store in out a loop which calls fname on each element of the array with srcParam and
97/// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
98template< typename OutIter >
99void genArrayCall(
100        InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
101        const CodeLocation & loc, const std::string & fname, OutIter && out,
102        const ast::ArrayType * array, const ast::Type * addCast = nullptr,
103        LoopDirection forward = LoopForward
104) {
105        static UniqueName indexName( "_index" );
106
107        // for a flexible array member nothing is done -- user must define own assignment
108        if ( ! array->dimension ) return;
109
110        if ( addCast ) {
111                // peel off array layer from cast
112                addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
113        }
114
115        ast::ptr< ast::Expr > begin, end;
116        std::string cmp, update;
117
[14c0f7b]118        const ast::Expr * dimension = deepCopy( array->dimension );
[fb4dc28]119        if ( forward ) {
120                // generate: for ( int i = 0; i < N; ++i )
121                begin = ast::ConstantExpr::from_int( loc, 0 );
[14c0f7b]122                end = dimension;
[fb4dc28]123                cmp = "?<?";
124                update = "++?";
125        } else {
126                // generate: for ( int i = N-1; i >= 0; --i )
127                begin = ast::UntypedExpr::createCall( loc, "?-?",
[14c0f7b]128                        { dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
[fb4dc28]129                end = ast::ConstantExpr::from_int( loc, 0 );
130                cmp = "?>=?";
131                update = "--?";
132        }
133
134        ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl(
135                loc, indexName.newName(), new ast::BasicType( ast::BasicType::SignedInt ),
136                new ast::SingleInit( loc, begin ) );
137        ast::ptr< ast::Expr > indexVar = new ast::VariableExpr( loc, index );
138
139        ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
140                loc, cmp, { indexVar, end } );
141
142        ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
143                loc, update, { indexVar } );
144
145        ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
146                loc, "?[?]", { dstParam, indexVar } );
147
148        // srcParam must keep track of the array indices to build the source parameter and/or
149        // array list initializer
150        srcParam.addArrayIndex( indexVar, array->dimension );
151
152        // for stmt's body, eventually containing call
153        ast::CompoundStmt * body = new ast::CompoundStmt( loc );
154        ast::ptr< ast::Stmt > listInit = genCall(
155                srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
156                forward );
157
158        // block containing the stmt and index variable
159        ast::CompoundStmt * block = new ast::CompoundStmt( loc );
160        block->push_back( new ast::DeclStmt( loc, index ) );
161        if ( listInit ) { block->push_back( listInit ); }
162        block->push_back( new ast::ForStmt( loc, {}, cond, inc, body ) );
163
164        *out++ = block;
165}
166
167template< typename OutIter >
168ast::ptr< ast::Stmt > genCall(
169        InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
170        const CodeLocation & loc, const std::string & fname, OutIter && out,
171        const ast::Type * type, const ast::Type * addCast, LoopDirection forward
172) {
173        if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
174                genArrayCall(
175                        srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
176                        forward );
177                return {};
178        } else {
179                return genScalarCall(
180                        srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
181        }
182}
183
[8913de4]184} // namespace
185
[fb4dc28]186ast::ptr< ast::Stmt > genImplicitCall(
187        InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
188        const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
189        LoopDirection forward
190) {
191        // unnamed bit fields are not copied as they cannot be accessed
192        if ( isUnnamedBitfield( obj ) ) return {};
193
194        ast::ptr< ast::Type > addCast;
195        if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
196                assert( dstParam->result );
197                addCast = dstParam->result;
198        }
199
200        std::vector< ast::ptr< ast::Stmt > > stmts;
201        genCall(
202                srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
203
204        if ( stmts.empty() ) {
205                return {};
206        } else if ( stmts.size() == 1 ) {
207                const ast::Stmt * callStmt = stmts.front();
208                if ( addCast ) {
209                        // implicitly generated ctor/dtor calls should be wrapped so that later passes are
210                        // aware they were generated.
211                        callStmt = new ast::ImplicitCtorDtorStmt( callStmt->location, callStmt );
212                }
213                return callStmt;
214        } else {
215                assert( false );
216                return {};
217        }
218}
219
220} // namespace SymTab
221
222// Local Variables: //
223// tab-width: 4 //
224// mode: c++ //
225// compile-command: "make install" //
226// End: //
227
228
Note: See TracBrowser for help on using the repository browser.