source: src/SymTab/GenImplicitCall.cpp@ d1551a5

Last change on this file since d1551a5 was 5bf685f, checked in by Andrew Beach <ajbeach@…>, 21 months ago

Replayed maybeClone with maybeCopy, removed unused helppers in utility.h and pushed some includes out of headers.

  • Property mode set to 100644
File size: 7.9 KB
Line 
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
18#include "AST/Copy.hpp" // for deepCopy
19#include "AST/Decl.hpp" // for ObjectDecl
20#include "AST/Expr.hpp" // for ConstantExpr, UntypedExpr,...
21#include "AST/Init.hpp" // for SingleInit
22#include "AST/Inspect.hpp" // for isUnnamedBitfield
23#include "AST/Stmt.hpp" // for ExprStmt
24#include "AST/Type.hpp" // for ArrayType, BasicType, ...
25#include "CodeGen/OperatorTable.h" // for isCtorDtor
26#include "Common/UniqueName.h" // for UniqueName
27#include "Common/utility.h" // for splice
28
29namespace SymTab {
30
31namespace {
32
33template< typename OutIter >
34ast::ptr< ast::Stmt > genCall(
35 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
36 const CodeLocation & loc, const std::string & fname, OutIter && out,
37 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
38
39/// inserts into out a generated call expression to function fname with arguments dstParam and
40/// srcParam. Should only be called with non-array types.
41/// optionally returns a statement which must be inserted prior to the containing loop, if
42/// there is one
43template< typename OutIter >
44ast::ptr< ast::Stmt > genScalarCall(
45 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
46 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
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
99template< typename OutIter >
100void genArrayCall(
101 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
102 const CodeLocation & loc, const std::string & fname, OutIter && out,
103 const ast::ArrayType * array, const ast::Type * addCast = nullptr,
104 LoopDirection forward = LoopForward
105) {
106 static UniqueName indexName( "_index" );
107
108 // for a flexible array member nothing is done -- user must define own assignment
109 if ( ! array->dimension ) return;
110
111 if ( addCast ) {
112 // peel off array layer from cast
113 addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
114 }
115
116 ast::ptr< ast::Expr > begin, end;
117 std::string cmp, update;
118
119 const ast::Expr * dimension = deepCopy( array->dimension );
120 if ( forward ) {
121 // generate: for ( int i = 0; i < N; ++i )
122 begin = ast::ConstantExpr::from_int( loc, 0 );
123 end = dimension;
124 cmp = "?<?";
125 update = "++?";
126 } else {
127 // generate: for ( int i = N-1; i >= 0; --i )
128 begin = ast::UntypedExpr::createCall( loc, "?-?",
129 { dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
130 end = ast::ConstantExpr::from_int( loc, 0 );
131 cmp = "?>=?";
132 update = "--?";
133 }
134
135 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl(
136 loc, indexName.newName(), new ast::BasicType( ast::BasicType::SignedInt ),
137 new ast::SingleInit( loc, begin ) );
138 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr( loc, index );
139
140 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
141 loc, cmp, { indexVar, end } );
142
143 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
144 loc, update, { indexVar } );
145
146 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
147 loc, "?[?]", { dstParam, indexVar } );
148
149 // srcParam must keep track of the array indices to build the source parameter and/or
150 // array list initializer
151 srcParam.addArrayIndex( indexVar, array->dimension );
152
153 // for stmt's body, eventually containing call
154 ast::CompoundStmt * body = new ast::CompoundStmt( loc );
155 ast::ptr< ast::Stmt > listInit = genCall(
156 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
157 forward );
158
159 // block containing the stmt and index variable
160 ast::CompoundStmt * block = new ast::CompoundStmt( loc );
161 block->push_back( new ast::DeclStmt( loc, index ) );
162 if ( listInit ) { block->push_back( listInit ); }
163 block->push_back( new ast::ForStmt( loc, {}, cond, inc, body ) );
164
165 *out++ = block;
166}
167
168template< typename OutIter >
169ast::ptr< ast::Stmt > genCall(
170 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
171 const CodeLocation & loc, const std::string & fname, OutIter && out,
172 const ast::Type * type, const ast::Type * addCast, LoopDirection forward
173) {
174 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
175 genArrayCall(
176 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
177 forward );
178 return {};
179 } else {
180 return genScalarCall(
181 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
182 }
183}
184
185} // namespace
186
187ast::ptr< ast::Stmt > genImplicitCall(
188 InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
189 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
190 LoopDirection forward
191) {
192 // unnamed bit fields are not copied as they cannot be accessed
193 if ( isUnnamedBitfield( obj ) ) return {};
194
195 ast::ptr< ast::Type > addCast;
196 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
197 assert( dstParam->result );
198 addCast = dstParam->result;
199 }
200
201 std::vector< ast::ptr< ast::Stmt > > stmts;
202 genCall(
203 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
204
205 if ( stmts.empty() ) {
206 return {};
207 } else if ( stmts.size() == 1 ) {
208 const ast::Stmt * callStmt = stmts.front();
209 if ( addCast ) {
210 // implicitly generated ctor/dtor calls should be wrapped so that later passes are
211 // aware they were generated.
212 callStmt = new ast::ImplicitCtorDtorStmt( callStmt->location, callStmt );
213 }
214 return callStmt;
215 } else {
216 assert( false );
217 return {};
218 }
219}
220
221} // namespace SymTab
222
223// Local Variables: //
224// tab-width: 4 //
225// mode: c++ //
226// compile-command: "make install" //
227// End: //
228
229
Note: See TracBrowser for help on using the repository browser.