source: src/ResolvExpr/ConversionCost.cc@ 74b007ba

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 74b007ba was 74b007ba, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Remove unused isDynamicLayout parameter from autogen, add some more debug information

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