source: src/ResolvExpr/ConversionCost.cc@ d1685588

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

Add reference cost field to cost tuple

  • Property mode set to 100644
File size: 15.5 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 if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
251 cost = Cost::safe;
252 } else { // xxx - this discards pointer qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
253 int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
254 if ( assignResult < 0 ) {
255 cost = Cost::safe;
256 } else if ( assignResult > 0 ) {
257 cost = Cost::unsafe;
258 } // if
259 } // if
260 } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
261 cost = Cost::unsafe;
262 } // if
263 }
264
265 void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
266
267 void ConversionCost::visit(ReferenceType *refType) {
268 // Note: dest can never be a reference, since it would have been caught in an earlier check
269 assert( ! dynamic_cast< ReferenceType * >( dest ) );
270 // convert reference to rvalue: cv T1 & => T2
271 // recursively compute conversion cost from T1 to T2.
272 // cv can be safely dropped because of 'implicit dereference' behavior.
273 refType->get_base()->accept( *this );
274 cost.incReference();
275 }
276
277 void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
278
279 void ConversionCost::visit(StructInstType *inst) {
280 if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
281 if ( inst->get_name() == destAsInst->get_name() ) {
282 cost = Cost::zero;
283 } // if
284 } // if
285 }
286
287 void ConversionCost::visit(UnionInstType *inst) {
288 if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
289 if ( inst->get_name() == destAsInst->get_name() ) {
290 cost = Cost::zero;
291 } // if
292 } // if
293 }
294
295 void ConversionCost::visit( __attribute((unused)) EnumInstType *inst ) {
296 static Type::Qualifiers q;
297 static BasicType integer( q, BasicType::SignedInt );
298 integer.accept( *this ); // safe if dest >= int
299 if ( cost < Cost::unsafe ) {
300 cost.incSafe();
301 } // if
302 }
303
304 void ConversionCost::visit( __attribute((unused)) TraitInstType *inst) {
305 }
306
307 void ConversionCost::visit(TypeInstType *inst) {
308 EqvClass eqvClass;
309 NamedTypeDecl *namedType;
310 if ( env.lookup( inst->get_name(), eqvClass ) ) {
311 cost = conversionCost( eqvClass.type, dest, indexer, env );
312 } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) {
313 if ( inst->get_name() == destAsInst->get_name() ) {
314 cost = Cost::zero;
315 }
316 } else if ( ( namedType = indexer.lookupType( inst->get_name() ) ) ) {
317 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
318 // all typedefs should be gone by this point
319 assert( type );
320 if ( type->get_base() ) {
321 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
322 } // if
323 } // if
324 }
325
326 void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
327 Cost c = Cost::zero;
328 if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
329 std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
330 std::list< Type* >::const_iterator destIt = destAsTuple->get_types().begin();
331 while ( srcIt != tupleType->get_types().end() && destIt != destAsTuple->get_types().end() ) {
332 Cost newCost = conversionCost( *srcIt++, *destIt++, indexer, env );
333 if ( newCost == Cost::infinity ) {
334 return;
335 } // if
336 c += newCost;
337 } // while
338 if ( destIt != destAsTuple->get_types().end() ) {
339 cost = Cost::infinity;
340 } else {
341 cost = c;
342 } // if
343 } // if
344 }
345
346 void ConversionCost::visit( __attribute((unused)) VarArgsType *varArgsType) {
347 if ( dynamic_cast< VarArgsType* >( dest ) ) {
348 cost = Cost::zero;
349 }
350 }
351
352 void ConversionCost::visit( __attribute((unused)) ZeroType *zeroType) {
353 if ( dynamic_cast< ZeroType* >( dest ) ) {
354 cost = Cost::zero;
355 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
356 // copied from visit(BasicType*) for signed int, but +1 for safe conversions
357 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
358 if ( tableResult == -1 ) {
359 cost = Cost::unsafe;
360 } else {
361 cost = Cost::zero;
362 cost.incSafe( tableResult + 1 );
363 }
364 } else if ( dynamic_cast< PointerType* >( dest ) ) {
365 cost = Cost::safe;
366 }
367 }
368
369 void ConversionCost::visit( __attribute((unused)) OneType *oneType) {
370 if ( dynamic_cast< OneType* >( dest ) ) {
371 cost = Cost::zero;
372 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
373 // copied from visit(BasicType*) for signed int, but +1 for safe conversions
374 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
375 if ( tableResult == -1 ) {
376 cost = Cost::unsafe;
377 } else {
378 cost = Cost::zero;
379 cost.incSafe( tableResult + 1 );
380 }
381 }
382 }
383} // namespace ResolvExpr
384
385// Local Variables: //
386// tab-width: 4 //
387// mode: c++ //
388// compile-command: "make install" //
389// End: //
Note: See TracBrowser for help on using the repository browser.