source: src/GenPoly/Lvalue.cc @ 9a34b5a

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 9a34b5a was 9a34b5a, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

Remove redundant casts from reference translation and generate dereference ApplicationExpr? instead of UntypedExpr?

Generating ApplicationExpr? in this context is necessary so that the Box pass correctly removes dereferences from polymorphic code.

  • Property mode set to 100644
File size: 10.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// Lvalue.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Mar 17 09:11:18 2017
13// Update Count     : 5
14//
15
16#include <cassert>
17
18#include "Lvalue.h"
19
20#include "GenPoly.h"
21
22#include "SynTree/Declaration.h"
23#include "SynTree/Type.h"
24#include "SynTree/Expression.h"
25#include "SynTree/Statement.h"
26#include "SynTree/Visitor.h"
27#include "SynTree/Mutator.h"
28#include "SymTab/Indexer.h"
29#include "SymTab/Autogen.h"
30#include "ResolvExpr/Resolver.h"
31#include "ResolvExpr/typeops.h"
32
33#include "Common/UniqueName.h"
34#include "Common/utility.h"
35#include "InitTweak/InitTweak.h"
36
37#include "Common/PassVisitor.h"
38
39// need to be careful about polymorphic references... e.g. in *? (___operator_deref__A0_1_0_0__Fd0_Pd0_intrinsic___1)
40// the variable is automatically dereferenced and this causes errors dereferencing void*.
41
42namespace GenPoly {
43        namespace {
44                // TODO: fold this into the general createDeref function??
45                Expression * mkDeref( Expression * arg ) {
46                        if ( SymTab::dereferenceOperator ) {
47                                VariableExpr * deref = new VariableExpr( SymTab::dereferenceOperator );
48                                deref->set_result( new PointerType( Type::Qualifiers(), deref->get_result() ) );
49                                Type * base = InitTweak::getPointerBase( arg->get_result() );
50                                assertf( base, "expected pointer type in dereference (type was %s)", toString( arg->get_result() ).c_str() );
51                                ApplicationExpr * ret = new ApplicationExpr( deref, { arg } );
52                                delete ret->get_result();
53                                ret->set_result( new ReferenceType( Type::Qualifiers(), base->clone() ) );
54                                return ret;
55                        } else {
56                                return UntypedExpr::createDeref( arg );
57                        }
58                }
59
60                struct ReferenceConversions final {
61                        Expression * postmutate( CastExpr * castExpr );
62                };
63
64                /// Intrinsic functions that take reference parameters don't REALLY take reference parameters -- their reference arguments must always be implicitly dereferenced.
65                struct FixIntrinsicArgs final {
66                        Expression * postmutate( ApplicationExpr *appExpr );
67                };
68
69
70                /// Replace reference types with pointer types
71                struct ReferenceTypeElimination final {
72                        Type * postmutate( ReferenceType * refType );
73                };
74
75                /// GCC-like Generalized Lvalues (which have since been removed from GCC)
76                /// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
77                /// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c)
78                struct GeneralizedLvalue final {
79                        Expression * postmutate( AddressExpr * addressExpr );
80                };
81        } // namespace
82
83        void convertLvalue( std::list< Declaration* >& translationUnit ) {
84                std::cerr << "convertLvalue" << std::endl;
85                PassVisitor<ReferenceConversions> refCvt;
86                PassVisitor<ReferenceTypeElimination> elim;
87                PassVisitor<GeneralizedLvalue> genLval;
88                PassVisitor<FixIntrinsicArgs> fixer;
89                mutateAll( translationUnit, refCvt );
90                mutateAll( translationUnit, fixer );
91                mutateAll( translationUnit, elim );
92                mutateAll( translationUnit, genLval );
93        }
94
95        namespace {
96                Type* isLvalueRet( FunctionType *function ) {
97                        if ( function->get_returnVals().empty() ) return 0;
98                        Type *ty = function->get_returnVals().front()->get_type();
99                        return dynamic_cast< ReferenceType * >( ty ) ;
100                }
101
102                bool isIntrinsicApp( ApplicationExpr *appExpr ) {
103                        if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( appExpr->get_function() ) ) {
104                                return varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic;
105                        } else {
106                                return false;
107                        } // if
108                }
109
110                bool isDeref( Expression * expr ) {
111                        if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( expr ) ) {
112                                return InitTweak::getFunctionName( untyped ) == "*?";
113                        } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
114                                if ( DeclarationWithType * func = InitTweak::getFunction( appExpr ) ) {
115                                        return func->get_linkage() == LinkageSpec::Intrinsic && InitTweak::getFunctionName( appExpr ) == "*?";
116                                }
117                        }
118                        return false;
119                }
120
121                bool isIntrinsicReference( Expression * expr ) {
122                        if ( isDeref( expr ) ) return true;
123                        else if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( expr ) ) {
124                                return InitTweak::getFunctionName( untyped ) == "?[?]";
125                        } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
126                                if ( DeclarationWithType * func = InitTweak::getFunction( appExpr ) ) {
127                                        return func->get_linkage() == LinkageSpec::Intrinsic && InitTweak::getFunctionName( appExpr ) == "?[?]";
128                                }
129                        }
130                        return false;
131                }
132
133                void fixArg( Expression *& arg, Type * formal ) {
134                        if ( dynamic_cast<ReferenceType*>( formal ) ) {
135                                // if the parameter is a reference, add a dereference to the reference-typed argument.
136                                Type * baseType = InitTweak::getPointerBase( arg->get_result() );
137                                assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->get_result() ) );
138                                PointerType * ptrType = new PointerType( Type::Qualifiers(), baseType->clone() );
139                                delete arg->get_result();
140                                arg->set_result( ptrType );
141                                arg = mkDeref( new CastExpr( arg, arg->get_result()->clone() ) );
142                        }
143                }
144
145                Expression * FixIntrinsicArgs::postmutate( ApplicationExpr * appExpr ) {
146                        // intrinsic functions don't really take reference-typed parameters, so they require an implicit dereference on their arguments.
147                        if ( DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
148                                if ( function->get_linkage() == LinkageSpec::Intrinsic ) {
149                                        FunctionType * ftype = GenPoly::getFunctionType( function->get_type() );
150                                        assertf( ftype, "Function declaration does not have function type." );
151                                        for ( auto p : group_iterate( appExpr->get_args(), ftype->get_parameters() ) ) {
152                                                Expression *& arg = std::get<0>( p );
153                                                DeclarationWithType * formal = std::get<1>( p );
154                                                std::cerr << "pair<0>: " << arg << std::endl;
155                                                std::cerr << "pair<1>: " << formal->get_type() << std::endl;
156                                                if ( isIntrinsicReference( arg ) ) { // intrinsic functions that turn pointers into references
157                                                        // if argument is dereference or array subscript, the result isn't REALLY a reference, so it's not necessary to fix the argument
158                                                        std::cerr << "skipping intrinsic reference" << std::endl;
159                                                        continue;
160                                                } else {
161                                                        fixArg( arg, formal->get_type() );
162                                                }
163                                        }
164                                }
165                        }
166                        return appExpr;
167                }
168
169                Expression * ReferenceConversions::postmutate( CastExpr * castExpr ) {
170                        // xxx - is it possible to convert directly between reference types with a different base? E.g.,
171                        //   int x;
172                        //   (double&)x;
173                        // At the moment, I am working off of the assumption that this is illegal, thus the cast becomes redundant
174                        // after this pass, so trash the cast altogether. If that changes, care must be taken to insert the correct
175                        // pointer casts in the right places.
176
177                        // conversion to reference type
178                        if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_result() ) ) {
179                                (void)refType;
180                                if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( castExpr->get_arg()->get_result() ) ) {
181                                        // nothing to do if casting from reference to reference.
182                                        (void)otherRef;
183                                        std::cerr << "convert reference to reference -- nop" << std::endl;
184                                        if ( isIntrinsicReference( castExpr->get_arg() ) ) {
185                                                Expression * callExpr = castExpr->get_arg();
186                                                std::cerr << "but arg is deref -- &" << std::endl;
187                                                std::cerr << callExpr << std::endl;
188                                                // move environment out to new top-level
189                                                callExpr->set_env( castExpr->get_env() );
190                                                castExpr->set_arg( nullptr );
191                                                castExpr->set_env( nullptr );
192                                                delete castExpr;
193                                                return callExpr;
194                                        }
195                                        assertf( false, "non-intrinsic reference with cast of reference to reference not yet supported: ", toString( castExpr ) );
196                                        std::cerr << castExpr << std::endl;
197                                        return castExpr;
198                                } else if ( castExpr->get_arg()->get_result()->get_lvalue() ) {
199                                        // conversion from lvalue to reference
200                                        // xxx - keep cast, but turn into pointer cast??
201                                        // xxx - memory
202                                        std::cerr << "convert lvalue to reference -- &" << std::endl;
203                                        std::cerr << castExpr->get_arg() << std::endl;
204                                        Expression * ret = new AddressExpr( castExpr->get_arg() );
205                                        ret->set_env( castExpr->get_env() );
206                                        castExpr->set_env( nullptr );
207                                        castExpr->set_arg( nullptr );
208                                        delete castExpr;
209                                        return ret;
210                                } else {
211                                        // rvalue to reference conversion -- introduce temporary
212                                }
213                                assertf( false, "Only conversions to reference from lvalue are currently supported: %s", toString( castExpr ).c_str() );
214                        } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_arg()->get_result() ) ) {
215                                // conversion from reference to rvalue
216                                // should be easy, just need to move deref code up here?
217                                std::cerr << "convert reference to rvalue -- *" << std::endl;
218                                if ( isIntrinsicReference( castExpr->get_arg() ) ) {
219                                        std::cerr << "but arg is intrinsic reference -- nop" << std::endl;
220                                        return castExpr;
221                                }
222                                std::cerr << "was = " << castExpr << std::endl;
223
224                                Expression * deref = mkDeref( castExpr->get_arg() );
225                                deref->set_env( castExpr->get_env() );
226                                castExpr->set_arg( nullptr );
227                                castExpr->set_env( nullptr );
228                                delete castExpr;
229                                std::cerr << "now: " << deref << std::endl;
230                                return deref;
231                        }
232                        return castExpr;
233                }
234
235                Type * ReferenceTypeElimination::postmutate( ReferenceType * refType ) {
236                        Type * base = refType->get_base();
237                        refType->set_base( nullptr );
238                        delete refType;
239                        return new PointerType( Type::Qualifiers(), base );
240                }
241
242                Expression * GeneralizedLvalue::postmutate( AddressExpr * addrExpr ) {
243                        if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( addrExpr->get_arg() ) ) {
244                                Expression * arg1 = commaExpr->get_arg1()->clone();
245                                Expression * arg2 = commaExpr->get_arg2()->clone();
246                                delete addrExpr;
247                                return new CommaExpr( arg1, new AddressExpr( arg2 ) );
248                        } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( addrExpr->get_arg() ) ) {
249                                Expression * arg1 = condExpr->get_arg1()->clone();
250                                Expression * arg2 = condExpr->get_arg2()->clone();
251                                Expression * arg3 = condExpr->get_arg3()->clone();
252                                delete addrExpr;
253                                return new ConditionalExpr( arg1, new AddressExpr( arg2 ), new AddressExpr( arg3 ) );
254                        }
255                        return addrExpr;
256                }
257        } // namespace
258} // namespace GenPoly
259
260// Local Variables: //
261// tab-width: 4 //
262// mode: c++ //
263// compile-command: "make install" //
264// End: //
Note: See TracBrowser for help on using the repository browser.