source: src/ResolvExpr/ConversionCost.cc@ 89be1c68

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 stuck-waitfor-destruct with_gc
Last change on this file since 89be1c68 was 89be1c68, checked in by Rob Schluntz <rschlunt@…>, 9 years ago

Remove Cost constructors, use only named members

This change makes it easier to read code involving costs, since in almost every case, only a single part of the cost tuple is relevant. Furthermore, this change makes it much simpler to add another dimension to the cost tuple, since only Cost.h needs to be updated, rather than every location using the cost constructor.

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