source: src/ResolvExpr/CastCost.cpp@ 7552fde

Last change on this file since 7552fde was d3aa55e9, checked in by JiadaL <j82liang@…>, 15 months ago
  1. Disallow implicit conversion from cfa enum to int during on the function call site; 2. implement the reverse enum loop
  • Property mode set to 100644
File size: 5.9 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// CastCost.cpp --
8//
9// Author : Richard C. Bilson
10// Created On : Sun May 17 06:57:43 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue Oct 4 15:00:00 2019
13// Update Count : 9
14//
15
16#include "CastCost.hpp"
17
18#include <cassert> // for assert
19
20#include "AST/Print.hpp"
21#include "AST/SymbolTable.hpp"
22#include "AST/Type.hpp"
23#include "AST/TypeEnvironment.hpp"
24#include "ConversionCost.hpp" // for ConversionCost
25#include "Cost.hpp" // for Cost, Cost::infinity
26#include "ResolvExpr/ConversionCost.hpp" // for conversionCost
27#include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable
28#include "ResolvExpr/Unify.hpp" // for typesCompatibleIgnoreQualifiers
29
30#if 0
31#define PRINT(x) x
32#else
33#define PRINT(x)
34#endif
35
36namespace ResolvExpr {
37
38Cost castCost(
39 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
40 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
41);
42
43namespace {
44 struct CastCost : public ConversionCost {
45 using ConversionCost::previsit;
46 using ConversionCost::postvisit;
47
48 CastCost(
49 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
50 const ast::TypeEnvironment & env, CostCalculation costFunc )
51 : ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
52
53 void postvisit( const ast::EnumInstType * enumInst ) {
54 cost = conversionCost( enumInst, dst, srcIsLvalue, symtab, env );
55
56 if (Cost::unsafe < cost) {
57 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
58 Cost intCost = costCalc( integer, dst, srcIsLvalue, symtab, env );
59 cost = intCost < cost? intCost: cost;
60 }
61 if ( enumInst->base->isTyped && enumInst->base->base ) {
62 auto baseConversionCost =
63 castCost( enumInst->base->base, dst, srcIsLvalue, symtab, env );
64 cost = baseConversionCost < cost? baseConversionCost: cost;
65 }
66 }
67
68 void postvisit( const ast::BasicType * basicType ) {
69 auto ptr = dynamic_cast< const ast::PointerType * >( dst );
70 if ( ptr && basicType->isInteger() ) {
71 // needed for, e.g. unsigned long => void *
72 cost = Cost::unsafe;
73 } else {
74 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
75 if ( Cost::unsafe < cost ) {
76 if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
77 // Always explict cast only for typed enum
78 if (enumInst->base->isTyped) cost = Cost::unsafe;
79 }
80 }
81 }
82 }
83
84 void postvisit( const ast::ZeroType * zero ) {
85 cost = conversionCost( zero, dst, srcIsLvalue, symtab, env );
86 if ( Cost::unsafe < cost ) {
87 if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
88 if (enumInst->base->isTyped) cost = Cost::unsafe;
89 }
90 }
91 }
92
93 void postvisit( const ast::OneType * one ) {
94 cost = conversionCost( one, dst, srcIsLvalue, symtab, env );
95 if ( Cost::unsafe < cost ) {
96 if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(dst)) {
97 if (enumInst->base->isTyped) cost = Cost::unsafe;
98 }
99 }
100 }
101
102 void postvisit( const ast::PointerType * pointerType ) {
103 if ( auto ptr = dynamic_cast< const ast::PointerType * >( dst ) ) {
104 if (
105 pointerType->qualifiers <= ptr->qualifiers
106 && typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, env )
107 ) {
108 cost = Cost::safe;
109 } else {
110 ast::TypeEnvironment newEnv{ env };
111 if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
112 newEnv.add( wParams->forall );
113 }
114 int castResult = ptrsCastable( pointerType->base, ptr->base, symtab, newEnv );
115 if ( castResult > 0 ) {
116 cost = Cost::safe;
117 } else if ( castResult < 0 ) {
118 cost = Cost::infinity;
119 }
120 }
121 } else if ( auto basic = dynamic_cast< const ast::BasicType * >( dst ) ) {
122 if ( basic->isInteger() ) {
123 // necessary for, e.g. void * => unsigned long
124 cost = Cost::unsafe;
125 }
126 }
127 }
128 };
129
130} // anonymous namespace
131
132Cost castCost(
133 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
134 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
135) {
136 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
137 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
138 // check cast cost against bound type, if present
139 if ( eqvClass->bound ) {
140 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
141 } else {
142 return Cost::infinity;
143 }
144 } else if ( const ast::NamedTypeDecl * named = symtab.lookupType( typeInst->name ) ) {
145 // all typedefs should be gone by now
146 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
147 if ( type->base ) {
148 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
149 }
150 }
151 }
152
153 PRINT(
154 std::cerr << "castCost ::: src is ";
155 ast::print( std::cerr, src );
156 std::cerr << std::endl << "dest is ";
157 ast::print( std::cerr, dst );
158 std::cerr << std::endl << "env is" << std::endl;
159 ast::print( std::cerr, env, 2 );
160 )
161
162 if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) {
163 PRINT( std::cerr << "compatible!" << std::endl; )
164 if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {
165 return Cost::spec;
166 }
167 return Cost::zero;
168 } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
169 return Cost::safe;
170 } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
171 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
172 return convertToReferenceCost(
173 src, refType, srcIsLvalue, symtab, env, ptrsCastable );
174 } else {
175 ast::Pass< CastCost > converter(
176 dst, srcIsLvalue, symtab, env, castCost );
177 src->accept( converter );
178 return converter.core.cost;
179 }
180}
181
182} // namespace ResolvExpr
183
184// Local Variables: //
185// tab-width: 4 //
186// mode: c++ //
187// compile-command: "make install" //
188// End: //
Note: See TracBrowser for help on using the repository browser.