source: src/ResolvExpr/CastCost.cc@ fed6a0f

ADT ast-experimental
Last change on this file since fed6a0f was e563edf, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Header Clean-up: Clearing out typeops, moving things to Unify because that header already exist.

  • Property mode set to 100644
File size: 9.1 KB
RevLine 
[a32b204]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//
[0b150ec]7// CastCost.cc --
[a32b204]8//
9// Author : Richard C. Bilson
10// Created On : Sun May 17 06:57:43 2015
[7d01cf44]11// Last Modified By : Andrew Beach
[cf32116]12// Last Modified On : Tue Oct 4 15:00:00 2019
13// Update Count : 9
[a32b204]14//
15
[ea6332d]16#include <cassert> // for assert
17
[3c89751]18#include "AST/Print.hpp"
19#include "AST/SymbolTable.hpp"
20#include "AST/Type.hpp"
21#include "AST/TypeEnvironment.hpp"
[ea6332d]22#include "ConversionCost.h" // for ConversionCost
23#include "Cost.h" // for Cost, Cost::infinity
24#include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass
[e563edf]25#include "ResolvExpr/typeops.h" // for ptrsCastable
26#include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers
[ea6332d]27#include "SymTab/Indexer.h" // for Indexer
28#include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl
29#include "SynTree/Type.h" // for PointerType, Type, TypeInstType
[51b73452]30
[150ec33]31#if 0
32#define PRINT(x) x
33#else
34#define PRINT(x)
35#endif
[51b73452]36
37namespace ResolvExpr {
[3c89751]38 struct CastCost_old : public ConversionCost {
[a32b204]39 public:
[7d01cf44]40 CastCost_old( const Type * dest, bool srcIsLvalue,
41 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
[0b150ec]42
[bd0b6b62]43 using ConversionCost::previsit;
44 using ConversionCost::postvisit;
[7870799]45 void postvisit( const BasicType * basicType );
46 void postvisit( const PointerType * pointerType );
[a32b204]47 };
[51b73452]48
[7d01cf44]49 Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
50 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
[ef5b828]51 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
52 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
[00ac42e]53 if ( eqvClass->type ) {
[7d01cf44]54 return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );
[0b150ec]55 } else {
56 return Cost::infinity;
57 }
[ef5b828]58 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
[a32b204]59 // all typedefs should be gone by this point
[ef5b828]60 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );
[eb0aedb]61 if ( type->base ) {
[7d01cf44]62 return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;
[a32b204]63 } // if
64 } // if
65 } // if
[150ec33]66
67 PRINT(
68 std::cerr << "castCost ::: src is ";
69 src->print( std::cerr );
70 std::cerr << std::endl << "dest is ";
71 dest->print( std::cerr );
72 std::cerr << std::endl << "env is" << std::endl;
73 env.print( std::cerr, 8 );
74 )
75
[a32b204]76 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
[150ec33]77 PRINT( std::cerr << "compatible!" << std::endl; )
[89be1c68]78 return Cost::zero;
[ef5b828]79 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
[89be1c68]80 return Cost::safe;
[7870799]81 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
[150ec33]82 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
[7d01cf44]83 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
[0c6596f]84 return ptrsCastable( t1, t2, env, indexer );
85 });
[a32b204]86 } else {
[7870799]87 PassVisitor<CastCost_old> converter(
[7d01cf44]88 dest, srcIsLvalue, indexer, env,
89 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))
[c8e4d2f8]90 castCost );
[a32b204]91 src->accept( converter );
[bd0b6b62]92 if ( converter.pass.get_cost() == Cost::infinity ) {
[a32b204]93 return Cost::infinity;
94 } else {
[1521de20]95 // xxx - why are we adding cost 0 here?
[bd0b6b62]96 return converter.pass.get_cost() + Cost::zero;
[a32b204]97 } // if
[c11e31c]98 } // if
[a32b204]99 }
[51b73452]100
[7d01cf44]101 CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,
102 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
103 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {
[a32b204]104 }
[51b73452]105
[ef5b828]106 void CastCost_old::postvisit( const BasicType * basicType ) {
107 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );
[543159b]108 if ( destAsPointer && basicType->isInteger() ) {
[ef5b828]109 // necessary for, e.g. unsigned long => void *
[89be1c68]110 cost = Cost::unsafe;
[a32b204]111 } else {
[7d01cf44]112 cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );
[a32b204]113 } // if
114 }
[51b73452]115
[ef5b828]116 void CastCost_old::postvisit( const PointerType * pointerType ) {
117 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
[7870799]118 if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
[89be1c68]119 cost = Cost::safe;
[a32b204]120 } else {
121 TypeEnvironment newEnv( env );
[eb0aedb]122 newEnv.add( pointerType->forall );
123 newEnv.add( pointerType->base->forall );
124 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );
[1521de20]125 if ( castResult > 0 ) {
[89be1c68]126 cost = Cost::safe;
[1521de20]127 } else if ( castResult < 0 ) {
[52f85e0]128 cost = Cost::infinity;
[a32b204]129 } // if
130 } // if
[7870799]131 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
[543159b]132 if ( destAsBasic->isInteger() ) {
[ef5b828]133 // necessary for, e.g. void * => unsigned long
[89be1c68]134 cost = Cost::unsafe;
[543159b]135 } // if
136 }
[a32b204]137 }
[c8e4d2f8]138
[3c89751]139namespace {
140 struct CastCost_new : public ConversionCost_new {
141 using ConversionCost_new::previsit;
142 using ConversionCost_new::postvisit;
143
[7870799]144 CastCost_new(
[cf32116]145 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
[3c89751]146 const ast::TypeEnvironment & env, CostCalculation costFunc )
[cf32116]147 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
[3c89751]148
149 void postvisit( const ast::BasicType * basicType ) {
150 auto ptr = dynamic_cast< const ast::PointerType * >( dst );
151 if ( ptr && basicType->isInteger() ) {
152 // needed for, e.g. unsigned long => void *
153 cost = Cost::unsafe;
154 } else {
[cf32116]155 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
[3c89751]156 }
157 }
158
159 void postvisit( const ast::PointerType * pointerType ) {
160 if ( auto ptr = dynamic_cast< const ast::PointerType * >( dst ) ) {
161 if (
162 pointerType->qualifiers <= ptr->qualifiers
163 && typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, symtab, env )
164 ) {
165 cost = Cost::safe;
166 } else {
167 ast::TypeEnvironment newEnv{ env };
[361bf01]168 if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
[3c89751]169 newEnv.add( wParams->forall );
170 }
171 int castResult = ptrsCastable( pointerType->base, ptr->base, symtab, newEnv );
172 if ( castResult > 0 ) {
173 cost = Cost::safe;
174 } else if ( castResult < 0 ) {
175 cost = Cost::infinity;
176 }
177 }
178 } else if ( auto basic = dynamic_cast< const ast::BasicType * >( dst ) ) {
179 if ( basic->isInteger() ) {
180 // necessary for, e.g. void * => unsigned long
181 cost = Cost::unsafe;
182 }
183 }
184 }
185 };
[cf32116]186
187 #warning For overload resolution between the two versions.
188 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
189 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
190 return ptrsCastable( t1, t2, symtab, env );
191 }
192 Cost localCastCost(
193 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
194 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
195 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
[3c89751]196} // anonymous namespace
197
[cf32116]198
199
[7870799]200Cost castCost(
[cf32116]201 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
202 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
[3c89751]203) {
204 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
[3e5dd913]205 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
[3c89751]206 // check cast cost against bound type, if present
207 if ( eqvClass->bound ) {
[cf32116]208 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
[3c89751]209 } else {
210 return Cost::infinity;
211 }
212 } else if ( const ast::NamedTypeDecl * named = symtab.lookupType( typeInst->name ) ) {
213 // all typedefs should be gone by now
214 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
215 if ( type->base ) {
[cf32116]216 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
[3c89751]217 }
218 }
219 }
220
221 PRINT(
222 std::cerr << "castCost ::: src is ";
223 ast::print( std::cerr, src );
224 std::cerr << std::endl << "dest is ";
225 ast::print( std::cerr, dst );
226 std::cerr << std::endl << "env is" << std::endl;
227 ast::print( std::cerr, env, 2 );
228 )
229
230 if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
231 PRINT( std::cerr << "compatible!" << std::endl; )
[c8e4d2f8]232 return Cost::zero;
[3c89751]233 } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
234 return Cost::safe;
235 } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
236 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
237 #warning cast on ptrsCastable artifact of having two functions, remove when port done
[7870799]238 return convertToReferenceCost(
[cf32116]239 src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
[3c89751]240 } else {
241 #warning cast on castCost artifact of having two functions, remove when port done
[cf32116]242 ast::Pass< CastCost_new > converter(
243 dst, srcIsLvalue, symtab, env, localCastCost );
[3c89751]244 src->accept( converter );
[7ff3e522]245 return converter.core.cost;
[c8e4d2f8]246 }
[3c89751]247}
248
[51b73452]249} // namespace ResolvExpr
[a32b204]250
251// Local Variables: //
252// tab-width: 4 //
253// mode: c++ //
254// compile-command: "make install" //
255// End: //
Note: See TracBrowser for help on using the repository browser.