source: src/ResolvExpr/ConversionCost.cc@ 5fb6830

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 5fb6830 was 5ccb10d, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Set reference size to base size, clean up debug code, remove more old-style NULLs from prelude

  • Property mode set to 100644
File size: 16.7 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// ConversionCost.cc --
8//
9// Author : Richard C. Bilson
10// Created On : Sun May 17 07:06:19 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Wed Mar 2 17:35:46 2016
13// Update Count : 6
14//
15
16#include "ConversionCost.h"
17#include "typeops.h"
18#include "SynTree/Type.h"
19#include "SynTree/Visitor.h"
20#include "SymTab/Indexer.h"
21
22namespace ResolvExpr {
23 const Cost Cost::zero = Cost( 0, 0, 0, 0 );
24 const Cost Cost::infinity = Cost( -1, -1, -1, -1 );
25 const Cost Cost::unsafe = Cost( 1, 0, 0, 0 );
26 const Cost Cost::poly = Cost( 0, 1, 0, 0 );
27 const Cost Cost::safe = Cost( 0, 0, 1, 0 );
28 const Cost Cost::reference = Cost( 0, 0, 0, 1 );
29
30#if 0
31#define PRINT(x) x
32#else
33#define PRINT(x)
34#endif
35
36 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
37 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
38 EqvClass eqvClass;
39 NamedTypeDecl *namedType;
40 PRINT( std::cerr << "type inst " << destAsTypeInst->get_name(); )
41 if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
42 if ( eqvClass.type ) {
43 return conversionCost( src, eqvClass.type, indexer, env );
44 } else {
45 return Cost::infinity;
46 }
47 } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) {
48 PRINT( std::cerr << " found" << std::endl; )
49 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
50 // all typedefs should be gone by this point
51 assert( type );
52 if ( type->get_base() ) {
53 return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
54 } // if
55 } // if
56 PRINT( std::cerr << " not found" << std::endl; )
57 } // if
58 PRINT(
59 std::cerr << "src is ";
60 src->print( std::cerr );
61 std::cerr << std::endl << "dest is ";
62 dest->print( std::cerr );
63 std::cerr << std::endl << "env is" << std::endl;
64 env.print( std::cerr, 8 );
65 )
66 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
67 PRINT( std::cerr << "compatible!" << std::endl; )
68 return Cost::zero;
69 } else if ( dynamic_cast< VoidType* >( dest ) ) {
70 return Cost::safe;
71 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
72 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
73 return convertToReferenceCost( src, refType, indexer, env );
74 } else {
75 ConversionCost converter( dest, indexer, env );
76 src->accept( converter );
77 if ( converter.get_cost() == Cost::infinity ) {
78 return Cost::infinity;
79 } else {
80 return converter.get_cost() + Cost::zero;
81 } // if
82 } // if
83 }
84
85 Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
86 PRINT( std::cerr << "convert to reference cost..." << std::endl; )
87 if ( diff > 0 ) {
88 // TODO: document this
89 Cost cost = convertToReferenceCost( safe_dynamic_cast< ReferenceType * >( src )->get_base(), dest, diff-1, indexer, env );
90 cost.incReference();
91 return cost;
92 } else if ( diff < -1 ) {
93 // TODO: document this
94 Cost cost = convertToReferenceCost( src, safe_dynamic_cast< ReferenceType * >( dest )->get_base(), diff+1, indexer, env );
95 cost.incReference();
96 return cost;
97 } else if ( diff == 0 ) {
98 ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
99 ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
100 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
101 PRINT( std::cerr << "converting between references" << std::endl; )
102 if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
103 return Cost::safe;
104 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
105 int assignResult = ptrsAssignable( srcAsRef->get_base(), destAsRef->get_base(), env );
106 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
107 if ( assignResult < 0 ) {
108 return Cost::safe;
109 } else if ( assignResult > 0 ) {
110 return Cost::unsafe;
111 } // if
112 } // if
113 } else {
114 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
115 ConversionCost converter( dest, indexer, env );
116 src->accept( converter );
117 return converter.get_cost();
118 } // if
119 } else {
120 ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
121 assert( diff == -1 && destAsRef );
122 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->get_base(), indexer, env ) ) {
123 PRINT( std::cerr << "converting compatible base type" << std::endl; )
124 if ( src->get_lvalue() ) {
125 PRINT(
126 std::cerr << "lvalue to reference conversion" << std::endl;
127 std::cerr << src << " => " << destAsRef << std::endl;
128 )
129 // lvalue-to-reference conversion: cv lvalue T => cv T &
130 if ( src->get_qualifiers() == destAsRef->get_base()->get_qualifiers() ) {
131 return Cost::reference; // cost needs to be non-zero to add cast
132 } if ( src->get_qualifiers() < destAsRef->get_base()->get_qualifiers() ) {
133 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
134 } else {
135 return Cost::unsafe;
136 } // if
137 } else if ( destAsRef->get_base()->get_const() ) {
138 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
139 // rvalue-to-const-reference conversion: T => const T &
140 return Cost::safe;
141 } else {
142 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
143 // rvalue-to-reference conversion: T => T &
144 return Cost::unsafe;
145 } // if
146 } // if
147 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
148 }
149 return Cost::infinity;
150 }
151
152 Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
153 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
154 return convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env );
155 }
156
157 ConversionCost::ConversionCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env )
158 : dest( dest ), indexer( indexer ), cost( Cost::infinity ), env( env ) {
159 }
160
161/*
162 Old
163 ===
164 Double
165 |
166 Float
167 |
168 ULong
169 / \
170 UInt Long
171 \ /
172 Int
173 |
174 Ushort
175 |
176 Short
177 |
178 Uchar
179 / \
180 Schar Char
181
182 New
183 ===
184 +-----LongDoubleComplex--+
185 LongDouble--+ | +-LongDoubleImag
186 | +---DoubleComplex---+ |
187 Double------+ | +----DoubleImag
188 | +-FloatComplex-+ |
189 Float---------+ +-------FloatImag
190 |
191 ULongLong
192 |
193 LongLong
194 |
195 ULong
196 / \
197 UInt Long
198 \ /
199 Int
200 |
201 Ushort
202 |
203 Short
204 |
205 Uchar
206 / \
207 Schar Char
208 \ /
209 Bool
210*/
211
212 static const int costMatrix[ BasicType::NUMBER_OF_BASIC_TYPES ][ BasicType::NUMBER_OF_BASIC_TYPES ] =
213 {
214 /* Src \ Dest: Bool Char SChar UChar Short UShort Int UInt Long ULong LLong ULLong Float Double LDbl FCplex DCplex LDCplex FImag DImag LDImag */
215 /* Bool */ { 0, 1, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 11, 12, 13, -1, -1, -1 },
216 /* Char */ { -1, 0, -1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 10, 11, 12, -1, -1, -1 },
217 /* SChar */ { -1, -1, 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 10, 11, 12, -1, -1, -1 },
218 /* UChar */ { -1, -1, -1, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 9, 10, 11, -1, -1, -1 },
219 /* Short */ { -1, -1, -1, -1, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 8, 9, 10, -1, -1, -1 },
220 /* UShort */{ -1, -1, -1, -1, -1, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 7, 8, 9, -1, -1, -1 },
221 /* Int */ { -1, -1, -1, -1, -1, -1, 0, 1, 1, 2, 3, 4, 5, 6, 7, 6, 7, 8, -1, -1, -1 },
222 /* UInt */ { -1, -1, -1, -1, -1, -1, -1, 0, -1, 1, 2, 3, 4, 5, 6, 5, 6, 7, -1, -1, -1 },
223 /* Long */ { -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 5, 6, 7, -1, -1, -1 },
224 /* ULong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 4, 5, 6, -1, -1, -1 },
225 /* LLong */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 3, 4, 5, -1, -1, -1 },
226 /* ULLong */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 2, 3, 4, -1, -1, -1 },
227 /* Float */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 1, 2, 3, -1, -1, -1 },
228 /* Double */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, 1, 2, -1, -1, -1 },
229 /* LDbl */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1 },
230 /* FCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, -1, -1 },
231 /* DCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, -1 },
232 /* LDCplex */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1 },
233 /* FImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, 0, 1, 2 },
234 /* DImag */ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, -1, 0, 1 },
235 /* LDImag */{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0 }
236 };
237
238 void ConversionCost::visit( __attribute((unused)) VoidType *voidType ) {
239 cost = Cost::infinity;
240 }
241
242 void ConversionCost::visit(BasicType *basicType) {
243 if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
244 int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
245 if ( tableResult == -1 ) {
246 cost = Cost::unsafe;
247 } else {
248 cost = Cost::zero;
249 cost.incSafe( tableResult );
250 } // if
251 } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
252 // xxx - not positive this is correct, but appears to allow casting int => enum
253 cost = Cost::unsafe;
254 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
255 cost = Cost::unsafe;
256 } // if
257 }
258
259 void ConversionCost::visit(PointerType *pointerType) {
260 if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
261 PRINT( std::cerr << pointerType << " ===> " << destAsPtr; )
262 Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
263 Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
264 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
265 if ( tq1 == tq2 ) {
266 // types are the same
267 cost = Cost::zero;
268 } else {
269 // types are the same, except otherPointer has more qualifiers
270 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
271 cost = Cost::safe;
272 }
273 } else { // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
274 int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
275 PRINT( std::cerr << " :: " << assignResult << std::endl; )
276 if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
277 cost = Cost::safe;
278 } else if ( assignResult > 0 ) {
279 cost = Cost::unsafe;
280 } // if
281 // assignResult == 0 means Cost::Infinity
282 } // if
283 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
284 cost = Cost::unsafe;
285 } // if
286 }
287
288 void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
289
290 void ConversionCost::visit(ReferenceType *refType) {
291 // Note: dest can never be a reference, since it would have been caught in an earlier check
292 assert( ! dynamic_cast< ReferenceType * >( dest ) );
293 // convert reference to rvalue: cv T1 & => T2
294 // recursively compute conversion cost from T1 to T2.
295 // cv can be safely dropped because of 'implicit dereference' behavior.
296 refType->get_base()->accept( *this );
297 if ( refType->get_base()->get_qualifiers() == dest->get_qualifiers() ) {
298 cost.incReference(); // prefer exact qualifiers
299 } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {
300 cost.incSafe(); // then gaining qualifiers
301 } else {
302 cost.incUnsafe(); // lose qualifiers as last resort
303 }
304 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
305 }
306
307 void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
308
309 void ConversionCost::visit(StructInstType *inst) {
310 if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
311 if ( inst->get_name() == destAsInst->get_name() ) {
312 cost = Cost::zero;
313 } // if
314 } // if
315 }
316
317 void ConversionCost::visit(UnionInstType *inst) {
318 if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
319 if ( inst->get_name() == destAsInst->get_name() ) {
320 cost = Cost::zero;
321 } // if
322 } // if
323 }
324
325 void ConversionCost::visit( __attribute((unused)) EnumInstType *inst ) {
326 static Type::Qualifiers q;
327 static BasicType integer( q, BasicType::SignedInt );
328 integer.accept( *this ); // safe if dest >= int
329 if ( cost < Cost::unsafe ) {
330 cost.incSafe();
331 } // if
332 }
333
334 void ConversionCost::visit( __attribute((unused)) TraitInstType *inst) {
335 }
336
337 void ConversionCost::visit(TypeInstType *inst) {
338 EqvClass eqvClass;
339 NamedTypeDecl *namedType;
340 if ( env.lookup( inst->get_name(), eqvClass ) ) {
341 cost = conversionCost( eqvClass.type, dest, indexer, env );
342 } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) {
343 if ( inst->get_name() == destAsInst->get_name() ) {
344 cost = Cost::zero;
345 }
346 } else if ( ( namedType = indexer.lookupType( inst->get_name() ) ) ) {
347 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
348 // all typedefs should be gone by this point
349 assert( type );
350 if ( type->get_base() ) {
351 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
352 } // if
353 } // if
354 }
355
356 void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
357 Cost c = Cost::zero;
358 if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
359 std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
360 std::list< Type* >::const_iterator destIt = destAsTuple->get_types().begin();
361 while ( srcIt != tupleType->get_types().end() && destIt != destAsTuple->get_types().end() ) {
362 Cost newCost = conversionCost( *srcIt++, *destIt++, indexer, env );
363 if ( newCost == Cost::infinity ) {
364 return;
365 } // if
366 c += newCost;
367 } // while
368 if ( destIt != destAsTuple->get_types().end() ) {
369 cost = Cost::infinity;
370 } else {
371 cost = c;
372 } // if
373 } // if
374 }
375
376 void ConversionCost::visit( __attribute((unused)) VarArgsType *varArgsType) {
377 if ( dynamic_cast< VarArgsType* >( dest ) ) {
378 cost = Cost::zero;
379 }
380 }
381
382 void ConversionCost::visit( __attribute((unused)) ZeroType *zeroType) {
383 if ( dynamic_cast< ZeroType* >( dest ) ) {
384 cost = Cost::zero;
385 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
386 // copied from visit(BasicType*) for signed int, but +1 for safe conversions
387 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
388 if ( tableResult == -1 ) {
389 cost = Cost::unsafe;
390 } else {
391 cost = Cost::zero;
392 cost.incSafe( tableResult + 1 );
393 }
394 } else if ( dynamic_cast< PointerType* >( dest ) ) {
395 cost = Cost::safe;
396 }
397 }
398
399 void ConversionCost::visit( __attribute((unused)) OneType *oneType) {
400 if ( dynamic_cast< OneType* >( dest ) ) {
401 cost = Cost::zero;
402 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
403 // copied from visit(BasicType*) for signed int, but +1 for safe conversions
404 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
405 if ( tableResult == -1 ) {
406 cost = Cost::unsafe;
407 } else {
408 cost = Cost::zero;
409 cost.incSafe( tableResult + 1 );
410 }
411 }
412 }
413} // namespace ResolvExpr
414
415// Local Variables: //
416// tab-width: 4 //
417// mode: c++ //
418// compile-command: "make install" //
419// End: //
Note: See TracBrowser for help on using the repository browser.