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

aaron-thesisarm-ehcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since 5ccb10d was 5ccb10d, checked in by Rob Schluntz <rschlunt@…>, 5 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.