source: src/GenPoly/BoxNew.cpp@ 3cbe320

stuck-waitfor-destruct
Last change on this file since 3cbe320 was 1ee0a4da, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Translated the box pass to the new AST. This includes direct as possible translations of the existing passes are two fix in passes which correct AST problems the direct translation causes. Outside the box pass there have already been many changes, ad there is another in Instantiate Generics, which disconnects designators instead of leaving them connected to the original polymorphic type, which breaks the invarants once the fields are removed in the Eraser sub-pass. There was also a change that was made and un-made in one commit. If translate from the new-AST to the old-AST part way you must, where possible, sort the TypeEnvKey values by string comparison. However, it now passes over that so it would be just extra complexity and run time, so I removed it. I stand at the exit from a great woods, just shy of a year from when I entered it. It has been a difficult and tiring journey. The path has been long and at times comically winding; but most often it was invisible, hidden under an impenetrable canopy and I spend days looking for it. All for a short jog forward before getting lost again. In front of me is another woods. It looks smaller, but I can't see the other side. Anyways, time to keep walking.

  • Property mode set to 100644
File size: 95.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 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// BoxNew.cpp -- Implement polymorphic function calls and types.
8//
9// Author : Andrew Beach
10// Created On : Thr Oct 6 13:39:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Oct 2 17:00:00 2023
13// Update Count : 0
14//
15
16#include "Box.h"
17
18#include "AST/Decl.hpp" // for Decl, FunctionDecl, ...
19#include "AST/Expr.hpp" // for AlignofExpr, ConstantExpr, ...
20#include "AST/Init.hpp" // for Init, SingleInit
21#include "AST/Inspect.hpp" // for getFunctionName
22#include "AST/Pass.hpp" // for Pass, WithDeclsToAdd, ...
23#include "AST/Stmt.hpp" // for CompoundStmt, ExprStmt, ...
24#include "AST/Vector.hpp" // for vector
25#include "AST/GenericSubstitution.hpp" // for genericSubstitution
26#include "CodeGen/OperatorTable.h" // for isAssignment
27#include "Common/ScopedMap.h" // for ScopedMap
28#include "Common/UniqueName.h" // for UniqueName
29#include "Common/utility.h" // for toCString, group_iterate
30#include "GenPoly/FindFunction.h" // for findFunction
31#include "GenPoly/GenPoly.h" // for getFunctionType, ...
32#include "GenPoly/Lvalue.h" // for generalizedLvalue
33#include "GenPoly/ScopedSet.h" // for ScopedSet
34#include "GenPoly/ScrubTyVars.h" // for scrubTypeVars, scrubAllTypeVars
35#include "ResolvExpr/Unify.h" // for typesCompatible
36#include "SymTab/Mangler.h" // for mangle, mangleType
37
38namespace GenPoly {
39
40namespace {
41
42/// Common field of several sub-passes of box.
43struct BoxPass {
44 TypeVarMap scopeTypeVars;
45 BoxPass() : scopeTypeVars( ast::TypeData() ) {}
46};
47
48// TODO: Could this be a common helper somewhere?
49ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {
50 ast::FunctionType * type = new ast::FunctionType(
51 decl->type->isVarArgs, decl->type->qualifiers
52 );
53 for ( auto type_param : decl->type_params ) {
54 type->forall.emplace_back( new ast::TypeInstType( type_param ) );
55 }
56 for ( auto assertion : decl->assertions ) {
57 type->assertions.emplace_back( new ast::VariableExpr(
58 assertion->location, assertion ) );
59 }
60 for ( auto param : decl->params ) {
61 type->params.emplace_back( param->get_type() );
62 }
63 for ( auto retval : decl->returns ) {
64 type->returns.emplace_back( retval->get_type() );
65 }
66 return type;
67}
68
69// --------------------------------------------------------------------------
70/// Adds layout-generation functions to polymorphic types.
71struct LayoutFunctionBuilder final :
72 public ast::WithDeclsToAdd<>,
73 public ast::WithShortCircuiting,
74 public ast::WithVisitorRef<LayoutFunctionBuilder> {
75 void previsit( ast::StructDecl const * decl );
76 void previsit( ast::UnionDecl const * decl );
77};
78
79// Formally takeOtypeOnly
80/// Get all sized type declarations; those that affect a layout function.
81ast::vector<ast::TypeDecl> takeSizedParams(
82 ast::vector<ast::TypeDecl> const & decls ) {
83 ast::vector<ast::TypeDecl> sizedParams;
84 for ( ast::ptr<ast::TypeDecl> const & decl : decls ) {
85 if ( decl->isComplete() ) {
86 sizedParams.emplace_back( decl );
87 }
88 }
89 return sizedParams;
90}
91
92ast::BasicType * makeSizeAlignType() {
93 return new ast::BasicType( ast::BasicType::LongUnsignedInt );
94}
95
96/// Adds parameters for otype size and alignment to a function type.
97void addOTypeParams(
98 ast::FunctionDecl * decl,
99 ast::vector<ast::TypeDecl> const & sizedParams ) {
100 // TODO: Can we fold this into buildLayoutFunction to avoid rebuilding?
101 ast::FunctionType * type = ast::mutate( decl->type.get() );
102 for ( ast::ptr<ast::TypeDecl> const & sizedParam : sizedParams ) {
103 ast::TypeInstType inst( sizedParam );
104 std::string paramName = Mangle::mangleType( &inst );
105 decl->params.emplace_back( new ast::ObjectDecl(
106 sizedParam->location,
107 sizeofName( paramName ),
108 makeSizeAlignType()
109 ) );
110 type->params.emplace_back( makeSizeAlignType() );
111 decl->params.emplace_back( new ast::ObjectDecl(
112 sizedParam->location,
113 alignofName( paramName ),
114 makeSizeAlignType()
115 ) );
116 type->params.emplace_back( makeSizeAlignType() );
117 }
118 decl->type = type;
119}
120
121ast::Type * makeSizeAlignOutType() {
122 return new ast::PointerType( makeSizeAlignType() );
123}
124
125struct LayoutData {
126 ast::FunctionDecl * function;
127 ast::ObjectDecl * sizeofParam;
128 ast::ObjectDecl * alignofParam;
129 ast::ObjectDecl * offsetofParam;
130};
131
132// TODO: Is there a better way to handle the different besides a flag?
133LayoutData buildLayoutFunction(
134 CodeLocation const & location, ast::AggregateDecl const * aggr,
135 bool isInFunction, bool isStruct ) {
136 ast::ObjectDecl * sizeParam = new ast::ObjectDecl(
137 location,
138 sizeofName( aggr->name ),
139 makeSizeAlignOutType()
140 );
141 ast::ObjectDecl * alignParam = new ast::ObjectDecl(
142 location,
143 alignofName( aggr->name ),
144 makeSizeAlignOutType()
145 );
146 ast::ObjectDecl * offsetParam = nullptr;
147 ast::vector<ast::DeclWithType> params = { sizeParam, alignParam };
148 if ( isStruct ) {
149 offsetParam = new ast::ObjectDecl(
150 location,
151 offsetofName( aggr->name ),
152 makeSizeAlignOutType()
153 );
154 params.push_back( offsetParam );
155 }
156
157 // Routines at global scope marked "static" to prevent multiple
158 // definitions is separate translation units because each unit generates
159 // copies of the default routines for each aggregate.
160 ast::FunctionDecl * layoutDecl = new ast::FunctionDecl(
161 location,
162 layoutofName( aggr ),
163 {}, // forall
164 {}, // assertions
165 std::move( params ),
166 {}, // returns
167 new ast::CompoundStmt( location ),
168 isInFunction ? ast::Storage::Classes() : ast::Storage::Static,
169 ast::Linkage::AutoGen,
170 {}, // attrs
171 ast::Function::Inline,
172 ast::FixedArgs
173 );
174 layoutDecl->fixUniqueId();
175 return LayoutData{ layoutDecl, sizeParam, alignParam, offsetParam };
176}
177
178/// Makes a binary operation.
179ast::Expr * makeOp( CodeLocation const & location, std::string const & name,
180 ast::Expr const * lhs, ast::Expr const * rhs ) {
181 return new ast::UntypedExpr( location,
182 new ast::NameExpr( location, name ), { lhs, rhs } );
183}
184
185/// Make a binary operation and wrap it in a statement.
186ast::Stmt * makeOpStmt( CodeLocation const & location, std::string const & name,
187 ast::Expr const * lhs, ast::Expr const * rhs ) {
188 return new ast::ExprStmt( location, makeOp( location, name, lhs, rhs ) );
189}
190
191/// Returns the dereference of a local pointer variable.
192ast::Expr * derefVar(
193 CodeLocation const & location, ast::ObjectDecl const * var ) {
194 return ast::UntypedExpr::createDeref( location,
195 new ast::VariableExpr( location, var ) );
196}
197
198/// Makes an if-statement with a single-expression then and no else.
199ast::Stmt * makeCond( CodeLocation const & location,
200 ast::Expr const * cond, ast::Expr const * thenPart ) {
201 return new ast::IfStmt( location,
202 cond, new ast::ExprStmt( location, thenPart ), nullptr );
203}
204
205/// Makes a statement that aligns lhs to rhs (rhs should be an integer
206/// power of two).
207ast::Stmt * makeAlignTo( CodeLocation const & location,
208 ast::Expr const * lhs, ast::Expr const * rhs ) {
209 // Check that the lhs is zeroed out to the level of rhs.
210 ast::Expr * ifCond = makeOp( location, "?&?", lhs,
211 makeOp( location, "?-?", rhs,
212 ast::ConstantExpr::from_ulong( location, 1 ) ) );
213 // If not aligned, increment to alignment.
214 ast::Expr * ifExpr = makeOp( location, "?+=?", ast::deepCopy( lhs ),
215 makeOp( location, "?-?", ast::deepCopy( rhs ),
216 ast::deepCopy( ifCond ) ) );
217 return makeCond( location, ifCond, ifExpr );
218}
219
220/// Makes a statement that assigns rhs to lhs if lhs < rhs.
221ast::Stmt * makeAssignMax( CodeLocation const & location,
222 ast::Expr const * lhs, ast::Expr const * rhs ) {
223 return makeCond( location,
224 makeOp( location, "?<?", ast::deepCopy( lhs ), ast::deepCopy( rhs ) ),
225 makeOp( location, "?=?", lhs, rhs ) );
226}
227
228void LayoutFunctionBuilder::previsit( ast::StructDecl const * decl ) {
229 // Do not generate layout function for empty tag structures.
230 visit_children = false;
231 if ( decl->members.empty() ) return;
232
233 // Get parameters that can change layout, exiting early if none.
234 ast::vector<ast::TypeDecl> sizedParams =
235 takeSizedParams( decl->params );
236 if ( sizedParams.empty() ) return;
237
238 CodeLocation const & location = decl->location;
239
240 // Build layout function signature.
241 LayoutData layout =
242 buildLayoutFunction( location, decl, isInFunction(), true );
243 ast::FunctionDecl * layoutDecl = layout.function;
244 // Also return these or extract them from the parameter list?
245 ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
246 ast::ObjectDecl const * alignofParam = layout.alignofParam;
247 ast::ObjectDecl const * offsetofParam = layout.offsetofParam;
248 assert( nullptr != layout.offsetofParam );
249 addOTypeParams( layoutDecl, sizedParams );
250
251 // Calculate structure layout in function body.
252 // Initialize size and alignment to 0 and 1
253 // (Will have at least one member to update size).
254 auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
255 kids.emplace_back( makeOpStmt( location, "?=?",
256 derefVar( location, sizeofParam ),
257 ast::ConstantExpr::from_ulong( location, 0 )
258 ) );
259 kids.emplace_back( makeOpStmt( location, "?=?",
260 derefVar( location, alignofParam ),
261 ast::ConstantExpr::from_ulong( location, 1 )
262 ) );
263 // TODO: Polymorphic types will be out of the struct declaration scope.
264 // Should be removed by PolyGenericCalculator.
265 for ( auto const & member : enumerate( decl->members ) ) {
266 auto dwt = member.val.strict_as<ast::DeclWithType>();
267 ast::Type const * memberType = dwt->get_type();
268
269 if ( 0 < member.idx ) {
270 // Make sure all later members have padding to align them.
271 kids.emplace_back( makeAlignTo( location,
272 derefVar( location, sizeofParam ),
273 new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
274 ) );
275 }
276
277 // Place current size in the current offset index.
278 kids.emplace_back( makeOpStmt( location, "?=?",
279 makeOp( location, "?[?]",
280 new ast::VariableExpr( location, offsetofParam ),
281 ast::ConstantExpr::from_ulong( location, member.idx ) ),
282 derefVar( location, sizeofParam ) ) );
283
284 // Add member size to current size.
285 kids.emplace_back( makeOpStmt( location, "?+=?",
286 derefVar( location, sizeofParam ),
287 new ast::SizeofExpr( location, ast::deepCopy( memberType ) ) ) );
288
289 // Take max of member alignment and global alignment.
290 // (As align is always 2^n, this will always be a multiple of both.)
291 kids.emplace_back( makeAssignMax( location,
292 derefVar( location, alignofParam ),
293 new ast::AlignofExpr( location, ast::deepCopy( memberType ) ) ) );
294 }
295 // Make sure the type is end-padded to a multiple of its alignment.
296 kids.emplace_back( makeAlignTo( location,
297 derefVar( location, sizeofParam ),
298 derefVar( location, alignofParam ) ) );
299
300 declsToAddAfter.emplace_back( layoutDecl );
301}
302
303void LayoutFunctionBuilder::previsit( ast::UnionDecl const * decl ) {
304 visit_children = false;
305 // Do not generate layout function for empty tag unions.
306 if ( decl->members.empty() ) return;
307
308 // Get parameters that can change layout, exiting early if none.
309 ast::vector<ast::TypeDecl> sizedParams =
310 takeSizedParams( decl->params );
311 if ( sizedParams.empty() ) return;
312
313 CodeLocation const & location = decl->location;
314
315 // Build layout function signature.
316 LayoutData layout =
317 buildLayoutFunction( location, decl, isInFunction(), false );
318 ast::FunctionDecl * layoutDecl = layout.function;
319 // Also return these or extract them from the parameter list?
320 ast::ObjectDecl const * sizeofParam = layout.sizeofParam;
321 ast::ObjectDecl const * alignofParam = layout.alignofParam;
322 assert( nullptr == layout.offsetofParam );
323 addOTypeParams( layoutDecl, sizedParams );
324
325 // Calculate union layout in function body.
326 // Both are simply the maximum for union (actually align is always the
327 // LCM, but with powers of two that is also the maximum).
328 auto & kids = layoutDecl->stmts.get_and_mutate()->kids;
329 kids.emplace_back( makeOpStmt( location,
330 "?=?", derefVar( location, sizeofParam ),
331 ast::ConstantExpr::from_ulong( location, 1 )
332 ) );
333 kids.emplace_back( makeOpStmt( location,
334 "?=?", derefVar( location, alignofParam ),
335 ast::ConstantExpr::from_ulong( location, 1 )
336 ) );
337 // TODO: Polymorphic types will be out of the union declaration scope.
338 for ( auto const & member : decl->members ) {
339 auto dwt = member.strict_as<ast::DeclWithType>();
340 ast::Type const * memberType = dwt->get_type();
341
342 // Take max member size and global size.
343 kids.emplace_back( makeAssignMax( location,
344 derefVar( location, sizeofParam ),
345 new ast::SizeofExpr( location, ast::deepCopy( memberType ) )
346 ) );
347
348 // Take max of member alignment and global alignment.
349 kids.emplace_back( makeAssignMax( location,
350 derefVar( location, alignofParam ),
351 new ast::AlignofExpr( location, ast::deepCopy( memberType ) )
352 ) );
353 }
354 kids.emplace_back( makeAlignTo( location,
355 derefVar( location, sizeofParam ),
356 derefVar( location, alignofParam ) ) );
357
358 declsToAddAfter.emplace_back( layoutDecl );
359}
360
361// --------------------------------------------------------------------------
362/// Application expression transformer.
363/// * Replaces polymorphic return types with out-parameters.
364/// * Replaces call to polymorphic functions with adapter calls which handles
365/// dynamic arguments and return values.
366/// * Adds appropriate type variables to the function calls.
367struct CallAdapter final :
368 public BoxPass,
369 public ast::WithConstTypeSubstitution,
370 public ast::WithGuards,
371 public ast::WithShortCircuiting,
372 public ast::WithStmtsToAdd<>,
373 public ast::WithVisitorRef<CallAdapter> {
374 CallAdapter();
375
376 void previsit( ast::Decl const * decl );
377 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
378 void previsit( ast::TypeDecl const * decl );
379 void previsit( ast::CommaExpr const * expr );
380 ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
381 ast::Expr const * postvisit( ast::UntypedExpr const * expr );
382 void previsit( ast::AddressExpr const * expr );
383 ast::Expr const * postvisit( ast::AddressExpr const * expr );
384 ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
385 void previsit( ast::PointerType const * type );
386 void previsit( ast::FunctionType const * type );
387
388 void beginScope();
389 void endScope();
390private:
391 // Many helpers here use a mutable ApplicationExpr as an in/out parameter
392 // instead of using the return value, to save on mutates and free up the
393 // return value.
394
395 /// Pass the extra type parameters from polymorphic generic arguments or
396 /// return types into a function application.
397 ast::vector<ast::Expr>::iterator passArgTypeVars(
398 ast::ApplicationExpr * expr, ast::Type const * parmType,
399 ast::Type const * argBaseType, ast::vector<ast::Expr>::iterator arg,
400 const TypeVarMap & exprTyVars, std::set<std::string> & seenTypes );
401 /// Passes extra type parameters into a polymorphic function application.
402 ast::vector<ast::Expr>::iterator passTypeVars(
403 ast::ApplicationExpr * expr,
404 ast::Type const * polyRetType,
405 ast::FunctionType const * funcType,
406 const TypeVarMap & exprTyVars );
407 /// Wraps a function application with a new temporary for the
408 /// out-parameter return value.
409 ast::Expr const * addRetParam(
410 ast::ApplicationExpr * expr, ast::Type const * retType );
411 /// Wraps a function application returning a polymorphic type with a new
412 /// temporary for the out-parameter return value.
413 ast::Expr const * addDynRetParam(
414 ast::ApplicationExpr * expr, ast::Type const * polyType );
415 /// Modify a call so it passes the function through the correct adapter.
416 ast::Expr const * applyAdapter(
417 ast::ApplicationExpr * expr,
418 ast::FunctionType const * function );
419 /// Convert a single argument into its boxed form to pass the parameter.
420 void boxParam( ast::ptr<ast::Expr> & arg,
421 ast::Type const * formal, TypeVarMap const & exprTyVars );
422 /// Box every argument from arg forward, matching the functionType
423 /// parameter list. arg should point into expr's argument list.
424 void boxParams(
425 ast::ApplicationExpr const * expr,
426 ast::vector<ast::Expr>::iterator arg,
427 ast::FunctionType const * function,
428 const TypeVarMap & typeVars );
429 /// Adds the inferred parameters derived from the assertions of the
430 /// expression to the call.
431 void addInferredParams(
432 ast::ApplicationExpr * expr,
433 ast::vector<ast::Expr>::iterator arg,
434 ast::FunctionType const * functionType,
435 const TypeVarMap & typeVars );
436 /// Stores assignment operators from assertion list in
437 /// local map of assignment operations.
438 void passAdapters(
439 ast::ApplicationExpr * expr,
440 ast::FunctionType const * type,
441 const TypeVarMap & typeVars );
442 /// Create an adapter function based on the type of the adaptee and the
443 /// real type with the type substitutions applied.
444 ast::FunctionDecl * makeAdapter(
445 ast::FunctionType const * adaptee,
446 ast::FunctionType const * realType,
447 std::string const & mangleName,
448 TypeVarMap const & typeVars,
449 CodeLocation const & location ) const;
450 /// Replaces intrinsic operator functions with their arithmetic desugaring.
451 ast::Expr const * handleIntrinsics( ast::ApplicationExpr const * );
452 /// Inserts a new temporary variable into the current scope with an
453 /// auto-generated name.
454 ast::ObjectDecl * makeTemporary(
455 CodeLocation const & location, ast::Type const * type );
456
457 /// Set of adapter functions in the current scope.
458 ScopedMap< std::string, ast::DeclWithType const * > adapters;
459 std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
460 ast::DeclWithType const * retval;
461 UniqueName tmpNamer;
462};
463
464/// Replaces a polymorphic type with its concrete equivalant under the
465/// current environment (returns itself if concrete).
466/// If `doClone` is set to false, will not clone interior types
467ast::Type const * replaceWithConcrete(
468 ast::Type const * type,
469 ast::TypeSubstitution const & typeSubs,
470 bool doCopy = true );
471
472/// Replaces all the type parameters of a generic type with their
473/// concrete equivalents under the current environment.
474void replaceParametersWithConcrete(
475 ast::vector<ast::Expr> & params,
476 ast::TypeSubstitution const & typeSubs ) {
477 for ( ast::ptr<ast::Expr> & paramExpr : params ) {
478 ast::TypeExpr const * param = paramExpr.as<ast::TypeExpr>();
479 assertf( param, "Aggregate parameters should be type expressions." );
480 paramExpr = ast::mutate_field( param, &ast::TypeExpr::type,
481 replaceWithConcrete( param->type.get(), typeSubs, false ) );
482 }
483}
484
485ast::Type const * replaceWithConcrete(
486 ast::Type const * type,
487 ast::TypeSubstitution const & typeSubs,
488 bool doCopy ) {
489 if ( auto instType = dynamic_cast<ast::TypeInstType const *>( type ) ) {
490 ast::Type const * concrete = typeSubs.lookup( instType );
491 return ( nullptr != concrete ) ? concrete : instType;
492 } else if ( auto structType =
493 dynamic_cast<ast::StructInstType const *>( type ) ) {
494 ast::StructInstType * newType =
495 doCopy ? ast::deepCopy( structType ) : ast::mutate( structType );
496 replaceParametersWithConcrete( newType->params, typeSubs );
497 return newType;
498 } else if ( auto unionType =
499 dynamic_cast<ast::UnionInstType const *>( type ) ) {
500 ast::UnionInstType * newType =
501 doCopy ? ast::deepCopy( unionType ) : ast::mutate( unionType );
502 replaceParametersWithConcrete( newType->params, typeSubs );
503 return newType;
504 } else {
505 return type;
506 }
507}
508
509std::string makePolyMonoSuffix(
510 ast::FunctionType const * function,
511 TypeVarMap const & typeVars ) {
512 // TODO
513 // NOTE: This function previously used isPolyObj, which failed to produce
514 // the correct thing in some situations. It's not clear to [Rob Schluntz]
515 // why this wasn't working.
516
517 // If the return type or a parameter type involved polymorphic types,
518 // then the adapter will need to take those polymorphic types as pointers.
519 // Therefore, there can be two different functions with the same mangled
520 // name, so we need to further mangle the names.
521 std::stringstream name;
522 for ( auto ret : function->returns ) {
523 name << ( isPolyType( ret, typeVars ) ? 'P' : 'M' );
524 }
525 name << '_';
526 for ( auto arg : function->params ) {
527 name << ( isPolyType( arg, typeVars ) ? 'P' : 'M' );
528 }
529 return name.str();
530}
531
532std::string mangleAdapterName(
533 ast::FunctionType const * function,
534 TypeVarMap const & typeVars ) {
535 return Mangle::mangle( function, {} )
536 + makePolyMonoSuffix( function, typeVars );
537}
538
539std::string makeAdapterName( std::string const & mangleName ) {
540 return "_adapter" + mangleName;
541}
542
543void makeRetParam( ast::FunctionType * type ) {
544 ast::ptr<ast::Type> & retParam = type->returns.front();
545
546 // Make a new parameter that is a pointer to the type of the old return value.
547 retParam = new ast::PointerType( retParam.get() );
548 type->params.emplace( type->params.begin(), retParam );
549
550 // We don't need the return value any more.
551 type->returns.clear();
552}
553
554ast::FunctionType * makeAdapterType(
555 ast::FunctionType const * adaptee,
556 TypeVarMap const & typeVars ) {
557 ast::FunctionType * adapter = ast::deepCopy( adaptee );
558 if ( isDynRet( adapter, typeVars ) ) {
559 makeRetParam( adapter );
560 }
561 adapter->params.emplace( adapter->params.begin(),
562 new ast::PointerType( new ast::FunctionType( ast::VariableArgs ) )
563 );
564 return adapter;
565}
566
567CallAdapter::CallAdapter() : tmpNamer( "_temp" ) {}
568
569void CallAdapter::previsit( ast::Decl const * ) {
570 // Prevent type declaration information from leaking out.
571 GuardScope( scopeTypeVars );
572}
573
574ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
575 if ( nullptr == decl->stmts ) {
576 // This may keep TypeDecls we don't ever want from sneaking in.
577 // Not visiting child nodes might just be faster.
578 GuardScope( scopeTypeVars );
579 return decl;
580 }
581
582 GuardScope( scopeTypeVars );
583 GuardValue( retval );
584
585 // Process polymorphic return value.
586 retval = nullptr;
587 ast::FunctionType const * type = decl->type;
588 if ( isDynRet( type ) && decl->linkage != ast::Linkage::C ) {
589 //retval = type->returns.front();
590 retval = decl->returns.front();
591
592 // Give names to unnamed return values.
593 if ( "" == retval->name ) {
594 auto mutRet = ast::mutate( retval );
595 mutRet->name = "_retparam";
596 mutRet->linkage = ast::Linkage::C;
597 retval = mutRet;
598 decl = ast::mutate_field_index( decl,
599 &ast::FunctionDecl::returns, 0, mutRet );
600 }
601 }
602
603 // The formal_usage/expr_id values may be off if we get them from the
604 // type, trying the declaration instead.
605 makeTypeVarMap( type, scopeTypeVars );
606
607 // Get all needed adapters from the call. We will forward them.
608 ast::vector<ast::FunctionType> functions;
609 for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
610 auto atype = assertion->result.get();
611 findFunction( atype, functions, scopeTypeVars, needsAdapter );
612 }
613
614 for ( ast::ptr<ast::Type> const & arg : type->params ) {
615 findFunction( arg, functions, scopeTypeVars, needsAdapter );
616 }
617
618 for ( auto funcType : functions ) {
619 std::string mangleName = mangleAdapterName( funcType, scopeTypeVars );
620 if ( adapters.contains( mangleName ) ) continue;
621 std::string adapterName = makeAdapterName( mangleName );
622 // TODO: The forwarding here is problematic because these
623 // declarations are not rooted anywhere in the translation unit.
624 adapters.insert(
625 mangleName,
626 new ast::ObjectDecl(
627 decl->location,
628 adapterName,
629 new ast::PointerType(
630 makeAdapterType( funcType, scopeTypeVars ) ),
631 nullptr, // init
632 ast::Storage::Classes(),
633 ast::Linkage::C
634 )
635 );
636 }
637
638 return decl;
639}
640
641void CallAdapter::previsit( ast::TypeDecl const * decl ) {
642 addToTypeVarMap( decl, scopeTypeVars );
643}
644
645void CallAdapter::previsit( ast::CommaExpr const * expr ) {
646 // Attempting to find application expressions that were mutated by the
647 // copy constructor passes to use an explicit return variable, so that
648 // the variable can be reused as a parameter to the call rather than
649 // creating a new temporary variable. Previously this step was an
650 // optimization, but
651 // ...
652 // with the introduction of tuples and UniqueExprs, it is necessary to
653 // ensure that they use the same variable.
654 // Essentially, looking for pattern:
655 // (x=f(...), x)
656 // To compound the issue, the right side can be *x, etc.
657 // because of lvalue-returning functions
658 if ( auto assign = expr->arg1.as<ast::UntypedExpr>() ) {
659 if ( CodeGen::isAssignment( ast::getFunctionName( assign ) ) ) {
660 assert( 2 == assign->args.size() );
661 if ( auto app = assign->args.back().as<ast::ApplicationExpr>() ) {
662 // First argument is assignable, so it must be an lvalue,
663 // so it should be legal to takes its address.
664 retVals.insert_or_assign( app, assign->args.front() );
665 }
666 }
667 }
668}
669
670ast::Expr const * CallAdapter::postvisit( ast::ApplicationExpr const * expr ) {
671 assert( expr->func->result );
672 ast::FunctionType const * function = getFunctionType( expr->func->result );
673 assertf( function, "ApplicationExpr has non-function type %s",
674 toCString( expr->func->result ) );
675
676 if ( auto newExpr = handleIntrinsics( expr ) ) {
677 return newExpr;
678 }
679
680 ast::ApplicationExpr * mutExpr = ast::mutate( expr );
681 ast::Expr const * ret = expr;
682
683 // TODO: This entire section should probably be refactored to do less
684 // pushing to the front/middle of a vector.
685 ptrdiff_t initArgCount = mutExpr->args.size();
686
687 TypeVarMap exprTypeVars = { ast::TypeData() };
688 // TODO: Should this take into account the variables already bound in
689 // scopeTypeVars ([ex] remove them from exprTypeVars)?
690 makeTypeVarMap( function, exprTypeVars );
691 auto dynRetType = isDynRet( function, exprTypeVars );
692
693 // NOTE: addDynRetParam needs to know the actual (generated) return type
694 // so it can make a temporary variable, so pass the result type form the
695 // `expr` `passTypeVars` needs to know the program-text return type ([ex]
696 // the distinction between _conc_T30 and T3(int)) concRetType may not be
697 // a good name in one or both of these places.
698 // TODO A more appropriate name change is welcome.
699 if ( dynRetType ) {
700 ast::Type const * result = mutExpr->result;
701 ast::Type const * concRetType = result->isVoid() ? nullptr : result;
702 // [Comment from before translation.]
703 // Used to use dynRetType instead of concRetType.
704 ret = addDynRetParam( mutExpr, concRetType );
705 } else if ( needsAdapter( function, scopeTypeVars )
706 && !needsAdapter( function, exprTypeVars ) ) {
707 // TODO:
708 // The !needsAdapter check may be incorrect. It seems there is some
709 // situation where an adapter is applied where it shouldn't be,
710 // and this fixes it for some case. More investigation is needed.
711
712 // Change the application so it calls the adapter rather than the
713 // passed function.
714 ret = applyAdapter( mutExpr, function );
715 }
716
717 assert( typeSubs );
718 ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );
719 // Used to use dynRetType instead of concRetType; this changed so that
720 // the correct type parameters are passed for return types (it should be
721 // the concrete type's parameters, not the formal type's).
722 ast::vector<ast::Expr>::iterator argIt =
723 passTypeVars( mutExpr, concRetType, function, exprTypeVars );
724 addInferredParams( mutExpr, argIt, function, exprTypeVars );
725
726 argIt = mutExpr->args.begin();
727 std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
728
729 boxParams( mutExpr, argIt, function, exprTypeVars );
730 passAdapters( mutExpr, function, exprTypeVars );
731
732 return ret;
733}
734
735bool isPolyDeref( ast::UntypedExpr const * expr,
736 TypeVarMap const & typeVars,
737 ast::TypeSubstitution const * typeSubs ) {
738 if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
739 if ( auto name = expr->func.as<ast::NameExpr>() ) {
740 if ( "*?" == name->name ) {
741 return true;
742 }
743 }
744 }
745 return false;
746}
747
748ast::Expr const * CallAdapter::postvisit( ast::UntypedExpr const * expr ) {
749 if ( isPolyDeref( expr, scopeTypeVars, typeSubs ) ) {
750 // TODO Pretty sure this is just a memory management change.
751 // Also, I don't understand what this is doing.
752 //ast::Expr const * ret = expr->args.front();
753 //expr->args.clear();
754 //return ret;
755 return expr->args.front();
756 }
757 return expr;
758}
759
760void CallAdapter::previsit( ast::AddressExpr const * ) {
761 visit_children = false;
762}
763
764ast::Expr const * CallAdapter::postvisit( ast::AddressExpr const * expr ) {
765 assert( expr->arg->result );
766 assert( !expr->arg->result->isVoid() );
767
768 bool doesNeedAdapter = false;
769 if ( auto un = expr->arg.as<ast::UntypedExpr>() ) {
770 if ( isPolyDeref( un, scopeTypeVars, typeSubs ) ) {
771 if ( auto app = un->args.front().as<ast::ApplicationExpr>() ) {
772 assert( app->func->result );
773 auto function = getFunctionType( app->func->result );
774 assert( function );
775 doesNeedAdapter = needsAdapter( function, scopeTypeVars );
776 }
777 }
778 }
779 // isPolyType check needs to happen before mutating expr arg,
780 // so pull it forward out of the if condition.
781 expr = ast::mutate_field( expr, &ast::AddressExpr::arg,
782 expr->arg->accept( *visitor ) );
783 // But must happen after mutate, since argument might change
784 // (ex. intrinsic *?, ?[?]) re-evaluate above comment.
785 bool polyType = isPolyType( expr->arg->result, scopeTypeVars, typeSubs );
786 if ( polyType || doesNeedAdapter ) {
787 ast::Expr * ret = ast::mutate( expr->arg.get() );
788 ret->result = ast::deepCopy( expr->result );
789 return ret;
790 } else {
791 return expr;
792 }
793}
794
795ast::ReturnStmt const * CallAdapter::previsit( ast::ReturnStmt const * stmt ) {
796 // Since retval is set when the return type is dynamic, this function
797 // should have been converted to void return & out parameter.
798 if ( retval && stmt->expr ) {
799 assert( stmt->expr->result );
800 assert( !stmt->expr->result->isVoid() );
801 return ast::mutate_field( stmt, &ast::ReturnStmt::expr, nullptr );
802 }
803 return stmt;
804}
805
806void CallAdapter::previsit( ast::PointerType const * type ) {
807 GuardScope( scopeTypeVars );
808 makeTypeVarMap( type, scopeTypeVars );
809}
810
811void CallAdapter::previsit( ast::FunctionType const * type ) {
812 GuardScope( scopeTypeVars );
813 makeTypeVarMap( type, scopeTypeVars );
814}
815
816void CallAdapter::beginScope() {
817 adapters.beginScope();
818}
819
820void CallAdapter::endScope() {
821 adapters.endScope();
822}
823
824/// Find instances of polymorphic type parameters.
825struct PolyFinder {
826 TypeVarMap const & typeVars;
827 bool result = false;
828 PolyFinder( TypeVarMap const & tvs ) : typeVars( tvs ) {}
829
830 void previsit( ast::TypeInstType const * type ) {
831 if ( isPolyType( type, typeVars ) ) result = true;
832 }
833};
834
835/// True if these is an instance of a polymorphic type parameter in the type.
836bool hasPolymorphism( ast::Type const * type, TypeVarMap const & typeVars ) {
837 return ast::Pass<PolyFinder>::read( type, typeVars );
838}
839
840// arg is an in/out parameter that matches the return value.
841ast::vector<ast::Expr>::iterator CallAdapter::passArgTypeVars(
842 ast::ApplicationExpr * expr, ast::Type const * paramType,
843 ast::Type const * argBaseType, ast::vector<ast::Expr>::iterator arg,
844 const TypeVarMap & exprTypeVars, std::set<std::string> & seenTypes ) {
845 ast::Type const * polyType = isPolyType( paramType, exprTypeVars );
846 if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
847 return arg;
848 }
849
850 std::string typeName = Mangle::mangleType( polyType );
851 if ( seenTypes.count( typeName ) ) return arg;
852
853 arg = expr->args.insert( arg,
854 new ast::SizeofExpr( expr->location, ast::deepCopy( argBaseType ) )
855 );
856 arg++;
857 arg = expr->args.insert( arg,
858 new ast::AlignofExpr( expr->location, ast::deepCopy( argBaseType ) )
859 );
860 arg++;
861 if ( dynamic_cast<ast::StructInstType const *>( polyType ) ) {
862 auto argBaseStructType =
863 dynamic_cast<ast::StructInstType const *>( argBaseType );
864 if ( nullptr == argBaseStructType ) {
865 SemanticError( expr,
866 "Cannot pass non-structure type for generic struct: " );
867 }
868
869 // Zero-length arrays are forbidden by C, so don't pass
870 // offset for empty structure.
871 if ( !argBaseStructType->base->members.empty() ) {
872 arg = expr->args.insert( arg,
873 new ast::OffsetPackExpr(
874 expr->location,
875 ast::deepCopy( argBaseStructType ) )
876 );
877 arg++;
878 }
879 }
880
881 seenTypes.insert( typeName );
882 return arg;
883}
884
885ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
886 ast::ApplicationExpr * expr,
887 ast::Type const * polyRetType,
888 ast::FunctionType const * function,
889 const TypeVarMap & exprTypeVars ) {
890 assert( typeSubs );
891 ast::vector<ast::Expr>::iterator arg = expr->args.begin();
892 // Pass size/align for type variables.
893 for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
894 if ( !typeVar->base->isComplete() ) continue;
895 ast::Type const * concrete = typeSubs->lookup( typeVar );
896 if ( !concrete ) {
897 // Should this be an assertion?
898 SemanticError( expr, toString( typeSubs,
899 "\nunbound type variable: ", typeVar->typeString(),
900 " in application " ) );
901 }
902 arg = expr->args.insert( arg,
903 new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
904 arg++;
905 arg = expr->args.insert( arg,
906 new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
907 arg++;
908 }
909
910 // Add size/align for generic types to parameter list.
911 if ( !expr->func->result ) return arg;
912 ast::FunctionType const * funcType = getFunctionType( expr->func->result );
913 assert( funcType );
914
915 // This iterator points at first original argument.
916 ast::vector<ast::Expr>::const_iterator funcArg;
917 // Names for generic types we've seen.
918 std::set<std::string> seenTypes;
919
920 // A polymorphic return type may need to be added to the argument list.
921 if ( polyRetType ) {
922 assert( typeSubs );
923 auto concRetType = replaceWithConcrete( polyRetType, *typeSubs );
924 // TODO: This write-back may not be correct.
925 arg = passArgTypeVars( expr, polyRetType, concRetType,
926 arg, exprTypeVars, seenTypes );
927 // Skip the return parameter in the argument list.
928 funcArg = arg + 1;
929 } else {
930 funcArg = arg;
931 }
932
933 // TODO:
934 // I believe this is (starts as) the number of original arguments to the
935 // function with the args before funcArg all being inserted.
936 ptrdiff_t argsToPass = std::distance( funcArg, expr->args.cend() );
937
938 // Add type information args for presently unseen types in parameter list.
939 ast::vector<ast::Type>::const_iterator funcParam = funcType->params.begin();
940 // assert( funcType->params.size() == argsToPass );
941 for ( ; funcParam != funcType->params.end() && 0 < argsToPass
942 ; ++funcParam, --argsToPass ) {
943 assert( 0 < argsToPass );
944 assert( argsToPass <= (ptrdiff_t)expr->args.size() );
945 ptrdiff_t index = expr->args.size() - argsToPass;
946 ast::Type const * argType = expr->args[index]->result;
947 if ( nullptr == argType ) continue;
948 arg = passArgTypeVars( expr, *funcParam, argType,
949 arg, exprTypeVars, seenTypes );
950 }
951 return arg;
952}
953
954ast::Expr const * CallAdapter::addRetParam(
955 ast::ApplicationExpr * expr, ast::Type const * retType ) {
956 // Create temporary to hold return value of polymorphic function and
957 // produce that temporary as a result using a comma expression.
958 assert( retType );
959
960 ast::Expr * paramExpr = nullptr;
961 // Try to use existing return value parameter if it exists,
962 // otherwise create a new temporary.
963 if ( retVals.count( expr ) ) {
964 paramExpr = ast::deepCopy( retVals[ expr ] );
965 } else {
966 auto newObj = makeTemporary( expr->location, ast::deepCopy( retType ) );
967 paramExpr = new ast::VariableExpr( expr->location, newObj );
968 }
969 ast::Expr * retExpr = ast::deepCopy( paramExpr );
970
971 // If the type of the temporary is not polpmorphic, box temporary by
972 // taking its address; otherwise the temporary is already boxed and can
973 // be used directly.
974 if ( !isPolyType( paramExpr->result, scopeTypeVars, typeSubs ) ) {
975 paramExpr = new ast::AddressExpr( paramExpr->location, paramExpr );
976 }
977 // Add argument to function call.
978 expr->args.insert( expr->args.begin(), paramExpr );
979 // Build a comma expression to call the function and return a value.
980 ast::CommaExpr * comma = new ast::CommaExpr(
981 expr->location, expr, retExpr );
982 comma->env = expr->env;
983 expr->env = nullptr;
984 return comma;
985}
986
987ast::Expr const * CallAdapter::addDynRetParam(
988 ast::ApplicationExpr * expr, ast::Type const * polyType ) {
989 assert( typeSubs );
990 ast::Type const * concrete = replaceWithConcrete( polyType, *typeSubs );
991 // Add out-parameter for return value.
992 return addRetParam( expr, concrete );
993}
994
995ast::Expr const * CallAdapter::applyAdapter(
996 ast::ApplicationExpr * expr,
997 ast::FunctionType const * function ) {
998 ast::Expr const * ret = expr;
999 if ( isDynRet( function, scopeTypeVars ) ) {
1000 ret = addRetParam( expr, function->returns.front() );
1001 }
1002 std::string mangleName = mangleAdapterName( function, scopeTypeVars );
1003 std::string adapterName = makeAdapterName( mangleName );
1004
1005 // Cast adaptee to `void (*)()`, since it may have any type inside a
1006 // polymorphic function.
1007 ast::Type const * adapteeType = new ast::PointerType(
1008 new ast::FunctionType( ast::VariableArgs ) );
1009 expr->args.insert( expr->args.begin(),
1010 new ast::CastExpr( expr->location, expr->func, adapteeType ) );
1011 // The result field is never set on NameExpr. / Now it is.
1012 auto head = new ast::NameExpr( expr->location, adapterName );
1013 head->result = ast::deepCopy( adapteeType );
1014 expr->func = head;
1015
1016 return ret;
1017}
1018
1019/// Cast parameters to polymorphic functions so that types are replaced with
1020/// `void *` if they are type parameters in the formal type.
1021/// This gets rid of warnings from gcc.
1022void addCast(
1023 ast::ptr<ast::Expr> & actual,
1024 ast::Type const * formal,
1025 TypeVarMap const & typeVars ) {
1026 // Type contains polymorphism, but isn't exactly a polytype, in which
1027 // case it has some real actual type (ex. unsigned int) and casting to
1028 // `void *` is wrong.
1029 if ( hasPolymorphism( formal, typeVars )
1030 && !isPolyType( formal, typeVars ) ) {
1031 ast::Type const * newType = ast::deepCopy( formal );
1032 newType = scrubTypeVars( newType, typeVars );
1033 actual = new ast::CastExpr( actual->location, actual, newType );
1034 }
1035}
1036
1037void CallAdapter::boxParam( ast::ptr<ast::Expr> & arg,
1038 ast::Type const * param, TypeVarMap const & exprTypeVars ) {
1039 assertf( arg->result, "arg does not have result: %s", toCString( arg ) );
1040 addCast( arg, param, exprTypeVars );
1041 if ( !needsBoxing( param, arg->result, exprTypeVars, typeSubs ) ) {
1042 return;
1043 }
1044 CodeLocation const & location = arg->location;
1045
1046 if ( arg->get_lvalue() ) {
1047 // The argument expression may be CFA lvalue, but not C lvalue,
1048 // so apply generalizedLvalue transformations.
1049 // if ( auto var = dynamic_cast<ast::VariableExpr const *>( arg ) ) {
1050 // if ( dynamic_cast<ast::ArrayType const *>( varExpr->var->get_type() ) ){
1051 // // temporary hack - don't box arrays, because &arr is not the same as &arr[0]
1052 // return;
1053 // }
1054 // }
1055 arg = generalizedLvalue( new ast::AddressExpr( arg->location, arg ) );
1056 if ( !ResolvExpr::typesCompatible( param, arg->result ) ) {
1057 // Silence warnings by casting boxed parameters when the actually
1058 // type does not match up with the formal type.
1059 arg = new ast::CastExpr( location, arg, ast::deepCopy( param ) );
1060 }
1061 } else {
1062 // Use type computed in unification to declare boxed variables.
1063 ast::ptr<ast::Type> newType = ast::deepCopy( param );
1064 if ( typeSubs ) typeSubs->apply( newType );
1065 // TODO: Is this right? (Why wouldn't it be?)
1066 // I think this is to make sure we can write to the temporary.
1067 //newType.get_and_mutate()->qt = ast::CV::Qualifiers();
1068 //reset_qualifiers( newType );
1069 ast::ObjectDecl * newObj = makeTemporary( location, newType );
1070 auto assign = ast::UntypedExpr::createCall( location, "?=?", {
1071 new ast::VariableExpr( location, newObj ),
1072 arg,
1073 } );
1074 stmtsToAddBefore.push_back( new ast::ExprStmt( location, assign ) );
1075 arg = new ast::AddressExpr(
1076 new ast::VariableExpr( location, newObj ) );
1077 }
1078}
1079
1080void CallAdapter::boxParams(
1081 ast::ApplicationExpr const * expr,
1082 ast::vector<ast::Expr>::iterator arg,
1083 ast::FunctionType const * function,
1084 const TypeVarMap & typeVars ) {
1085 for ( auto param : function->params ) {
1086 assertf( arg != expr->args.end(),
1087 "boxParams: missing argument for param %s to %s in %s",
1088 toCString( param ), toCString( function ), toCString( expr ) );
1089 boxParam( *arg, param, typeVars );
1090 ++arg;
1091 }
1092}
1093
1094void CallAdapter::addInferredParams(
1095 ast::ApplicationExpr * expr,
1096 ast::vector<ast::Expr>::iterator arg,
1097 ast::FunctionType const * functionType,
1098 TypeVarMap const & typeVars ) {
1099 ast::vector<ast::Expr>::iterator cur = arg;
1100 for ( auto assertion : functionType->assertions ) {
1101 auto inferParam = expr->inferred.inferParams().find(
1102 assertion->var->uniqueId );
1103 assertf( inferParam != expr->inferred.inferParams().end(),
1104 "addInferredParams missing inferred parameter: %s in: %s",
1105 toCString( assertion ), toCString( expr ) );
1106 ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
1107 boxParam( newExpr, assertion->result, typeVars );
1108 cur = expr->args.insert( cur, newExpr.release() );
1109 ++cur;
1110 }
1111}
1112
1113/// Modifies the ApplicationExpr to accept adapter functions for its
1114/// assertion and parameters, declares the required adapters.
1115void CallAdapter::passAdapters(
1116 ast::ApplicationExpr * expr,
1117 ast::FunctionType const * type,
1118 const TypeVarMap & exprTypeVars ) {
1119 // Collect a list of function types passed as parameters or implicit
1120 // parameters (assertions).
1121 ast::vector<ast::Type> const & paramList = type->params;
1122 ast::vector<ast::FunctionType> functions;
1123
1124 for ( ast::ptr<ast::VariableExpr> const & assertion : type->assertions ) {
1125 findFunction( assertion->result, functions, exprTypeVars, needsAdapter );
1126 }
1127 for ( ast::ptr<ast::Type> const & arg : paramList ) {
1128 findFunction( arg, functions, exprTypeVars, needsAdapter );
1129 }
1130
1131 // Parameter function types for which an appropriate adapter has been
1132 // generated. We cannot use the types after applying substitutions,
1133 // since two different parameter types may be unified to the same type.
1134 std::set<std::string> adaptersDone;
1135
1136 CodeLocation const & location = expr->location;
1137
1138 for ( ast::ptr<ast::FunctionType> const & funcType : functions ) {
1139 std::string mangleName = Mangle::mangle( funcType );
1140
1141 // Only attempt to create an adapter or pass one as a parameter if we
1142 // haven't already done so for this pre-substitution parameter
1143 // function type.
1144 // The second part of the result if is if the element was inserted.
1145 if ( !adaptersDone.insert( mangleName ).second ) continue;
1146
1147 // Apply substitution to type variables to figure out what the
1148 // adapter's type should look like. (Copy to make the release safe.)
1149 assert( typeSubs );
1150 auto result = typeSubs->apply( ast::deepCopy( funcType ) );
1151 ast::FunctionType * realType = ast::mutate( result.node.release() );
1152 mangleName = Mangle::mangle( realType );
1153 mangleName += makePolyMonoSuffix( funcType, exprTypeVars );
1154
1155 // Check if the adapter has already been created, or has to be.
1156 using AdapterIter = decltype(adapters)::iterator;
1157 AdapterIter adapter = adapters.find( mangleName );
1158 if ( adapter == adapters.end() ) {
1159 ast::FunctionDecl * newAdapter = makeAdapter(
1160 funcType, realType, mangleName, exprTypeVars, location );
1161 std::pair<AdapterIter, bool> answer =
1162 adapters.insert( mangleName, newAdapter );
1163 adapter = answer.first;
1164 stmtsToAddBefore.push_back(
1165 new ast::DeclStmt( location, newAdapter ) );
1166 }
1167 assert( adapter != adapters.end() );
1168
1169 // Add the approprate adapter as a parameter.
1170 expr->args.insert( expr->args.begin(),
1171 new ast::VariableExpr( location, adapter->second ) );
1172 }
1173}
1174
1175// Parameter and argument may be used wrong around here.
1176ast::Expr * makeAdapterArg(
1177 ast::DeclWithType const * param,
1178 ast::Type const * arg,
1179 ast::Type const * realParam,
1180 TypeVarMap const & typeVars,
1181 CodeLocation const & location ) {
1182 assert( param );
1183 assert( arg );
1184 assert( realParam );
1185 if ( isPolyType( realParam, typeVars ) && !isPolyType( arg ) ) {
1186 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref(
1187 location,
1188 new ast::CastExpr( location,
1189 new ast::VariableExpr( location, param ),
1190 new ast::PointerType( ast::deepCopy( arg ) )
1191 )
1192 );
1193 deref->result = ast::deepCopy( arg );
1194 return deref;
1195 }
1196 return new ast::VariableExpr( location, param );
1197}
1198
1199// This seems to be one of the problematic functions.
1200void addAdapterParams(
1201 ast::ApplicationExpr * adaptee,
1202 ast::vector<ast::Type>::const_iterator arg,
1203 ast::vector<ast::DeclWithType>::iterator param,
1204 ast::vector<ast::DeclWithType>::iterator paramEnd,
1205 ast::vector<ast::Type>::const_iterator realParam,
1206 TypeVarMap const & typeVars,
1207 CodeLocation const & location ) {
1208 UniqueName paramNamer( "_p" );
1209 for ( ; param != paramEnd ; ++param, ++arg, ++realParam ) {
1210 if ( "" == (*param)->name ) {
1211 auto mutParam = (*param).get_and_mutate();
1212 mutParam->name = paramNamer.newName();
1213 mutParam->linkage = ast::Linkage::C;
1214 }
1215 adaptee->args.push_back(
1216 makeAdapterArg( *param, *arg, *realParam, typeVars, location ) );
1217 }
1218}
1219
1220ast::FunctionDecl * CallAdapter::makeAdapter(
1221 ast::FunctionType const * adaptee,
1222 ast::FunctionType const * realType,
1223 std::string const & mangleName,
1224 TypeVarMap const & typeVars,
1225 CodeLocation const & location ) const {
1226 ast::FunctionType * adapterType = makeAdapterType( adaptee, typeVars );
1227 adapterType = ast::mutate( scrubTypeVars( adapterType, typeVars ) );
1228
1229 // Some of these names will be overwritten, but it gives a default.
1230 UniqueName pNamer( "_param" );
1231 UniqueName rNamer( "_ret" );
1232
1233 bool first = true;
1234
1235 ast::FunctionDecl * adapterDecl = new ast::FunctionDecl( location,
1236 makeAdapterName( mangleName ),
1237 {}, // forall
1238 {}, // assertions
1239 map_range<ast::vector<ast::DeclWithType>>( adapterType->params,
1240 [&pNamer, &location, &first]( ast::ptr<ast::Type> const & param ) {
1241 // [Trying to make the generated code match exactly more often.]
1242 if ( first ) {
1243 first = false;
1244 return new ast::ObjectDecl( location, "_adaptee", param );
1245 }
1246 return new ast::ObjectDecl( location, pNamer.newName(), param );
1247 } ), // params
1248 map_range<ast::vector<ast::DeclWithType>>( adapterType->returns,
1249 [&rNamer, &location]( ast::ptr<ast::Type> const & retval ) {
1250 return new ast::ObjectDecl( location, rNamer.newName(), retval );
1251 } ), // returns
1252 nullptr, // stmts
1253 ast::Storage::Classes(), // storage
1254 ast::Linkage::C // linkage
1255 // attrs
1256 // fs
1257 // isVarArgs
1258 );
1259
1260 ast::DeclWithType * adapteeDecl =
1261 adapterDecl->params.front().get_and_mutate();
1262 adapteeDecl->name = "_adaptee";
1263
1264 // Do not carry over attributes to real type parameters/return values.
1265 auto mutRealType = ast::mutate( realType );
1266 for ( ast::ptr<ast::Type> & decl : mutRealType->params ) {
1267 if ( decl->attributes.empty() ) continue;
1268 auto mut = ast::mutate( decl.get() );
1269 mut->attributes.clear();
1270 decl = mut;
1271 }
1272 for ( ast::ptr<ast::Type> & decl : mutRealType->returns ) {
1273 if ( decl->attributes.empty() ) continue;
1274 auto mut = ast::mutate( decl.get() );
1275 mut->attributes.clear();
1276 decl = mut;
1277 }
1278 realType = mutRealType;
1279
1280 ast::ApplicationExpr * adapteeApp = new ast::ApplicationExpr( location,
1281 new ast::CastExpr( location,
1282 new ast::VariableExpr( location, adapteeDecl ),
1283 new ast::PointerType( realType )
1284 )
1285 );
1286
1287 for ( auto group : group_iterate( realType->assertions,
1288 adapterType->assertions, adaptee->assertions ) ) {
1289 auto assertArg = std::get<0>( group );
1290 auto assertParam = std::get<1>( group );
1291 auto assertReal = std::get<2>( group );
1292 adapteeApp->args.push_back( makeAdapterArg(
1293 assertParam->var, assertArg->var->get_type(),
1294 assertReal->var->get_type(), typeVars, location
1295 ) );
1296 }
1297
1298 ast::vector<ast::Type>::const_iterator
1299 arg = realType->params.begin(),
1300 param = adapterType->params.begin(),
1301 realParam = adaptee->params.begin();
1302 ast::vector<ast::DeclWithType>::iterator
1303 paramDecl = adapterDecl->params.begin();
1304 // Skip adaptee parameter in the adapter type.
1305 ++param;
1306 ++paramDecl;
1307
1308 ast::Stmt * bodyStmt;
1309 // Returns void/nothing.
1310 if ( realType->returns.empty() ) {
1311 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1312 realParam, typeVars, location );
1313 bodyStmt = new ast::ExprStmt( location, adapteeApp );
1314 // Returns a polymorphic type.
1315 } else if ( isDynType( adaptee->returns.front(), typeVars ) ) {
1316 if ( "" == (*paramDecl)->name ) {
1317 // TODO: Is it easier to make sure it has a name in the first
1318 // place? - I believe this is done, however, I could remove the
1319 // condition and just rename for clarity.
1320 assertf( false, "Wasn't expecting to get here." );
1321 auto mutParam = paramDecl->get_and_mutate();
1322 mutParam->name = "_ret";
1323 mutParam->linkage = ast::Linkage::C;
1324 }
1325 ast::UntypedExpr * assign = new ast::UntypedExpr( location,
1326 new ast::NameExpr( location, "?=?" ) );
1327 ast::UntypedExpr * deref = ast::UntypedExpr::createDeref( location,
1328 new ast::CastExpr( location,
1329 new ast::VariableExpr( location, *paramDecl++ ),
1330 new ast::PointerType(
1331 ast::deepCopy( realType->returns.front() ) ) ) );
1332 assign->args.push_back( deref );
1333 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1334 realParam, typeVars, location );
1335 assign->args.push_back( adapteeApp );
1336 bodyStmt = new ast::ExprStmt( location, assign );
1337 // Adapter for a function that returns a monomorphic value.
1338 } else {
1339 addAdapterParams( adapteeApp, arg, paramDecl, adapterDecl->params.end(),
1340 realParam, typeVars, location );
1341 bodyStmt = new ast::ReturnStmt( location, adapteeApp );
1342 }
1343
1344 adapterDecl->stmts = new ast::CompoundStmt( location, { bodyStmt } );
1345 return adapterDecl;
1346}
1347
1348ast::Expr const * makeIncrDecrExpr(
1349 CodeLocation const & location,
1350 ast::ApplicationExpr const * expr,
1351 ast::Type const * polyType,
1352 bool isIncr ) {
1353 ast::NameExpr * opExpr =
1354 new ast::NameExpr( location, isIncr ? "?+=?" : "?-=?" );
1355 ast::UntypedExpr * addAssign = new ast::UntypedExpr( location, opExpr );
1356 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1357 addAssign->args.push_back( address->arg );
1358 } else {
1359 addAssign->args.push_back( expr->args.front() );
1360 }
1361 addAssign->args.push_back( new ast::NameExpr( location,
1362 sizeofName( Mangle::mangleType( polyType ) ) ) );
1363 addAssign->result = ast::deepCopy( expr->result );
1364 addAssign->env = expr->env ? expr->env : addAssign->env;
1365 return addAssign;
1366}
1367
1368/// Handles intrinsic functions for postvisit ApplicationExpr.
1369ast::Expr const * CallAdapter::handleIntrinsics(
1370 ast::ApplicationExpr const * expr ) {
1371 auto varExpr = expr->func.as<ast::VariableExpr>();
1372 if ( !varExpr || varExpr->var->linkage != ast::Linkage::Intrinsic ) {
1373 return nullptr;
1374 }
1375 std::string const & varName = varExpr->var->name;
1376
1377 // Index Intrinsic:
1378 if ( "?[?]" == varName ) {
1379 assert( expr->result );
1380 assert( 2 == expr->args.size() );
1381
1382 ast::Type const * baseType1 =
1383 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1384 ast::Type const * baseType2 =
1385 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1386 // If neither argument is a polymorphic pointer, do nothing.
1387 if ( !baseType1 && !baseType2 ) {
1388 return expr;
1389 }
1390 // The arguments cannot both be polymorphic pointers.
1391 assert( !baseType1 || !baseType2 );
1392 // (So exactly one of the arguments is a polymorphic pointer.)
1393
1394 CodeLocation const & location = expr->location;
1395 CodeLocation const & location1 = expr->args.front()->location;
1396 CodeLocation const & location2 = expr->args.back()->location;
1397
1398 ast::UntypedExpr * ret = new ast::UntypedExpr( location,
1399 new ast::NameExpr( location, "?+?" ) );
1400 if ( baseType1 ) {
1401 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1402 expr->args.back(),
1403 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1404 } );
1405 ret->args.push_back( expr->args.front() );
1406 ret->args.push_back( multiply );
1407 } else {
1408 assert( baseType2 );
1409 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1410 expr->args.front(),
1411 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1412 } );
1413 ret->args.push_back( multiply );
1414 ret->args.push_back( expr->args.back() );
1415 }
1416 ret->result = ast::deepCopy( expr->result );
1417 ret->env = expr->env ? expr->env : ret->env;
1418 return ret;
1419 // Dereference Intrinsic:
1420 } else if ( "*?" == varName ) {
1421 assert( expr->result );
1422 assert( 1 == expr->args.size() );
1423
1424 // If this isn't for a poly type, then do nothing.
1425 if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
1426 return expr;
1427 }
1428
1429 // Remove dereference from polymorphic types since they are boxed.
1430 ast::Expr * ret = ast::deepCopy( expr->args.front() );
1431 // Fix expression type to remove pointer.
1432 ret->result = expr->result;
1433 ret->env = expr->env ? expr->env : ret->env;
1434 return ret;
1435 // Post-Increment/Decrement Intrinsics:
1436 } else if ( "?++" == varName || "?--" == varName ) {
1437 assert( expr->result );
1438 assert( 1 == expr->args.size() );
1439
1440 ast::Type const * baseType =
1441 isPolyType( expr->result, scopeTypeVars, typeSubs );
1442 if ( nullptr == baseType ) {
1443 return expr;
1444 }
1445 ast::Type * tempType = ast::deepCopy( expr->result );
1446 if ( typeSubs ) {
1447 auto result = typeSubs->apply( tempType );
1448 tempType = ast::mutate( result.node.release() );
1449 }
1450 CodeLocation const & location = expr->location;
1451 ast::ObjectDecl * newObj = makeTemporary( location, tempType );
1452 ast::VariableExpr * tempExpr =
1453 new ast::VariableExpr( location, newObj );
1454 ast::UntypedExpr * assignExpr = new ast::UntypedExpr( location,
1455 new ast::NameExpr( location, "?=?" ) );
1456 assignExpr->args.push_back( ast::deepCopy( tempExpr ) );
1457 if ( auto address = expr->args.front().as<ast::AddressExpr>() ) {
1458 assignExpr->args.push_back( ast::deepCopy( address->arg ) );
1459 } else {
1460 assignExpr->args.push_back( ast::deepCopy( expr->args.front() ) );
1461 }
1462 return new ast::CommaExpr( location,
1463 new ast::CommaExpr( location,
1464 assignExpr,
1465 makeIncrDecrExpr( location, expr, baseType, "?++" == varName )
1466 ),
1467 tempExpr
1468 );
1469 // Pre-Increment/Decrement Intrinsics:
1470 } else if ( "++?" == varName || "--?" == varName ) {
1471 assert( expr->result );
1472 assert( 1 == expr->args.size() );
1473
1474 ast::Type const * baseType =
1475 isPolyType( expr->result, scopeTypeVars, typeSubs );
1476 if ( nullptr == baseType ) {
1477 return expr;
1478 }
1479 return makeIncrDecrExpr(
1480 expr->location, expr, baseType, "++?" == varName );
1481 // Addition and Subtration Intrinsics:
1482 } else if ( "?+?" == varName || "?-?" == varName ) {
1483 assert( expr->result );
1484 assert( 2 == expr->args.size() );
1485
1486 auto baseType1 =
1487 isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
1488 auto baseType2 =
1489 isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
1490
1491 CodeLocation const & location = expr->location;
1492 CodeLocation const & location1 = expr->args.front()->location;
1493 CodeLocation const & location2 = expr->args.back()->location;
1494 // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
1495 if ( baseType1 && baseType2 ) {
1496 auto divide = ast::UntypedExpr::createCall( location, "?/?", {
1497 expr,
1498 new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
1499 } );
1500 if ( expr->env ) divide->env = expr->env;
1501 return divide;
1502 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1503 } else if ( baseType1 ) {
1504 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1505 expr->args.back(),
1506 new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
1507 } );
1508 return ast::mutate_field_index(
1509 expr, &ast::ApplicationExpr::args, 1, multiply );
1510 // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
1511 } else if ( baseType2 ) {
1512 auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
1513 expr->args.front(),
1514 new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
1515 } );
1516 return ast::mutate_field_index(
1517 expr, &ast::ApplicationExpr::args, 0, multiply );
1518 }
1519 // Addition and Subtration Relative Assignment Intrinsics:
1520 } else if ( "?+=?" == varName || "?-=?" == varName ) {
1521 assert( expr->result );
1522 assert( 2 == expr->args.size() );
1523
1524 CodeLocation const & location1 = expr->args.front()->location;
1525 CodeLocation const & location2 = expr->args.back()->location;
1526 auto baseType = isPolyPtr( expr->result, scopeTypeVars, typeSubs );
1527 // LHS op RHS -> LHS op (RHS * sizeof(LHS))
1528 if ( baseType ) {
1529 auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
1530 expr->args.back(),
1531 new ast::SizeofExpr( location1, deepCopy( baseType ) ),
1532 } );
1533 return ast::mutate_field_index(
1534 expr, &ast::ApplicationExpr::args, 1, multiply );
1535 }
1536 }
1537 return expr;
1538}
1539
1540ast::ObjectDecl * CallAdapter::makeTemporary(
1541 CodeLocation const & location, ast::Type const * type ) {
1542 auto newObj = new ast::ObjectDecl( location, tmpNamer.newName(), type );
1543 stmtsToAddBefore.push_back( new ast::DeclStmt( location, newObj ) );
1544 return newObj;
1545}
1546
1547// --------------------------------------------------------------------------
1548/// Creates the adapter functions. TODO
1549/// * Move polymorphic returns in function types to pointer-type parameters.
1550/// * Adds type size and assertion parameters to parameter lists.
1551struct DeclAdapter final :
1552 public BoxPass,
1553 public ast::WithGuards {
1554 void handleAggrDecl();
1555
1556 void previsit( ast::StructDecl const * decl );
1557 void previsit( ast::UnionDecl const * decl );
1558 void previsit( ast::TraitDecl const * decl );
1559 void previsit( ast::TypeDecl const * decl );
1560 void previsit( ast::PointerType const * type );
1561 void previsit( ast::FunctionType const * type );
1562 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
1563 ast::DeclWithType const * postvisit( ast::FunctionDecl const * decl );
1564 void previsit( ast::CompoundStmt const * stmt );
1565private:
1566 ast::FunctionDecl * addAdapters( ast::FunctionDecl * decl );
1567
1568 std::map<UniqueId, std::string> adapterName;
1569};
1570
1571// at must point within [dst.begin(), dst.end()].
1572template< typename T >
1573void spliceAt( std::vector< T > & dst, typename std::vector< T >::iterator at,
1574 std::vector< T > & src ) {
1575 std::vector< T > tmp;
1576 tmp.reserve( dst.size() + src.size() );
1577 typename std::vector< T >::iterator it = dst.begin();
1578 while ( it != at ) {
1579 assert( it != dst.end() );
1580 tmp.emplace_back( std::move( *it ) );
1581 ++it;
1582 }
1583 for ( T & x : src ) { tmp.emplace_back( std::move( x ) ); }
1584 while ( it != dst.end() ) {
1585 tmp.emplace_back( std::move( *it ) );
1586 ++it;
1587 }
1588
1589 dst.clear();
1590 src.clear();
1591 tmp.swap( dst );
1592}
1593
1594void DeclAdapter::previsit( ast::StructDecl const * ) {
1595 // Prevent type vars from leaking into the containing scope.
1596 GuardScope( scopeTypeVars );
1597}
1598
1599void DeclAdapter::previsit( ast::UnionDecl const * ) {
1600 // Prevent type vars from leaking into the containing scope.
1601 GuardScope( scopeTypeVars );
1602}
1603
1604void DeclAdapter::previsit( ast::TraitDecl const * ) {
1605 // Prevent type vars from leaking into the containing scope.
1606 GuardScope( scopeTypeVars );
1607}
1608
1609void DeclAdapter::previsit( ast::TypeDecl const * decl ) {
1610 addToTypeVarMap( decl, scopeTypeVars );
1611}
1612
1613void DeclAdapter::previsit( ast::PointerType const * type ) {
1614 GuardScope( scopeTypeVars );
1615 makeTypeVarMap( type, scopeTypeVars );
1616}
1617
1618// TODO: I think this code is redundent.
1619void DeclAdapter::previsit( ast::FunctionType const * type ) {
1620 GuardScope( scopeTypeVars );
1621 makeTypeVarMap( type, scopeTypeVars );
1622}
1623
1624ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
1625 GuardScope( scopeTypeVars );
1626 makeTypeVarMap( decl, scopeTypeVars );
1627
1628 auto mutDecl = mutate( decl );
1629
1630 // Move polymorphic return type to parameter list.
1631 if ( isDynRet( mutDecl->type ) ) {
1632 auto ret = strict_dynamic_cast<ast::ObjectDecl *>(
1633 mutDecl->returns.front().get_and_mutate() );
1634 ret->set_type( new ast::PointerType( ret->type ) );
1635 mutDecl->params.insert( mutDecl->params.begin(), ret );
1636 mutDecl->returns.erase( mutDecl->returns.begin() );
1637 ret->init = nullptr;
1638 }
1639
1640 // Add size/align and assertions for type parameters to parameter list.
1641 std::vector<ast::ptr<ast::DeclWithType>>::iterator last = mutDecl->params.begin();
1642 std::vector<ast::ptr<ast::DeclWithType>> inferredParams;
1643 // size/align/offset parameters may not be used in body, pass along with unused attribute.
1644 // TODO: These should be created with proper location and name.
1645 // TODO: makeSizeAlign[Out]Type are the same as these types, but they may
1646 // be logically different.
1647 ast::ObjectDecl newObj( mutDecl->location, "",
1648 new ast::BasicType( ast::BasicType::LongUnsignedInt ),
1649 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr,
1650 { new ast::Attribute( "unused" ) } );
1651 ast::ObjectDecl newPtr( mutDecl->location, "",
1652 new ast::PointerType( new ast::BasicType( ast::BasicType::LongUnsignedInt ) ),
1653 nullptr, ast::Storage::Classes(), ast::Linkage::C, nullptr );
1654 for ( ast::ptr<ast::TypeDecl> & typeParam : mutDecl->type_params ) {
1655 auto mutParam = mutate( typeParam.get() );
1656 // Add all size and alignment parameters to parameter list.
1657 if ( mutParam->isComplete() ) {
1658 //ast::TypeInstType paramType( typeParam->name, typeParam );
1659 ast::TypeInstType paramType( mutParam );
1660 std::string paramName = Mangle::mangleType( &paramType );
1661
1662 ast::ObjectDecl * sizeParam = ast::deepCopy( &newObj );
1663 sizeParam->location = typeParam->location;
1664 sizeParam->name = sizeofName( paramName );
1665 last = mutDecl->params.insert( last, sizeParam );
1666 ++last;
1667
1668 ast::ObjectDecl * alignParam = ast::deepCopy( &newObj );
1669 alignParam->location = typeParam->location;
1670 alignParam->name = alignofName( paramName );
1671 last = mutDecl->params.insert( last, alignParam );
1672 ++last;
1673 }
1674 // TODO: These should possibly all be gone.
1675 // More all assertions into parameter list.
1676 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
1677 // Assertion parameters may not be used in body,
1678 // pass along with unused attribute.
1679 assert.get_and_mutate()->attributes.push_back(
1680 new ast::Attribute( "unused" ) );
1681 inferredParams.push_back( assert );
1682 }
1683 mutParam->assertions.clear();
1684 typeParam = mutParam;
1685 }
1686 // TODO: New version of inner loop.
1687 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
1688 // Assertion parameters may not be used in body,
1689 // pass along with unused attribute.
1690 assert.get_and_mutate()->attributes.push_back(
1691 new ast::Attribute( "unused" ) );
1692 inferredParams.push_back( assert );
1693 }
1694 mutDecl->assertions.clear();
1695
1696 // Add size/align for generic parameter types to parameter list.
1697 std::set<std::string> seenTypes;
1698 std::vector<ast::ptr<ast::DeclWithType>> otypeParams;
1699 for ( ast::ptr<ast::DeclWithType> & funcParam : mutDecl->params ) {
1700 ast::Type const * polyType = isPolyType( funcParam->get_type(), scopeTypeVars );
1701 if ( !polyType || dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1702 continue;
1703 }
1704 std::string typeName = Mangle::mangleType( polyType );
1705 if ( seenTypes.count( typeName ) ) continue;
1706
1707 ast::ObjectDecl * sizeParam = ast::deepCopy( &newObj );
1708 sizeParam->location = funcParam->location;
1709 sizeParam->name = sizeofName( typeName );
1710 otypeParams.emplace_back( sizeParam );
1711
1712 ast::ObjectDecl * alignParam = ast::deepCopy( &newObj );
1713 alignParam->location = funcParam->location;
1714 alignParam->name = alignofName( typeName );
1715 otypeParams.emplace_back( alignParam );
1716
1717 if ( auto * polyStruct =
1718 dynamic_cast<ast::StructInstType const *>( polyType ) ) {
1719 // Zero-length arrays are illegal in C, so empty structs have no
1720 // offset array.
1721 if ( !polyStruct->base->members.empty() ) {
1722 ast::ObjectDecl * offsetParam = ast::deepCopy( &newPtr );
1723 offsetParam->location = funcParam->location;
1724 offsetParam->name = offsetofName( typeName );
1725 otypeParams.emplace_back( offsetParam );
1726 }
1727 }
1728 seenTypes.insert( typeName );
1729 }
1730
1731 // TODO: A unified way of putting these together might be nice.
1732 // Put the list together: adapters (in helper) otype parameters,
1733 // inferred params., layout params. (done) and finally explicit params.
1734 spliceBegin( inferredParams, otypeParams );
1735 spliceAt( mutDecl->params, last, inferredParams );
1736 mutDecl = addAdapters( mutDecl );
1737
1738 return mutDecl;
1739}
1740
1741ast::DeclWithType const * DeclAdapter::postvisit(
1742 ast::FunctionDecl const * decl ) {
1743 ast::FunctionDecl * mutDecl = mutate( decl );
1744 if ( !mutDecl->returns.empty() && mutDecl->stmts
1745 // Intrinsic functions won't be using the _retval so no need to
1746 // generate it.
1747 && mutDecl->linkage != ast::Linkage::Intrinsic
1748 // Remove check for prefix once thunks properly use ctor/dtors.
1749 && !isPrefix( mutDecl->name, "_thunk" )
1750 && !isPrefix( mutDecl->name, "_adapter" ) ) {
1751 assert( 1 == mutDecl->returns.size() );
1752 ast::DeclWithType const * retval = mutDecl->returns.front();
1753 if ( "" == retval->name ) {
1754 retval = ast::mutate_field(
1755 retval, &ast::DeclWithType::name, "_retval" );
1756 mutDecl->returns.front() = retval;
1757 }
1758 auto stmts = mutDecl->stmts.get_and_mutate();
1759 stmts->kids.push_front( new ast::DeclStmt( retval->location, retval ) );
1760 ast::DeclWithType * newRet = ast::deepCopy( retval );
1761 mutDecl->returns.front() = newRet;
1762 }
1763 // Errors should have been caught by this point, remove initializers from
1764 // parameters to allow correct codegen of default arguments.
1765 for ( ast::ptr<ast::DeclWithType> & param : mutDecl->params ) {
1766 if ( auto obj = param.as<ast::ObjectDecl>() ) {
1767 param = ast::mutate_field( obj, &ast::ObjectDecl::init, nullptr );
1768 }
1769 }
1770 // TODO: Can this be updated as we go along?
1771 mutDecl->type = makeFunctionType( mutDecl );
1772 return mutDecl;
1773}
1774
1775void DeclAdapter::previsit( ast::CompoundStmt const * ) {
1776 GuardScope( scopeTypeVars );
1777 // TODO: It is entirely possible the scope doesn't need to spread
1778 // across multiple functions. Otherwise, find a better clear.
1779 std::set<TypeVarMap::key_type> keys;
1780 for ( auto pair : const_cast<TypeVarMap const &>( scopeTypeVars ) ) {
1781 keys.insert( pair.first );
1782 }
1783 for ( auto key : keys ) {
1784 scopeTypeVars.erase( key );
1785 }
1786}
1787
1788// It actually does mutate in-place, but does the return for consistency.
1789ast::FunctionDecl * DeclAdapter::addAdapters( ast::FunctionDecl * mutDecl ) {
1790 std::vector<ast::ptr<ast::FunctionType>> functions;
1791 for ( ast::ptr<ast::DeclWithType> & arg : mutDecl->params ) {
1792 ast::Type const * type = arg->get_type();
1793 type = findAndReplaceFunction( type, functions, scopeTypeVars, needsAdapter );
1794 arg.get_and_mutate()->set_type( type );
1795 }
1796 std::set<std::string> adaptersDone;
1797 for ( ast::ptr<ast::FunctionType> const & func : functions ) {
1798 std::string mangleName = mangleAdapterName( func, scopeTypeVars );
1799 if ( adaptersDone.find( mangleName ) != adaptersDone.end() ) {
1800 continue;
1801 }
1802 std::string adapterName = makeAdapterName( mangleName );
1803 // The adapter may not actually be used, so make sure it has unused.
1804 mutDecl->params.insert( mutDecl->params.begin(), new ast::ObjectDecl(
1805 mutDecl->location, adapterName,
1806 new ast::PointerType( makeAdapterType( func, scopeTypeVars ) ),
1807 nullptr, {}, {}, nullptr,
1808 { new ast::Attribute( "unused" ) } ) );
1809 adaptersDone.insert( adaptersDone.begin(), mangleName );
1810 }
1811 return mutDecl;
1812}
1813
1814// --------------------------------------------------------------------------
1815// TODO: Ideally, there would be no floating nodes at all.
1816/// Corrects the floating nodes created in CallAdapter.
1817struct RewireAdapters final : public ast::WithGuards {
1818 ScopedMap<std::string, ast::ObjectDecl const *> adapters;
1819 void beginScope() { adapters.beginScope(); }
1820 void endScope() { adapters.endScope(); }
1821 void previsit( ast::FunctionDecl const * decl );
1822 ast::VariableExpr const * previsit( ast::VariableExpr const * expr );
1823};
1824
1825void RewireAdapters::previsit( ast::FunctionDecl const * decl ) {
1826 GuardScope( adapters );
1827 for ( ast::ptr<ast::DeclWithType> const & param : decl->params ) {
1828 if ( auto objectParam = param.as<ast::ObjectDecl>() ) {
1829 adapters.insert( objectParam->name, objectParam );
1830 }
1831 }
1832}
1833
1834ast::VariableExpr const * RewireAdapters::previsit(
1835 ast::VariableExpr const * expr ) {
1836 // If the node is not floating, we can skip.
1837 if ( expr->var->isManaged() ) return expr;
1838 auto it = adapters.find( expr->var->name );
1839 assertf( it != adapters.end(), "Could not correct floating node." );
1840 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
1841
1842}
1843
1844// --------------------------------------------------------------------------
1845// TODO: This is kind of a blind test. I believe all withExprs are handled
1846// in the resolver and we could clear them out after that.
1847struct RemoveWithExprs final {
1848 ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl ) {
1849 if ( decl->withExprs.empty() ) return decl;
1850 auto mutDecl = mutate( decl );
1851 mutDecl->withExprs.clear();
1852 return mutDecl;
1853 }
1854};
1855
1856// --------------------------------------------------------------------------
1857/// Inserts code to access polymorphic layout inforation.
1858/// * Replaces member and size/alignment/offsetof expressions on polymorphic
1859/// generic types with calculated expressions.
1860/// * Replaces member expressions for polymorphic types with calculated
1861/// add-field-offset-and-dereference.
1862/// * Calculates polymorphic offsetof expressions from offset array.
1863/// * Inserts dynamic calculation of polymorphic type layouts where needed.
1864struct PolyGenericCalculator final :
1865 public BoxPass,
1866 public ast::WithConstTypeSubstitution,
1867 public ast::WithDeclsToAdd<>,
1868 public ast::WithGuards,
1869 public ast::WithStmtsToAdd<>,
1870 public ast::WithVisitorRef<PolyGenericCalculator> {
1871 PolyGenericCalculator();
1872
1873 void previsit( ast::ObjectDecl const * decl );
1874 void previsit( ast::FunctionDecl const * decl );
1875 void previsit( ast::TypedefDecl const * decl );
1876 void previsit( ast::TypeDecl const * decl );
1877 ast::Decl const * postvisit( ast::TypeDecl const * decl );
1878 ast::StructDecl const * previsit( ast::StructDecl const * decl );
1879 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
1880 void previsit( ast::PointerType const * type );
1881 void previsit( ast::FunctionType const * type );
1882 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
1883 ast::Expr const * postvisit( ast::MemberExpr const * expr );
1884 void previsit( ast::AddressExpr const * expr );
1885 ast::Expr const * postvisit( ast::AddressExpr const * expr );
1886 ast::Expr const * postvisit( ast::SizeofExpr const * expr );
1887 ast::Expr const * postvisit( ast::AlignofExpr const * expr );
1888 ast::Expr const * postvisit( ast::OffsetofExpr const * expr );
1889 ast::Expr const * postvisit( ast::OffsetPackExpr const * expr );
1890
1891 void beginScope();
1892 void endScope();
1893private:
1894 /// Makes a new variable in the current scope with the given name,
1895 /// type and optional initializer.
1896 ast::ObjectDecl * makeVar(
1897 CodeLocation const & location, std::string const & name,
1898 ast::Type const * type, ast::Init const * init = nullptr );
1899 /// Returns true if the type has a dynamic layout;
1900 /// such a layout will be stored in appropriately-named local variables
1901 /// when the function returns.
1902 bool findGeneric( CodeLocation const & location, ast::Type const * );
1903 /// Adds type parameters to the layout call; will generate the
1904 /// appropriate parameters if needed.
1905 void addOTypeParamsToLayoutCall(
1906 ast::UntypedExpr * layoutCall,
1907 const ast::vector<ast::Type> & otypeParams );
1908 /// Change the type of generic aggregate members to char[].
1909 void mutateMembers( ast::AggregateDecl * aggr );
1910 /// Returns the calculated sizeof expression for type, or nullptr for use
1911 /// C sizeof().
1912 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
1913
1914 /// Enters a new scope for type-variables,
1915 /// adding the type variables from the provided type.
1916 void beginTypeScope( ast::Type const * );
1917 /// Enters a new scope for known layouts and offsets, and queues exit calls.
1918 void beginGenericScope();
1919
1920 /// Set of generic type layouts known in the current scope,
1921 /// indexed by sizeofName.
1922 ScopedSet<std::string> knownLayouts;
1923 /// Set of non-generic types for which the offset array exists in the
1924 /// current scope, indexed by offsetofName.
1925 ScopedSet<std::string> knownOffsets;
1926 /// Namer for VLA (variable length array) buffers.
1927 UniqueName bufNamer;
1928 /// AddressExpr argument is MemberExpr? (TODO: What?)
1929 ast::Expr const * addrMember = nullptr;
1930 /// Used to avoid recursing too deep in type declarations.
1931 bool expect_func_type = false;
1932};
1933
1934PolyGenericCalculator::PolyGenericCalculator() :
1935 knownLayouts(), knownOffsets(), bufNamer( "_buf" )
1936{}
1937
1938/// Converts polymorphic type into a suitable monomorphic representation.
1939/// Currently: __attribute__((aligned(8) )) char[size_T];
1940ast::Type * polyToMonoType( CodeLocation const & location,
1941 ast::Type const * declType ) {
1942 auto charType = new ast::BasicType( ast::BasicType::Char );
1943 auto size = new ast::NameExpr( location,
1944 sizeofName( Mangle::mangleType( declType ) ) );
1945 auto aligned = new ast::Attribute( "aligned",
1946 { ast::ConstantExpr::from_int( location, 8 ) } );
1947 auto ret = new ast::ArrayType( charType, size,
1948 ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
1949 ret->attributes.push_back( aligned );
1950 return ret;
1951}
1952
1953void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
1954 beginTypeScope( decl->type );
1955}
1956
1957void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
1958 beginGenericScope();
1959 beginTypeScope( decl->type );
1960
1961 // - Tried inserting this code.
1962 // Make sure that any type information passed into the function is
1963 // accounted for.
1964 // TODO: For some reason going through decl->params/->get_type() does
1965 // not work. Possibly something is not getting updated.
1966 for ( ast::ptr<ast::Type> const & funcParam : decl->type->params ) {
1967 // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
1968 ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
1969 if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
1970 knownLayouts.insert( Mangle::mangleType( polyType ) );
1971 }
1972 }
1973}
1974
1975void PolyGenericCalculator::previsit( ast::TypedefDecl const * decl ) {
1976 assertf( false, "All typedef declarations should be removed." );
1977 beginTypeScope( decl->base );
1978}
1979
1980void PolyGenericCalculator::previsit( ast::TypeDecl const * decl ) {
1981 addToTypeVarMap( decl, scopeTypeVars );
1982}
1983
1984ast::Decl const * PolyGenericCalculator::postvisit(
1985 ast::TypeDecl const * decl ) {
1986 ast::Type const * base = decl->base;
1987 if ( nullptr == base) return decl;
1988
1989 // Add size/align variables for opaque type declarations.
1990 ast::TypeInstType inst( decl->name, decl );
1991 std::string typeName = Mangle::mangleType( &inst );
1992 ast::Type * layoutType = new ast::BasicType(
1993 ast::BasicType::LongUnsignedInt );
1994
1995 ast::ObjectDecl * sizeDecl = new ast::ObjectDecl( decl->location,
1996 sizeofName( typeName ), layoutType,
1997 new ast::SingleInit( decl->location,
1998 new ast::SizeofExpr( decl->location, deepCopy( base ) )
1999 )
2000 );
2001 ast::ObjectDecl * alignDecl = new ast::ObjectDecl( decl->location,
2002 alignofName( typeName ), layoutType,
2003 new ast::SingleInit( decl->location,
2004 new ast::AlignofExpr( decl->location, deepCopy( base ) )
2005 )
2006 );
2007
2008 // Ensure that the initializing sizeof/alignof exprs are properly mutated.
2009 sizeDecl->accept( *visitor );
2010 alignDecl->accept( *visitor );
2011
2012 // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
2013 // can occur at global scope.
2014 declsToAddAfter.push_back( alignDecl );
2015 // replace with sizeDecl.
2016 return sizeDecl;
2017}
2018
2019ast::StructDecl const * PolyGenericCalculator::previsit(
2020 ast::StructDecl const * decl ) {
2021 //return strict_dynamic_cast<ast::StructDecl *>( mutateMembers( decl ) );
2022 auto mutDecl = mutate( decl );
2023 mutateMembers( mutDecl );
2024 return mutDecl;
2025}
2026
2027ast::UnionDecl const * PolyGenericCalculator::previsit(
2028 ast::UnionDecl const * decl ) {
2029 //return strict_dynamic_cast<ast::UnionDecl *>( mutateMembers( decl ) );
2030 auto mutDecl = mutate( decl );
2031 mutateMembers( mutDecl );
2032 return mutDecl;
2033}
2034
2035void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
2036 beginTypeScope( type );
2037}
2038
2039void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
2040 beginTypeScope( type );
2041
2042 GuardValue( expect_func_type );
2043 GuardScope( *this );
2044
2045 // The other functions type we will see in this scope are probably
2046 // function parameters they don't help us with the layout and offsets so
2047 // don't mark them as known in this scope.
2048 expect_func_type = false;
2049
2050 // Make sure that any type information passed into the function is
2051 // accounted for.
2052 for ( ast::ptr<ast::Type> const & funcParam : type->params ) {
2053 // Condition here duplicates that in `DeclAdapter::previsit( FunctionDecl const * )`
2054 ast::Type const * polyType = isPolyType( funcParam, scopeTypeVars );
2055 if ( polyType && !dynamic_cast<ast::TypeInstType const *>( polyType ) ) {
2056 knownLayouts.insert( Mangle::mangleType( polyType ) );
2057 }
2058 }
2059}
2060
2061//void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
2062ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
2063 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
2064 if ( !decl || !findGeneric( decl->location, decl->type ) ) {
2065 return stmt;
2066 }
2067
2068 // Change initialization of a polymorphic value object to allocate via a
2069 // variable-length-array (alloca was previouly used, but it cannot be
2070 // safely used in loops).
2071 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
2072 bufNamer.newName(),
2073 polyToMonoType( decl->location, decl->type ),
2074 nullptr, {}, ast::Linkage::C
2075 );
2076 stmtsToAddBefore.push_back( new ast::DeclStmt( stmt->location, newBuf ) );
2077
2078 // If the object has a cleanup attribute, the clean-up should be on the
2079 // buffer, not the pointer. [Perhaps this should be lifted?]
2080 auto matchAndMove = [newBuf]( ast::ptr<ast::Attribute> & attr ) {
2081 if ( "cleanup" == attr->name ) {
2082 newBuf->attributes.push_back( attr );
2083 return true;
2084 }
2085 return false;
2086 };
2087
2088 auto mutDecl = mutate( decl );
2089
2090 //mutDecl->attributes.remove_if( matchAndMove );
2091 // TODO: This common helper might work, but does not officially support
2092 // side effects.
2093 erase_if( mutDecl->attributes, matchAndMove );
2094
2095 mutDecl->init = new ast::SingleInit( decl->location,
2096 new ast::VariableExpr( decl->location, newBuf ) );
2097
2098 return ast::mutate_field( stmt, &ast::DeclStmt::decl, mutDecl );
2099}
2100
2101/// Checks if memberDecl matches the decl from an aggregate.
2102bool isMember( ast::DeclWithType const * memberDecl, ast::Decl const * decl ) {
2103 // No matter the field, if the name is different it is not the same.
2104 if ( memberDecl->name != decl->name ) {
2105 return false;
2106 }
2107
2108 if ( memberDecl->name.empty() ) {
2109 // Plan-9 Field: Match on unique_id.
2110 return ( memberDecl->uniqueId == decl->uniqueId );
2111 }
2112
2113 ast::DeclWithType const * declWithType =
2114 strict_dynamic_cast<ast::DeclWithType const *>( decl );
2115
2116 if ( memberDecl->mangleName.empty() || declWithType->mangleName.empty() ) {
2117 // Tuple-Element Field: Expect neither had mangled name;
2118 // accept match on simple name (like field_2) only.
2119 assert( memberDecl->mangleName.empty() );
2120 assert( declWithType->mangleName.empty() );
2121 return true;
2122 }
2123
2124 // Ordinary Field: Use full name to accommodate overloading.
2125 return ( memberDecl->mangleName == declWithType->mangleName );
2126}
2127
2128/// Finds the member in the base list that matches the given declaration;
2129/// returns its index, or -1 if not present.
2130long findMember( ast::DeclWithType const * memberDecl,
2131 const ast::vector<ast::Decl> & baseDecls ) {
2132 for ( auto pair : enumerate( baseDecls ) ) {
2133 if ( isMember( memberDecl, pair.val.get() ) ) {
2134 return pair.idx;
2135 }
2136 }
2137 return -1;
2138}
2139
2140/// Returns an index expression into the offset array for a type.
2141ast::Expr * makeOffsetIndex( CodeLocation const & location,
2142 ast::Type const * objectType, long i ) {
2143 std::string name = offsetofName( Mangle::mangleType( objectType ) );
2144 return ast::UntypedExpr::createCall( location, "?[?]", {
2145 new ast::NameExpr( location, name ),
2146 ast::ConstantExpr::from_ulong( location, i ),
2147 } );
2148}
2149
2150ast::Expr const * PolyGenericCalculator::postvisit(
2151 ast::MemberExpr const * expr ) {
2152 // Only mutate member expressions for polymorphic types.
2153 int typeDepth;
2154 ast::Type const * objectType = hasPolyBase(
2155 expr->aggregate->result, scopeTypeVars, &typeDepth
2156 );
2157 if ( !objectType ) return expr;
2158 // Ensure layout for this type is available.
2159 // The boolean result is ignored.
2160 findGeneric( expr->location, objectType );
2161
2162 // Replace member expression with dynamically-computed layout expression.
2163 ast::Expr * newMemberExpr = nullptr;
2164 if ( auto structType = dynamic_cast<ast::StructInstType const *>( objectType ) ) {
2165 long offsetIndex = findMember( expr->member, structType->base->members );
2166 if ( -1 == offsetIndex ) return expr;
2167
2168 // Replace member expression with pointer to struct plus offset.
2169 ast::UntypedExpr * fieldLoc = new ast::UntypedExpr( expr->location,
2170 new ast::NameExpr( expr->location, "?+?" ) );
2171 ast::Expr * aggr = deepCopy( expr->aggregate );
2172 aggr->env = nullptr;
2173 fieldLoc->args.push_back( aggr );
2174 fieldLoc->args.push_back(
2175 makeOffsetIndex( expr->location, objectType, offsetIndex ) );
2176 fieldLoc->result = deepCopy( expr->result );
2177 newMemberExpr = fieldLoc;
2178 // Union members are all at offset zero, so just use the aggregate expr.
2179 } else if ( dynamic_cast<ast::UnionInstType const *>( objectType ) ) {
2180 ast::Expr * aggr = deepCopy( expr->aggregate );
2181 aggr->env = nullptr;
2182 aggr->result = deepCopy( expr->result );
2183 newMemberExpr = aggr;
2184 } else {
2185 return expr;
2186 }
2187 assert( newMemberExpr );
2188
2189 // Must apply the generic substitution to the member type to handle cases
2190 // where the member is a generic parameter subsituted by a known concrete
2191 // type. [ex]
2192 // forall( T ) struct Box { T x; }
2193 // forall( T ) void f() {
2194 // Box( T * ) b; b.x;
2195 // }
2196 // TODO: expr->result should be exactly expr->member->get_type() after
2197 // substitution, so it doesn't seem like it should be necessary to apply
2198 // the substitution manually. For some reason this is not currently the
2199 // case. This requires more investigation.
2200 ast::Type const * memberType = deepCopy( expr->member->get_type() );
2201 ast::TypeSubstitution sub = genericSubstitution( objectType );
2202 auto result = sub.apply( memberType );
2203 memberType = result.node.get(); // .release();
2204 // Not all members of a polymorphic type are themselves of a polymorphic
2205 // type; in this cas the member expression should be wrapped and
2206 // dereferenced to form an lvalue.
2207 if ( !isPolyType( memberType, scopeTypeVars ) ) {
2208 auto ptrCastExpr = new ast::CastExpr( expr->location, newMemberExpr,
2209 new ast::PointerType( memberType ) );
2210 auto derefExpr = ast::UntypedExpr::createDeref( expr->location,
2211 ptrCastExpr );
2212 newMemberExpr = derefExpr;
2213 }
2214
2215 return newMemberExpr;
2216}
2217
2218void PolyGenericCalculator::previsit( ast::AddressExpr const * expr ) {
2219 // Is the argument a MemberExpr before mutating?
2220 GuardValue( addrMember ) = expr->arg.as<ast::MemberExpr>();
2221}
2222
2223ast::Expr const * PolyGenericCalculator::postvisit(
2224 ast::AddressExpr const * expr ) {
2225 // arg has to have been a MemberExpr and has been mutated.
2226 if ( nullptr == addrMember || expr->arg == addrMember ) {
2227 return expr;
2228 }
2229 ast::UntypedExpr const * untyped = expr->arg.as<ast::UntypedExpr>();
2230 if ( !untyped || getFunctionName( untyped ) != "?+?" ) {
2231 return expr;
2232 }
2233 // MemberExpr was converted to pointer + offset; and it is not valid C to
2234 // take the address of an addition, so stript the address-of.
2235 // TODO: should expr->arg->result be changed to expr->result?
2236 ast::Expr * ret = mutate( expr->arg.get() );
2237 ret->env = expr->env;
2238 return ret;
2239}
2240
2241ast::Expr const * PolyGenericCalculator::postvisit(
2242 ast::SizeofExpr const * expr ) {
2243 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2244 ast::Expr const * gen = genSizeof( expr->location, type );
2245 return ( gen ) ? gen : expr;
2246}
2247
2248ast::Expr const * PolyGenericCalculator::postvisit(
2249 ast::AlignofExpr const * expr ) {
2250 ast::Type const * type = expr->type ? expr->type : expr->expr->result;
2251 if ( findGeneric( expr->location, type ) ) {
2252 return new ast::NameExpr( expr->location,
2253 alignofName( Mangle::mangleType( type ) ) );
2254 } else {
2255 return expr;
2256 }
2257}
2258
2259ast::Expr const * PolyGenericCalculator::postvisit(
2260 ast::OffsetofExpr const * expr ) {
2261 ast::Type const * type = expr->type;
2262 if ( !findGeneric( expr->location, type ) ) return expr;
2263
2264 // Structures replace offsetof expression with an index into offset array.
2265 if ( auto structType = dynamic_cast<ast::StructInstType const *>( type ) ) {
2266 long offsetIndex = findMember( expr->member, structType->base->members );
2267 if ( -1 == offsetIndex ) return expr;
2268
2269 return makeOffsetIndex( expr->location, type, offsetIndex );
2270 // All union members are at offset zero.
2271 } else if ( dynamic_cast<ast::UnionInstType const *>( type ) ) {
2272 return ast::ConstantExpr::from_ulong( expr->location, 0 );
2273 } else {
2274 return expr;
2275 }
2276}
2277
2278ast::Expr const * PolyGenericCalculator::postvisit(
2279 ast::OffsetPackExpr const * expr ) {
2280 ast::StructInstType const * type = expr->type;
2281
2282 // Pull offset back from generated type information.
2283 if ( findGeneric( expr->location, type ) ) {
2284 return new ast::NameExpr( expr->location,
2285 offsetofName( Mangle::mangleType( type ) ) );
2286 }
2287
2288 std::string offsetName = offsetofName( Mangle::mangleType( type ) );
2289 // Use the already generated offsets for this type.
2290 if ( knownOffsets.contains( offsetName ) ) {
2291 return new ast::NameExpr( expr->location, offsetName );
2292 }
2293
2294 knownOffsets.insert( offsetName );
2295
2296 auto baseMembers = type->base->members;
2297 ast::Type const * offsetType = new ast::BasicType(
2298 ast::BasicType::LongUnsignedInt );
2299
2300 // Build initializer list for offset array.
2301 ast::vector<ast::Init> inits;
2302 for ( ast::ptr<ast::Decl> & member : baseMembers ) {
2303 auto memberDecl = member.as<ast::DeclWithType>();
2304 assertf( memberDecl, "Requesting offset of non-DWT member: %s",
2305 toCString( member ) );
2306 inits.push_back( new ast::SingleInit( expr->location,
2307 new ast::OffsetofExpr( expr->location,
2308 deepCopy( type ),
2309 memberDecl
2310 )
2311 ) );
2312 }
2313
2314 auto offsetArray = makeVar( expr->location, offsetName,
2315 new ast::ArrayType(
2316 offsetType,
2317 ast::ConstantExpr::from_ulong( expr->location, baseMembers.size() ),
2318 ast::FixedLen,
2319 ast::DynamicDim
2320 ),
2321 new ast::ListInit( expr->location, std::move( inits ) )
2322 );
2323
2324 return new ast::VariableExpr( expr->location, offsetArray );
2325}
2326
2327void PolyGenericCalculator::beginScope() {
2328 knownLayouts.beginScope();
2329 knownOffsets.beginScope();
2330}
2331
2332void PolyGenericCalculator::endScope() {
2333 knownOffsets.endScope();
2334 knownLayouts.endScope();
2335}
2336
2337ast::ObjectDecl * PolyGenericCalculator::makeVar(
2338 CodeLocation const & location, std::string const & name,
2339 ast::Type const * type, ast::Init const * init ) {
2340 ast::ObjectDecl * ret = new ast::ObjectDecl( location, name, type, init );
2341 stmtsToAddBefore.push_back( new ast::DeclStmt( location, ret ) );
2342 return ret;
2343}
2344
2345/// Returns true if any of the otype parameters have a dynamic layout; and
2346/// puts all otype parameters in the output list.
2347bool findGenericParams(
2348 ast::vector<ast::Type> & out,
2349 ast::vector<ast::TypeDecl> const & baseParams,
2350 ast::vector<ast::Expr> const & typeParams ) {
2351 bool hasDynamicLayout = false;
2352
2353 for ( auto pair : group_iterate( baseParams, typeParams ) ) {
2354 auto baseParam = std::get<0>( pair );
2355 auto typeParam = std::get<1>( pair );
2356 if ( !baseParam->isComplete() ) continue;
2357 ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
2358 assertf( typeExpr, "All type parameters should be type expressions." );
2359
2360 ast::Type const * type = typeExpr->type.get();
2361 out.push_back( type );
2362 if ( isPolyType( type ) ) hasDynamicLayout = true;
2363 }
2364
2365 return hasDynamicLayout;
2366}
2367
2368bool PolyGenericCalculator::findGeneric(
2369 CodeLocation const & location, ast::Type const * type ) {
2370 type = replaceTypeInst( type, typeSubs );
2371
2372 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
2373 // Assumes that getting put in the scopeTypeVars includes having the
2374 // layout variables set.
2375 if ( scopeTypeVars.contains( *inst ) ) {
2376 return true;
2377 }
2378 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
2379 // Check if this type already has a layout generated for it.
2380 std::string typeName = Mangle::mangleType( type );
2381 if ( knownLayouts.contains( typeName ) ) return true;
2382
2383 // Check if any type parameters have dynamic layout;
2384 // If none do, this type is (or will be) monomorphized.
2385 ast::vector<ast::Type> sizedParams;
2386 if ( !findGenericParams( sizedParams,
2387 inst->base->params, inst->params ) ) {
2388 return false;
2389 }
2390
2391 // Insert local variables for layout and generate call to layout
2392 // function.
2393 // Done early so as not to interfere with the later addition of
2394 // parameters to the layout call.
2395 knownLayouts.insert( typeName );
2396 ast::Type const * layoutType = makeSizeAlignType();
2397
2398 int memberCount = inst->base->members.size();
2399 if ( 0 == memberCount ) {
2400 // All empty structures have the same layout (size 1, align 1).
2401 makeVar( location,
2402 sizeofName( typeName ), layoutType,
2403 new ast::SingleInit( location,
2404 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2405 makeVar( location,
2406 alignofName( typeName ), ast::deepCopy( layoutType ),
2407 new ast::SingleInit( location,
2408 ast::ConstantExpr::from_ulong( location, 1 ) ) );
2409 // Since 0-length arrays are forbidden in C, skip the offset array.
2410 } else {
2411 ast::ObjectDecl const * sizeofVar = makeVar( location,
2412 sizeofName( typeName ), deepCopy( layoutType ), nullptr );
2413 ast::ObjectDecl const * alignofVar = makeVar( location,
2414 alignofName( typeName ), deepCopy( layoutType ), nullptr );
2415 ast::ObjectDecl const * offsetofVar = makeVar( location,
2416 offsetofName( typeName ),
2417 new ast::ArrayType(
2418 layoutType,
2419 ast::ConstantExpr::from_int( location, memberCount ),
2420 ast::FixedLen,
2421 ast::DynamicDim
2422 ),
2423 nullptr
2424 );
2425
2426 // Generate call to layout function.
2427 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2428 new ast::NameExpr( location, layoutofName( inst->base ) ),
2429 {
2430 new ast::AddressExpr(
2431 new ast::VariableExpr( location, sizeofVar ) ),
2432 new ast::AddressExpr(
2433 new ast::VariableExpr( location, alignofVar ) ),
2434 new ast::VariableExpr( location, offsetofVar ),
2435 } );
2436
2437 addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2438
2439 stmtsToAddBefore.emplace_back(
2440 new ast::ExprStmt( location, layoutCall ) );
2441 }
2442
2443 return true;
2444 } else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
2445 // Check if this type already has a layout generated for it.
2446 std::string typeName = Mangle::mangleType( type );
2447 if ( knownLayouts.contains( typeName ) ) return true;
2448
2449 // Check if any type parameters have dynamic layout;
2450 // If none do, this type is (or will be) monomorphized.
2451 ast::vector<ast::Type> sizedParams;
2452 if ( !findGenericParams( sizedParams,
2453 inst->base->params, inst->params ) ) {
2454 return false;
2455 }
2456
2457 // Insert local variables for layout and generate call to layout
2458 // function.
2459 // Done early so as not to interfere with the later addition of
2460 // parameters to the layout call.
2461 knownLayouts.insert( typeName );
2462 ast::Type const * layoutType = makeSizeAlignType();
2463
2464 ast::ObjectDecl * sizeofVar = makeVar( location,
2465 sizeofName( typeName ), layoutType );
2466 ast::ObjectDecl * alignofVar = makeVar( location,
2467 alignofName( typeName ), ast::deepCopy( layoutType ) );
2468
2469 ast::UntypedExpr * layoutCall = new ast::UntypedExpr( location,
2470 new ast::NameExpr( location, layoutofName( inst->base ) ),
2471 {
2472 new ast::AddressExpr(
2473 new ast::VariableExpr( location, sizeofVar ) ),
2474 new ast::AddressExpr(
2475 new ast::VariableExpr( location, alignofVar ) ),
2476 } );
2477
2478 addOTypeParamsToLayoutCall( layoutCall, sizedParams );
2479
2480 stmtsToAddBefore.emplace_back(
2481 new ast::ExprStmt( location, layoutCall ) );
2482
2483 return true;
2484 }
2485 return false;
2486}
2487
2488void PolyGenericCalculator::addOTypeParamsToLayoutCall(
2489 ast::UntypedExpr * layoutCall,
2490 const ast::vector<ast::Type> & otypeParams ) {
2491 CodeLocation const & location = layoutCall->location;
2492 ast::vector<ast::Expr> & args = layoutCall->args;
2493 for ( ast::ptr<ast::Type> const & param : otypeParams ) {
2494 if ( findGeneric( location, param ) ) {
2495 // Push size/align vars for a generic parameter back.
2496 std::string paramName = Mangle::mangleType( param );
2497 args.emplace_back(
2498 new ast::NameExpr( location, sizeofName( paramName ) ) );
2499 args.emplace_back(
2500 new ast::NameExpr( location, alignofName( paramName ) ) );
2501 } else {
2502 args.emplace_back(
2503 new ast::SizeofExpr( location, ast::deepCopy( param ) ) );
2504 args.emplace_back(
2505 new ast::AlignofExpr( location, ast::deepCopy( param ) ) );
2506 }
2507 }
2508}
2509
2510void PolyGenericCalculator::mutateMembers( ast::AggregateDecl * aggr ) {
2511 std::set<std::string> genericParams;
2512 for ( ast::ptr<ast::TypeDecl> const & decl : aggr->params ) {
2513 genericParams.insert( decl->name );
2514 }
2515 for ( ast::ptr<ast::Decl> & decl : aggr->members ) {
2516 auto field = decl.as<ast::ObjectDecl>();
2517 if ( nullptr == field ) continue;
2518
2519 ast::Type const * type = replaceTypeInst( field->type, typeSubs );
2520 auto typeInst = dynamic_cast<ast::TypeInstType const *>( type );
2521 if ( nullptr == typeInst ) continue;
2522
2523 // Do not try to monoporphize generic parameters.
2524 if ( scopeTypeVars.contains( ast::TypeEnvKey( *typeInst ) ) &&
2525 !genericParams.count( typeInst->name ) ) {
2526 // Polymorphic aggregate members should be converted into
2527 // monomorphic members. Using char[size_T] here respects
2528 // the expected sizing rules of an aggregate type.
2529 decl = ast::mutate_field( field, &ast::ObjectDecl::type,
2530 polyToMonoType( field->location, field->type ) );
2531 }
2532 }
2533}
2534
2535ast::Expr const * PolyGenericCalculator::genSizeof(
2536 CodeLocation const & location, ast::Type const * type ) {
2537 if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
2538 // Generate calculated size for possibly generic array.
2539 ast::Expr const * sizeofBase = genSizeof( location, array->base );
2540 if ( nullptr == sizeofBase ) return nullptr;
2541 ast::Expr const * dim = array->dimension;
2542 return makeOp( location, "?*?", sizeofBase, dim );
2543 } else if ( findGeneric( location, type ) ) {
2544 // Generate calculated size for generic type.
2545 return new ast::NameExpr( location, sizeofName(
2546 Mangle::mangleType( type ) ) );
2547 } else {
2548 return nullptr;
2549 }
2550}
2551
2552void PolyGenericCalculator::beginTypeScope( ast::Type const * type ) {
2553 GuardScope( scopeTypeVars );
2554 makeTypeVarMap( type, scopeTypeVars );
2555}
2556
2557void PolyGenericCalculator::beginGenericScope() {
2558 GuardScope( *this );
2559 // We expect the first function type see to be the type relating to this
2560 // scope but any further type is probably some unrelated function pointer
2561 // keep track of whrich is the first.
2562 GuardValue( expect_func_type ) = true;
2563}
2564
2565// --------------------------------------------------------------------------
2566/// No common theme found.
2567/// * Replaces initialization of polymorphic values with alloca.
2568/// * Replaces declaration of dtype/ftype with appropriate void expression.
2569/// * Replaces sizeof expressions of polymorphic types with a variable.
2570/// * Strips fields from generic structure declarations.
2571struct Eraser final :
2572 public BoxPass,
2573 public ast::WithGuards {
2574 template<typename decl_t>
2575 decl_t const * handleDecl( decl_t const * decl, ast::Type const * type );
2576
2577 ast::ObjectDecl const * previsit( ast::ObjectDecl const * decl );
2578 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
2579 ast::TypedefDecl const * previsit( ast::TypedefDecl const * decl );
2580 ast::StructDecl const * previsit( ast::StructDecl const * decl );
2581 ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
2582 void previsit( ast::TypeDecl const * decl );
2583 void previsit( ast::PointerType const * type );
2584 void previsit( ast::FunctionType const * type );
2585};
2586
2587template<typename decl_t>
2588decl_t const * Eraser::handleDecl(
2589 decl_t const * decl, ast::Type const * type ) {
2590 GuardScope( scopeTypeVars );
2591 makeTypeVarMap( type, scopeTypeVars );
2592 return scrubAllTypeVars( decl );
2593}
2594
2595ast::ObjectDecl const * Eraser::previsit( ast::ObjectDecl const * decl ) {
2596 return handleDecl( decl, decl->type );
2597}
2598
2599ast::FunctionDecl const * Eraser::previsit( ast::FunctionDecl const * decl ) {
2600 return handleDecl( decl, decl->type );
2601}
2602
2603ast::TypedefDecl const * Eraser::previsit( ast::TypedefDecl const * decl ) {
2604 return handleDecl( decl, decl->base );
2605}
2606
2607/// Strips the members from a generic aggregate.
2608template<typename node_t>
2609node_t const * stripGenericMembers( node_t const * decl ) {
2610 if ( !decl->params.empty() ) {
2611 auto mutDecl = ast::mutate( decl );
2612 mutDecl->members.clear();
2613 return mutDecl;
2614 }
2615 return decl;
2616}
2617
2618ast::StructDecl const * Eraser::previsit( ast::StructDecl const * decl ) {
2619 return stripGenericMembers( decl );
2620}
2621
2622ast::UnionDecl const * Eraser::previsit( ast::UnionDecl const * decl ) {
2623 return stripGenericMembers( decl );
2624}
2625
2626void Eraser::previsit( ast::TypeDecl const * decl ) {
2627 addToTypeVarMap( decl, scopeTypeVars );
2628}
2629
2630void Eraser::previsit( ast::PointerType const * type ) {
2631 GuardScope( scopeTypeVars );
2632 makeTypeVarMap( type, scopeTypeVars );
2633}
2634
2635void Eraser::previsit( ast::FunctionType const * type ) {
2636 GuardScope( scopeTypeVars );
2637 makeTypeVarMap( type, scopeTypeVars );
2638}
2639
2640} // namespace
2641
2642// --------------------------------------------------------------------------
2643void box( ast::TranslationUnit & translationUnit ) {
2644 ast::Pass<LayoutFunctionBuilder>::run( translationUnit );
2645 ast::Pass<CallAdapter>::run( translationUnit );
2646 ast::Pass<DeclAdapter>::run( translationUnit );
2647 ast::Pass<RewireAdapters>::run( translationUnit );
2648 ast::Pass<RemoveWithExprs>::run( translationUnit );
2649 ast::Pass<PolyGenericCalculator>::run( translationUnit );
2650 ast::Pass<Eraser>::run( translationUnit );
2651}
2652
2653} // namespace GenPoly
2654
2655// Local Variables: //
2656// tab-width: 4 //
2657// mode: c++ //
2658// compile-command: "make install" //
2659// End: //
Note: See TracBrowser for help on using the repository browser.