source: src/SymTab/GenImplicitCall.cpp@ baad96e

Last change on this file since baad96e was 4e2f1b2, checked in by Andrew Beach <ajbeach@…>, 19 months ago

Clean-up of GenImplicitCall module. Changing the return type for consistency spilled out into some other files, but that should also saves some operations. The other big one is the template instances were reduced to one and then the templates removed.

  • 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//
[4e2f1b2]7// GenImplicitCall.cpp -- Generate code for implicit operator calls.
[fb4dc28]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
[5bf685f]27#include "Common/utility.h" // for splice
[fb4dc28]28
29namespace SymTab {
30
[8913de4]31namespace {
32
[4e2f1b2]33using Inserter = std::back_insert_iterator<std::list<ast::ptr<ast::Stmt>>>;
34
[fb4dc28]35ast::ptr< ast::Stmt > genCall(
[0bd3faf]36 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
[4e2f1b2]37 const CodeLocation & loc, const std::string & fname, Inserter && out,
[fb4dc28]38 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
39
40/// inserts into out a generated call expression to function fname with arguments dstParam and
41/// srcParam. Should only be called with non-array types.
42/// optionally returns a statement which must be inserted prior to the containing loop, if
43/// there is one
44ast::ptr< ast::Stmt > genScalarCall(
[0bd3faf]45 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
[4e2f1b2]46 const CodeLocation & loc, std::string fname, Inserter && out, const ast::Type * type,
[fb4dc28]47 const ast::Type * addCast = nullptr
48) {
49 bool isReferenceCtorDtor = false;
50 if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
51 // reference constructors are essentially application of the rebind operator.
52 // apply & to both arguments, do not need a cast
53 fname = "?=?";
54 dstParam = new ast::AddressExpr( dstParam );
55 addCast = nullptr;
56 isReferenceCtorDtor = true;
57 }
58
59 // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
60 // "?=?", "?{}", or "^?{}"
61 ast::UntypedExpr * fExpr = new ast::UntypedExpr( loc, new ast::NameExpr( loc, fname ) );
62
63 if ( addCast ) {
64 // cast to T& with qualifiers removed, so that qualified objects can be constructed and
65 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
66 // is considered a qualifier - for AddressExpr to resolve, its argument must have an
67 // lvalue-qualified type, so remove all qualifiers except lvalue.
68 // xxx -- old code actually removed lvalue too...
69 ast::ptr< ast::Type > guard = addCast; // prevent castType from mutating addCast
70 ast::ptr< ast::Type > castType = addCast;
71 ast::remove_qualifiers(
72 castType,
73 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
74 dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
75 }
76 fExpr->args.emplace_back( dstParam );
77
78 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
79
80 // fetch next set of arguments
81 ++srcParam;
82
83 // return if adding reference fails -- will happen on default ctor and dtor
84 if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
85
86 std::vector< ast::ptr< ast::Expr > > args = *srcParam;
87 splice( fExpr->args, args );
88
89 *out++ = new ast::ExprStmt{ loc, fExpr };
90
91 srcParam.clearArrayIndices();
92
93 return listInit;
94}
95
96
97/// Store in out a loop which calls fname on each element of the array with srcParam and
98/// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
99void genArrayCall(
[0bd3faf]100 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
[4e2f1b2]101 const CodeLocation & loc, const std::string & fname, Inserter && out,
[fb4dc28]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
167ast::ptr< ast::Stmt > genCall(
[0bd3faf]168 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
[4e2f1b2]169 const CodeLocation & loc, const std::string & fname, Inserter && out,
[fb4dc28]170 const ast::Type * type, const ast::Type * addCast, LoopDirection forward
171) {
172 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
173 genArrayCall(
[4e2f1b2]174 srcParam, dstParam, loc, fname, std::forward< Inserter&& >( out ), at, addCast,
[fb4dc28]175 forward );
176 return {};
177 } else {
178 return genScalarCall(
[4e2f1b2]179 srcParam, dstParam, loc, fname, std::forward< Inserter&& >( out ), type, addCast );
[fb4dc28]180 }
181}
182
[8913de4]183} // namespace
184
[4e2f1b2]185const ast::Stmt * genImplicitCall(
[0bd3faf]186 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
[fb4dc28]187 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
188 LoopDirection forward
189) {
190 // unnamed bit fields are not copied as they cannot be accessed
[4e2f1b2]191 if ( isUnnamedBitfield( obj ) ) return nullptr;
[fb4dc28]192
193 ast::ptr< ast::Type > addCast;
194 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
195 assert( dstParam->result );
196 addCast = dstParam->result;
197 }
198
[4e2f1b2]199 std::list< ast::ptr< ast::Stmt > > stmts;
[fb4dc28]200 genCall(
201 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
202
[4e2f1b2]203 if ( stmts.empty() ) return nullptr;
204 assert( stmts.size() == 1 );
205
206 const ast::Stmt * callStmt = stmts.front().release();
207 // Implicitly generated ctor/dtor calls should be wrapped so that
208 // later passes are aware they were generated.
209 if ( addCast ) {
210 callStmt = new ast::ImplicitCtorDtorStmt( callStmt->location, callStmt );
[fb4dc28]211 }
[4e2f1b2]212 return callStmt;
[fb4dc28]213}
214
215} // namespace SymTab
216
217// Local Variables: //
218// tab-width: 4 //
219// mode: c++ //
220// compile-command: "make install" //
221// End: //
Note: See TracBrowser for help on using the repository browser.