Changeset fc12f05
- Timestamp:
- Nov 13, 2023, 3:43:43 AM (23 months ago)
- Branches:
- master
- Children:
- 25f2798
- Parents:
- 0030b508 (diff), 2174191 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 5 added
- 114 deleted
- 134 edited
- 3 moved
Legend:
- Unmodified
- Added
- Removed
-
doc/bibliography/pl.bib
r0030b508 rfc12f05 4108 4108 } 4109 4109 4110 @article{Buhr2 2,4110 @article{Buhr23, 4111 4111 contributer = {pabuhr@plg}, 4112 4112 author = {Peter A. Buhr and Colby A. Parsons and Thierry Delisle and He Nan Li}, … … 4114 4114 journal = spe, 4115 4115 year = 2023, 4116 month = sep, 4117 note = {\url{https://onlinelibrary.wiley.com/doi/pdf/10.1002/spe.3262}} 4116 month = dec, 4117 volume = 53, 4118 number = 12, 4119 pages = {2463-2500}, 4120 note = {\url{https://onlinelibrary.wiley.com/doi/10.1002/spe.3262}, 4118 4121 } 4119 4122 … … 4133 4136 journal = spe, 4134 4137 year = 1983, 4138 month = jul, 4135 4139 volume = 13, 4136 4140 number = 7, 4137 4141 pages = {577-596}, 4138 month = jul4139 4142 } 4140 4143 -
driver/as.cc
r0030b508 rfc12f05 11 11 // Created On : Wed Aug 1 10:49:42 2018 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Wed Dec 8 07:56:12 202114 // Update Count : 1 3613 // Last Modified On : Tue Oct 24 20:45:06 2023 14 // Update Count : 159 15 15 // 16 16 … … 45 45 char * dcursor; 46 46 if ( (dcursor = strstr( start, ".Ldebug_info0:" ) ) ) { // debug information ? 47 47 // fprintf( stderr, "found .Ldebug_info0:\n" ); 48 #if defined( __i386 ) || defined( __x86_64 ) 48 49 if ( char * cursor = strstr( dcursor, ".long\t.LASF" ) ) { // language code ? 50 // fprintf( stderr, ".long\t.LASF\n" ); 51 #elif defined( __aarch64__ ) 52 if ( char * cursor = strstr( dcursor, ".4byte\t.LASF" ) ) { // language code ? 53 // fprintf( stderr, ".4byte\t.LASF\n" ); 54 #else 55 #error unsupported architecture 56 #endif 49 57 for ( int i = 0; i < 2; i += 1 ) { // move N (magic) lines forward 50 58 cursor = strstr( cursor, "\n" ) + 1; … … 55 63 if ( *(cursor - 2) == '0' && *(cursor - 1) == 'x' && 56 64 (*cursor == 'c' || *cursor == '1' || *cursor == '2') ) { // C99/C89/C 65 // fprintf( stderr, "language code C99/C89/C %c\n", *cursor ); 57 66 // Expand file by one byte to hold 2 character Cforall language code. 58 67 if ( ftruncate( fd, size + 1 ) ) { perror( "ftruncate" ); exit( EXIT_FAILURE ); }; 59 68 memmove( cursor + 2, cursor + 1, start + size - cursor - 1 ); // move remaining text 1 character right 60 69 } else if ( *(cursor - 3) == '0' && *(cursor - 2) == 'x' && *(cursor - 1) == '1' && *cursor == 'd' ) { // C11 70 // fprintf( stderr, "language code C11 %c\n", *cursor ); 61 71 } else { 62 72 for ( int i = 0; i < 6; i += 1 ) { // move N (magic) lines forward -
libcfa/prelude/Makefile.am
r0030b508 rfc12f05 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Thu Jan 13 17:06:27 202214 ## Update Count : 2 1513 ## Last Modified On : Wed Nov 1 21:09:25 2023 14 ## Update Count : 221 15 15 ############################################################################### 16 16 … … 21 21 # put into lib for now 22 22 cfalibdir = ${CFA_LIBDIR} 23 cfalib_DATA = gcc-builtins.cf builtins.cf extras.cfprelude.cfa bootloader.c defines.hfa23 cfalib_DATA = gcc-builtins.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c defines.hfa 24 24 25 EXTRA_DIST = bootloader.cf builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cf25 EXTRA_DIST = bootloader.cfa builtins.c builtins.def extras.c extras.regx extras.regx2 prelude-gen.cc prototypes.awk prototypes.c prototypes.sed sync-builtins.cfa 26 26 27 27 CC = @LOCAL_CFACC@ … … 36 36 37 37 # create extra forward types/declarations to reduce inclusion of library files 38 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c38 extras.cfa : ${srcdir}/extras.regx ${srcdir}/extras.c 39 39 @echo '# 2 "${@}" // needed for error messages from this file' > ${@} 40 40 ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx >> ${@} … … 42 42 43 43 # create forward declarations for gcc builtins 44 gcc-builtins.cf : gcc-builtins.c ${srcdir}/prototypes.sed44 gcc-builtins.cfa : gcc-builtins.c ${srcdir}/prototypes.sed 45 45 @echo '# 2 "${@}" // needed for error messages from this file' > ${@} 46 46 ${AM_V_GEN}gcc -I${srcdir} -E -P $< | sed -r -f ${srcdir}/prototypes.sed >> ${@} 47 47 48 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf ${srcdir}/prototypes.c48 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cfa ${srcdir}/prototypes.c 49 49 ${AM_V_GEN}gcc -I${srcdir} -E ${srcdir}/prototypes.c | awk -f ${srcdir}/prototypes.awk > ${@} 50 50 … … 59 59 60 60 # create forward declarations for cfa builtins 61 builtins.cf : builtins.c @LOCAL_CFACC@61 builtins.cfa : builtins.c @LOCAL_CFACC@ 62 62 ${AM_V_GEN}gcc ${AM_CFLAGS} -E ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po -D__cforall 63 ${AM_V_at}sed -i 's/builtins.o/builtins.cf /g' $(DEPDIR)/builtins.Po63 ${AM_V_at}sed -i 's/builtins.o/builtins.cfa/g' $(DEPDIR)/builtins.Po 64 64 65 65 include $(DEPDIR)/builtins.Po 66 66 67 bootloader.c : ${srcdir}/bootloader.cf prelude.cfa extras.cf gcc-builtins.cf builtins.cf@CFACPP@68 ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf ${@} # use src/cfa-cpp as not in lib until after install67 bootloader.c : ${srcdir}/bootloader.cfa prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @CFACPP@ 68 ${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cfa ${@} # use src/cfa-cpp as not in lib until after install 69 69 70 70 maintainer-clean-local : 71 71 rm -rf $(DEPDIR) 72 72 73 MOSTLYCLEANFILES = bootloader.c builtins.cf extras.cf gcc-builtins.c gcc-builtins.cfprelude.cfa73 MOSTLYCLEANFILES = bootloader.c builtins.cfa extras.cfa gcc-builtins.c gcc-builtins.cfa prelude.cfa 74 74 DISTCLEANFILES = $(DEPDIR)/builtins.Po 75 75 MAINTAINERCLEANFILES = ${addprefix ${libdir}/,${cfalib_DATA}} ${addprefix ${libdir}/,${lib_LIBRARIES}} 76 76 77 77 if ENABLE_DISTCC 78 distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cf builtins.cf extras.cfprelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh78 distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ defines.hfa gcc-builtins.cfa builtins.cfa extras.cfa prelude.cfa bootloader.c $(srcdir)/../../tools/build/push2dist.sh 79 79 ${AM_V_GEN}$(srcdir)/../../tools/build/push2dist.sh @CFADIR_HASH@ @DIST_BWLIMIT@ 80 80 @echo "Dummy file to track distribution to remote hosts" > ${@} -
libcfa/prelude/prototypes.awk
r0030b508 rfc12f05 10 10 # Created On : Sat May 16 07:57:37 2015 11 11 # Last Modified By : Peter A. Buhr 12 # Last Modified On : Sat Feb 8 09:46:58 202013 # Update Count : 3 612 # Last Modified On : Wed Nov 1 20:44:04 2023 13 # Update Count : 37 14 14 # 15 15 … … 150 150 # extras 151 151 printf( "\n#include \"builtins.def\"\n\n" ); 152 printf( "\n#include \"sync-builtins.cf \"\n\n" );152 printf( "\n#include \"sync-builtins.cfa\"\n\n" ); 153 153 printf( "extern const char *__PRETTY_FUNCTION__;\n" ); 154 154 printf( "float _Complex __builtin_complex( float, float );\n" ); -
libcfa/src/Makefile.am
r0030b508 rfc12f05 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Sep 18 17:06:56202314 ## Update Count : 26 413 ## Last Modified On : Wed Nov 1 19:03:42 2023 14 ## Update Count : 266 15 15 ############################################################################### 16 16 … … 195 195 if ENABLE_DISTCC 196 196 197 ../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cf ../prelude/builtins.cf ../prelude/extras.cf../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh197 ../prelude/distribution: @LOCAL_CFACC@ @LOCAL_CC1@ @CFACPP@ ../prelude/defines.hfa ../prelude/gcc-builtins.cfa ../prelude/builtins.cfa ../prelude/extras.cfa ../prelude/prelude.cfa ../prelude/bootloader.c $(srcdir)/../../tools/build/push2dist.sh 198 198 @+make -C ../prelude distribution 199 199 … … 202 202 endif ENABLE_DISTCC 203 203 204 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf@LOCAL_CFACC@ @CFACPP@204 prelude.o : prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@ 205 205 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@} 206 206 207 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf@LOCAL_CFACC@ @CFACPP@207 prelude.lo: prelude.cfa extras.cfa gcc-builtins.cfa builtins.cfa @LOCAL_CFACC@ @CFACPP@ 208 208 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 209 209 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@} -
libcfa/src/collections/string.cfa
r0030b508 rfc12f05 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 2 12:05:57202313 // Update Count : 20 612 // Last Modified On : Wed Oct 18 21:52:09 2023 13 // Update Count : 208 14 14 // 15 15 … … 138 138 139 139 void ?|?( ifstream & in, _Istream_Sstr f ) { 140 (ifstream &)(in | f); ends( in );140 (ifstream &)(in | f); 141 141 } 142 142 -
libcfa/src/collections/string_res.cfa
r0030b508 rfc12f05 10 10 // Created On : Fri Sep 03 11:00:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Aug 14 18:06:01202313 // Update Count : 1 212 // Last Modified On : Wed Oct 18 21:54:54 2023 13 // Update Count : 15 14 14 // 15 15 … … 236 236 // get bytes 237 237 try { 238 *(temp.Handle.ulink->EndVbyte) = '\0'; // pre-assign empty cstring 238 239 in | wdi( lenReadable, temp.Handle.ulink->EndVbyte ); 239 240 } catch (cstring_length*) { … … 247 248 } 248 249 249 250 if ( temp.Handle.lnth > 0 ) s = temp; 250 251 return in; 251 252 } 252 253 253 254 void ?|?( ifstream & in, string_res & this ) { 254 (ifstream &)(in | this); ends( in );255 (ifstream &)(in | this); 255 256 } 256 257 … … 268 269 cstr[wd] = '\0'; // guard null terminate string 269 270 try { 271 cstr[0] = '\0'; // pre-assign as empty cstring 270 272 is | cf; 271 273 } catch( cstring_length * ) { 272 274 cont = true; 273 275 } finally { 274 if ( ! cf.flags.ignore ) *(f.s) = cstr; // ok to initialize string 276 if ( ! cf.flags.ignore && // ok to initialize string 277 cstr[0] != '\0' ) { // something was read 278 *(f.s) = cstr; 279 } 275 280 } // try 276 281 for ( ; cont; ) { // overflow read ? 277 282 cont = false; 278 283 try { 284 cstr[0] = '\0'; // pre-assign as empty cstring 279 285 is | cf; 280 286 } catch( cstring_length * ) { 281 287 cont = true; // continue not allowed 282 288 } finally { 283 if ( ! cf.flags.ignore ) *(f.s) += cstr; // build string chunk at a time 289 if ( ! cf.flags.ignore && 290 cstr[0] != '\0' ) { // something was read 291 *(f.s) += cstr; // build string chunk at a time 292 } 284 293 } // try 285 294 } // for … … 288 297 289 298 void ?|?( ifstream & in, _Istream_Rstr f ) { 290 (ifstream &)(in | f); ends( in );299 (ifstream &)(in | f); 291 300 } 292 301 -
libcfa/src/concurrency/channel.hfa
r0030b508 rfc12f05 130 130 static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) { 131 131 memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work 132 __atomic_thread_fence( __ATOMIC_SEQ_CST );133 132 wake_one( cons ); 134 133 } … … 137 136 static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) { 138 137 memcpy( (void *)&retval, prods`first.extra, sizeof(T) ); 139 __atomic_thread_fence( __ATOMIC_SEQ_CST );140 138 wake_one( prods ); 141 139 } -
libcfa/src/concurrency/cofor.cfa
r0030b508 rfc12f05 4 4 // cofor ( uC++ COFOR ) 5 5 6 thread cofor_ runner{6 thread cofor_task { 7 7 ssize_t low, high; 8 8 __cofor_body_t loop_body; 9 9 }; 10 10 11 static void ?{}( cofor_ runner& this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) {11 static void ?{}( cofor_task & this, ssize_t low, ssize_t high, __cofor_body_t loop_body ) { 12 12 this.low = low; 13 13 this.high = high; … … 15 15 } 16 16 17 void main( cofor_ runner& this ) with( this ) {17 void main( cofor_task & this ) with( this ) { 18 18 for ( ssize_t i = low; i < high; i++ ) 19 19 loop_body(i); … … 29 29 ssize_t i = 0; 30 30 ssize_t stride_iter = low; 31 cofor_ runner* runners[ threads ];31 cofor_task * runners[ threads ]; 32 32 for ( i; threads ) { 33 33 runners[i] = alloc(); -
libcfa/src/concurrency/cofor.hfa
r0030b508 rfc12f05 1 1 #include <thread.hfa> 2 #include <locks.hfa> 3 #include <list.hfa> 2 4 3 5 ////////////////////////////////////////////////////////////////////////////////////////// … … 14 16 __Cofor__( low, high, __CFA_loopLambda__ ); \ 15 17 } 18 19 struct runner_node { 20 void * value; 21 inline dlink(runner_node); 22 }; 23 P9_EMBEDDED( runner_node, dlink(runner_node) ) 24 25 thread cofor_runner { 26 go_mutex mutex_lock; // MX lock 27 dlist( runner_node ) items; 28 void (*func)(void *); 29 volatile bool done; 30 }; 31 32 void ?{}( cofor_runner & this ) { this.done = false; } 33 34 void main( cofor_runner & this ) with(this) { 35 while ( !done || !items`isEmpty ) { 36 lock( mutex_lock ); 37 runner_node * node = &try_pop_front( items ); 38 unlock( mutex_lock ); 39 func( node->value ); 40 free( node->value ); 41 free( node ); 42 } 43 } 44 45 void start_runners( cofor_runner * thds, unsigned nprocs, void (*func)(void *) ) { 46 for ( i; nprocs ) { 47 thds[i].func = func; 48 } 49 } 50 51 void end_runners( cofor_runner * thds, unsigned nprocs ) { 52 for ( i; nprocs ) { 53 thds[i].done = true; 54 } 55 } 56 57 void send_work( cofor_runner * thds, unsigned nprocs, unsigned & curr_proc, void * value ) { 58 runner_node * node = malloc(); 59 (*node){}; 60 node->value = value; 61 lock( thds[curr_proc].mutex_lock ); 62 insert_last( thds[curr_proc].items, *node ); 63 unlock( thds[curr_proc].mutex_lock ); 64 curr_proc = ( curr_proc + 1 ) % nprocs; 65 } 16 66 17 67 ////////////////////////////////////////////////////////////////////////////////////////// … … 42 92 delete( this.runner ); 43 93 } 44 -
libcfa/src/concurrency/kernel.hfa
r0030b508 rfc12f05 303 303 // gets the number of constructed processors on the cluster 304 304 static inline unsigned get_proc_count( cluster & this ) { return this.procs.constructed; } 305 static inline unsigned get_proc_count() { return publicTLS_get( this_processor )->cltr->procs.constructed; } 305 306 306 307 // set the number of internal processors -
libcfa/src/concurrency/locks.hfa
r0030b508 rfc12f05 182 182 static inline void lock( mcs_spin_lock & l, mcs_spin_node & n ) { 183 183 n.locked = true; 184 185 #if defined(__ARM_ARCH) 186 __asm__ __volatile__ ( "DMB ISH" ::: ); 187 #endif 188 184 189 mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST); 185 190 if( prev == 0p ) return; 186 191 prev->next = &n; 192 193 #if defined(__ARM_ARCH) 194 __asm__ __volatile__ ( "DMB ISH" ::: ); 195 #endif 196 187 197 while( __atomic_load_n(&n.locked, __ATOMIC_RELAXED) ) Pause(); 198 199 #if defined(__ARM_ARCH) 200 __asm__ __volatile__ ( "DMB ISH" ::: ); 201 #endif 188 202 } 189 203 190 204 static inline void unlock(mcs_spin_lock & l, mcs_spin_node & n) { 205 #if defined(__ARM_ARCH) 206 __asm__ __volatile__ ( "DMB ISH" ::: ); 207 #endif 208 191 209 mcs_spin_node * n_ptr = &n; 192 210 if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return; 193 211 while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) Pause(); 212 213 #if defined(__ARM_ARCH) 214 __asm__ __volatile__ ( "DMB ISH" ::: ); 215 #endif 216 194 217 n.next->locked = false; 195 218 } -
libcfa/src/fstream.cfa
r0030b508 rfc12f05 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Aug 18 10:41:17202313 // Update Count : 54 112 // Last Modified On : Wed Oct 18 22:05:54 2023 13 // Update Count : 549 14 14 // 15 15 … … 230 230 void nlOff( ifstream & os ) { os.nlOnOff$ = false; } 231 231 232 void ends( ifstream & is ) {}233 234 232 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; } 235 233 … … 311 309 } // if 312 310 va_end( args ); 311 // if ( len == 0 ) throw ExceptionInst( missing_data ); 313 312 return len; 314 313 } // fmt -
libcfa/src/fstream.hfa
r0030b508 rfc12f05 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Aug 18 10:41:15202313 // Update Count : 2 5812 // Last Modified On : Wed Oct 18 20:30:12 2023 13 // Update Count : 261 14 14 // 15 15 … … 117 117 void nlOn( ifstream & ); 118 118 void nlOff( ifstream & ); 119 void ends( ifstream & );120 119 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 120 ifstream & ungetc( ifstream & is, char c ); 121 bool eof( ifstream & is ); 121 122 122 123 bool fail( ifstream & is ); 123 124 void clear( ifstream & ); 124 bool eof( ifstream & is );125 125 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r" 126 126 void open( ifstream & is, const char name[] ); 127 127 void close( ifstream & is ); 128 129 128 ifstream & read( ifstream & is, char data[], size_t size ); 130 ifstream & ungetc( ifstream & is, char c );131 129 132 130 void ?{}( ifstream & is ); -
libcfa/src/iostream.cfa
r0030b508 rfc12f05 1 2 1 // 3 2 // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo … … 11 10 // Created On : Wed May 27 17:56:53 2015 12 11 // Last Modified By : Peter A. Buhr 13 // Last Modified On : S un Oct 8 12:10:21202314 // Update Count : 1 56412 // Last Modified On : Sat Nov 11 07:06:27 2023 13 // Update Count : 1803 15 14 // 16 15 … … 785 784 return is; 786 785 } // ?|? 787 ISTYPE_VOID_IMPL( bool & )788 786 789 787 istype & ?|?( istype & is, char & c ) { … … 797 795 return is; 798 796 } // ?|? 799 ISTYPE_VOID_IMPL( char & )800 797 801 798 istype & ?|?( istype & is, signed char & sc ) { … … 803 800 return is; 804 801 } // ?|? 805 ISTYPE_VOID_IMPL( signed char & )806 802 807 803 istype & ?|?( istype & is, unsigned char & usc ) { … … 809 805 return is; 810 806 } // ?|? 811 ISTYPE_VOID_IMPL( unsigned char & )812 807 813 808 istype & ?|?( istype & is, short int & si ) { … … 815 810 return is; 816 811 } // ?|? 817 ISTYPE_VOID_IMPL( short int & )818 812 819 813 istype & ?|?( istype & is, unsigned short int & usi ) { … … 821 815 return is; 822 816 } // ?|? 823 ISTYPE_VOID_IMPL( unsigned short int & )824 817 825 818 istype & ?|?( istype & is, int & i ) { … … 827 820 return is; 828 821 } // ?|? 829 ISTYPE_VOID_IMPL( int & )830 822 831 823 istype & ?|?( istype & is, unsigned int & ui ) { … … 833 825 return is; 834 826 } // ?|? 835 ISTYPE_VOID_IMPL( unsigned int & )836 827 837 828 istype & ?|?( istype & is, long int & li ) { … … 839 830 return is; 840 831 } // ?|? 841 ISTYPE_VOID_IMPL( long int & )842 832 843 833 istype & ?|?( istype & is, unsigned long int & ulli ) { … … 845 835 return is; 846 836 } // ?|? 847 ISTYPE_VOID_IMPL( unsigned long int & )848 837 849 838 istype & ?|?( istype & is, long long int & lli ) { … … 851 840 return is; 852 841 } // ?|? 853 ISTYPE_VOID_IMPL( long long int & )854 842 855 843 istype & ?|?( istype & is, unsigned long long int & ulli ) { … … 857 845 return is; 858 846 } // ?|? 859 ISTYPE_VOID_IMPL( unsigned long long int & )860 847 861 848 #if defined( __SIZEOF_INT128__ ) … … 863 850 return (istype &)(is | (unsigned int128 &)llli); 864 851 } // ?|? 865 ISTYPE_VOID_IMPL( int128 & )866 852 867 853 istype & ?|?( istype & is, unsigned int128 & ullli ) { … … 880 866 return is; 881 867 } // ?|? 882 ISTYPE_VOID_IMPL( unsigned int128 & )883 868 #endif // __SIZEOF_INT128__ 884 869 … … 887 872 return is; 888 873 } // ?|? 889 ISTYPE_VOID_IMPL( float & )890 874 891 875 istype & ?|?( istype & is, double & d ) { … … 893 877 return is; 894 878 } // ?|? 895 ISTYPE_VOID_IMPL( double & )896 879 897 880 istype & ?|?( istype & is, long double & ld ) { … … 899 882 return is; 900 883 } // ?|? 901 ISTYPE_VOID_IMPL( long double & )902 884 903 885 istype & ?|?( istype & is, float _Complex & fc ) { … … 907 889 return is; 908 890 } // ?|? 909 ISTYPE_VOID_IMPL( float _Complex & )910 891 911 892 istype & ?|?( istype & is, double _Complex & dc ) { … … 915 896 return is; 916 897 } // ?|? 917 ISTYPE_VOID_IMPL( double _Complex & )918 898 919 899 istype & ?|?( istype & is, long double _Complex & ldc ) { … … 923 903 return is; 924 904 } // ?|? 925 ISTYPE_VOID_IMPL( long double _Complex & )926 905 927 906 istype & ?|?( istype & is, const char fmt[] ) { … … 929 908 return is; 930 909 } // ?|? 931 ISTYPE_VOID_IMPL( const char * )932 910 933 911 // manipulators … … 937 915 938 916 void ?|?( istype & is, istype & (* manip)( istype & ) ) { 939 manip( is ); ends( is );917 manip( is ); 940 918 } // ?|? 941 919 … … 966 944 char fmtstr[ sizeof("%*[]") + nscanset ]; 967 945 int pos = 0; 968 fmtstr[pos] = '%'; pos += 1; 969 fmtstr[pos] = '*'; pos += 1; 970 fmtstr[pos] = '['; pos += 1; 946 strcpy( &fmtstr[pos], "%*[" ); pos += 3; 971 947 strcpy( &fmtstr[pos], f.scanset ); pos += nscanset; 972 fmtstr[pos] = ']'; pos += 1; 973 fmtstr[pos] = '\0'; 974 fmt( is, fmtstr, (void*)0 ); // last arg is dummy: suppress gcc warning 975 } 976 else for ( f.wd ) fmt( is, "%*c" ); 948 strcpy( &fmtstr[pos], "]" ); 949 fmt( is, fmtstr, "" ); // skip scanset 950 } else { 951 char ch; 952 // fprintf( stderr, "skip " ); 953 for ( f.wd ) { // skip N characters 954 if ( eof( is ) ) break; 955 fmt( is, "%c", &ch ); 956 // fprintf( stderr, "`%c' ", ch ); 957 } // for 958 } // if 977 959 return is; 978 960 } 979 ISTYPE_VOID_IMPL( _Istream_Cskip )980 961 981 962 istype & ?|?( istype & is, _Istream_Cstr f ) { 982 const char * scanset = f.scanset; 963 const char * scanset; 964 size_t nscanset = 0; 983 965 if ( f.flags.delimiter ) scanset = f.delimiter; // getline ? 984 985 size_t len = 0; 986 if ( scanset ) len = strlen( scanset ); 987 char fmtstr[len + 16]; 988 int start = 1; 966 else scanset = f.scanset; 967 if ( scanset ) nscanset = strlen( scanset ); 968 969 char fmtstr[nscanset + 32]; // storage for scanset and format codes 989 970 fmtstr[0] = '%'; 990 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 991 // no maximum width necessary because text ignored => width is read width 992 if ( f.wd != -1 ) { 971 972 int pos = 1; 973 int args; 974 bool check = true; 975 976 if ( f.flags.ignore ) { check = false; fmtstr[1] = '*'; pos += 1; } 977 int rwd = f.wd; 978 if ( f.wd != -1 ) { // => just ignore versus ignore with width 993 979 // wd is buffer bytes available (for input chars + null terminator) 994 980 // rwd is count of input chars 995 int rwd; 996 if (f.flags.rwd) { 997 verify (f.wd >= 0); 998 rwd = f.wd; 981 // no maximum width necessary because text ignored => width is read width 982 if ( f.flags.rwd ) check = false; 983 else rwd = f.wd - 1; 984 pos += sprintf( &fmtstr[pos], "%d", rwd ); 985 } // if 986 987 if ( ! scanset ) { // %s, %*s, %ws, %*ws 988 // fprintf( stderr, "cstr %s\n", f.s ); 989 strcpy( &fmtstr[pos], "s%n" ); 990 int len = 0; // may not be set in fmt 991 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 992 else args = fmt( is, fmtstr, f.s, &len ); 993 // fprintf( stderr, "cstr %s %d %d %d %s\n", fmtstr, args, len, f.wd, f.s ); 994 if ( check && len >= rwd && ! eof( is ) ) { // might not fit 995 char peek; 996 fmt( is, "%c", &peek ); // check for whitespace terminator 997 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 998 if ( ! eof( is ) ) { 999 ungetc( is, peek ); 1000 if ( ! isspace( peek ) ) throw ExceptionInst( cstring_length ); 1001 } // if 1002 } // if 1003 // FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed. 1004 if ( rwd > 0 && args == 0 ) f.s[0]= '\0'; // read failed => no pattern match => set string to null 1005 } else { 1006 if ( f.flags.delimiter ) { // getline 1007 // fprintf( stderr, "getline\n" ); 1008 sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset ); 1009 // fprintf( stderr, "getline %s %d\n", fmtstr, f.wd ); 1010 int len = 0; // may not be set in fmt 1011 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1012 else args = fmt( is, fmtstr, f.s, &len ); 1013 // fprintf( stderr, "getline %s %d %d %d\n", fmtstr, args, f.wd, eof( is ) ); 1014 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1015 char peek; 1016 fmt( is, "%c", &peek ); // check for delimiter 1017 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 1018 if ( ! eof( is ) ) { 1019 if ( peek != f.delimiter[0] ) { 1020 ungetc( is, peek ); 1021 throw ExceptionInst( cstring_length ); 1022 } // if 1023 } // if 1024 } else fmt( is, "%*c" ); // remove delimiter 999 1025 } else { 1000 verify (f.wd >= 1); 1001 rwd = f.wd - 1; 1026 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1027 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1028 sprintf( &fmtstr[pos], "[%s%s]%%n", f.flags.inex ? "^" : "", scanset ); 1029 // fprintf( stderr, "incl/excl %s %d\n", fmtstr, f.wd ); 1030 int len = 0; // may not be set in fmt 1031 if ( f.flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*' 1032 else args = fmt( is, fmtstr, f.s, &len ); 1033 // fprintf( stderr, "incl/excl %s \"%s\" %d %d %d %d %d %c\n", fmtstr, f.s, args, f.wd, len, eof( is ), check, f.s[f.wd] ); 1034 if ( check && len == rwd && ! eof( is ) ) { // might not fit 1035 // fprintf( stderr, "overflow\n" ); 1036 char peek; 1037 fmt( is, "%c", &peek ); // check for whitespace terminator 1038 // fprintf( stderr, "peek %d '%c'\n", args, peek ); 1039 if ( ! eof( is ) ) { 1040 ungetc( is, peek ); 1041 if ( f.flags.inex ^ strchr( f.scanset, peek ) != 0p ) throw ExceptionInst( cstring_length ); 1042 } // if 1043 } // if 1002 1044 } // if 1003 start += sprintf( &fmtstr[start], "%d", rwd ); 1004 } 1005 1006 if ( ! scanset ) { 1007 // %s, %*s, %ws, %*ws 1008 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1009 // printf( "cstr %s\n", fmtstr ); 1010 } else { 1011 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1012 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1013 fmtstr[start] = '['; start += 1; 1014 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1015 strcpy( &fmtstr[start], scanset ); // copy includes '\0' 1016 len += start; 1017 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1018 // printf( "incl/excl %s\n", fmtstr ); 1019 } // if 1020 1021 int check = f.wd - 2; 1022 if (! f.flags.ignore ) { 1023 f.s[0] = '\0'; 1024 if ( ! f.flags.rwd ) f.s[check] = '\0'; // insert sentinel 1025 } 1026 len = fmt( is, fmtstr, f.s ); 1027 //fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s ); 1028 1029 if ( ! f.flags.ignore && ! f.flags.rwd && f.s[check] != '\0' ) { // sentinel overwritten ? 1030 // buffer filled, but would we have kept going? 1031 if ( ! eof( is ) ) { 1032 char peek; 1033 fmt( is, "%c", &peek ); 1034 ungetc( is, peek ); 1035 bool hasMore; 1036 if (f.flags.delimiter) { // getline 1037 hasMore = (peek != f.delimiter[0]); 1038 } else if (f.scanset) { // incl/excl 1039 bool peekMatch = strchr(f.scanset, peek) != 0p; 1040 hasMore = f.flags.inex ? (!peekMatch) : (peekMatch); 1041 } else { // %s 1042 hasMore = !isspace(peek); 1043 } 1044 if (hasMore) throw (cstring_length){ &cstring_length_vt }; 1045 } // if 1046 } // if 1047 1048 if ( f.flags.delimiter ) { // getline ? 1049 if ( len == 0 ) f.s[0] = '\0'; // empty read => argument unchanged => set empty 1050 if ( ! eof( is ) ) { // ignore delimiter, may not be present because of width 1051 char delimiter; 1052 fmt( is, "%c", &delimiter ); 1053 if ( delimiter != f.delimiter[0] ) ungetc( is, delimiter ); 1054 } // if 1055 } //if 1056 return is; 1057 } // ?|? 1058 ISTYPE_VOID_IMPL( _Istream_Cstr ) 1045 if ( rwd > 0 && args == 0 ) f.s[0]= '\0'; // read failed => no pattern match => set string to null 1046 } // if 1047 if ( args == 1 && eof( is ) ) { // data but scan ended at EOF 1048 // fprintf( stderr, "clear\n" ); 1049 clear( is ); // => reset EOF => detect again on next read 1050 } // if 1051 return is; 1052 } // ?|? 1059 1053 1060 1054 istype & ?|?( istype & is, _Istream_Char f ) { … … 1062 1056 return is; 1063 1057 } // ?|? 1064 ISTYPE_VOID_IMPL( _Istream_Char )1065 1058 } // distribution 1066 1059 … … 1079 1072 return is; \ 1080 1073 } /* ?|? */ \ 1081 ISTYPE_VOID_IMPL( _Istream_Manip(T) ) \1082 1074 } // distribution 1083 1075 … … 1107 1099 return is; 1108 1100 } // ?|? 1109 ISTYPE_VOID_IMPL( _Istream_Manip(float _Complex) )1110 1101 1111 1102 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { … … 1118 1109 return is; 1119 1110 } // ?|? 1120 ISTYPE_VOID_IMPL( _Istream_Manip(double _Complex) )1121 1111 1122 1112 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { … … 1129 1119 return is; 1130 1120 } // ?|? 1131 ISTYPE_VOID_IMPL( _Istream_Manip(long double _Complex) )1132 1121 } // distribution 1133 1122 -
libcfa/src/iostream.hfa
r0030b508 rfc12f05 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 8 12:02:55202313 // Update Count : 5 6812 // Last Modified On : Wed Oct 18 21:21:20 2023 13 // Update Count : 583 14 14 // 15 15 … … 306 306 // *********************************** istream *********************************** 307 307 308 #define ISTYPE_VOID( T ) void ?|?( istype &, T )309 #define ISTYPE_VOID_IMPL( T ) \310 void ?|?( istype & is, T t ) { \311 (istype &)(is | t); ends( is ); \312 } // ?|?313 314 308 forall( istype & ) 315 309 trait basic_istream { … … 320 314 void nlOn( istype & ); // read newline 321 315 void nlOff( istype & ); // scan newline 322 void ends( istype & os ); // end of output statement323 316 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 324 317 istype & ungetc( istype &, char ); 325 318 bool eof( istype & ); 319 void clear( istype & ); 326 320 }; // basic_istream 327 321 … … 329 323 trait istream { 330 324 bool fail( istype & ); 331 void clear( istype &);325 void open( istype & is, const char name[], const char mode[] ); 332 326 void open( istype & is, const char name[] ); 333 327 void close( istype & is ); … … 342 336 forall( istype & | basic_istream( istype ) ) { 343 337 istype & ?|?( istype &, bool & ); 344 ISTYPE_VOID( bool & );345 338 346 339 istype & ?|?( istype &, char & ); 347 ISTYPE_VOID( char & );348 340 istype & ?|?( istype &, signed char & ); 349 ISTYPE_VOID( signed char & );350 341 istype & ?|?( istype &, unsigned char & ); 351 ISTYPE_VOID( unsigned char & );352 342 353 343 istype & ?|?( istype &, short int & ); 354 ISTYPE_VOID( short int & );355 344 istype & ?|?( istype &, unsigned short int & ); 356 ISTYPE_VOID( unsigned short int & );357 345 istype & ?|?( istype &, int & ); 358 ISTYPE_VOID( int & );359 346 istype & ?|?( istype &, unsigned int & ); 360 ISTYPE_VOID( unsigned int & );361 347 istype & ?|?( istype &, long int & ); 362 ISTYPE_VOID( long int & );363 348 istype & ?|?( istype &, unsigned long int & ); 364 ISTYPE_VOID( unsigned long int & );365 349 istype & ?|?( istype &, long long int & ); 366 ISTYPE_VOID( long long int & );367 350 istype & ?|?( istype &, unsigned long long int & ); 368 ISTYPE_VOID( unsigned long long int & );369 351 #if defined( __SIZEOF_INT128__ ) 370 352 istype & ?|?( istype &, int128 & ); 371 ISTYPE_VOID( int128 & );372 353 istype & ?|?( istype &, unsigned int128 & ); 373 ISTYPE_VOID( unsigned int128 & );374 354 #endif // __SIZEOF_INT128__ 375 355 376 356 istype & ?|?( istype &, float & ); 377 ISTYPE_VOID( float & );378 357 istype & ?|?( istype &, double & ); 379 ISTYPE_VOID( double & );380 358 istype & ?|?( istype &, long double & ); 381 ISTYPE_VOID( long double & );382 359 383 360 istype & ?|?( istype &, float _Complex & ); 384 ISTYPE_VOID( float _Complex & );385 361 istype & ?|?( istype &, double _Complex & ); 386 ISTYPE_VOID( double _Complex & );387 362 istype & ?|?( istype &, long double _Complex & ); 388 ISTYPE_VOID( long double _Complex & );389 363 390 364 istype & ?|?( istype &, const char [] ); 391 ISTYPE_VOID( const char [] );392 365 393 366 // manipulators 394 367 istype & ?|?( istype &, istype & (*)( istype & ) ); 395 ISTYPE_VOID( istype & (*)( istype & ) );396 368 istype & nl( istype & is ); 397 369 istype & nlOn( istype & ); … … 402 374 403 375 ExceptionDecl( cstring_length ); 376 ExceptionDecl( missing_data ); 404 377 405 378 // *********************************** manipulators *********************************** 406 379 380 // skip does not compose with other C string manipulators. 407 381 struct _Istream_Cskip { 408 382 const char * scanset; … … 416 390 forall( istype & | basic_istream( istype ) ) { 417 391 istype & ?|?( istype & is, _Istream_Cskip f ); 418 ISTYPE_VOID( _Istream_Cskip );419 392 } 420 393 … … 458 431 forall( istype & | basic_istream( istype ) ) { 459 432 istype & ?|?( istype & is, _Istream_Cstr f ); 460 ISTYPE_VOID( _Istream_Cstr );461 433 } 462 434 … … 471 443 forall( istype & | basic_istream( istype ) ) { 472 444 istype & ?|?( istype & is, _Istream_Char f ); 473 ISTYPE_VOID( _Istream_Char );474 445 } 475 446 … … 490 461 forall( istype & | basic_istream( istype ) ) { \ 491 462 istype & ?|?( istype & is, _Istream_Manip(T) f ); \ 492 ISTYPE_VOID( _Istream_Manip(T) ); \493 463 } // ?|? 494 464 -
src/AST/Decl.hpp
r0030b508 rfc12f05 125 125 126 126 /// Object declaration `int foo()` 127 class FunctionDecl : public DeclWithType {127 class FunctionDecl final : public DeclWithType { 128 128 public: 129 129 std::vector<ptr<TypeDecl>> type_params; … … 314 314 class EnumDecl final : public AggregateDecl { 315 315 public: 316 bool isTyped;// isTyped indicated if the enum has a declaration like:316 // isTyped indicated if the enum has a declaration like: 317 317 // enum (type_optional) Name {...} 318 ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum 318 bool isTyped; 319 // if isTyped == true && base.get() == nullptr, it is a "void" type enum 320 ptr<Type> base; 319 321 enum class EnumHiding { Visible, Hide } hide; 320 322 … … 374 376 375 377 /// Assembly declaration: `asm ... ( "..." : ... )` 376 class AsmDecl : public Decl {378 class AsmDecl final : public Decl { 377 379 public: 378 380 ptr<AsmStmt> stmt; 379 381 380 382 AsmDecl( const CodeLocation & loc, AsmStmt * stmt ) 381 : Decl( loc, "", {}, {}), stmt(stmt) {}383 : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {} 382 384 383 385 const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); } … … 388 390 389 391 /// C-preprocessor directive `#...` 390 class DirectiveDecl : public Decl {392 class DirectiveDecl final : public Decl { 391 393 public: 392 394 ptr<DirectiveStmt> stmt; 393 395 394 396 DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt ) 395 : Decl( loc, "", {}, {}), stmt(stmt) {}397 : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {} 396 398 397 399 const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); } … … 402 404 403 405 /// Static Assertion `_Static_assert( ... , ... );` 404 class StaticAssertDecl : public Decl {406 class StaticAssertDecl final : public Decl { 405 407 public: 406 408 ptr<Expr> cond; … … 408 410 409 411 StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg ) 410 : Decl( loc, "", {}, {}), cond( condition ), msg( msg ) {}412 : Decl( loc, "", {}, Linkage::C ), cond( condition ), msg( msg ) {} 411 413 412 414 const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Fwd.hpp
r0030b508 rfc12f05 68 68 class MutexStmt; 69 69 class CorunStmt; 70 class CoforStmt; 70 71 71 72 class Expr; -
src/AST/Node.cpp
r0030b508 rfc12f05 194 194 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >; 195 195 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >; 196 template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::weak >; 197 template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::strong >; 196 198 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >; 197 199 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >; -
src/AST/Pass.cpp
r0030b508 rfc12f05 19 19 20 20 PassVisitorStats pass_visitor_stats; 21 // TODO: There was a counter for every syntax node created. 22 // This has not been translated to the new ast. 21 23 // Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr; 22 24 -
src/AST/Pass.hpp
r0030b508 rfc12f05 172 172 const ast::Stmt * visit( const ast::MutexStmt * ) override final; 173 173 const ast::Stmt * visit( const ast::CorunStmt * ) override final; 174 const ast::Stmt * visit( const ast::CoforStmt * ) override final; 174 175 const ast::Expr * visit( const ast::ApplicationExpr * ) override final; 175 176 const ast::Expr * visit( const ast::UntypedExpr * ) override final; -
src/AST/Pass.impl.hpp
r0030b508 rfc12f05 1134 1134 1135 1135 //-------------------------------------------------------------------------- 1136 // CoforStmt 1137 template< typename core_t > 1138 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CoforStmt * node ) { 1139 VISIT_START( node ); 1140 1141 if ( __visit_children() ) { 1142 // for statements introduce a level of scope (for the initialization) 1143 guard_symtab guard { *this }; 1144 maybe_accept( node, &CoforStmt::inits ); 1145 maybe_accept_top( node, &CoforStmt::cond ); 1146 maybe_accept_top( node, &CoforStmt::inc ); 1147 maybe_accept_as_compound( node, &CoforStmt::body ); 1148 } 1149 1150 VISIT_END( Stmt, node ); 1151 } 1152 1153 //-------------------------------------------------------------------------- 1136 1154 // ApplicationExpr 1137 1155 template< typename core_t > -
src/AST/Print.cpp
r0030b508 rfc12f05 934 934 } 935 935 936 virtual const ast::Stmt * visit( const ast::CoforStmt * node ) override final { 937 os << "Cofor Statement" << endl; 938 939 if ( ! node->inits.empty() ) { 940 os << indent << "... initialization:" << endl; 941 ++indent; 942 for ( const ast::Stmt * stmt : node->inits ) { 943 os << indent+1; 944 safe_print( stmt ); 945 } 946 --indent; 947 } 948 949 if ( node->cond ) { 950 os << indent << "... condition:" << endl; 951 ++indent; 952 os << indent; 953 node->cond->accept( *this ); 954 --indent; 955 } 956 957 if ( node->inc ) { 958 os << indent << "... increment:" << endl; 959 ++indent; 960 os << indent; 961 node->inc->accept( *this ); 962 --indent; 963 } 964 965 if ( node->body ) { 966 os << indent << "... with body:" << endl; 967 ++indent; 968 os << indent; 969 node->body->accept( *this ); 970 --indent; 971 } 972 os << endl; 973 print( node->labels ); 974 975 return node; 976 } 977 936 978 virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final { 937 979 ++indent; -
src/AST/Stmt.hpp
r0030b508 rfc12f05 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 29 #define MUTATE_FRIEND \ 30 30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 32 32 … … 340 340 341 341 CatchClause( const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond, 342 342 const Stmt * body ) 343 343 : StmtClause(loc), decl(decl), cond(cond), body(body), kind(kind) {} 344 344 … … 380 380 // Base class of WaitFor/WaitUntil statements 381 381 // form: KEYWORD(...) ... timeout(...) ... else ... 382 class WaitStmt : public Stmt { 383 public: 384 382 class WaitStmt : public Stmt { 383 public: 384 ptr<Expr> timeout_time; 385 385 ptr<Stmt> timeout_stmt; 386 386 ptr<Expr> timeout_cond; … … 388 388 ptr<Expr> else_cond; 389 389 390 390 WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 391 391 : Stmt(loc, std::move(labels)) {} 392 392 393 393 private: 394 394 WaitStmt * clone() const override = 0; 395 395 MUTATE_FRIEND 396 396 }; … … 444 444 class WaitUntilStmt final : public WaitStmt { 445 445 public: 446 447 448 449 struct ClauseNode { 450 451 452 453 454 455 456 457 458 459 460 461 462 : op(op), left(left), right(right), leaf(nullptr), 463 464 465 466 467 468 469 470 471 472 473 446 // Non-ast node used during compilation to store data needed to generate predicates 447 // and set initial status values for clauses 448 // Used to create a tree corresponding to the structure of the clauses in a WaitUntil 449 struct ClauseNode { 450 enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag 451 // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing 452 453 ClauseNode * left; 454 ClauseNode * right; 455 WhenClause * leaf; // only set if this node is a leaf (points into vector of clauses) 456 457 bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses 458 bool whenState; // used to track if when_cond is toggled on or off for generating init values 459 bool childOfAnd; // true on leaf nodes that are children of AND, false otherwise 460 461 ClauseNode( Op op, ClauseNode * left, ClauseNode * right ) 462 : op(op), left(left), right(right), leaf(nullptr), 463 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 464 ClauseNode( Op op, WhenClause * leaf ) 465 : op(op), left(nullptr), right(nullptr), leaf(leaf), 466 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 467 ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {} 468 469 ~ClauseNode() { 470 if ( left ) delete left; 471 if ( right ) delete right; 472 } 473 }; 474 474 475 475 std::vector<ptr<WhenClause>> clauses; 476 476 ClauseNode * predicateTree; 477 477 478 478 WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 479 479 : WaitStmt(loc, std::move(labels)) {} 480 480 481 481 ~WaitUntilStmt() { delete predicateTree; } 482 482 483 483 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 522 522 std::vector<ptr<Expr>> mutexObjs; 523 523 524 MutexStmt( const CodeLocation & loc, const Stmt * stmt, 524 MutexStmt( const CodeLocation & loc, const Stmt * stmt, 525 525 const std::vector<ptr<Expr>> && mutexes, const std::vector<Label> && labels = {} ) 526 526 : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {} … … 543 543 private: 544 544 CorunStmt * clone() const override { return new CorunStmt{ *this }; } 545 MUTATE_FRIEND 546 }; 547 548 // Corun Statement 549 class CoforStmt final : public Stmt { 550 public: 551 std::vector<ptr<Stmt>> inits; 552 ptr<Expr> cond; 553 ptr<Expr> inc; 554 ptr<Stmt> body; 555 556 CoforStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond, 557 const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} ) 558 : Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {} 559 560 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 561 private: 562 CoforStmt * clone() const override { return new CoforStmt{ *this }; } 545 563 MUTATE_FRIEND 546 564 }; -
src/AST/Type.hpp
r0030b508 rfc12f05 34 34 35 35 namespace ast { 36 37 template< typename T > class Pass;38 36 39 37 class Type : public Node { -
src/AST/Visitor.hpp
r0030b508 rfc12f05 60 60 virtual const ast::Stmt * visit( const ast::MutexStmt * ) = 0; 61 61 virtual const ast::Stmt * visit( const ast::CorunStmt * ) = 0; 62 virtual const ast::Stmt * visit( const ast::CoforStmt * ) = 0; 62 63 virtual const ast::Expr * visit( const ast::ApplicationExpr * ) = 0; 63 64 virtual const ast::Expr * visit( const ast::UntypedExpr * ) = 0; -
src/AST/module.mk
r0030b508 rfc12f05 20 20 AST/Bitfield.hpp \ 21 21 AST/Chain.hpp \ 22 AST/Convert.cpp \23 AST/Convert.hpp \24 22 AST/Copy.cpp \ 25 23 AST/Copy.hpp \ -
src/BasicTypes-gen.cc
r0030b508 rfc12f05 117 117 // { LongDoubleImaginary, "LongDoubleImaginary", "LDI", "long double _Imaginary", "Ie", false, LongDoubleComplex, -1, -1, 17 }, 118 118 119 { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 119 { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 120 120 { uFloat128xComplex, "uFloat128xComplex", "_FLDXC", "_Float128x _Complex", "CDF128x_", Floating, -1, -1, -1, 18 } 121 121 }; // graph … … 127 127 void generateCosts( int row ) { 128 128 bool seen[NUMBER_OF_BASIC_TYPES] = { false /*, ... */ }; 129 129 130 130 struct el_cost { 131 131 int i; 132 132 int path; 133 133 int sign; 134 134 135 135 el_cost( int i = 0, int p = 0, int s = 0 ) : i(i), path(p), sign(s) {} 136 136 137 137 // reverse the sense for use in largest-on-top priority queue 138 138 bool operator< (const el_cost& o) const { … … 195 195 return; 196 196 } // if 197 197 198 198 i = graph[col].middle; 199 199 if ( i == -1 ) assert("invalid ancestor assumption"); … … 272 272 size_t start, end; 273 273 274 275 #define TypeH TOP_SRCDIR "src/SynTree/Type.h" 276 resetInput( file, TypeH, buffer, code, str ); 277 278 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH ); 274 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 275 resetInput( file, TypeH_AST, buffer, code, str ); 276 277 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST ); 279 278 start += sizeof( STARTMK ); // includes newline 280 279 code << str.substr( 0, start ); … … 284 283 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 285 284 code << "\t\t" << graph[r].name << "," << endl; 286 } // for 285 } // for 287 286 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl; 288 287 code << "\t} kind;" << endl; 289 288 code << "\t"; // indentation for end marker 290 289 291 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );290 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST ); 292 291 code << str.substr( start ); 293 292 294 output( file, TypeH , code );293 output( file, TypeH_AST, code ); 295 294 // cout << code.str(); 296 295 297 296 298 #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"299 resetInput( file, TypeC , buffer, code, str );300 301 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );297 #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp" 298 resetInput( file, TypeC_AST, buffer, code, str ); 299 300 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST ); 302 301 start += sizeof( STARTMK ); // includes newline 303 302 code << str.substr( 0, start ); … … 307 306 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 308 307 code << "\t\"" << graph[r].type << "\"," << endl; 309 } // for 310 code << "};" << endl; 311 312 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC ); 313 code << str.substr( start ); 314 315 output( file, TypeC, code ); 316 // cout << code.str(); 317 318 319 // TEMPORARY DURING CHANGE OVER 320 #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp" 321 resetInput( file, TypeH_AST, buffer, code, str ); 322 323 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST ); 324 start += sizeof( STARTMK ); // includes newline 325 code << str.substr( 0, start ); 326 327 code << "\t" << BYMK << endl; 328 code << "\tenum Kind {" << endl; 329 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 330 code << "\t\t" << graph[r].name << "," << endl; 331 } // for 332 code << "\t\tNUMBER_OF_BASIC_TYPES" << endl; 333 code << "\t} kind;" << endl; 334 code << "\t"; // indentation for end marker 335 336 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST ); 337 code << str.substr( start ); 338 339 output( file, TypeH_AST, code ); 340 // cout << code.str(); 341 342 343 #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp" 344 resetInput( file, TypeC_AST, buffer, code, str ); 345 346 if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST ); 347 start += sizeof( STARTMK ); // includes newline 348 code << str.substr( 0, start ); 349 350 code << BYMK << endl; 351 code << "const char * BasicType::typeNames[] = {" << endl; 352 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 353 code << "\t\"" << graph[r].type << "\"," << endl; 354 } // for 308 } // for 355 309 code << "};" << endl; 356 310 … … 391 345 end += sizeof( STARTMK ); 392 346 code << str.substr( start, end - start ); 393 347 394 348 code << "\t" << BYMK << endl; 395 code << "\tstatic const int costMatrix[ BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl349 code << "\tstatic const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl 396 350 << "\t\t/* "; 397 351 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 411 365 code << "\tstatic const int maxIntCost = " << *max_element(costMatrix[SignedInt], costMatrix[SignedInt] + NUMBER_OF_BASIC_TYPES) << ";" << endl; 412 366 code << "\t"; // indentation for end marker 413 367 414 368 if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ConversionCost ); 415 369 if ( (end = str.find( STARTMK, start + 1 )) == string::npos ) Abort( "start", ConversionCost ); … … 418 372 419 373 code << "\t" << BYMK << endl; 420 code << "\tstatic const int signMatrix[ BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl374 code << "\tstatic const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl 421 375 << "\t\t/* "; 422 376 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 450 404 enum { PER_ROW = 6 }; 451 405 code << "\t" << BYMK << endl; 452 code << "\t#define BT BasicType::" << endl;453 code << "\tstatic const B asicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl406 code << "\t#define BT ast::BasicType::" << endl; 407 code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl 454 408 << "\t\t/*\t\t "; 455 409 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles … … 505 459 "\t\t\t// - \"Di\" char32_t\n" 506 460 "\t\t\t// - \"Ds\" char16_t\n"; 507 508 code << "\t\t\tconst std::string basicTypes[ BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;461 462 code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl; 509 463 for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { 510 464 code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl; 511 } // for 465 } // for 512 466 code << "\t\t\t}; // basicTypes" << endl; 513 467 code << "\t\t\t"; // indentation for end marker -
src/CodeGen/FixMain.cc
r0030b508 rfc12f05 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.cc -- 7 // FixMain.cc -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 13 13 // Update Count : 0 14 14 // 15 16 15 17 16 #include "FixMain.h" … … 23 22 24 23 #include "AST/Decl.hpp" 24 #include "AST/Pass.hpp" 25 25 #include "AST/Type.hpp" 26 #include " Common/PassVisitor.h"26 #include "AST/Vector.hpp" 27 27 #include "Common/SemanticError.h" // for SemanticError 28 28 #include "CodeGen/GenType.h" // for GenType 29 #include "SynTree/Declaration.h" // for FunctionDecl, operator<<30 #include "SynTree/Type.h" // for FunctionType31 29 #include "SymTab/Mangler.h" 32 30 … … 35 33 namespace { 36 34 37 struct FindMainCore {38 FunctionDecl * main_signature= nullptr;35 struct FindMainCore final { 36 ast::FunctionDecl const * main_declaration = nullptr; 39 37 40 void previsit( FunctionDecl* decl ) {41 if ( FixMain::isMain( decl ) ) {42 if ( main_ signature) {38 void previsit( ast::FunctionDecl const * decl ) { 39 if ( isMain( decl ) ) { 40 if ( main_declaration ) { 43 41 SemanticError( decl, "Multiple definition of main routine\n" ); 44 42 } 45 main_ signature= decl;43 main_declaration = decl; 46 44 } 47 45 } 48 46 }; 49 47 48 std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) { 49 return genType( types[at], "", Options( false, false, false, false ) ); 50 50 } 51 51 52 template<typename container> 53 std::string genTypeAt(const container& p, size_t idx) { 54 return genType((*std::next(p.begin(), idx))->get_type(), ""); 55 } 56 57 void FixMain::fix( std::list< Declaration * > & translationUnit, 58 std::ostream &os, const char* bootloader_filename ) { 59 PassVisitor< FindMainCore > main_finder; 60 acceptAll( translationUnit, main_finder ); 61 FunctionDecl * main_signature = main_finder.pass.main_signature; 62 63 if( main_signature ) { 64 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 65 main_signature->mangleName = SymTab::Mangler::mangle(main_signature); 66 67 os << main_signature->get_scopedMangleName() << "("; 68 const auto& params = main_signature->get_functionType()->get_parameters(); 69 switch(params.size()) { 70 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break; 71 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break; 72 case 0: break; 73 default : assert(false); 74 } 75 os << "); }\n"; 76 77 std::ifstream bootloader(bootloader_filename, std::ios::in); 78 assertf( bootloader.is_open(), "cannot open bootloader.c\n" ); 79 os << bootloader.rdbuf(); 80 } 81 } 82 83 namespace { 84 85 ObjectDecl * signedIntObj() { 86 return new ObjectDecl( 87 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 88 new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ); 52 ast::ObjectDecl * makeIntObj(){ 53 return new ast::ObjectDecl( CodeLocation(), "", 54 new ast::BasicType( ast::BasicType::SignedInt ) ); 89 55 } 90 56 91 ObjectDecl * makeArgvObj() { 92 return new ObjectDecl( 93 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 94 new PointerType( Type::Qualifiers(), 95 new PointerType( Type::Qualifiers(), 96 new BasicType( Type::Qualifiers(), BasicType::Char ) ) ), 97 nullptr ); 57 ast::ObjectDecl * makeCharStarStarObj() { 58 return new ast::ObjectDecl( CodeLocation(), "", 59 new ast::PointerType( 60 new ast::PointerType( 61 new ast::BasicType( ast::BasicType::Char ) ) ) ); 98 62 } 99 63 100 std::string create_mangled_main_function_name( FunctionType * function_type ) { 101 std::unique_ptr<FunctionDecl> decl( new FunctionDecl( 102 "main", Type::StorageClasses(), LinkageSpec::Cforall, 103 function_type, nullptr ) ); 104 return SymTab::Mangler::mangle( decl.get() ); 64 std::string getMangledNameOfMain( 65 ast::vector<ast::DeclWithType> && params, ast::ArgumentFlag isVarArgs ) { 66 ast::ptr<ast::FunctionDecl> decl = new ast::FunctionDecl( 67 CodeLocation(), 68 "main", 69 ast::vector<ast::TypeDecl>(), 70 ast::vector<ast::DeclWithType>(), 71 std::move( params ), 72 { makeIntObj() }, 73 nullptr, 74 ast::Storage::Classes(), 75 ast::Linkage::Spec(), 76 ast::vector<ast::Attribute>(), 77 ast::Function::Specs(), 78 isVarArgs 79 ); 80 return Mangle::mangle( decl.get() ); 105 81 } 106 82 107 std::string mangled_0_argument_main() { 108 FunctionType* main_type = new FunctionType( Type::Qualifiers(), true ); 109 main_type->get_returnVals().push_back( signedIntObj() ); 110 return create_mangled_main_function_name( main_type ); 83 std::string getMangledNameOf0ParameterMain() { 84 return getMangledNameOfMain( {}, ast::VariableArgs ); 111 85 } 112 86 113 std::string mangled_2_argument_main() { 114 FunctionType* main_type = new FunctionType( Type::Qualifiers(), false ); 115 main_type->get_returnVals().push_back( signedIntObj() ); 116 main_type->get_parameters().push_back( signedIntObj() ); 117 main_type->get_parameters().push_back( makeArgvObj() ); 118 return create_mangled_main_function_name( main_type ); 87 std::string getMangledNameOf2ParameterMain() { 88 return getMangledNameOfMain( { 89 makeIntObj(), 90 makeCharStarStarObj(), 91 }, ast::FixedArgs ); 119 92 } 120 93 … … 122 95 // This breaks if you move it out of the function. 123 96 static const std::string mangled_mains[] = { 124 mangled_0_argument_main(),125 mangled_2_argument_main(),126 // mangled_3_argument_main(),97 getMangledNameOf0ParameterMain(), 98 getMangledNameOf2ParameterMain(), 99 //getMangledNameOf3ParameterMain(), 127 100 }; 128 101 … … 133 106 } 134 107 108 struct FixLinkageCore final { 109 ast::Linkage::Spec const spec; 110 FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {} 111 112 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) { 113 if ( decl->name != "main" ) return decl; 114 return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec ); 115 } 116 }; 117 135 118 } // namespace 136 119 137 bool FixMain::isMain( FunctionDecl * decl ) { 138 if ( std::string("main") != decl->name ) { 139 return false; 140 } 141 return is_main( SymTab::Mangler::mangle( decl, true, true ) ); 142 } 143 144 bool FixMain::isMain( const ast::FunctionDecl * decl ) { 120 bool isMain( const ast::FunctionDecl * decl ) { 145 121 if ( std::string("main") != decl->name ) { 146 122 return false; … … 149 125 } 150 126 151 }; 127 void fixMainLinkage( ast::TranslationUnit & translationUnit, 128 bool replace_main ) { 129 ast::Linkage::Spec const spec = 130 ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C; 131 ast::Pass<FixLinkageCore>::run( translationUnit, spec ); 132 } 133 134 void fixMainInvoke( ast::TranslationUnit & translationUnit, 135 std::ostream &os, const char * bootloader_filename ) { 136 137 ast::Pass<FindMainCore> main_finder; 138 ast::accept_all( translationUnit, main_finder ); 139 if ( nullptr == main_finder.core.main_declaration ) return; 140 141 ast::FunctionDecl * main_declaration = 142 ast::mutate( main_finder.core.main_declaration ); 143 144 main_declaration->mangleName = Mangle::mangle( main_declaration ); 145 146 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 147 os << main_declaration->scopedMangleName() << "("; 148 const auto& params = main_declaration->type->params; 149 switch ( params.size() ) { 150 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break; 151 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break; 152 case 0: break; 153 default : assert(false); 154 } 155 os << "); }\n"; 156 157 std::ifstream bootloader( bootloader_filename, std::ios::in ); 158 assertf( bootloader.is_open(), "cannot open bootloader.c\n" ); 159 os << bootloader.rdbuf(); 160 } 161 162 } // namespace CodeGen -
src/CodeGen/FixMain.h
r0030b508 rfc12f05 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // FixMain.h -- 7 // FixMain.h -- Tools to change a Cforall main into a C main. 8 8 // 9 9 // Author : Thierry Delisle … … 17 17 18 18 #include <iosfwd> 19 #include <memory>20 #include <list>21 19 22 #include "SynTree/LinkageSpec.h"23 24 class Declaration;25 class FunctionDecl;26 20 namespace ast { 27 21 class FunctionDecl; 22 class TranslationUnit; 28 23 } 29 24 30 25 namespace CodeGen { 31 26 32 class FixMain { 33 public : 34 static inline LinkageSpec::Spec mainLinkage() { 35 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C; 36 } 27 /// Is this function a program main function? 28 bool isMain( const ast::FunctionDecl * decl ); 37 29 38 static inline void setReplaceMain(bool val) { 39 replace_main = val; 40 } 30 /// Adjust the linkage of main functions. 31 void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain ); 41 32 42 static bool isMain(FunctionDecl* decl); 43 static bool isMain(const ast::FunctionDecl * decl); 44 45 static void fix( std::list< Declaration * > & decls, 46 std::ostream &os, const char* bootloader_filename ); 47 48 private: 49 static bool replace_main; 50 }; 33 /// Add a wrapper around to run the Cforall main. 34 void fixMainInvoke( ast::TranslationUnit & transUnit, 35 std::ostream & os, const char * bootloaderFilename ); 51 36 52 37 } // namespace CodeGen -
src/CodeGen/FixNames.cc
r0030b508 rfc12f05 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h"25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "FixMain.h" // for FixMain 27 26 #include "SymTab/Mangler.h" // for Mangler 28 #include "SynTree/LinkageSpec.h" // for Cforall, isMangled29 #include "SynTree/Constant.h" // for Constant30 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarat...31 #include "SynTree/Expression.h" // for ConstantExpr32 #include "SynTree/Label.h" // for Label, noLabels33 #include "SynTree/Statement.h" // for ReturnStmt, CompoundStmt34 #include "SynTree/Type.h" // for Type, BasicType, Type::Qualifiers35 #include "SynTree/Visitor.h" // for Visitor, acceptAll36 27 #include "CompilationState.h" 37 28 38 29 namespace CodeGen { 39 class FixNames : public WithGuards {40 public:41 void postvisit( ObjectDecl *objectDecl );42 void postvisit( FunctionDecl *functionDecl );43 30 44 void previsit( CompoundStmt *compoundStmt ); 45 private: 46 int scopeLevel = 1; 47 48 void fixDWT( DeclarationWithType *dwt ); 49 }; 50 51 void fixNames( std::list< Declaration* > & translationUnit ) { 52 PassVisitor<FixNames> fixer; 53 acceptAll( translationUnit, fixer ); 54 } 55 56 void FixNames::fixDWT( DeclarationWithType * dwt ) { 57 if ( dwt->get_name() != "" ) { 58 if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) { 59 if (!useNewAST) { 60 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) ); 61 } 62 dwt->set_scopeLevel( scopeLevel ); 63 } // if 64 } // if 65 } 66 67 void FixNames::postvisit( ObjectDecl * objectDecl ) { 68 fixDWT( objectDecl ); 69 } 70 71 void FixNames::postvisit( FunctionDecl * functionDecl ) { 72 fixDWT( functionDecl ); 73 74 if ( FixMain::isMain( functionDecl ) ) { 75 int nargs = functionDecl->get_functionType()->get_parameters().size(); 76 if( !(nargs == 0 || nargs == 2 || nargs == 3) ) { 77 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n"); 78 } 79 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) ); 80 } 81 } 82 83 void FixNames::previsit( CompoundStmt * ) { 84 scopeLevel++; 85 GuardAction( [this](){ scopeLevel--; } ); 86 } 31 namespace { 87 32 88 33 /// Does work with the main function and scopeLevels. 89 class FixNames _newfinal {34 class FixNames final { 90 35 int scopeLevel = 1; 91 36 … … 103 48 104 49 const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) { 105 if ( FixMain::isMain( functionDecl ) ) {50 if ( isMain( functionDecl ) ) { 106 51 auto mutDecl = ast::mutate( functionDecl ); 107 52 … … 138 83 }; 139 84 85 } // namespace 86 140 87 void fixNames( ast::TranslationUnit & translationUnit ) { 141 ast::Pass<FixNames _new>::run( translationUnit );88 ast::Pass<FixNames>::run( translationUnit ); 142 89 } 143 90 -
src/CodeGen/FixNames.h
r0030b508 rfc12f05 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 18 namespace ast { 22 19 class TranslationUnit; … … 24 21 25 22 namespace CodeGen { 26 /// mangles object and function names 27 void fixNames( std::list< Declaration* > & translationUnit ); 23 28 24 /// Sets scope levels and fills in main's default return. 29 25 void fixNames( ast::TranslationUnit & translationUnit ); 26 30 27 } // namespace CodeGen 31 28 -
src/CodeGen/GenType.cc
r0030b508 rfc12f05 19 19 #include <sstream> // for operator<<, ostringstream, basic_os... 20 20 21 #include "CodeGenerator.h" // for CodeGenerator 22 #include "SynTree/Declaration.h" // for DeclarationWithType 23 #include "SynTree/Expression.h" // for Expression 24 #include "SynTree/Type.h" // for PointerType, Type, FunctionType 25 #include "SynTree/Visitor.h" // for Visitor 21 #include "AST/Print.hpp" // for print 22 #include "AST/Vector.hpp" // for vector 23 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new 24 #include "Common/UniqueName.h" // for UniqueName 26 25 27 26 namespace CodeGen { 28 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 29 std::string typeString; 30 GenType( const std::string &typeString, const Options &options ); 31 32 void previsit( BaseSyntaxNode * ); 33 void postvisit( BaseSyntaxNode * ); 34 35 void postvisit( FunctionType * funcType ); 36 void postvisit( VoidType * voidType ); 37 void postvisit( BasicType * basicType ); 38 void postvisit( PointerType * pointerType ); 39 void postvisit( ArrayType * arrayType ); 40 void postvisit( ReferenceType * refType ); 41 void postvisit( StructInstType * structInst ); 42 void postvisit( UnionInstType * unionInst ); 43 void postvisit( EnumInstType * enumInst ); 44 void postvisit( TypeInstType * typeInst ); 45 void postvisit( TupleType * tupleType ); 46 void postvisit( VarArgsType * varArgsType ); 47 void postvisit( ZeroType * zeroType ); 48 void postvisit( OneType * oneType ); 49 void postvisit( GlobalScopeType * globalType ); 50 void postvisit( TraitInstType * inst ); 51 void postvisit( TypeofType * typeof ); 52 void postvisit( VTableType * vtable ); 53 void postvisit( QualifiedType * qualType ); 54 55 private: 56 void handleQualifiers( Type *type ); 57 std::string handleGeneric( ReferenceToType * refType ); 58 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 59 60 Options options; 61 }; 62 63 std::string genType( Type *type, const std::string &baseString, const Options &options ) { 64 PassVisitor<GenType> gt( baseString, options ); 27 28 namespace { 29 30 #warning Remove the _new when old version is removed. 31 struct GenType_new : 32 public ast::WithShortCircuiting, 33 public ast::WithVisitorRef<GenType_new> { 34 std::string result; 35 GenType_new( const std::string &typeString, const Options &options ); 36 37 void previsit( ast::Node const * ); 38 void postvisit( ast::Node const * ); 39 40 void postvisit( ast::FunctionType const * type ); 41 void postvisit( ast::VoidType const * type ); 42 void postvisit( ast::BasicType const * type ); 43 void postvisit( ast::PointerType const * type ); 44 void postvisit( ast::ArrayType const * type ); 45 void postvisit( ast::ReferenceType const * type ); 46 void postvisit( ast::StructInstType const * type ); 47 void postvisit( ast::UnionInstType const * type ); 48 void postvisit( ast::EnumInstType const * type ); 49 void postvisit( ast::TypeInstType const * type ); 50 void postvisit( ast::TupleType const * type ); 51 void postvisit( ast::VarArgsType const * type ); 52 void postvisit( ast::ZeroType const * type ); 53 void postvisit( ast::OneType const * type ); 54 void postvisit( ast::GlobalScopeType const * type ); 55 void postvisit( ast::TraitInstType const * type ); 56 void postvisit( ast::TypeofType const * type ); 57 void postvisit( ast::VTableType const * type ); 58 void postvisit( ast::QualifiedType const * type ); 59 60 private: 61 void handleQualifiers( ast::Type const *type ); 62 std::string handleGeneric( ast::BaseInstType const * type ); 63 void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic ); 64 std::string genParamList( const ast::vector<ast::Type> & ); 65 66 Options options; 67 }; 68 69 GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {} 70 71 void GenType_new::previsit( ast::Node const * ) { 72 // Turn off automatic recursion for all nodes, to allow each visitor to 73 // precisely control the order in which its children are visited. 74 visit_children = false; 75 } 76 77 void GenType_new::postvisit( ast::Node const * node ) { 78 std::stringstream ss; 79 ast::print( ss, node ); 80 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 81 } 82 83 void GenType_new::postvisit( ast::VoidType const * type ) { 84 result = "void " + result; 85 handleQualifiers( type ); 86 } 87 88 void GenType_new::postvisit( ast::BasicType const * type ) { 89 ast::BasicType::Kind kind = type->kind; 90 assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES ); 91 result = std::string( ast::BasicType::typeNames[kind] ) + " " + result; 92 handleQualifiers( type ); 93 } 94 95 void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) { 96 std::ostringstream os; 97 if ( result != "" ) { 98 if ( result[ 0 ] == '*' ) { 99 os << "(" << result << ")"; 100 } else { 101 os << result; 102 } 103 } 104 os << "["; 105 if ( isStatic ) { 106 os << "static "; 107 } 108 if ( qualifiers.is_const ) { 109 os << "const "; 110 } 111 if ( qualifiers.is_volatile ) { 112 os << "volatile "; 113 } 114 if ( qualifiers.is_restrict ) { 115 os << "__restrict "; 116 } 117 if ( qualifiers.is_atomic ) { 118 os << "_Atomic "; 119 } 120 if ( dimension != 0 ) { 121 ast::Pass<CodeGenerator_new>::read( dimension, os, options ); 122 } else if ( isVarLen ) { 123 // no dimension expression on a VLA means it came in with the * token 124 os << "*"; 125 } 126 os << "]"; 127 128 result = os.str(); 129 130 base->accept( *visitor ); 131 } 132 133 void GenType_new::postvisit( ast::PointerType const * type ) { 134 if ( type->isStatic || type->isVarLen || type->dimension ) { 135 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 136 } else { 137 handleQualifiers( type ); 138 if ( result[ 0 ] == '?' ) { 139 result = "* " + result; 140 } else { 141 result = "*" + result; 142 } 143 type->base->accept( *visitor ); 144 } 145 } 146 147 void GenType_new::postvisit( ast::ArrayType const * type ) { 148 genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic ); 149 } 150 151 void GenType_new::postvisit( ast::ReferenceType const * type ) { 152 assertf( !options.genC, "Reference types should not reach code generation." ); 153 handleQualifiers( type ); 154 result = "&" + result; 155 type->base->accept( *visitor ); 156 } 157 158 void GenType_new::postvisit( ast::FunctionType const * type ) { 159 std::ostringstream os; 160 161 if ( result != "" ) { 162 if ( result[ 0 ] == '*' ) { 163 os << "(" << result << ")"; 164 } else { 165 os << result; 166 } 167 } 168 169 if ( type->params.empty() ) { 170 if ( type->isVarArgs ) { 171 os << "()"; 172 } else { 173 os << "(void)"; 174 } 175 } else { 176 os << "(" ; 177 178 os << genParamList( type->params ); 179 180 if ( type->isVarArgs ) { 181 os << ", ..."; 182 } 183 os << ")"; 184 } 185 186 result = os.str(); 187 188 if ( type->returns.size() == 0 ) { 189 result = "void " + result; 190 } else { 191 type->returns.front()->accept( *visitor ); 192 } 193 194 // Add forall clause. 195 if( !type->forall.empty() && !options.genC ) { 196 //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." ); 65 197 std::ostringstream os; 66 67 if ( ! type->get_attributes().empty() ) { 68 PassVisitor<CodeGenerator> cg( os, options ); 69 cg.pass.genAttributes( type->get_attributes() ); 70 } // if 71 72 type->accept( gt ); 73 return os.str() + gt.pass.typeString; 74 } 75 76 std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) { 77 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) ); 78 } 79 80 std::string genPrettyType( Type * type, const std::string & baseString ) { 81 return genType( type, baseString, true, false ); 82 } 83 84 GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {} 85 86 // *** BaseSyntaxNode 87 void GenType::previsit( BaseSyntaxNode * ) { 88 // turn off automatic recursion for all nodes, to allow each visitor to 89 // precisely control the order in which its children are visited. 90 visit_children = false; 91 } 92 93 void GenType::postvisit( BaseSyntaxNode * node ) { 94 std::stringstream ss; 95 node->print( ss ); 96 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 97 } 98 99 void GenType::postvisit( VoidType * voidType ) { 100 typeString = "void " + typeString; 101 handleQualifiers( voidType ); 102 } 103 104 void GenType::postvisit( BasicType * basicType ) { 105 BasicType::Kind kind = basicType->kind; 106 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES ); 107 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString; 108 handleQualifiers( basicType ); 109 } 110 111 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) { 198 ast::Pass<CodeGenerator_new> cg( os, options ); 199 os << "forall("; 200 cg.core.genCommaList( type->forall ); 201 os << ")" << std::endl; 202 result = os.str() + result; 203 } 204 } 205 206 std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) { 207 if ( !type->params.empty() ) { 112 208 std::ostringstream os; 113 if ( typeString != "" ) { 114 if ( typeString[ 0 ] == '*' ) { 115 os << "(" << typeString << ")"; 116 } else { 117 os << typeString; 118 } // if 119 } // if 120 os << "["; 121 122 if ( isStatic ) { 123 os << "static "; 124 } // if 125 if ( qualifiers.is_const ) { 126 os << "const "; 127 } // if 128 if ( qualifiers.is_volatile ) { 129 os << "volatile "; 130 } // if 131 if ( qualifiers.is_restrict ) { 132 os << "__restrict "; 133 } // if 134 if ( qualifiers.is_atomic ) { 135 os << "_Atomic "; 136 } // if 137 if ( dimension != 0 ) { 138 PassVisitor<CodeGenerator> cg( os, options ); 139 dimension->accept( cg ); 140 } else if ( isVarLen ) { 141 // no dimension expression on a VLA means it came in with the * token 142 os << "*"; 143 } // if 144 os << "]"; 145 146 typeString = os.str(); 147 148 base->accept( *visitor ); 149 } 150 151 void GenType::postvisit( PointerType * pointerType ) { 152 assert( pointerType->base != 0); 153 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) { 154 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() ); 155 } else { 156 handleQualifiers( pointerType ); 157 if ( typeString[ 0 ] == '?' ) { 158 typeString = "* " + typeString; 159 } else { 160 typeString = "*" + typeString; 161 } // if 162 pointerType->base->accept( *visitor ); 163 } // if 164 } 165 166 void GenType::postvisit( ArrayType * arrayType ) { 167 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() ); 168 } 169 170 void GenType::postvisit( ReferenceType * refType ) { 171 assert( 0 != refType->base ); 172 assertf( ! options.genC, "Reference types should not reach code generation." ); 173 handleQualifiers( refType ); 174 typeString = "&" + typeString; 175 refType->base->accept( *visitor ); 176 } 177 178 void GenType::postvisit( FunctionType * funcType ) { 179 std::ostringstream os; 180 181 if ( typeString != "" ) { 182 if ( typeString[ 0 ] == '*' ) { 183 os << "(" << typeString << ")"; 184 } else { 185 os << typeString; 186 } // if 187 } // if 188 189 /************* parameters ***************/ 190 191 const std::list<DeclarationWithType *> &pars = funcType->parameters; 192 193 if ( pars.empty() ) { 194 if ( funcType->get_isVarArgs() ) { 195 os << "()"; 196 } else { 197 os << "(void)"; 198 } // if 199 } else { 200 PassVisitor<CodeGenerator> cg( os, options ); 201 os << "(" ; 202 203 cg.pass.genCommaList( pars.begin(), pars.end() ); 204 205 if ( funcType->get_isVarArgs() ) { 206 os << ", ..."; 207 } // if 208 os << ")"; 209 } // if 210 211 typeString = os.str(); 212 213 if ( funcType->returnVals.size() == 0 ) { 214 typeString = "void " + typeString; 215 } else { 216 funcType->returnVals.front()->get_type()->accept( *visitor ); 217 } // if 218 219 // add forall 220 if( ! funcType->forall.empty() && ! options.genC ) { 221 // assertf( ! genC, "Aggregate type parameters should not reach code generation." ); 222 std::ostringstream os; 223 PassVisitor<CodeGenerator> cg( os, options ); 224 os << "forall("; 225 cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() ); 226 os << ")" << std::endl; 227 typeString = os.str() + typeString; 228 } 229 } 230 231 std::string GenType::handleGeneric( ReferenceToType * refType ) { 232 if ( ! refType->parameters.empty() ) { 233 std::ostringstream os; 234 PassVisitor<CodeGenerator> cg( os, options ); 235 os << "("; 236 cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); 237 os << ") "; 238 return os.str(); 239 } 240 return ""; 241 } 242 243 void GenType::postvisit( StructInstType * structInst ) { 244 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString; 245 if ( options.genC ) typeString = "struct " + typeString; 246 handleQualifiers( structInst ); 247 } 248 249 void GenType::postvisit( UnionInstType * unionInst ) { 250 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString; 251 if ( options.genC ) typeString = "union " + typeString; 252 handleQualifiers( unionInst ); 253 } 254 255 void GenType::postvisit( EnumInstType * enumInst ) { 256 if ( enumInst->baseEnum && enumInst->baseEnum->base ) { 257 typeString = genType(enumInst->baseEnum->base, typeString, options); 258 } else { 259 typeString = enumInst->name + " " + typeString; 260 if ( options.genC ) { 261 typeString = "enum " + typeString; 262 } 263 } 264 handleQualifiers( enumInst ); 265 } 266 267 void GenType::postvisit( TypeInstType * typeInst ) { 268 assertf( ! options.genC, "Type instance types should not reach code generation." ); 269 typeString = typeInst->name + " " + typeString; 270 handleQualifiers( typeInst ); 271 } 272 273 void GenType::postvisit( TupleType * tupleType ) { 274 assertf( ! options.genC, "Tuple types should not reach code generation." ); 275 unsigned int i = 0; 276 std::ostringstream os; 277 os << "["; 278 for ( Type * t : *tupleType ) { 279 i++; 280 os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", "); 281 } 282 os << "] "; 283 typeString = os.str() + typeString; 284 } 285 286 void GenType::postvisit( VarArgsType * varArgsType ) { 287 typeString = "__builtin_va_list " + typeString; 288 handleQualifiers( varArgsType ); 289 } 290 291 void GenType::postvisit( ZeroType * zeroType ) { 292 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 293 typeString = (options.pretty ? "zero_t " : "long int ") + typeString; 294 handleQualifiers( zeroType ); 295 } 296 297 void GenType::postvisit( OneType * oneType ) { 298 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 299 typeString = (options.pretty ? "one_t " : "long int ") + typeString; 300 handleQualifiers( oneType ); 301 } 302 303 void GenType::postvisit( GlobalScopeType * globalType ) { 304 assertf( ! options.genC, "Global scope type should not reach code generation." ); 305 handleQualifiers( globalType ); 306 } 307 308 void GenType::postvisit( TraitInstType * inst ) { 309 assertf( ! options.genC, "Trait types should not reach code generation." ); 310 typeString = inst->name + " " + typeString; 311 handleQualifiers( inst ); 312 } 313 314 void GenType::postvisit( TypeofType * typeof ) { 315 std::ostringstream os; 316 PassVisitor<CodeGenerator> cg( os, options ); 317 os << "typeof("; 318 typeof->expr->accept( cg ); 319 os << ") " << typeString; 320 typeString = os.str(); 321 handleQualifiers( typeof ); 322 } 323 324 void GenType::postvisit( VTableType * vtable ) { 325 assertf( ! options.genC, "Virtual table types should not reach code generation." ); 326 std::ostringstream os; 327 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString; 328 typeString = os.str(); 329 handleQualifiers( vtable ); 330 } 331 332 void GenType::postvisit( QualifiedType * qualType ) { 333 assertf( ! options.genC, "Qualified types should not reach code generation." ); 334 std::ostringstream os; 335 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString; 336 typeString = os.str(); 337 handleQualifiers( qualType ); 338 } 339 340 void GenType::handleQualifiers( Type * type ) { 341 if ( type->get_const() ) { 342 typeString = "const " + typeString; 343 } // if 344 if ( type->get_volatile() ) { 345 typeString = "volatile " + typeString; 346 } // if 347 if ( type->get_restrict() ) { 348 typeString = "__restrict " + typeString; 349 } // if 350 if ( type->get_atomic() ) { 351 typeString = "_Atomic " + typeString; 352 } // if 353 } 209 ast::Pass<CodeGenerator_new> cg( os, options ); 210 os << "("; 211 cg.core.genCommaList( type->params ); 212 os << ") "; 213 return os.str(); 214 } 215 return ""; 216 } 217 218 void GenType_new::postvisit( ast::StructInstType const * type ) { 219 result = type->name + handleGeneric( type ) + " " + result; 220 if ( options.genC ) result = "struct " + result; 221 handleQualifiers( type ); 222 } 223 224 void GenType_new::postvisit( ast::UnionInstType const * type ) { 225 result = type->name + handleGeneric( type ) + " " + result; 226 if ( options.genC ) result = "union " + result; 227 handleQualifiers( type ); 228 } 229 230 void GenType_new::postvisit( ast::EnumInstType const * type ) { 231 if ( type->base && type->base->base ) { 232 result = genType( type->base->base, result, options ); 233 } else { 234 result = type->name + " " + result; 235 if ( options.genC ) { 236 result = "enum " + result; 237 } 238 } 239 handleQualifiers( type ); 240 } 241 242 void GenType_new::postvisit( ast::TypeInstType const * type ) { 243 assertf( !options.genC, "TypeInstType should not reach code generation." ); 244 result = type->name + " " + result; 245 handleQualifiers( type ); 246 } 247 248 void GenType_new::postvisit( ast::TupleType const * type ) { 249 assertf( !options.genC, "TupleType should not reach code generation." ); 250 unsigned int i = 0; 251 std::ostringstream os; 252 os << "["; 253 for ( ast::ptr<ast::Type> const & t : type->types ) { 254 i++; 255 os << genType( t, "", options ) << (i == type->size() ? "" : ", "); 256 } 257 os << "] "; 258 result = os.str() + result; 259 } 260 261 void GenType_new::postvisit( ast::VarArgsType const * type ) { 262 result = "__builtin_va_list " + result; 263 handleQualifiers( type ); 264 } 265 266 void GenType_new::postvisit( ast::ZeroType const * type ) { 267 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 268 result = (options.pretty ? "zero_t " : "long int ") + result; 269 handleQualifiers( type ); 270 } 271 272 void GenType_new::postvisit( ast::OneType const * type ) { 273 // Ideally these wouldn't hit codegen at all, but should be safe to make them ints. 274 result = (options.pretty ? "one_t " : "long int ") + result; 275 handleQualifiers( type ); 276 } 277 278 void GenType_new::postvisit( ast::GlobalScopeType const * type ) { 279 assertf( !options.genC, "GlobalScopeType should not reach code generation." ); 280 handleQualifiers( type ); 281 } 282 283 void GenType_new::postvisit( ast::TraitInstType const * type ) { 284 assertf( !options.genC, "TraitInstType should not reach code generation." ); 285 result = type->name + " " + result; 286 handleQualifiers( type ); 287 } 288 289 void GenType_new::postvisit( ast::TypeofType const * type ) { 290 std::ostringstream os; 291 os << "typeof("; 292 ast::Pass<CodeGenerator_new>::read( type, os, options ); 293 os << ") " << result; 294 result = os.str(); 295 handleQualifiers( type ); 296 } 297 298 void GenType_new::postvisit( ast::VTableType const * type ) { 299 assertf( !options.genC, "Virtual table types should not reach code generation." ); 300 std::ostringstream os; 301 os << "vtable(" << genType( type->base, "", options ) << ") " << result; 302 result = os.str(); 303 handleQualifiers( type ); 304 } 305 306 void GenType_new::postvisit( ast::QualifiedType const * type ) { 307 assertf( !options.genC, "QualifiedType should not reach code generation." ); 308 std::ostringstream os; 309 os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result; 310 result = os.str(); 311 handleQualifiers( type ); 312 } 313 314 void GenType_new::handleQualifiers( ast::Type const * type ) { 315 if ( type->is_const() ) { 316 result = "const " + result; 317 } 318 if ( type->is_volatile() ) { 319 result = "volatile " + result; 320 } 321 if ( type->is_restrict() ) { 322 result = "__restrict " + result; 323 } 324 if ( type->is_atomic() ) { 325 result = "_Atomic " + result; 326 } 327 } 328 329 std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) { 330 auto cur = range.begin(); 331 auto end = range.end(); 332 if ( cur == end ) return ""; 333 std::ostringstream oss; 334 UniqueName param( "__param_" ); 335 while ( true ) { 336 oss << genType( *cur++, options.genC ? param.newName() : "", options ); 337 if ( cur == end ) break; 338 oss << ", "; 339 } 340 return oss.str(); 341 } 342 343 } // namespace 344 345 std::string genType( ast::Type const * type, const std::string & base, const Options & options ) { 346 std::ostringstream os; 347 if ( !type->attributes.empty() ) { 348 ast::Pass<CodeGenerator_new> cg( os, options ); 349 cg.core.genAttributes( type->attributes ); 350 } 351 352 return os.str() + ast::Pass<GenType_new>::read( type, base, options ); 353 } 354 355 std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) { 356 return ast::Pass<GenType_new>::read( type, base, options ); 357 } 358 354 359 } // namespace CodeGen 355 360 -
src/CodeGen/GenType.h
r0030b508 rfc12f05 21 21 22 22 class Type; 23 namespace ast { 24 class Type; 25 } 23 26 24 27 namespace CodeGen { … … 26 29 std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false ); 27 30 std::string genPrettyType( Type * type, const std::string & baseString ); 31 32 std::string genType( ast::Type const * type, const std::string & base, const Options & options ); 33 std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ); 34 28 35 } // namespace CodeGen 29 36 -
src/CodeGen/Generate.cc
r0030b508 rfc12f05 19 19 #include <string> // for operator<< 20 20 21 #include "CodeGenerator .h" // for CodeGenerator, doSemicolon, oper...21 #include "CodeGeneratorNew.hpp" // for CodeGenerator_new, doSemicolon, ... 22 22 #include "GenType.h" // for genPrettyType 23 #include "Common/PassVisitor.h" // for PassVisitor24 #include "SynTree/LinkageSpec.h" // for isBuiltin, isGeneratable25 #include "SynTree/BaseSyntaxNode.h" // for BaseSyntaxNode26 #include "SynTree/Declaration.h" // for Declaration27 #include "SynTree/Type.h" // for Type28 23 29 24 using namespace std; 30 25 31 26 namespace CodeGen { 32 namespace {33 /// Removes misc. nodes that should not exist in CodeGen34 struct TreeCleaner {35 void premutate( CompoundStmt * stmt );36 Statement * postmutate( ImplicitCtorDtorStmt * stmt );37 27 38 static bool shouldClean( Declaration * ); 39 }; 40 41 void cleanTree( std::list< Declaration * > & translationUnit ) { 42 PassVisitor<TreeCleaner> cleaner; 43 filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false ); 44 mutateAll( translationUnit, cleaner ); 45 } // cleanTree 46 } // namespace 47 48 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 49 cleanTree( translationUnit ); 50 51 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes ); 52 for ( auto & dcl : translationUnit ) { 53 if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) { 54 cgv.pass.updateLocation( dcl ); 55 dcl->accept(cgv); 56 if ( doSemicolon( dcl ) ) { 57 os << ";"; 58 } // if 59 os << cgv.pass.endl; 60 } // if 61 } // for 28 namespace { 29 bool shouldClean( ast::Decl const * decl ) { 30 return dynamic_cast<ast::TraitDecl const *>( decl ); 62 31 } 63 32 64 void generate( BaseSyntaxNode * node, std::ostream & os ) { 65 if ( Type * type = dynamic_cast< Type * >( node ) ) { 66 os << genPrettyType( type, "" ); 67 } else { 68 PassVisitor<CodeGenerator> cgv( os, true, false, false, false ); 69 node->accept( cgv ); 70 } 71 os << std::endl; 72 } 73 74 namespace { 75 void TreeCleaner::premutate( CompoundStmt * cstmt ) { 76 filter( cstmt->kids, [](Statement * stmt) { 77 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) { 78 return shouldClean( declStmt->decl ); 79 } 80 return false; 81 }, false ); 33 /// Removes various nodes that should not exist in CodeGen. 34 struct TreeCleaner_new { 35 ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) { 36 auto mutStmt = ast::mutate( stmt ); 37 erase_if( mutStmt->kids, []( ast::Stmt const * stmt ){ 38 auto declStmt = dynamic_cast<ast::DeclStmt const *>( stmt ); 39 return ( declStmt ) ? shouldClean( declStmt->decl ) : false; 40 } ); 41 return mutStmt; 82 42 } 83 43 84 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) { 85 Statement * callStmt = nullptr; 86 std::swap( stmt->callStmt, callStmt ); 87 delete stmt; 88 return callStmt; 44 ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) { 45 return stmt->callStmt; 89 46 } 47 }; 48 } // namespace 90 49 91 bool TreeCleaner::shouldClean( Declaration * decl ) { 92 return dynamic_cast< TraitDecl * >( decl ); 50 void generate( ast::TranslationUnit & translationUnit, std::ostream & os, bool doIntrinsics, 51 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) { 52 erase_if( translationUnit.decls, shouldClean ); 53 ast::Pass<TreeCleaner_new>::run( translationUnit ); 54 55 ast::Pass<CodeGenerator_new> cgv( os, 56 Options( pretty, generateC, lineMarks, printExprTypes ) ); 57 for ( auto & decl : translationUnit.decls ) { 58 if ( decl->linkage.is_generatable && (doIntrinsics || !decl->linkage.is_builtin ) ) { 59 cgv.core.updateLocation( decl ); 60 decl->accept( cgv ); 61 if ( doSemicolon( decl ) ) { 62 os << ";"; 63 } 64 os << cgv.core.endl; 93 65 } 94 } // namespace 66 } 67 } 68 95 69 } // namespace CodeGen 96 70 -
src/CodeGen/Generate.h
r0030b508 rfc12f05 22 22 class Declaration; 23 23 24 namespace ast { 25 class TranslationUnit; 26 } 27 24 28 namespace CodeGen { 25 /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)26 void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false );27 29 28 /// Generate code for a single node -- helpful for debugging in gdb 29 void generate( BaseSyntaxNode * node, std::ostream & os ); 30 /// Generates all code in transUnit and writing it to the os. 31 /// doIntrinsics: Should intrinsic functions be printed? 32 /// pretty: Format output nicely (e.g., uses unmangled names, etc.). 33 /// generateC: Make sure the output only consists of C code (allows some assertions, etc.) 34 /// lineMarks: Output line marks (processed line directives) in the output. 35 /// printExprTypes: Print the types of expressions in comments. 36 void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics, 37 bool pretty, bool generateC, bool lineMarks, bool printExprTypes ); 38 30 39 } // namespace CodeGen 31 40 -
src/CodeGen/LinkOnce.cc
r0030b508 rfc12f05 22 22 #include "AST/Expr.hpp" 23 23 #include "AST/Pass.hpp" 24 #include "Common/PassVisitor.h" // for PassVisitor, WithShortCircuiting25 24 26 25 namespace CodeGen { 27 26 28 27 namespace { 29 30 bool is_cfa_linkonce_old( Attribute const * attr ) {31 return std::string("cfa_linkonce") == attr->name;32 }33 34 bool is_section_attribute_old( Attribute const * attr ) {35 return std::string("section") == attr->name;36 }37 38 class LinkOnceVisitorCore : public WithShortCircuiting {39 public:40 void previsit( Declaration * ) {41 visit_children = false;42 }43 44 void previsit( DeclarationWithType * decl ) {45 std::list< Attribute * > & attributes = decl->attributes;46 // See if we can find the element:47 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );48 if ( attributes.end() != found ) {49 // Remove any other sections:50 attributes.remove_if( is_section_attribute_old );51 // Iterator to the cfa_linkonce attribute should still be valid.52 Attribute * attribute = *found;53 assert( attribute->parameters.empty() );54 assert( !decl->mangleName.empty() );55 // Overwrite the attribute in place.56 const std::string section_name = ".gnu.linkonce." + decl->mangleName;57 attribute->name = "section";58 attribute->parameters.push_back(59 new ConstantExpr( Constant::from_string( section_name ) )60 );61 62 // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce63 // visibility is a mess otherwise64 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));65 66 }67 visit_children = false;68 }69 };70 28 71 29 bool is_cfa_linkonce( ast::Attribute const * attr ) { … … 122 80 } // namespace 123 81 124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {125 PassVisitor<LinkOnceVisitorCore> translator;126 acceptAll( translationUnit, translator );127 }128 129 82 void translateLinkOnce( ast::TranslationUnit & translationUnit ) { 130 83 ast::Pass<LinkOnceCore>::run( translationUnit ); -
src/CodeGen/LinkOnce.h
r0030b508 rfc12f05 20 20 // for now its almost the only attribute we handle. 21 21 22 #include <list> // for list23 22 24 class Declaration;25 23 namespace ast { 26 24 class TranslationUnit; … … 29 27 namespace CodeGen { 30 28 31 void translateLinkOnce( std::list< Declaration *> & translationUnit );32 29 void translateLinkOnce( ast::TranslationUnit & translationUnit ); 33 30 /* Convert the cfa_linkonce attribute on top level declaration into -
src/CodeGen/OperatorTable.cc
r0030b508 rfc12f05 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Feb 18 15:55:01 202013 // Update Count : 5 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 3 16:00:00 2023 13 // Update Count : 56 14 14 // 15 15 16 #include <algorithm> // for any_of 17 #include <map> // for map, _Rb_tree_const_iterator, map<>::const_iterator 18 #include <utility> // for pair 19 using namespace std; 16 #include "OperatorTable.h" 20 17 21 #include "OperatorTable.h"22 #include "Common/utility.h"18 #include <cassert> // for assert 19 #include <unordered_map> // for unordered_map 23 20 24 21 namespace CodeGen { 25 const OperatorInfo CodeGen::tableValues[] = {26 // inputName symbol outputName friendlyName type27 { "?[?]", "", "_operator_index", "Index", OT_INDEX },28 { "?{}", "=", "_constructor", "Constructor", OT_CTOR },29 { "^?{}", "", "_destructor", "Destructor", OT_DTOR },30 { "?()", "", "_operator_call", "Call Operator", OT_CALL },31 { "?++", "++", "_operator_postincr", "Postfix Increment", OT_POSTFIXASSIGN },32 { "?--", "--", "_operator_postdecr", "Postfix Decrement", OT_POSTFIXASSIGN },33 { "*?", "*", "_operator_deref", "Dereference", OT_PREFIX },34 { "+?", "+", "_operator_unaryplus", "Plus", OT_PREFIX },35 { "-?", "-", "_operator_unaryminus", "Minus", OT_PREFIX },36 { "~?", "~", "_operator_bitnot", "Bitwise Not", OT_PREFIX },37 { "!?", "!", "_operator_lognot", "Logical Not", OT_PREFIX },38 { "++?", "++", "_operator_preincr", "Prefix Increment", OT_PREFIXASSIGN },39 { "--?", "--", "_operator_predecr", "Prefix Decrement", OT_PREFIXASSIGN },40 { "?\\?", "\\", "_operator_exponential", "Exponentiation", OT_INFIX },41 { "?*?", "*", "_operator_multiply", "Multiplication", OT_INFIX },42 { "?/?", "/", "_operator_divide", "Division", OT_INFIX },43 { "?%?", "%", "_operator_modulus", "Modulo", OT_INFIX },44 { "?+?", "+", "_operator_add", "Addition", OT_INFIX },45 { "?-?", "-", "_operator_subtract", "Substraction", OT_INFIX },46 { "?<<?", "<<", "_operator_shiftleft", "Shift Left", OT_INFIX },47 { "?>>?", ">>", "_operator_shiftright", "Shift Right", OT_INFIX },48 { "?<?", "<", "_operator_less", "Less-than", OT_INFIX },49 { "?>?", ">", "_operator_greater", "Greater-than", OT_INFIX },50 { "?<=?", "<=", "_operator_lessequal", "Less-than-or-Equal", OT_INFIX },51 { "?>=?", ">=", "_operator_greaterequal", "Greater-than-or-Equal", OT_INFIX },52 { "?==?", "==", "_operator_equal", "Equality", OT_INFIX },53 { "?!=?", "!=", "_operator_notequal", "Not-Equal", OT_INFIX },54 { "?&?", "&", "_operator_bitand", "Bitwise And", OT_INFIX },55 { "?^?", "^", "_operator_bitxor", "Bitwise Xor", OT_INFIX },56 { "?|?", "|", "_operator_bitor", "Bitwise Or", OT_INFIX },57 { "?=?", "=", "_operator_assign", "Assignment", OT_INFIXASSIGN },58 { "?\\=?", "\\=", "_operator_expassign", "Exponentiation Assignment", OT_INFIXASSIGN },59 { "?*=?", "*=", "_operator_multassign", "Multiplication Assignment", OT_INFIXASSIGN },60 { "?/=?", "/=", "_operator_divassign", "Division Assignment", OT_INFIXASSIGN },61 { "?%=?", "%=", "_operator_modassign", "Modulo Assignment", OT_INFIXASSIGN },62 { "?+=?", "+=", "_operator_addassign", "Addition Assignment", OT_INFIXASSIGN },63 { "?-=?", "-=", "_operator_subassign", "Substrction Assignment", OT_INFIXASSIGN },64 { "?<<=?", "<<=", "_operator_shiftleftassign", "Shift Left Assignment", OT_INFIXASSIGN },65 { "?>>=?", ">>=", "_operator_shiftrightassign", "Shift Right Assignment", OT_INFIXASSIGN },66 { "?&=?", "&=", "_operator_bitandassign", "Bitwise And Assignment", OT_INFIXASSIGN },67 { "?^=?", "^=", "_operator_bitxorassign", "Bitwise Xor Assignment", OT_INFIXASSIGN },68 { "?|=?", "|=", "_operator_bitorassign", "Bitwise Or Assignment", OT_INFIXASSIGN },69 }; // tableValues70 22 71 std::map< std::string, OperatorInfo > CodeGen::table; 23 static const OperatorInfo tableValues[] = { 24 // inputName symbol outputName friendlyName type 25 { "?[?]", "", "_operator_index", "Index", OT_INDEX }, 26 { "?{}", "=", "_constructor", "Constructor", OT_CTOR }, 27 { "^?{}", "", "_destructor", "Destructor", OT_DTOR }, 28 { "?()", "", "_operator_call", "Call Operator", OT_CALL }, 29 { "?++", "++", "_operator_postincr", "Postfix Increment", OT_POSTFIXASSIGN }, 30 { "?--", "--", "_operator_postdecr", "Postfix Decrement", OT_POSTFIXASSIGN }, 31 { "*?", "*", "_operator_deref", "Dereference", OT_PREFIX }, 32 { "+?", "+", "_operator_unaryplus", "Plus", OT_PREFIX }, 33 { "-?", "-", "_operator_unaryminus", "Minus", OT_PREFIX }, 34 { "~?", "~", "_operator_bitnot", "Bitwise Not", OT_PREFIX }, 35 { "!?", "!", "_operator_lognot", "Logical Not", OT_PREFIX }, 36 { "++?", "++", "_operator_preincr", "Prefix Increment", OT_PREFIXASSIGN }, 37 { "--?", "--", "_operator_predecr", "Prefix Decrement", OT_PREFIXASSIGN }, 38 { "?\\?", "\\", "_operator_exponential", "Exponentiation", OT_INFIX }, 39 { "?*?", "*", "_operator_multiply", "Multiplication", OT_INFIX }, 40 { "?/?", "/", "_operator_divide", "Division", OT_INFIX }, 41 { "?%?", "%", "_operator_modulus", "Modulo", OT_INFIX }, 42 { "?+?", "+", "_operator_add", "Addition", OT_INFIX }, 43 { "?-?", "-", "_operator_subtract", "Substraction", OT_INFIX }, 44 { "?<<?", "<<", "_operator_shiftleft", "Shift Left", OT_INFIX }, 45 { "?>>?", ">>", "_operator_shiftright", "Shift Right", OT_INFIX }, 46 { "?<?", "<", "_operator_less", "Less-than", OT_INFIX }, 47 { "?>?", ">", "_operator_greater", "Greater-than", OT_INFIX }, 48 { "?<=?", "<=", "_operator_lessequal", "Less-than-or-Equal", OT_INFIX }, 49 { "?>=?", ">=", "_operator_greaterequal", "Greater-than-or-Equal", OT_INFIX }, 50 { "?==?", "==", "_operator_equal", "Equality", OT_INFIX }, 51 { "?!=?", "!=", "_operator_notequal", "Not-Equal", OT_INFIX }, 52 { "?&?", "&", "_operator_bitand", "Bitwise And", OT_INFIX }, 53 { "?^?", "^", "_operator_bitxor", "Bitwise Xor", OT_INFIX }, 54 { "?|?", "|", "_operator_bitor", "Bitwise Or", OT_INFIX }, 55 { "?=?", "=", "_operator_assign", "Assignment", OT_INFIXASSIGN }, 56 { "?\\=?", "\\=", "_operator_expassign", "Exponentiation Assignment", OT_INFIXASSIGN }, 57 { "?*=?", "*=", "_operator_multassign", "Multiplication Assignment", OT_INFIXASSIGN }, 58 { "?/=?", "/=", "_operator_divassign", "Division Assignment", OT_INFIXASSIGN }, 59 { "?%=?", "%=", "_operator_modassign", "Modulo Assignment", OT_INFIXASSIGN }, 60 { "?+=?", "+=", "_operator_addassign", "Addition Assignment", OT_INFIXASSIGN }, 61 { "?-=?", "-=", "_operator_subassign", "Substrction Assignment", OT_INFIXASSIGN }, 62 { "?<<=?", "<<=", "_operator_shiftleftassign", "Shift Left Assignment", OT_INFIXASSIGN }, 63 { "?>>=?", ">>=", "_operator_shiftrightassign", "Shift Right Assignment", OT_INFIXASSIGN }, 64 { "?&=?", "&=", "_operator_bitandassign", "Bitwise And Assignment", OT_INFIXASSIGN }, 65 { "?^=?", "^=", "_operator_bitxorassign", "Bitwise Xor Assignment", OT_INFIXASSIGN }, 66 { "?|=?", "|=", "_operator_bitorassign", "Bitwise Or Assignment", OT_INFIXASSIGN }, 67 }; // tableValues 72 68 73 CodeGen::CodeGen() { 74 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) }; 75 for ( int i = 0; i < numOps; i += 1 ) { 76 table[ tableValues[i].inputName ] = tableValues[i]; 77 } // for 69 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) }; 70 71 const OperatorInfo * operatorLookup( const std::string & inputName ) { 72 // Static information set up: 73 static std::unordered_map<std::string, const OperatorInfo *> inputTable; 74 if ( inputTable.empty() ) for ( const OperatorInfo & op : tableValues ) { 75 inputTable[ op.inputName ] = &op; 78 76 } 79 77 80 const OperatorInfo * operatorLookup( const string & funcName ) { 81 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter 82 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table 83 assert( ret ); 84 return ret; 78 if ( inputName.find_first_of( "?^*+-!", 0, 1 ) == std::string::npos ) return nullptr; // prefilter 79 const OperatorInfo * ret = inputTable.find( inputName )->second; 80 // This can only happen if an invalid identifier name has been used. 81 assert( ret ); 82 return ret; 83 } 84 85 bool isOperator( const std::string & inputName ) { 86 return operatorLookup( inputName ) != nullptr; 87 } 88 89 std::string operatorFriendlyName( const std::string & inputName ) { 90 const OperatorInfo * info = operatorLookup( inputName ); 91 if ( info ) return info->friendlyName; 92 return ""; 93 } 94 95 // This is only used in the demangler, so it is smaller (and only maybe slow). 96 const OperatorInfo * operatorLookupByOutput( const std::string & outputName ) { 97 if ( '_' != outputName[0] ) return nullptr; 98 for ( const OperatorInfo & op : tableValues ) { 99 if ( outputName == op.outputName ) { 100 return &op; 101 } 85 102 } 103 return nullptr; 104 } 86 105 87 bool isOperator( const string & funcName ) { 88 return operatorLookup( funcName ) != nullptr; 89 } 106 bool isConstructor( const std::string & inputName ) { 107 const OperatorInfo * info = operatorLookup( inputName ); 108 if ( info ) return info->type == OT_CTOR; 109 return false; 110 } 90 111 91 string operatorFriendlyName( const string & funcName ) {92 const OperatorInfo * info = operatorLookup( funcName );93 if ( info ) return info->friendlyName;94 return "";95 112 bool isDestructor( const std::string & inputName ) { 113 const OperatorInfo * info = operatorLookup( inputName ); 114 if ( info ) return info->type == OT_DTOR; 115 return false; 116 } 96 117 97 bool isConstructor( const string & funcName ) {98 const OperatorInfo * info = operatorLookup( funcName );99 if ( info ) return info->type == OT_CTOR;100 101 118 bool isCtorDtor( const std::string & inputName ) { 119 const OperatorInfo * info = operatorLookup( inputName ); 120 if ( info ) return info->type <= OT_CONSTRUCTOR; 121 return false; 122 } 102 123 103 bool isDestructor( const string & funcName ) {104 const OperatorInfo * info = operatorLookup( funcName );105 if ( info ) return info->type == OT_DTOR;106 107 124 bool isAssignment( const std::string & inputName ) { 125 const OperatorInfo * info = operatorLookup( inputName ); 126 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT; 127 return false; 128 } 108 129 109 bool isCtorDtor( const string & funcName ) {110 const OperatorInfo * info = operatorLookup( funcName );111 if ( info ) return info->type <= OT_CONSTRUCTOR;112 113 130 bool isCtorDtorAssign( const std::string & inputName ) { 131 const OperatorInfo * info = operatorLookup( inputName ); 132 if ( info ) return info->type <= OT_ASSIGNMENT; 133 return false; 134 } 114 135 115 bool isAssignment( const string & funcName ) {116 const OperatorInfo * info = operatorLookup( funcName );117 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;118 return false;119 }120 121 bool isCtorDtorAssign( const string & funcName ) {122 const OperatorInfo * info = operatorLookup( funcName );123 if ( info ) return info->type <= OT_ASSIGNMENT;124 return false;125 }126 127 CodeGen codegen; // initialize singleton package128 136 } // namespace CodeGen 129 137 -
src/CodeGen/OperatorTable.h
r0030b508 rfc12f05 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Feb 16 08:13:34 202013 // Update Count : 2 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 3 14:53:00 2023 13 // Update Count : 27 14 14 // 15 15 … … 17 17 18 18 #include <string> 19 #include <map>20 19 21 20 namespace CodeGen { 22 enum OperatorType {23 OT_CTOR,24 OT_DTOR,25 OT_CONSTRUCTOR = OT_DTOR,26 OT_PREFIXASSIGN,27 OT_POSTFIXASSIGN,28 OT_INFIXASSIGN,29 OT_ASSIGNMENT = OT_INFIXASSIGN,30 OT_CALL,31 OT_PREFIX,32 OT_INFIX,33 OT_POSTFIX,34 OT_INDEX,35 OT_LABELADDRESS,36 OT_CONSTANT37 };38 21 39 struct OperatorInfo { 40 std::string inputName; 41 std::string symbol; 42 std::string outputName; 43 std::string friendlyName; 44 OperatorType type; 45 }; 22 enum OperatorType { 23 OT_CTOR, 24 OT_DTOR, 25 OT_CONSTRUCTOR = OT_DTOR, 26 OT_PREFIXASSIGN, 27 OT_POSTFIXASSIGN, 28 OT_INFIXASSIGN, 29 OT_ASSIGNMENT = OT_INFIXASSIGN, 30 OT_CALL, 31 OT_PREFIX, 32 OT_INFIX, 33 OT_POSTFIX, 34 OT_INDEX, 35 OT_LABELADDRESS, 36 OT_CONSTANT 37 }; 46 38 47 class CodeGen { 48 friend const OperatorInfo * operatorLookup( const std::string & funcName ); 39 struct OperatorInfo { 40 // The Cforall special function name. 41 std::string inputName; 42 // The string used when the operator is used as an operator. 43 std::string symbol; 44 // The base name used in the mangled name. 45 std::string outputName; 46 // Human-readable name of the operator. 47 std::string friendlyName; 48 // The type of operator shows how it is used as an operator. 49 OperatorType type; 50 }; 49 51 50 static const OperatorInfo tableValues[]; 51 static std::map< std::string, OperatorInfo > table; 52 public: 53 CodeGen(); 54 }; // CodeGen 52 // Look up the operator (by inputName), return nullptr if no such operator. 53 const OperatorInfo * operatorLookup( const std::string & inputName ); 54 // Is there an operator with this name? 55 bool isOperator( const std::string & inputName ); 56 // Get the friendlyName of the operator with the inputName 57 std::string operatorFriendlyName( const std::string & inputName ); 58 // Get the OperatorInfo with the given outputName, if one exists. 59 const OperatorInfo * operatorLookupByOutput( const std::string & outputName ); 55 60 56 bool isOperator( const std::string & funcName ); 57 const OperatorInfo * operatorLookup( const std::string & funcName ); 58 std::string operatorFriendlyName( const std::string & funcName ); 61 // Is the operator a constructor, destructor or any form of assignment. 62 // (Last two are "or" combinations of the first three.) 63 bool isConstructor( const std::string & ); 64 bool isDestructor( const std::string & ); 65 bool isAssignment( const std::string & ); 66 bool isCtorDtor( const std::string & ); 67 bool isCtorDtorAssign( const std::string & ); 59 68 60 bool isConstructor( const std::string & );61 bool isDestructor( const std::string & );62 bool isAssignment( const std::string & );63 bool isCtorDtor( const std::string & );64 bool isCtorDtorAssign( const std::string & );65 69 } // namespace CodeGen 66 70 -
src/CodeGen/module.mk
r0030b508 rfc12f05 16 16 17 17 SRC_CODEGEN = \ 18 CodeGen/FixMain2.cc \ 19 CodeGen/FixMain.h \ 18 CodeGen/CodeGeneratorNew.cpp \ 19 CodeGen/CodeGeneratorNew.hpp \ 20 CodeGen/GenType.cc \ 21 CodeGen/GenType.h \ 20 22 CodeGen/OperatorTable.cc \ 21 23 CodeGen/OperatorTable.h 22 24 23 25 SRC += $(SRC_CODEGEN) \ 24 CodeGen/CodeGenerator.cc \25 CodeGen/CodeGenerator.h \26 26 CodeGen/Generate.cc \ 27 27 CodeGen/Generate.h \ 28 28 CodeGen/FixMain.cc \ 29 CodeGen/FixMain.h \ 29 30 CodeGen/FixNames.cc \ 30 31 CodeGen/FixNames.h \ 31 CodeGen/GenType.cc \32 CodeGen/GenType.h \33 32 CodeGen/LinkOnce.cc \ 34 33 CodeGen/LinkOnce.h \ -
src/Common/CodeLocationTools.cpp
r0030b508 rfc12f05 138 138 macro(MutexStmt, Stmt) \ 139 139 macro(CorunStmt, Stmt) \ 140 macro(CoforStmt, Stmt) \ 140 141 macro(ApplicationExpr, Expr) \ 141 142 macro(UntypedExpr, Expr) \ -
src/Common/Eval.cc
r0030b508 rfc12f05 19 19 20 20 #include "AST/Inspect.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "CodeGen/OperatorTable.h" // access: OperatorInfo 23 22 #include "AST/Pass.hpp" 24 23 #include "InitTweak/InitTweak.h" 25 #include "SynTree/Expression.h" 26 27 //------------------------------------------------------------- 28 // Old AST 29 struct EvalOld : public WithShortCircuiting { 30 long long int value = 0; // compose the result of the constant expression 31 bool valid = true; // true => constant expression and value is the result 32 // false => not constant expression, e.g., ++i 33 bool cfavalid = true; // true => constant expression and value computable 34 // false => constant expression but value not computable, e.g., sizeof(int) 35 36 void previsit( const BaseSyntaxNode * ) { visit_children = false; } 37 void postvisit( const BaseSyntaxNode * ) { valid = false; } 38 39 void postvisit( const SizeofExpr * ) { 40 } 41 42 void postvisit( const ConstantExpr * expr ) { 43 value = expr->intValue(); 44 } 45 46 void postvisit( const CastExpr * expr ) { 47 auto arg = eval(expr->arg); 48 valid = arg.second; 49 value = arg.first; 50 // TODO: perform type conversion on value if valid 51 } 52 53 void postvisit( const VariableExpr * const expr ) { 54 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) { 55 if ( EnumDecl * decl = inst->baseEnum ) { 56 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf 57 return; 58 } 59 } 60 } 61 valid = false; 62 } 63 64 void postvisit( const ApplicationExpr * expr ) { 65 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr)); 66 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; } 67 const std::string & fname = function->name; 68 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() ); 69 std::pair<long long int, bool> arg1, arg2; 70 arg1 = eval(expr->args.front()); 71 valid = valid && arg1.second; 72 if ( ! valid ) return; 73 if ( expr->args.size() == 2 ) { 74 arg2 = eval(expr->args.back()); 75 valid = valid && arg2.second; 76 if ( ! valid ) return; 77 } 78 if (fname == "?+?") { 79 value = arg1.first + arg2.first; 80 } else if (fname == "?-?") { 81 value = arg1.first - arg2.first; 82 } else if (fname == "?*?") { 83 value = arg1.first * arg2.first; 84 } else if (fname == "?/?") { 85 value = arg1.first / arg2.first; 86 } else if (fname == "?%?") { 87 value = arg1.first % arg2.first; 88 } else { 89 valid = false; 90 } 91 // TODO: implement other intrinsic functions 92 } 93 }; 94 95 //------------------------------------------------------------- 96 // New AST 24 97 25 struct EvalNew : public ast::WithShortCircuiting { 98 26 Evaluation result = { 0, true, true }; … … 270 198 }; 271 199 272 std::pair<long long int, bool> eval( const Expression * expr ) {273 PassVisitor<EvalOld> ev;274 if ( expr ) {275 expr->accept( ev );276 return std::make_pair( ev.pass.value, ev.pass.valid );277 } else {278 return std::make_pair( 0, false );279 }280 }281 282 200 Evaluation eval( const ast::Expr * expr ) { 283 201 if ( expr ) { -
src/Common/Eval.h
r0030b508 rfc12f05 30 30 31 31 /// Evaluates expr as a long long int. 32 /// If second is false, expr could not be evaluated.33 std::pair<long long int, bool> eval(const Expression * expr);34 32 Evaluation eval(const ast::Expr * expr); 35 33 -
src/Common/Examine.cc
r0030b508 rfc12f05 19 19 #include "CodeGen/OperatorTable.h" 20 20 #include "InitTweak/InitTweak.h" 21 22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {23 if (func->name != "main") return nullptr;24 if (func->type->parameters.size() != 1) return nullptr;25 26 auto param = func->type->parameters.front();27 28 auto type = dynamic_cast<ReferenceType * >(param->get_type());29 if (!type) return nullptr;30 31 auto obj = dynamic_cast<StructInstType *>(type->base);32 if (!obj) return nullptr;33 34 if (kind != obj->baseStruct->kind) return nullptr;35 36 return param;37 }38 21 39 22 namespace { … … 69 52 70 53 namespace { 71 Type * getDestructorParam( FunctionDecl * func ) {72 if ( !CodeGen::isDestructor( func->name ) ) return nullptr;73 74 auto params = func->type->parameters;75 if ( 1 != params.size() ) return nullptr;76 77 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );78 if ( ref ) {79 return ref->base;80 }81 return nullptr;82 }83 54 84 55 const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) { … … 88 59 } 89 60 90 }91 92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {93 if ( Type * type = getDestructorParam( func ) ) {94 auto stype = dynamic_cast<StructInstType *>( type );95 return stype && stype->baseStruct == type_decl;96 }97 return false;98 61 } 99 62 -
src/Common/Examine.h
r0030b508 rfc12f05 15 15 16 16 #include "AST/Decl.hpp" 17 #include "SynTree/Declaration.h"18 17 19 18 /// Check if this is a main function for a type of an aggregate kind. 20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );21 19 const ast::DeclWithType * isMainFor( 22 20 const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ); … … 24 22 25 23 /// Check if this function is a destructor for the given structure. 26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );27 24 bool isDestructorFor( 28 25 const ast::FunctionDecl * func, const ast::StructDecl * type ); -
src/Common/UniqueName.cc
r0030b508 rfc12f05 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.cc -- 7 // UniqueName.cc -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jun 8 14:47:49 201513 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:04:00 2023 13 // Update Count : 4 14 14 // 15 15 16 #include <string> 17 #include <sstream> 16 #include "UniqueName.h" 18 17 19 #include " UniqueName.h"18 #include "Common/ToString.hpp" 20 19 21 20 UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) { … … 23 22 24 23 std::string UniqueName::newName( const std::string &additional ) { 25 std::ostringstream os; 26 os << base << additional << count++; 27 return os.str(); 24 return toString( base, additional, count++ ); 28 25 } 29 26 -
src/Common/UniqueName.h
r0030b508 rfc12f05 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // UniqueName.h -- 7 // UniqueName.h -- Create a unique variants of a base name with a counter. 8 8 // 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 22:18:45 201713 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Nov 7 15:00:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 19 19 20 20 class UniqueName { 21 22 UniqueName( const std::string &base = "");21 public: 22 UniqueName( const std::string &base ); 23 23 std::string newName( const std::string &additional = "" ); 24 24 private: 25 25 std::string base; 26 26 int count; -
src/Common/module.mk
r0030b508 rfc12f05 31 31 Common/Indenter.cc \ 32 32 Common/Iterate.hpp \ 33 Common/PassVisitor.cc \34 Common/PassVisitor.h \35 Common/PassVisitor.impl.h \36 Common/PassVisitor.proto.h \37 33 Common/PersistentMap.h \ 38 34 Common/ResolvProtoDump.hpp \ -
src/Concurrency/Corun.cpp
r0030b508 rfc12f05 27 27 struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> { 28 28 UniqueName CorunFnNamer = "__CFA_corun_lambda_"s; 29 UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s; 30 // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s; 29 31 UniqueName RunnerBlockNamer = "__CFA_corun_block_"s; 32 33 string coforArgName = "__CFA_cofor_lambda_arg"; 34 string numProcsName = "__CFA_cofor_num_procs"; 35 string currProcsName = "__CFA_cofor_curr_procs"; 36 string thdArrName = "__CFA_cofor_thread_array"; 37 string loopTempName = "__CFA_cofor_loop_temp"; 38 30 39 31 40 const StructDecl * runnerBlockDecl = nullptr; 32 33 // Finds select_node decl 41 const StructDecl * coforRunnerDecl = nullptr; 42 43 // Finds runner_block (corun task) and cofor_runner (cofor task) decls 34 44 void previsit( const StructDecl * decl ) { 35 45 if ( !decl->body ) { … … 38 48 assert( !runnerBlockDecl ); 39 49 runnerBlockDecl = decl; 50 } else if ( "cofor_runner" == decl->name ) { 51 assert( !coforRunnerDecl ); 52 coforRunnerDecl = decl; 40 53 } 41 54 } 42 55 56 // codegen for cofor statements 57 Stmt * postvisit( const CoforStmt * stmt ) { 58 if ( !runnerBlockDecl || !coforRunnerDecl ) 59 SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>\n" ); 60 61 if ( stmt->inits.size() != 1 ) 62 SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control\n" ); 63 64 if ( !stmt->body ) 65 return nullptr; 66 67 const CodeLocation & loc = stmt->location; 68 const string fnName = CoforFnNamer.newName(); 69 70 CompoundStmt * body = new CompoundStmt( loc ); 71 72 // push back cofor initializer to generated body 73 body->push_back( deepCopy( stmt->inits.at(0) ) ); 74 75 CompoundStmt * fnBody = new CompoundStmt( loc ); 76 77 const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get()); 78 if ( ! declStmtPtr ) 79 SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?\n" ); 80 81 const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get()); 82 if ( ! declPtr ) 83 SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?\n" ); 84 85 Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) ); 86 87 // Generates: 88 // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val); 89 fnBody->push_back( new DeclStmt( loc, 90 new ObjectDecl( loc, 91 declPtr->name, 92 initType, 93 new SingleInit( loc, 94 UntypedExpr::createDeref( loc, 95 new CastExpr( loc, 96 new NameExpr( loc, coforArgName ), 97 new PointerType( initType ), ExplicitCast 98 ) 99 ) 100 ) 101 ) 102 )); 103 104 // push rest of cofor body into loop lambda 105 fnBody->push_back( deepCopy( stmt->body ) ); 106 107 // Generates: 108 // void __CFA_cofor_lambda_() { 109 // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val); 110 // stmt->body; 111 // } 112 Stmt * coforLambda = new DeclStmt( loc, 113 new FunctionDecl( loc, 114 fnName, // name 115 {}, // forall 116 { 117 new ObjectDecl( loc, 118 coforArgName, 119 new ast::PointerType( new ast::VoidType() ) 120 ) 121 }, // params 122 {}, // return 123 fnBody // body 124 ) 125 ); 126 body->push_back( coforLambda ); 127 128 // Generates: 129 // unsigned __CFA_cofor_num_procs = get_proc_count(); 130 body->push_back( new DeclStmt( loc, 131 new ObjectDecl( loc, 132 numProcsName, 133 new BasicType( BasicType::Kind::UnsignedInt ), 134 new SingleInit( loc, 135 new UntypedExpr( loc, 136 new NameExpr( loc, "get_proc_count" ), 137 {} 138 ) 139 ) 140 ) 141 ) 142 ); 143 144 // Generates: 145 // unsigned __CFA_cofor_curr_procs = 0; 146 body->push_back( new DeclStmt( loc, 147 new ObjectDecl( loc, 148 currProcsName, 149 new BasicType( BasicType::Kind::UnsignedInt ), 150 new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) ) 151 ) 152 ) 153 ); 154 155 // Generates: 156 // unsigned cofor_runner __CFA_cofor_thread_array[nprocs]; 157 body->push_back( new DeclStmt( loc, 158 new ObjectDecl( loc, 159 thdArrName, 160 new ast::ArrayType( 161 new StructInstType( coforRunnerDecl ), 162 new NameExpr( loc, numProcsName ), 163 ast::FixedLen, 164 ast::DynamicDim 165 ) 166 ) 167 ) 168 ); 169 170 // Generates: 171 // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ ); 172 body->push_back( new ExprStmt( loc, 173 new UntypedExpr( loc, 174 new NameExpr( loc, "start_runners" ), 175 { 176 new NameExpr( loc, thdArrName ), 177 new NameExpr( loc, numProcsName ), 178 new NameExpr( loc, fnName ) 179 } 180 ) 181 )); 182 183 // Generates: 184 // typeof(initializer) * __CFA_cofor_loop_temp = malloc(); 185 CompoundStmt * forLoopBody = new CompoundStmt( loc ); 186 forLoopBody->push_back( new DeclStmt( loc, 187 new ObjectDecl( loc, 188 loopTempName, 189 new PointerType( initType ), 190 new SingleInit( loc, 191 new UntypedExpr( loc, 192 new NameExpr( loc, "malloc" ), 193 {} 194 ) 195 ) 196 ) 197 ) 198 ); 199 200 // Generates: 201 // *__CFA_cofor_loop_temp = initializer; 202 forLoopBody->push_back( new ExprStmt( loc, 203 UntypedExpr::createAssign( loc, 204 UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ), 205 new NameExpr( loc, declPtr->name ) 206 ) 207 )); 208 209 // Generates: 210 // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs, 211 // __CFA_cofor_curr_procs, __CFA_cofor_loop_temp ); 212 forLoopBody->push_back( new ExprStmt( loc, 213 new UntypedExpr( loc, 214 new NameExpr( loc, "send_work" ), 215 { 216 new NameExpr( loc, thdArrName ), 217 new NameExpr( loc, numProcsName ), 218 new NameExpr( loc, currProcsName ), 219 new NameExpr( loc, loopTempName ) 220 } 221 ) 222 )); 223 224 body->push_back( new ForStmt( loc, 225 {}, 226 deepCopy( stmt->cond ), 227 deepCopy( stmt->inc ), 228 forLoopBody 229 )); 230 231 // Generates: 232 // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs ); 233 body->push_back( new ExprStmt( loc, 234 new UntypedExpr( loc, 235 new NameExpr( loc, "end_runners" ), 236 { 237 new NameExpr( loc, thdArrName ), 238 new NameExpr( loc, numProcsName ) 239 } 240 ) 241 )); 242 243 return body; 244 } 245 246 // codegen for corun statements 43 247 Stmt * postvisit( const CorunStmt * stmt ) { 44 if ( !runnerBlockDecl )248 if ( !runnerBlockDecl || !coforRunnerDecl ) 45 249 SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" ); 46 250 -
src/Concurrency/module.mk
r0030b508 rfc12f05 21 21 Concurrency/Corun.hpp \ 22 22 Concurrency/KeywordsNew.cpp \ 23 Concurrency/Keywords.cc \24 23 Concurrency/Keywords.h \ 25 24 Concurrency/WaitforNew.cpp \ 26 Concurrency/Waitfor.cc \27 25 Concurrency/Waitfor.h \ 28 26 Concurrency/Waituntil.cpp \ -
src/ControlStruct/module.mk
r0030b508 rfc12f05 16 16 17 17 SRC += \ 18 ControlStruct/ExceptDecl.cc \19 18 ControlStruct/ExceptDeclNew.cpp \ 20 19 ControlStruct/ExceptDecl.h \ 21 20 ControlStruct/ExceptTranslateNew.cpp \ 22 ControlStruct/ExceptTranslate.cc \23 21 ControlStruct/ExceptTranslate.h \ 24 22 ControlStruct/FixLabels.cpp \ 25 23 ControlStruct/FixLabels.hpp \ 26 ControlStruct/ForExprMutator.cc \27 ControlStruct/ForExprMutator.h \28 24 ControlStruct/HoistControlDecls.cpp \ 29 25 ControlStruct/HoistControlDecls.hpp \ 30 ControlStruct/LabelFixer.cc \31 ControlStruct/LabelFixer.h \32 ControlStruct/LabelGenerator.cc \33 ControlStruct/LabelGenerator.h \34 26 ControlStruct/LabelGeneratorNew.cpp \ 35 27 ControlStruct/LabelGeneratorNew.hpp \ 36 ControlStruct/MLEMutator.cc \37 ControlStruct/MLEMutator.h \38 28 ControlStruct/MultiLevelExit.cpp \ 39 ControlStruct/MultiLevelExit.hpp \ 40 ControlStruct/Mutate.cc \ 41 ControlStruct/Mutate.h 29 ControlStruct/MultiLevelExit.hpp 42 30 -
src/GenPoly/BoxNew.cpp
r0030b508 rfc12f05 39 39 40 40 namespace { 41 42 /// Common field of several sub-passes of box.43 struct BoxPass {44 TypeVarMap scopeTypeVars;45 BoxPass() : scopeTypeVars( ast::TypeData() ) {}46 };47 48 // TODO: Could this be a common helper somewhere?49 ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {50 ast::FunctionType * type = new ast::FunctionType(51 decl->type->isVarArgs, decl->type->qualifiers52 );53 for ( auto type_param : decl->type_params ) {54 type->forall.emplace_back( new ast::TypeInstType( type_param ) );55 }56 for ( auto assertion : decl->assertions ) {57 type->assertions.emplace_back( new ast::VariableExpr(58 assertion->location, assertion ) );59 }60 for ( auto param : decl->params ) {61 type->params.emplace_back( param->get_type() );62 }63 for ( auto retval : decl->returns ) {64 type->returns.emplace_back( retval->get_type() );65 }66 return type;67 }68 41 69 42 // -------------------------------------------------------------------------- … … 359 332 /// * Adds appropriate type variables to the function calls. 360 333 struct CallAdapter final : 361 public BoxPass,362 334 public ast::WithConstTypeSubstitution, 363 335 public ast::WithGuards, … … 376 348 ast::Expr const * postvisit( ast::AddressExpr const * expr ); 377 349 ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt ); 378 void previsit( ast::PointerType const * type );379 void previsit( ast::FunctionType const * type );380 350 381 351 void beginScope(); … … 440 410 CodeLocation const & location, ast::Type const * type ); 441 411 442 /// Set of adapter functions in the current scope.412 TypeVarMap scopeTypeVars; 443 413 ScopedMap< std::string, ast::DeclWithType const * > adapters; 444 414 std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals; … … 553 523 554 524 ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) { 525 // Prevent type declaration information from leaking out. 526 GuardScope( scopeTypeVars ); 527 555 528 if ( nullptr == decl->stmts ) { 556 // This may keep TypeDecls we don't ever want from sneaking in.557 // Not visiting child nodes might just be faster.558 GuardScope( scopeTypeVars );559 529 return decl; 560 530 } 561 531 562 GuardScope( scopeTypeVars );563 532 GuardValue( retval ); 564 533 … … 662 631 ptrdiff_t initArgCount = mutExpr->args.size(); 663 632 664 TypeVarMap exprTypeVars = { ast::TypeData() };633 TypeVarMap exprTypeVars; 665 634 // TODO: Should this take into account the variables already bound in 666 635 // scopeTypeVars ([ex] remove them from exprTypeVars)? … … 687 656 688 657 assert( typeSubs ); 689 ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );690 // Used to use dynRetType instead of concRetType; this changed so that691 // the correct type parameters are passed for return types (it should be692 // the concrete type's parameters, not the formal type's).693 658 ast::vector<ast::Expr>::iterator argIt = 694 659 passTypeVars( mutExpr, function ); … … 768 733 } 769 734 return stmt; 770 }771 772 void CallAdapter::previsit( ast::PointerType const * type ) {773 GuardScope( scopeTypeVars );774 makeTypeVarMap( type, scopeTypeVars );775 }776 777 void CallAdapter::previsit( ast::FunctionType const * type ) {778 GuardScope( scopeTypeVars );779 makeTypeVarMap( type, scopeTypeVars );780 735 } 781 736 … … 1427 1382 1428 1383 ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) { 1429 TypeVarMap localTypeVars = { ast::TypeData() };1384 TypeVarMap localTypeVars; 1430 1385 makeTypeVarMap( decl, localTypeVars ); 1431 1386 … … 1458 1413 layoutParams.emplace_back( alignParam ); 1459 1414 } 1460 // TODO: These should possibly all be gone. 1461 // More all assertions into parameter list. 1462 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) { 1463 // Assertion parameters may not be used in body, 1464 // pass along with unused attribute. 1465 assert.get_and_mutate()->attributes.push_back( 1466 new ast::Attribute( "unused" ) ); 1467 inferredParams.push_back( assert ); 1468 } 1469 mutParam->assertions.clear(); 1415 // Assertions should be stored in the main list. 1416 assert( mutParam->assertions.empty() ); 1470 1417 typeParam = mutParam; 1471 1418 } 1472 // TODO: New version of inner loop.1473 1419 for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) { 1474 1420 // Assertion parameters may not be used in body, … … 1485 1431 spliceBegin( mutDecl->params, layoutParams ); 1486 1432 addAdapters( mutDecl, localTypeVars ); 1433 1434 // Now have to update the type to match the declaration. 1435 ast::FunctionType * type = new ast::FunctionType( 1436 mutDecl->type->isVarArgs, mutDecl->type->qualifiers ); 1437 for ( auto type_param : mutDecl->type_params ) { 1438 type->forall.emplace_back( new ast::TypeInstType( type_param ) ); 1439 } 1440 for ( auto param : mutDecl->params ) { 1441 type->params.emplace_back( param->get_type() ); 1442 } 1443 for ( auto retval : mutDecl->returns ) { 1444 type->returns.emplace_back( retval->get_type() ); 1445 } 1446 mutDecl->type = type; 1487 1447 1488 1448 return mutDecl; … … 1518 1478 } 1519 1479 } 1520 // TODO: Can this be updated as we go along?1521 mutDecl->type = makeFunctionType( mutDecl );1522 1480 return mutDecl; 1523 1481 } … … 1575 1533 assertf( it != adapters.end(), "Could not correct floating node." ); 1576 1534 return ast::mutate_field( expr, &ast::VariableExpr::var, it->second ); 1577 1578 1535 } 1579 1536 … … 1587 1544 /// * Inserts dynamic calculation of polymorphic type layouts where needed. 1588 1545 struct PolyGenericCalculator final : 1589 public BoxPass,1590 1546 public ast::WithConstTypeSubstitution, 1591 1547 public ast::WithDeclsToAdd<>, … … 1595 1551 PolyGenericCalculator(); 1596 1552 1597 void previsit( ast::ObjectDecl const * decl );1598 1553 void previsit( ast::FunctionDecl const * decl ); 1599 1554 void previsit( ast::TypedefDecl const * decl ); … … 1602 1557 ast::StructDecl const * previsit( ast::StructDecl const * decl ); 1603 1558 ast::UnionDecl const * previsit( ast::UnionDecl const * decl ); 1604 void previsit( ast::PointerType const * type );1605 void previsit( ast::FunctionType const * type );1606 1559 ast::DeclStmt const * previsit( ast::DeclStmt const * stmt ); 1607 1560 ast::Expr const * postvisit( ast::MemberExpr const * expr ); … … 1635 1588 /// C sizeof(). 1636 1589 ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * ); 1637 1638 1590 /// Enters a new scope for type-variables, 1639 1591 /// adding the type variables from the provided type. 1640 1592 void beginTypeScope( ast::Type const * ); 1641 /// Enters a new scope for known layouts and offsets, and queues exit calls. 1642 void beginGenericScope();1643 1593 1594 /// The type variables and polymorphic parameters currently in scope. 1595 TypeVarMap scopeTypeVars; 1644 1596 /// Set of generic type layouts known in the current scope, 1645 1597 /// indexed by sizeofName. … … 1652 1604 /// If the argument of an AddressExpr is MemberExpr, it is stored here. 1653 1605 ast::MemberExpr const * addrMember = nullptr; 1654 /// Used to avoid recursing too deep in type declarations.1655 bool expect_func_type = false;1656 1606 }; 1657 1607 … … 1675 1625 } 1676 1626 1677 void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {1678 beginTypeScope( decl->type );1679 }1680 1681 1627 void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) { 1682 beginGenericScope();1628 GuardScope( *this ); 1683 1629 beginTypeScope( decl->type ); 1684 1630 } … … 1696 1642 ast::TypeDecl const * decl ) { 1697 1643 ast::Type const * base = decl->base; 1698 if ( nullptr == base ) return decl;1644 if ( nullptr == base ) return decl; 1699 1645 1700 1646 // Add size/align variables for opaque type declarations. … … 1721 1667 alignDecl->accept( *visitor ); 1722 1668 1723 // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls1724 // can occur at global scope.1669 // A little trick to replace this with two declarations. 1670 // Adding after makes sure that there is no conflict with adding stmts. 1725 1671 declsToAddAfter.push_back( alignDecl ); 1726 // replace with sizeDecl.1727 1672 return sizeDecl; 1728 1673 } … … 1742 1687 } 1743 1688 1744 void PolyGenericCalculator::previsit( ast::PointerType const * type ) {1745 beginTypeScope( type );1746 }1747 1748 void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {1749 beginTypeScope( type );1750 1751 GuardValue( expect_func_type );1752 GuardScope( *this );1753 1754 // The other functions type we will see in this scope are probably1755 // function parameters they don't help us with the layout and offsets so1756 // don't mark them as known in this scope.1757 expect_func_type = false;1758 }1759 1760 //void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {1761 1689 ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) { 1762 1690 ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>(); … … 1766 1694 1767 1695 // Change initialization of a polymorphic value object to allocate via a 1768 // variable-length-array (alloca was previouly used, but it cannot be 1769 // safely used in loops). 1696 // variable-length-array (alloca cannot be safely used in loops). 1770 1697 ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location, 1771 1698 bufNamer.newName(), … … 2248 2175 } 2249 2176 2250 void PolyGenericCalculator::beginGenericScope() {2251 GuardScope( *this );2252 // We expect the first function type see to be the type relating to this2253 // scope but any further type is probably some unrelated function pointer2254 // keep track of whrich is the first.2255 GuardValue( expect_func_type ) = true;2256 }2257 2258 2177 // -------------------------------------------------------------------------- 2259 /// No common theme found.2178 /// Removes unneeded or incorrect type information. 2260 2179 /// * Replaces initialization of polymorphic values with alloca. 2261 2180 /// * Replaces declaration of dtype/ftype with appropriate void expression. … … 2263 2182 /// * Strips fields from generic structure declarations. 2264 2183 struct Eraser final : 2265 public BoxPass,2266 2184 public ast::WithGuards { 2267 2185 void guardTypeVarMap( ast::Type const * type ) { … … 2278 2196 void previsit( ast::PointerType const * type ); 2279 2197 void previsit( ast::FunctionType const * type ); 2198 public: 2199 TypeVarMap scopeTypeVars; 2280 2200 }; 2281 2201 -
src/GenPoly/FindFunction.cc
r0030b508 rfc12f05 20 20 #include "AST/Pass.hpp" // for Pass 21 21 #include "AST/Type.hpp" 22 #include "Common/PassVisitor.h" // for PassVisitor23 22 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::iterator 24 23 #include "GenPoly/GenPoly.h" // for TyVarMap 25 24 #include "ScrubTyVars.h" // for ScrubTyVars 26 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl27 #include "SynTree/Mutator.h" // for Mutator, mutateAll28 #include "SynTree/Type.h" // for FunctionType, Type, Type::For...29 25 30 26 namespace GenPoly { 31 class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {32 public:33 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );34 35 void premutate( FunctionType * functionType );36 Type * postmutate( FunctionType * functionType );37 void premutate( PointerType * pointerType );38 private:39 void handleForall( const Type::ForallList &forall );40 41 std::list< FunctionType const * > & functions;42 TyVarMap tyVars;43 bool replaceMode;44 FindFunctionPredicate predicate;45 };46 47 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {48 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );49 type->acceptMutator( finder );50 }51 52 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {53 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );54 type = type->acceptMutator( finder );55 }56 57 FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )58 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {59 }60 61 void FindFunction::handleForall( const Type::ForallList &forall ) {62 for ( const Declaration * td : forall ) {63 TyVarMap::iterator var = tyVars.find( td->name );64 if ( var != tyVars.end() ) {65 tyVars.erase( var->first );66 } // if67 } // for68 }69 70 void FindFunction::premutate( FunctionType * functionType ) {71 visit_children = false;72 GuardScope( tyVars );73 handleForall( functionType->get_forall() );74 mutateAll( functionType->get_returnVals(), *visitor );75 }76 77 Type * FindFunction::postmutate( FunctionType * functionType ) {78 Type *ret = functionType;79 if ( predicate( functionType, tyVars ) ) {80 functions.push_back( functionType );81 if ( replaceMode ) {82 // replace type parameters in function type with void*83 ret = ScrubTyVars::scrub( functionType->clone(), tyVars );84 } // if85 } // if86 return ret;87 }88 89 void FindFunction::premutate( PointerType * pointerType ) {90 GuardScope( tyVars );91 handleForall( pointerType->get_forall() );92 }93 27 94 28 namespace { … … 154 88 void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) { 155 89 GuardScope( typeVars ); 156 //handleForall( type->forall );157 90 } 158 91 … … 164 97 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false ); 165 98 type->accept( pass ); 166 //(void)type;167 //(void)functions;168 //(void)typeVars;169 //(void)predicate;170 99 } 171 100 … … 175 104 ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true ); 176 105 return type->accept( pass ); 177 //(void)functions;178 //(void)typeVars;179 //(void)predicate;180 //return type;181 106 } 182 107 -
src/GenPoly/FindFunction.h
r0030b508 rfc12f05 16 16 #pragma once 17 17 18 #include <list> // for list19 20 18 #include "GenPoly.h" // for TyVarMap 21 19 22 class FunctionType;23 class Type;24 25 20 namespace GenPoly { 26 typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& );27 28 /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`29 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );30 /// like `findFunction`, but also replaces the function type with void ()(void)31 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );32 21 33 22 typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & ); -
src/GenPoly/GenPoly.cc
r0030b508 rfc12f05 29 29 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 30 30 #include "ResolvExpr/typeops.h" // for flatten 31 #include "SynTree/Constant.h" // for Constant32 #include "SynTree/Expression.h" // for Expression, TypeExpr, Constan...33 #include "SynTree/Type.h" // for Type, StructInstType, UnionIn...34 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution35 31 36 32 using namespace std; … … 39 35 namespace { 40 36 /// Checks a parameter list for polymorphic parameters; will substitute according to env if present 41 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {42 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {43 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );44 assertf(paramType, "Aggregate parameters should be type expressions");45 if ( isPolyType( paramType->get_type(), env ) ) return true;46 }47 return false;48 }49 50 37 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) { 51 38 for ( auto ¶m : params ) { … … 58 45 59 46 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 60 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {61 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {62 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );63 assertf(paramType, "Aggregate parameters should be type expressions");64 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;65 }66 return false;67 }68 69 47 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) { 70 48 for ( auto & param : params ) { … … 77 55 78 56 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 79 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {80 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {81 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );82 assertf(paramType, "Aggregate parameters should be type expressions");83 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true;84 }85 return false;86 }87 88 57 bool hasDynParams( 89 58 const std::vector<ast::ptr<ast::Expr>> & params, … … 99 68 return false; 100 69 } 101 102 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present103 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {104 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {105 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );106 assertf(paramType, "Aggregate parameters should be type expressions");107 if ( includesPolyType( paramType->get_type(), env ) ) return true;108 }109 return false;110 }111 112 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present113 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {114 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {115 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );116 assertf(paramType, "Aggregate parameters should be type expressions");117 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true;118 }119 return false;120 }121 }122 123 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) {124 if ( ! env ) return type;125 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {126 Type *newType = env->lookup( typeInst->get_name() );127 if ( newType ) return newType;128 }129 return type;130 }131 132 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {133 if ( ! env ) return type;134 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {135 Type *newType = env->lookup( typeInst->get_name() );136 if ( newType ) return newType;137 }138 return type;139 70 } 140 71 … … 146 77 } 147 78 return type; 148 }149 150 Type *isPolyType( Type *type, const TypeSubstitution *env ) {151 type = replaceTypeInst( type, env );152 153 if ( dynamic_cast< TypeInstType * >( type ) ) {154 return type;155 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {156 return isPolyType( arrayType->base, env );157 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {158 if ( hasPolyParams( structType->get_parameters(), env ) ) return type;159 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {160 if ( hasPolyParams( unionType->get_parameters(), env ) ) return type;161 }162 return 0;163 79 } 164 80 … … 178 94 } 179 95 180 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {181 type = replaceTypeInst( type, env );182 183 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {184 if ( tyVars.contains( typeInst->get_name() ) ) {185 return type;186 }187 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {188 return isPolyType( arrayType->base, tyVars, env );189 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {190 if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type;191 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {192 if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type;193 }194 return 0;195 }196 197 96 const ast::Type * isPolyType( const ast::Type * type, 198 97 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 211 110 } 212 111 213 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {214 type = replaceTypeInst( type, env );215 216 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {217 auto var = tyVars.find( typeInst->get_name() );218 if ( var != tyVars.end() && var->second.isComplete ) {219 return typeInst;220 }221 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {222 if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;223 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {224 if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;225 }226 return 0;227 }228 229 112 const ast::BaseInstType * isDynType( 230 113 const ast::Type * type, const TypeVarMap & typeVars, … … 249 132 } 250 133 251 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {252 if ( function->get_returnVals().empty() ) return 0;253 254 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );255 }256 257 134 const ast::BaseInstType *isDynRet( 258 135 const ast::FunctionType * type, const TypeVarMap & typeVars ) { … … 262 139 } 263 140 264 ReferenceToType *isDynRet( FunctionType *function ) {265 if ( function->get_returnVals().empty() ) return 0;266 267 TyVarMap forallTypes( TypeDecl::Data{} );268 makeTyVarMap( function, forallTypes );269 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );270 }271 272 141 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) { 273 142 if ( func->returns.empty() ) return nullptr; 274 143 275 TypeVarMap forallTypes = { ast::TypeData() };144 TypeVarMap forallTypes; 276 145 makeTypeVarMap( func, forallTypes ); 277 146 return isDynType( func->returns.front(), forallTypes ); 278 147 } 279 280 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {281 // if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {282 // return true;283 // } // if284 if ( isDynRet( adaptee, tyVars ) ) return true;285 286 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {287 // if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {288 if ( isDynType( (*innerArg)->get_type(), tyVars ) ) {289 return true;290 } // if291 } // for292 return false;293 }294 148 295 149 bool needsAdapter( … … 304 158 return false; 305 159 } 306 307 Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {308 type = replaceTypeInst( type, env );309 310 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {311 return isPolyType( ptr->get_base(), env );312 }313 return 0;314 }315 316 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {317 type = replaceTypeInst( type, env );318 319 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {320 return isPolyType( ptr->get_base(), tyVars, env );321 }322 return 0;323 }324 160 325 161 const ast::Type * isPolyPtr( … … 333 169 return nullptr; 334 170 } 335 336 Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {337 int dummy;338 if ( ! levels ) { levels = &dummy; }339 *levels = 0;340 341 while ( true ) {342 type = replaceTypeInst( type, env );343 344 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {345 type = ptr->get_base();346 ++(*levels);347 } else break;348 }349 350 return isPolyType( type, env );351 }352 353 Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {354 int dummy;355 if ( ! levels ) { levels = &dummy; }356 *levels = 0;357 358 while ( true ) {359 type = replaceTypeInst( type, env );360 361 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {362 type = ptr->get_base();363 ++(*levels);364 } else break;365 }366 367 return isPolyType( type, tyVars, env );368 }369 171 370 172 ast::Type const * hasPolyBase( … … 388 190 } 389 191 390 bool includesPolyType( Type *type, const TypeSubstitution *env ) {391 type = replaceTypeInst( type, env );392 393 if ( dynamic_cast< TypeInstType * >( type ) ) {394 return true;395 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {396 if ( includesPolyType( pointerType->get_base(), env ) ) return true;397 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {398 if ( includesPolyParams( structType->get_parameters(), env ) ) return true;399 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {400 if ( includesPolyParams( unionType->get_parameters(), env ) ) return true;401 }402 return false;403 }404 405 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {406 type = replaceTypeInst( type, env );407 408 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {409 if ( tyVars.contains( typeInstType->get_name() ) ) {410 return true;411 }412 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {413 if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true;414 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {415 if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true;416 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {417 if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true;418 }419 return false;420 }421 422 FunctionType * getFunctionType( Type *ty ) {423 PointerType *ptrType;424 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {425 return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise426 } else {427 return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise428 }429 }430 431 192 const ast::FunctionType * getFunctionType( const ast::Type * ty ) { 432 193 if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) { … … 437 198 } 438 199 439 VariableExpr * getBaseVar( Expression *expr, int *levels ) {440 int dummy;441 if ( ! levels ) { levels = &dummy; }442 *levels = 0;443 444 while ( true ) {445 if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {446 return varExpr;447 } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) {448 expr = memberExpr->get_aggregate();449 } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {450 expr = addressExpr->get_arg();451 } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {452 // look for compiler-inserted dereference operator453 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );454 if ( ! fn || fn->get_name() != std::string("*?") ) return 0;455 expr = *untypedExpr->begin_args();456 } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) {457 // copy constructors insert comma exprs, look at second argument which contains the variable458 expr = commaExpr->get_arg2();459 continue;460 } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) {461 int lvl1;462 int lvl2;463 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 );464 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 );465 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) {466 *levels = lvl1;467 return var1;468 }469 break;470 } else break;471 472 ++(*levels);473 }474 475 return 0;476 }477 478 200 namespace { 479 201 /// Checks if is a pointer to D … … 488 210 inline D const * as( B const * p ) { 489 211 return reinterpret_cast<D const *>( p ); 490 }491 492 /// Flattens a declaration list493 template<typename Output>494 void flattenList( list< DeclarationWithType* > src, Output out ) {495 for ( DeclarationWithType* decl : src ) {496 ResolvExpr::flatten( decl->get_type(), out );497 }498 }499 500 /// Flattens a list of types501 template<typename Output>502 void flattenList( list< Type* > src, Output out ) {503 for ( Type* ty : src ) {504 ResolvExpr::flatten( ty, out );505 }506 212 } 507 213 … … 515 221 } 516 222 517 /// Checks if two lists of parameters are equal up to polymorphic substitution.518 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) {519 if ( aparams.size() != bparams.size() ) return false;520 521 for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin();522 at != aparams.end(); ++at, ++bt ) {523 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at);524 assertf(aparam, "Aggregate parameters should be type expressions");525 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt);526 assertf(bparam, "Aggregate parameters should be type expressions");527 528 // xxx - might need to let VoidType be a wildcard here too; could have some voids529 // stuffed in for dtype-statics.530 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;531 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;532 }533 534 return true;535 }536 537 223 bool paramListsPolyCompatible( 538 224 std::vector<ast::ptr<ast::Expr>> const & lparams, … … 559 245 return true; 560 246 } 561 }562 563 bool typesPolyCompatible( Type *a, Type *b ) {564 type_index aid{ typeid(*a) };565 // polymorphic types always match566 if ( aid == type_index{typeid(TypeInstType)} ) return true;567 568 type_index bid{ typeid(*b) };569 // polymorphic types always match570 if ( bid == type_index{typeid(TypeInstType)} ) return true;571 572 // can't match otherwise if different types573 if ( aid != bid ) return false;574 575 // recurse through type structure (conditions borrowed from Unify.cc)576 if ( aid == type_index{typeid(BasicType)} ) {577 return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind();578 } else if ( aid == type_index{typeid(PointerType)} ) {579 PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b);580 581 // void pointers should match any other pointer type582 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )583 || typesPolyCompatible( ap->get_base(), bp->get_base() );584 } else if ( aid == type_index{typeid(ReferenceType)} ) {585 ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);586 return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )587 || typesPolyCompatible( ap->get_base(), bp->get_base() );588 } else if ( aid == type_index{typeid(ArrayType)} ) {589 ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);590 591 if ( aa->get_isVarLen() ) {592 if ( ! ba->get_isVarLen() ) return false;593 } else {594 if ( ba->get_isVarLen() ) return false;595 596 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() );597 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() );598 if ( ad && bd599 && ad->get_constant()->get_value() != bd->get_constant()->get_value() )600 return false;601 }602 603 return typesPolyCompatible( aa->get_base(), ba->get_base() );604 } else if ( aid == type_index{typeid(FunctionType)} ) {605 FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b);606 607 vector<Type*> aparams, bparams;608 flattenList( af->get_parameters(), back_inserter( aparams ) );609 flattenList( bf->get_parameters(), back_inserter( bparams ) );610 if ( aparams.size() != bparams.size() ) return false;611 612 vector<Type*> areturns, breturns;613 flattenList( af->get_returnVals(), back_inserter( areturns ) );614 flattenList( bf->get_returnVals(), back_inserter( breturns ) );615 if ( areturns.size() != breturns.size() ) return false;616 617 for ( unsigned i = 0; i < aparams.size(); ++i ) {618 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false;619 }620 for ( unsigned i = 0; i < areturns.size(); ++i ) {621 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false;622 }623 return true;624 } else if ( aid == type_index{typeid(StructInstType)} ) {625 StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b);626 627 if ( aa->get_name() != ba->get_name() ) return false;628 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );629 } else if ( aid == type_index{typeid(UnionInstType)} ) {630 UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b);631 632 if ( aa->get_name() != ba->get_name() ) return false;633 return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );634 } else if ( aid == type_index{typeid(EnumInstType)} ) {635 return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name();636 } else if ( aid == type_index{typeid(TraitInstType)} ) {637 return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name();638 } else if ( aid == type_index{typeid(TupleType)} ) {639 TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b);640 641 vector<Type*> atypes, btypes;642 flattenList( at->get_types(), back_inserter( atypes ) );643 flattenList( bt->get_types(), back_inserter( btypes ) );644 if ( atypes.size() != btypes.size() ) return false;645 646 for ( unsigned i = 0; i < atypes.size(); ++i ) {647 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false;648 }649 return true;650 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type651 247 } 652 248 … … 763 359 } 764 360 765 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {766 // is parameter is not polymorphic, don't need to box767 if ( ! isPolyType( param, exprTyVars ) ) return false;768 Type * newType = arg->clone();769 if ( env ) env->apply( newType );770 std::unique_ptr<Type> manager( newType );771 // if the argument's type is polymorphic, we don't need to box again!772 return ! isPolyType( newType );773 }774 775 361 bool needsBoxing( const ast::Type * param, const ast::Type * arg, 776 362 const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) { … … 786 372 return !isPolyType( newType ); 787 373 } 788 789 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {790 FunctionType * function = getFunctionType( appExpr->function->result );791 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );792 TyVarMap exprTyVars( TypeDecl::Data{} );793 makeTyVarMap( function, exprTyVars );794 return needsBoxing( param, arg, exprTyVars, env );795 }796 374 797 375 bool needsBoxing( … … 801 379 const ast::FunctionType * function = getFunctionType( expr->func->result ); 802 380 assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() ); 803 TypeVarMap exprTyVars = { ast::TypeData() };381 TypeVarMap exprTyVars; 804 382 makeTypeVarMap( function, exprTyVars ); 805 383 return needsBoxing( param, arg, exprTyVars, subst ); 806 384 } 807 385 808 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {809 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );810 }811 812 386 void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) { 813 387 typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) ); … … 817 391 typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) ); 818 392 } 819 820 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {821 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {822 assert( *tyVar );823 addToTyVarMap( *tyVar, tyVarMap );824 }825 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {826 makeTyVarMap( pointer->get_base(), tyVarMap );827 }828 }829 393 830 394 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) { … … 846 410 } 847 411 848 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {849 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {850 os << i->first << " (" << i->second << ") ";851 } // for852 os << std::endl;853 }854 855 412 } // namespace GenPoly 856 413 -
src/GenPoly/GenPoly.h
r0030b508 rfc12f05 23 23 #include "AST/Fwd.hpp" // for ApplicationExpr, BaseInstType, Func... 24 24 #include "SymTab/Mangler.h" // for Mangler 25 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type...26 #include "SynTree/SynTree.h" // for Visitor Nodes27 25 28 26 namespace ast { … … 32 30 namespace GenPoly { 33 31 34 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 35 using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >; 32 struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> { 33 TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {} 34 }; 36 35 37 36 /// Replaces a TypeInstType by its referrent in the environment, if applicable 38 Type* replaceTypeInst( Type* type, const TypeSubstitution* env );39 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );40 37 const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * ); 41 38 42 39 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 43 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );44 40 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 45 41 46 42 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 47 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );48 43 const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr ); 49 44 50 45 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided 51 ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );52 46 const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 ); 53 47 54 48 /// true iff function has dynamic-layout return type under the given type variable map 55 ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );56 49 const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars ); 57 50 58 51 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 59 ReferenceToType *isDynRet( FunctionType *function );60 52 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ); 61 53 62 54 /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type 63 bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );64 55 bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars ); 65 56 66 /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided67 Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );68 69 57 /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 70 Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );71 58 const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 ); 72 73 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;74 /// N will be stored in levels, if provided, will look up substitution in env if provided75 Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );76 59 77 60 /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise; 78 61 /// N will be stored in levels, if provided, will look up substitution in env if provided 79 Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );80 62 const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 ); 81 63 82 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one83 /// polymorphic parameter; will look up substitution in env if provided.84 bool includesPolyType( Type *type, const TypeSubstitution *env = 0 );85 86 /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with87 /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided.88 bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );89 90 64 /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise 91 FunctionType *getFunctionType( Type *ty );92 65 const ast::FunctionType * getFunctionType( const ast::Type * ty ); 93 66 94 /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;95 /// N will be stored in levels, if provided96 VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );97 98 67 /// true iff types are structurally identical, where TypeInstType's match any type. 99 bool typesPolyCompatible( Type *aty, Type *bty );100 68 bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ); 101 69 102 70 /// true if arg requires boxing given exprTyVars 103 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );104 71 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ); 105 72 106 73 /// true if arg requires boxing in the call to appExpr 107 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );108 74 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst ); 109 75 110 76 /// Adds the type variable `tyVar` to `tyVarMap` 111 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );112 77 void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars ); 113 78 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ); 114 79 115 80 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 116 void makeTyVarMap( Type *type, TyVarMap &tyVarMap );117 81 void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ); 118 82 void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars ); 119 120 /// Prints type variable map121 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );122 123 /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().124 inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }125 83 126 84 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 134 92 135 93 /// Gets the name of the layout function for a given aggregate type, given its declaration 136 inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }137 94 inline std::string layoutofName( ast::AggregateDecl const * decl ) { 138 95 return std::string( "_layoutof_" ) + decl->name; -
src/GenPoly/ScrubTyVars.cc
r0030b508 rfc12f05 21 21 #include "ScrubTyVars.h" 22 22 #include "SymTab/Mangler.h" // for mangleType 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Typ...24 #include "SynTree/Expression.h" // for Expression (ptr only), NameExpr25 #include "SynTree/Mutator.h" // for Mutator26 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type27 23 28 24 namespace GenPoly { 29 Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {30 if ( ! tyVars ) {31 if ( typeInst->get_isFtype() ) {32 delete typeInst;33 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );34 } else {35 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );36 delete typeInst;37 return ret;38 }39 }40 41 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );42 if ( tyVar != tyVars->end() ) {43 switch ( tyVar->second.kind ) {44 case TypeDecl::Dtype:45 case TypeDecl::Ttype:46 {47 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );48 delete typeInst;49 return ret;50 }51 case TypeDecl::Ftype:52 delete typeInst;53 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );54 default:55 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind);56 } // switch57 } // if58 return typeInst;59 }60 61 Type * ScrubTyVars::mutateAggregateType( Type * ty ) {62 if ( shouldScrub( ty ) ) {63 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );64 delete ty;65 return ret;66 }67 return ty;68 }69 70 Type * ScrubTyVars::postmutate( StructInstType * structInst ) {71 return mutateAggregateType( structInst );72 }73 74 Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {75 return mutateAggregateType( unionInst );76 }77 78 void ScrubTyVars::primeBaseScrub( Type * type ) {79 // need to determine whether type needs to be scrubbed to determine whether80 // automatic recursion is necessary81 if ( Type * t = shouldScrub( type ) ) {82 visit_children = false;83 GuardValue( dynType );84 dynType = t;85 }86 }87 88 Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {89 // sizeof( T ) => _sizeof_T parameter, which is the size of T90 if ( dynType ) {91 Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );92 return expr;93 } // if94 return szeof;95 }96 97 Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {98 // alignof( T ) => _alignof_T parameter, which is the alignment of T99 if ( dynType ) {100 Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );101 return expr;102 } // if103 return algnof;104 }105 106 Type * ScrubTyVars::postmutate( PointerType * pointer ) {107 if ( dynType ) {108 Type * ret = dynType->acceptMutator( *visitor );109 ret->get_qualifiers() |= pointer->get_qualifiers();110 pointer->base = nullptr;111 delete pointer;112 return ret;113 }114 return pointer;115 }116 25 117 26 namespace { -
src/GenPoly/ScrubTyVars.h
r0030b508 rfc12f05 19 19 20 20 #include "AST/Fwd.hpp" // for Node 21 #include "Common/PassVisitor.h"22 21 #include "GenPoly.h" // for TyVarMap, isPolyType, isDynType 23 #include "SynTree/Mutator.h" // for Mutator24 #include "SynTree/Type.h" // for Type (ptr only), PointerType (ptr only)25 26 class AlignofExpr;27 class Expression;28 class SizeofExpr;29 22 30 23 namespace GenPoly { 31 struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {32 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables33 enum ScrubMode { FromMap, DynamicFromMap, All };34 35 ScrubTyVars() : tyVars(nullptr), mode( All ) {}36 37 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {}38 39 public:40 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,41 /// and sizeof/alignof expressions with the proper variable42 template< typename SynTreeClass >43 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );44 45 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,46 /// and sizeof/alignof expressions with the proper variable47 template< typename SynTreeClass >48 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars );49 50 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type,51 /// and sizeof/alignof expressions with the proper variable52 template< typename SynTreeClass >53 static SynTreeClass *scrubAll( SynTreeClass *target );54 55 /// determine if children should be visited based on whether base type should be scrubbed.56 void primeBaseScrub( Type * );57 58 void premutate( TypeInstType * ) { visit_children = false; }59 void premutate( StructInstType * ) { visit_children = false; }60 void premutate( UnionInstType * ) { visit_children = false; }61 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }62 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }63 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }64 65 Type * postmutate( TypeInstType * typeInst );66 Type * postmutate( StructInstType * structInst );67 Type * postmutate( UnionInstType * unionInst );68 Expression * postmutate( SizeofExpr * szeof );69 Expression * postmutate( AlignofExpr * algnof );70 Type * postmutate( PointerType * pointer );71 72 private:73 /// Returns the type if it should be scrubbed, NULL otherwise.74 Type* shouldScrub( Type *ty ) {75 switch ( mode ) {76 case FromMap: return isPolyType( ty, *tyVars );77 case DynamicFromMap: return isDynType( ty, *tyVars );78 case All: return isPolyType( ty );79 }80 assert(false); return nullptr; // unreachable81 // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );82 }83 84 /// Mutates (possibly generic) aggregate types appropriately85 Type* mutateAggregateType( Type *ty );86 87 const TyVarMap *tyVars; ///< Type variables to scrub88 ScrubMode mode; ///< which type variables to scrub? [FromMap]89 90 Type * dynType = nullptr; ///< result of shouldScrub91 };92 93 template< typename SynTreeClass >94 SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {95 PassVisitor<ScrubTyVars> scrubber( tyVars );96 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );97 }98 99 template< typename SynTreeClass >100 SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {101 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );102 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );103 }104 105 template< typename SynTreeClass >106 SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {107 PassVisitor<ScrubTyVars> scrubber;108 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );109 }110 24 111 25 // ScrubMode and scrubTypeVarsBase are internal. -
src/GenPoly/SpecializeNew.cpp
r0030b508 rfc12f05 23 23 #include "GenPoly/GenPoly.h" // for getFunctionType 24 24 #include "ResolvExpr/FindOpenVars.h" // for findOpenVars 25 #include "ResolvExpr/TypeEnvironment.h" // for FirstOpen, FirstClosed26 25 27 26 namespace GenPoly { … … 81 80 } 82 81 83 // The number of elements in a type if it is a flattened tuple.84 size_t flatT upleSize( const ast::Type * type) {85 if ( auto tuple = dynamic_cast<const ast::TupleType *>( type ) ) {86 size_t sum = 0;87 for ( auto t : *tuple) {88 sum += flatT upleSize( t);89 } 90 return sum;91 } else {92 return 1;93 }82 // The number of elements in a list, if all tuples had been flattened. 83 size_t flatTypeListSize( const std::vector<ast::ptr<ast::Type>> & types ) { 84 size_t sum = 0; 85 for ( const ast::ptr<ast::Type> & type : types ) { 86 if ( const ast::TupleType * tuple = type.as<ast::TupleType>() ) { 87 sum += flatTypeListSize( tuple->types ); 88 } else { 89 sum += 1; 90 } 91 } 92 return sum; 94 93 } 95 94 96 95 // Find the total number of components in a parameter list. 97 96 size_t functionParameterSize( const ast::FunctionType * type ) { 98 size_t sum = 0; 99 for ( auto param : type->params ) { 100 sum += flatTupleSize( param ); 101 } 102 return sum; 97 return flatTypeListSize( type->params ); 103 98 } 104 99 -
src/GenPoly/module.mk
r0030b508 rfc12f05 23 23 SRC += $(SRC_GENPOLY) \ 24 24 GenPoly/BoxNew.cpp \ 25 GenPoly/Box.cc \26 25 GenPoly/Box.h \ 27 26 GenPoly/ErasableScopedMap.h \ … … 29 28 GenPoly/FindFunction.h \ 30 29 GenPoly/InstantiateGenericNew.cpp \ 31 GenPoly/InstantiateGeneric.cc \32 30 GenPoly/InstantiateGeneric.h \ 33 31 GenPoly/LvalueNew.cpp \ 34 GenPoly/Lvalue.cc \35 32 GenPoly/ScopedSet.h \ 36 33 GenPoly/ScrubTyVars.cc \ 37 34 GenPoly/ScrubTyVars.h \ 38 GenPoly/Specialize.cc \39 35 GenPoly/SpecializeNew.cpp \ 40 36 GenPoly/Specialize.h -
src/InitTweak/FixGlobalInit.cc
r0030b508 rfc12f05 20 20 #include <algorithm> // for replace_if 21 21 22 #include "Common/PassVisitor.h"23 #include "Common/UniqueName.h" // for UniqueName24 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt25 #include "SynTree/LinkageSpec.h" // for C26 #include "SynTree/Attribute.h" // for Attribute27 #include "SynTree/Constant.h" // for Constant28 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declaration29 #include "SynTree/Expression.h" // for ConstantExpr, Expression (ptr only)30 #include "SynTree/Initializer.h" // for ConstructorInit, Initializer31 #include "SynTree/Label.h" // for Label32 #include "SynTree/Statement.h" // for CompoundStmt, Statement (ptr only)33 #include "SynTree/Type.h" // for Type, Type::StorageClasses, Functi...34 #include "SynTree/Visitor.h" // for acceptAll, Visitor35 36 22 #include "AST/Expr.hpp" 37 23 #include "AST/Node.hpp" 38 24 #include "AST/Pass.hpp" 25 #include "Common/UniqueName.h" // for UniqueName 26 #include "InitTweak.h" // for isIntrinsicSingleArgCallStmt 39 27 40 28 namespace InitTweak { 41 class GlobalFixer : public WithShortCircuiting {42 public:43 GlobalFixer( bool inLibrary );44 45 void previsit( ObjectDecl *objDecl );46 void previsit( FunctionDecl *functionDecl );47 void previsit( StructDecl *aggregateDecl );48 void previsit( UnionDecl *aggregateDecl );49 void previsit( EnumDecl *aggregateDecl );50 void previsit( TraitDecl *aggregateDecl );51 void previsit( TypeDecl *typeDecl );52 53 UniqueName tempNamer;54 FunctionDecl * initFunction;55 FunctionDecl * destroyFunction;56 };57 58 29 class GlobalFixer_new : public ast::WithShortCircuiting { 59 30 public: … … 69 40 std::list< ast::ptr<ast::Stmt> > destroyStmts; 70 41 }; 71 72 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) {73 PassVisitor<GlobalFixer> visitor( inLibrary );74 acceptAll( translationUnit, visitor );75 GlobalFixer & fixer = visitor.pass;76 // don't need to include function if it's empty77 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {78 delete fixer.initFunction;79 } else {80 translationUnit.push_back( fixer.initFunction );81 } // if82 83 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {84 delete fixer.destroyFunction;85 } else {86 translationUnit.push_back( fixer.destroyFunction );87 } // if88 }89 90 GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) {91 std::list< Expression * > ctorParameters;92 std::list< Expression * > dtorParameters;93 if ( inLibrary ) {94 // Constructor/destructor attributes take a single parameter which95 // is the priority, with lower numbers meaning higher priority.96 // Functions specified with priority are guaranteed to run before97 // functions without a priority. To ensure that constructors and destructors98 // for library code are run before constructors and destructors for user code,99 // specify a priority when building the library. Priorities 0-100 are reserved by gcc.100 // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals,101 // allowing room for overriding with a higher priority.102 ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );103 dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );104 }105 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );106 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );107 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );108 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );109 }110 42 111 43 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { … … 141 73 } 142 74 143 void GlobalFixer::previsit( ObjectDecl *objDecl ) {144 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();145 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();146 147 // C allows you to initialize objects with constant expressions148 // xxx - this is an optimization. Need to first resolve constructors before we decide149 // to keep C-style initializer.150 // if ( isConstExpr( objDecl->get_init() ) ) return;151 152 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {153 // a decision should have been made by the resolver, so ctor and init are not both non-NULL154 assert( ! ctorInit->ctor || ! ctorInit->init );155 156 Statement * dtor = ctorInit->dtor;157 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {158 // don't need to call intrinsic dtor, because it does nothing, but159 // non-intrinsic dtors must be called160 destroyStatements.push_front( dtor );161 ctorInit->dtor = nullptr;162 } // if163 if ( Statement * ctor = ctorInit->ctor ) {164 addDataSectionAttribute( objDecl );165 initStatements.push_back( ctor );166 objDecl->init = nullptr;167 ctorInit->ctor = nullptr;168 } else if ( Initializer * init = ctorInit->init ) {169 objDecl->init = init;170 ctorInit->init = nullptr;171 } else {172 // no constructor and no initializer, which is okay173 objDecl->init = nullptr;174 } // if175 delete ctorInit;176 } // if177 }178 179 75 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 180 76 auto mutDecl = mutate(objDecl); … … 207 103 } 208 104 209 // only modify global variables210 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }211 void GlobalFixer::previsit( StructDecl * ) { visit_children = false; }212 void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; }213 void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; }214 void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; }215 void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; }216 217 105 } // namespace InitTweak 218 106 -
src/InitTweak/FixInitNew.cpp
r0030b508 rfc12f05 33 33 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 34 34 35 extern bool ctordtorp; // print all debug36 extern bool ctorp; // print ctor debug37 extern bool cpctorp; // print copy ctor debug38 extern bool dtorp; // print dtor debug35 bool ctordtorp = false; // print all debug 36 bool ctorp = false; // print ctor debug 37 bool cpctorp = false; // print copy ctor debug 38 bool dtorp = false; // print dtor debug 39 39 #define PRINT( text ) if ( ctordtorp ) { text } 40 40 #define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text } … … 178 178 /// (currently by FixInit) 179 179 struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> { 180 typedef std::list< ObjectDecl * > OrderedDecls;181 typedef std::list< OrderedDecls > OrderedDeclsStack;182 183 180 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {} 184 181 … … 194 191 ast::Pass<LabelFinder> & finder; 195 192 LabelFinder::LabelMap & labelVars; 196 OrderedDeclsStack reverseDeclOrder;197 193 }; 198 194 -
src/InitTweak/GenInit.cc
r0030b508 rfc12f05 29 29 #include "CompilationState.h" 30 30 #include "CodeGen/OperatorTable.h" 31 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort...32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/ToString.hpp" // for toCString … … 38 37 #include "InitTweak.h" // for isConstExpr, InitExpander, checkIn... 39 38 #include "ResolvExpr/Resolver.h" 40 #include "SymTab/Autogen.h" // for genImplicitCall41 39 #include "SymTab/GenImplicitCall.hpp" // for genImplicitCall 42 40 #include "SymTab/Mangler.h" // for Mangler 43 #include "SynTree/LinkageSpec.h" // for isOverridable, C44 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType45 #include "SynTree/Expression.h" // for VariableExpr, UntypedExpr, Address...46 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit, Initi...47 #include "SynTree/Label.h" // for Label48 #include "SynTree/Mutator.h" // for mutateAll49 #include "SynTree/Statement.h" // for CompoundStmt, ImplicitCtorDtorStmt50 #include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers51 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept52 41 #include "Tuples/Tuples.h" // for maybeImpure 53 42 #include "Validate/FindSpecialDecls.h" // for SizeType 54 43 55 44 namespace InitTweak { 56 namespace {57 const std::list<Label> noLabels;58 const std::list<Expression *> noDesignators;59 }60 61 struct ReturnFixer : public WithStmtsToAdd, public WithGuards {62 /// consistently allocates a temporary variable for the return value63 /// of a function so that anything which the resolver decides can be constructed64 /// into the return type of a function can be returned.65 static void makeReturnTemp( std::list< Declaration * > &translationUnit );66 67 void premutate( FunctionDecl *functionDecl );68 void premutate( ReturnStmt * returnStmt );69 70 protected:71 FunctionType * ftype = nullptr;72 std::string funcName;73 };74 75 struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor> {76 /// create constructor and destructor statements for object declarations.77 /// the actual call statements will be added in after the resolver has run78 /// so that the initializer expression is only removed if a constructor is found79 /// and the same destructor call is inserted in all of the appropriate locations.80 static void generateCtorDtor( std::list< Declaration * > &translationUnit );81 82 void previsit( ObjectDecl * );83 void previsit( FunctionDecl *functionDecl );84 85 // should not traverse into any of these declarations to find objects86 // that need to be constructed or destructed87 void previsit( StructDecl *aggregateDecl );88 void previsit( AggregateDecl * ) { visit_children = false; }89 void previsit( NamedTypeDecl * ) { visit_children = false; }90 void previsit( FunctionType * ) { visit_children = false; }91 92 void previsit( CompoundStmt * compoundStmt );93 94 private:95 // set of mangled type names for which a constructor or destructor exists in the current scope.96 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus97 // should not have a ConstructorInit generated.98 99 ManagedTypes managedTypes;100 bool inFunction = false;101 };102 103 struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {104 /// hoist dimension from array types in object declaration so that it uses a single105 /// const variable of type size_t, so that side effecting array dimensions are only106 /// computed once.107 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );108 109 void premutate( ObjectDecl * objectDecl );110 DeclarationWithType * postmutate( ObjectDecl * objectDecl );111 void premutate( FunctionDecl *functionDecl );112 // should not traverse into any of these declarations to find objects113 // that need to be constructed or destructed114 void premutate( AggregateDecl * ) { visit_children = false; }115 void premutate( NamedTypeDecl * ) { visit_children = false; }116 void premutate( FunctionType * ) { visit_children = false; }117 118 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)119 void premutate( EnumDecl * ) {}120 121 void hoist( Type * type );122 123 Type::StorageClasses storageClasses;124 bool inFunction = false;125 };126 127 struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {128 /// hoist dimension from array types in object declaration so that it uses a single129 /// const variable of type size_t, so that side effecting array dimensions are only130 /// computed once.131 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );132 133 void premutate( ObjectDecl * objectDecl );134 DeclarationWithType * postmutate( ObjectDecl * objectDecl );135 void premutate( FunctionDecl *functionDecl );136 // should not traverse into any of these declarations to find objects137 // that need to be constructed or destructed138 void premutate( AggregateDecl * ) { visit_children = false; }139 void premutate( NamedTypeDecl * ) { visit_children = false; }140 void premutate( FunctionType * ) { visit_children = false; }141 142 void hoist( Type * type );143 144 Type::StorageClasses storageClasses;145 bool inFunction = false;146 };147 148 void genInit( std::list< Declaration * > & translationUnit ) {149 if (!useNewAST) {150 HoistArrayDimension::hoistArrayDimension( translationUnit );151 }152 else {153 HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );154 }155 fixReturnStatements( translationUnit );156 157 if (!useNewAST) {158 CtorDtor::generateCtorDtor( translationUnit );159 }160 }161 162 void fixReturnStatements( std::list< Declaration * > & translationUnit ) {163 PassVisitor<ReturnFixer> fixer;164 mutateAll( translationUnit, fixer );165 }166 167 void ReturnFixer::premutate( ReturnStmt *returnStmt ) {168 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();169 assert( returnVals.size() == 0 || returnVals.size() == 1 );170 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address171 // is being returned172 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {173 // explicitly construct the return value using the return expression and the retVal object174 assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );175 176 ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );177 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {178 // return statement has already been mutated - don't need to do it again179 if ( varExpr->var == retVal ) return;180 }181 Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );182 assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );183 stmtsToAddBefore.push_back( stmt );184 185 // return the retVal object186 returnStmt->expr = new VariableExpr( returnVals.front() );187 } // if188 }189 190 void ReturnFixer::premutate( FunctionDecl *functionDecl ) {191 GuardValue( ftype );192 GuardValue( funcName );193 194 ftype = functionDecl->type;195 funcName = functionDecl->name;196 }197 198 // precompute array dimension expression, because constructor generation may duplicate it,199 // which would be incorrect if it is a side-effecting computation.200 void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {201 PassVisitor<HoistArrayDimension> hoister;202 mutateAll( translationUnit, hoister );203 }204 205 void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {206 GuardValue( storageClasses );207 storageClasses = objectDecl->get_storageClasses();208 }209 210 DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {211 hoist( objectDecl->get_type() );212 return objectDecl;213 }214 215 void HoistArrayDimension::hoist( Type * type ) {216 // if in function, generate const size_t var217 static UniqueName dimensionName( "_array_dim" );218 219 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.220 if ( ! inFunction ) return;221 if ( storageClasses.is_static ) return;222 223 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {224 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?225 226 // need to resolve array dimensions in order to accurately determine if constexpr227 ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );228 // array is variable-length when the dimension is not constexpr229 arrayType->isVarLen = ! isConstExpr( arrayType->dimension );230 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.231 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve232 // still try to detect constant expressions233 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;234 235 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );236 arrayDimension->get_type()->set_const( true );237 238 arrayType->set_dimension( new VariableExpr( arrayDimension ) );239 declsToAddBefore.push_back( arrayDimension );240 241 hoist( arrayType->get_base() );242 return;243 }244 }245 246 void HoistArrayDimension::premutate( FunctionDecl * ) {247 GuardValue( inFunction );248 inFunction = true;249 }250 251 // precompute array dimension expression, because constructor generation may duplicate it,252 // which would be incorrect if it is a side-effecting computation.253 void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {254 PassVisitor<HoistArrayDimension_NoResolve> hoister;255 mutateAll( translationUnit, hoister );256 }257 258 void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {259 GuardValue( storageClasses );260 storageClasses = objectDecl->get_storageClasses();261 }262 263 DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {264 hoist( objectDecl->get_type() );265 return objectDecl;266 }267 268 void HoistArrayDimension_NoResolve::hoist( Type * type ) {269 // if in function, generate const size_t var270 static UniqueName dimensionName( "_array_dim" );271 272 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.273 if ( ! inFunction ) return;274 if ( storageClasses.is_static ) return;275 276 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {277 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?278 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.279 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve280 // still try to detect constant expressions281 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;282 283 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );284 arrayDimension->get_type()->set_const( true );285 286 arrayType->set_dimension( new VariableExpr( arrayDimension ) );287 declsToAddBefore.push_back( arrayDimension );288 289 hoist( arrayType->get_base() );290 return;291 }292 }293 294 void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {295 GuardValue( inFunction );296 inFunction = true;297 }298 45 299 46 namespace { … … 526 273 } 527 274 528 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {529 PassVisitor<CtorDtor> ctordtor;530 acceptAll( translationUnit, ctordtor );531 }532 533 bool ManagedTypes::isManaged( Type * type ) const {534 // references are never constructed535 if ( dynamic_cast< ReferenceType * >( type ) ) return false;536 // need to clear and reset qualifiers when determining if a type is managed537 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );538 type->get_qualifiers() = Type::Qualifiers();539 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {540 // tuple is also managed if any of its components are managed541 if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {542 return true;543 }544 }545 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)546 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );547 }548 549 bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {550 Type * type = objDecl->get_type();551 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {552 // must always construct VLAs with an initializer, since this is an error in C553 if ( at->isVarLen && objDecl->init ) return true;554 type = at->get_base();555 }556 return isManaged( type );557 }558 559 // why is this not just on FunctionDecl?560 void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {561 // if this function is a user-defined constructor or destructor, mark down the type as "managed"562 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {563 std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();564 assert( ! params.empty() );565 Type * type = InitTweak::getPointerBase( params.front()->get_type() );566 assert( type );567 managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );568 }569 }570 571 void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {572 // don't construct members, but need to take note if there is a managed member,573 // because that means that this type is also managed574 for ( Declaration * member : aggregateDecl->get_members() ) {575 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {576 if ( isManaged( field ) ) {577 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that578 // polymorphic constructors make generic types managed types579 StructInstType inst( Type::Qualifiers(), aggregateDecl );580 managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );581 break;582 }583 }584 }585 }586 587 void ManagedTypes::beginScope() { managedTypes.beginScope(); }588 void ManagedTypes::endScope() { managedTypes.endScope(); }589 590 275 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 591 276 // references are never constructed … … 647 332 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 648 333 649 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {650 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor651 assertf( objDecl, "genCtorDtor passed null objDecl" );652 std::list< Statement * > stmts;653 InitExpander_old srcParam( maybeClone( arg ) );654 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );655 assert( stmts.size() <= 1 );656 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;657 658 }659 660 334 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 661 335 assertf(objDecl, "genCtorDtor passed null objDecl"); 662 336 InitExpander_new srcParam(arg); 663 337 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 664 }665 666 ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {667 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor668 // for each constructable object669 std::list< Statement * > ctor;670 std::list< Statement * > dtor;671 672 InitExpander_old srcParam( objDecl->get_init() );673 InitExpander_old nullParam( (Initializer *)NULL );674 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );675 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );676 677 // Currently genImplicitCall produces a single Statement - a CompoundStmt678 // which wraps everything that needs to happen. As such, it's technically679 // possible to use a Statement ** in the above calls, but this is inherently680 // unsafe, so instead we take the slightly less efficient route, but will be681 // immediately informed if somehow the above assumption is broken. In this case,682 // we could always wrap the list of statements at this point with a CompoundStmt,683 // but it seems reasonable at the moment for this to be done by genImplicitCall684 // itself. It is possible that genImplicitCall produces no statements (e.g. if685 // an array type does not have a dimension). In this case, it's fine to ignore686 // the object for the purposes of construction.687 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );688 if ( ctor.size() == 1 ) {689 // need to remember init expression, in case no ctors exist690 // if ctor does exist, want to use ctor expression instead of init691 // push this decision to the resolver692 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );693 return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );694 }695 return nullptr;696 }697 698 void CtorDtor::previsit( ObjectDecl * objDecl ) {699 managedTypes.handleDWT( objDecl );700 // hands off if @=, extern, builtin, etc.701 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C702 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {703 // constructed objects cannot be designated704 if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );705 // constructed objects should not have initializers nested too deeply706 if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );707 708 objDecl->set_init( genCtorInit( objDecl ) );709 }710 }711 712 void CtorDtor::previsit( FunctionDecl *functionDecl ) {713 visit_children = false; // do not try and construct parameters or forall parameters714 GuardValue( inFunction );715 inFunction = true;716 717 managedTypes.handleDWT( functionDecl );718 719 GuardScope( managedTypes );720 // go through assertions and recursively add seen ctor/dtors721 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {722 for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {723 managedTypes.handleDWT( assertion );724 }725 }726 727 maybeAccept( functionDecl->get_statements(), *visitor );728 }729 730 void CtorDtor::previsit( StructDecl *aggregateDecl ) {731 visit_children = false; // do not try to construct and destruct aggregate members732 733 managedTypes.handleStruct( aggregateDecl );734 }735 736 void CtorDtor::previsit( CompoundStmt * ) {737 GuardScope( managedTypes );738 338 } 739 339 -
src/InitTweak/GenInit.h
r0030b508 rfc12f05 22 22 #include "Common/CodeLocation.h" 23 23 #include "GenPoly/ScopedSet.h" // for ScopedSet 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 namespace InitTweak { 27 26 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 void genInit( std::list< Declaration * > & translationUnit );29 27 void genInit( ast::TranslationUnit & translationUnit ); 30 28 31 29 /// Converts return statements into copy constructor calls on the hidden return variable. 32 30 /// This pass must happen before auto-gen. 33 void fixReturnStatements( std::list< Declaration * > & translationUnit );34 31 void fixReturnStatements( ast::TranslationUnit & translationUnit ); 35 32 36 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 37 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );38 34 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 39 35 40 36 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer 41 ConstructorInit * genCtorInit( ObjectDecl * objDecl );42 37 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ); 43 44 class ManagedTypes {45 public:46 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed47 bool isManaged( Type * type ) const; // determine if type is managed48 49 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor50 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed51 52 void beginScope();53 void endScope();54 private:55 GenPoly::ScopedSet< std::string > managedTypes;56 };57 38 58 39 class ManagedTypes_new { -
src/InitTweak/InitTweak.cc
r0030b508 rfc12f05 29 29 #include "AST/Type.hpp" 30 30 #include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto... 31 #include "Common/PassVisitor.h"32 31 #include "Common/SemanticError.h" // for SemanticError 33 32 #include "Common/UniqueName.h" // for UniqueName … … 36 35 #include "InitTweak.h" 37 36 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 38 #include "SymTab/Autogen.h"39 #include "SymTab/Indexer.h" // for Indexer40 #include "SynTree/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic41 #include "SynTree/Attribute.h" // for Attribute42 #include "SynTree/Constant.h" // for Constant43 #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType44 #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati...45 #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation46 #include "SynTree/Label.h" // for Label47 #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt48 #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType49 #include "SynTree/Visitor.h" // for Visitor, maybeAccept50 37 #include "Tuples/Tuples.h" // for Tuples::isTtype 51 38 52 39 namespace InitTweak { 53 40 namespace { 54 struct HasDesignations : public WithShortCircuiting {55 bool hasDesignations = false;56 57 void previsit( BaseSyntaxNode * ) {58 // short circuit if we already know there are designations59 if ( hasDesignations ) visit_children = false;60 }61 62 void previsit( Designation * des ) {63 // short circuit if we already know there are designations64 if ( hasDesignations ) visit_children = false;65 else if ( ! des->get_designators().empty() ) {66 hasDesignations = true;67 visit_children = false;68 }69 }70 };71 72 struct InitDepthChecker : public WithGuards {73 bool depthOkay = true;74 Type * type;75 int curDepth = 0, maxDepth = 0;76 InitDepthChecker( Type * type ) : type( type ) {77 Type * t = type;78 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {79 maxDepth++;80 t = at->get_base();81 }82 maxDepth++;83 }84 void previsit( ListInit * ) {85 curDepth++;86 GuardAction( [this]() { curDepth--; } );87 if ( curDepth > maxDepth ) depthOkay = false;88 }89 };90 91 41 struct HasDesignations_new : public ast::WithShortCircuiting { 92 42 bool result = false; … … 107 57 }; 108 58 109 struct InitDepthChecker_new : public ast::WithGuards{59 struct InitDepthChecker_new { 110 60 bool result = true; 111 61 const ast::Type * type; … … 119 69 maxDepth++; 120 70 } 121 void previsit( ListInit * ) {71 void previsit( ast::ListInit const * ) { 122 72 curDepth++; 123 GuardAction( [this]() { curDepth--; } );124 73 if ( curDepth > maxDepth ) result = false; 125 74 } 126 }; 127 128 struct InitFlattener_old : public WithShortCircuiting { 129 void previsit( SingleInit * singleInit ) { 130 visit_children = false; 131 argList.push_back( singleInit->value->clone() ); 132 } 133 std::list< Expression * > argList; 75 void postvisit( ast::ListInit const * ) { 76 curDepth--; 77 } 134 78 }; 135 79 … … 144 88 145 89 } // anonymous namespace 146 147 std::list< Expression * > makeInitList( Initializer * init ) {148 PassVisitor<InitFlattener_old> flattener;149 maybeAccept( init, flattener );150 return flattener.pass.argList;151 }152 153 bool isDesignated( Initializer * init ) {154 PassVisitor<HasDesignations> finder;155 maybeAccept( init, finder );156 return finder.pass.hasDesignations;157 }158 159 bool checkInitDepth( ObjectDecl * objDecl ) {160 PassVisitor<InitDepthChecker> checker( objDecl->type );161 maybeAccept( objDecl->init, checker );162 return checker.pass.depthOkay;163 }164 90 165 91 bool isDesignated( const ast::Init * init ) { … … 180 106 return std::move( flattener.core.argList ); 181 107 } 182 183 class InitExpander_old::ExpanderImpl {184 public:185 virtual ~ExpanderImpl() = default;186 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;187 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;188 };189 190 class InitImpl_old : public InitExpander_old::ExpanderImpl {191 public:192 InitImpl_old( Initializer * init ) : init( init ) {}193 virtual ~InitImpl_old() = default;194 195 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {196 // this is wrong, but just a placeholder for now197 // if ( ! flattened ) flatten( indices );198 // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();199 return makeInitList( init );200 }201 202 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );203 private:204 Initializer * init;205 };206 207 class ExprImpl_old : public InitExpander_old::ExpanderImpl {208 public:209 ExprImpl_old( Expression * expr ) : arg( expr ) {}210 virtual ~ExprImpl_old() { delete arg; }211 212 virtual std::list< Expression * > next( std::list< Expression * > & indices ) {213 std::list< Expression * > ret;214 Expression * expr = maybeClone( arg );215 if ( expr ) {216 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {217 // go through indices and layer on subscript exprs ?[?]218 ++it;219 UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );220 subscriptExpr->get_args().push_back( expr );221 subscriptExpr->get_args().push_back( (*it)->clone() );222 expr = subscriptExpr;223 }224 ret.push_back( expr );225 }226 return ret;227 }228 229 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );230 private:231 Expression * arg;232 };233 234 InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}235 236 InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}237 238 std::list< Expression * > InitExpander_old::operator*() {239 return cur;240 }241 242 InitExpander_old & InitExpander_old::operator++() {243 cur = expander->next( indices );244 return *this;245 }246 247 // use array indices list to build switch statement248 void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {249 indices.push_back( index );250 indices.push_back( dimension );251 }252 253 void InitExpander_old::clearArrayIndices() {254 deleteAll( indices );255 indices.clear();256 }257 258 bool InitExpander_old::addReference() {259 bool added = false;260 for ( Expression *& expr : cur ) {261 expr = new AddressExpr( expr );262 added = true;263 }264 return added;265 }266 267 namespace {268 /// given index i, dimension d, initializer init, and callExpr f, generates269 /// if (i < d) f(..., init)270 /// ++i;271 /// so that only elements within the range of the array are constructed272 template< typename OutIterator >273 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {274 UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );275 cond->get_args().push_back( index->clone() );276 cond->get_args().push_back( dimension->clone() );277 278 std::list< Expression * > args = makeInitList( init );279 callExpr->get_args().splice( callExpr->get_args().end(), args );280 281 *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );282 283 UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );284 increment->get_args().push_back( index->clone() );285 *out++ = new ExprStmt( increment );286 }287 288 template< typename OutIterator >289 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {290 if ( idx == idxEnd ) return;291 Expression * index = *idx++;292 assert( idx != idxEnd );293 Expression * dimension = *idx++;294 295 // xxx - may want to eventually issue a warning here if we can detect296 // that the number of elements exceeds to dimension of the array297 if ( idx == idxEnd ) {298 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {299 for ( Initializer * init : *listInit ) {300 buildCallExpr( callExpr->clone(), index, dimension, init, out );301 }302 } else {303 buildCallExpr( callExpr->clone(), index, dimension, init, out );304 }305 } else {306 std::list< Statement * > branches;307 308 unsigned long cond = 0;309 ListInit * listInit = dynamic_cast< ListInit * >( init );310 if ( ! listInit ) {311 // xxx - this shouldn't be an error, but need a way to312 // terminate without creating output, so should catch this error313 SemanticError( init->location, "unbalanced list initializers" );314 }315 316 static UniqueName targetLabel( "L__autogen__" );317 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );318 for ( Initializer * init : *listInit ) {319 Expression * condition;320 // check for designations321 // if ( init-> ) {322 condition = new ConstantExpr( Constant::from_ulong( cond ) );323 ++cond;324 // } else {325 // condition = // ... take designation326 // cond = // ... take designation+1327 // }328 std::list< Statement * > stmts;329 build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );330 stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );331 CaseStmt * caseStmt = new CaseStmt( condition, stmts );332 branches.push_back( caseStmt );333 }334 *out++ = new SwitchStmt( index->clone(), branches );335 *out++ = new NullStmt( { switchLabel } );336 }337 }338 }339 340 // if array came with an initializer list: initialize each element341 // may have more initializers than elements in the array - need to check at each index that342 // we haven't exceeded size.343 // may have fewer initializers than elements in the array - need to default construct344 // remaining elements.345 // To accomplish this, generate switch statement, consuming all of expander's elements346 Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {347 if ( ! init ) return nullptr;348 CompoundStmt * block = new CompoundStmt();349 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );350 if ( block->get_kids().empty() ) {351 delete block;352 return nullptr;353 } else {354 init = nullptr; // init was consumed in creating the list init355 return block;356 }357 }358 359 Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {360 return nullptr;361 }362 363 Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {364 return expander->buildListInit( dst, indices );365 }366 108 367 109 class InitExpander_new::ExpanderImpl { … … 535 277 } 536 278 537 Type * getTypeofThis( FunctionType * ftype ) {538 assertf( ftype, "getTypeofThis: nullptr ftype" );539 ObjectDecl * thisParam = getParamThis( ftype );540 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );541 return refType->base;542 }543 544 279 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 545 280 assertf( ftype, "getTypeofThis: nullptr ftype" ); … … 552 287 } 553 288 554 ObjectDecl * getParamThis( FunctionType * ftype ) {555 assertf( ftype, "getParamThis: nullptr ftype" );556 auto & params = ftype->parameters;557 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );558 return strict_dynamic_cast< ObjectDecl * >( params.front() );559 }560 561 289 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 562 290 assertf( func, "getParamThis: nullptr ftype" ); … … 564 292 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 565 293 return params.front().strict_as<ast::ObjectDecl>(); 566 }567 568 bool tryConstruct( DeclarationWithType * dwt ) {569 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );570 if ( ! objDecl ) return false;571 return (objDecl->get_init() == nullptr ||572 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))573 && ! objDecl->get_storageClasses().is_extern574 && isConstructable( objDecl->type );575 }576 577 bool isConstructable( Type * type ) {578 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );579 294 } 580 295 … … 593 308 } 594 309 595 struct CallFinder_old {596 CallFinder_old( const std::list< std::string > & names ) : names( names ) {}597 598 void postvisit( ApplicationExpr * appExpr ) {599 handleCallExpr( appExpr );600 }601 602 void postvisit( UntypedExpr * untypedExpr ) {603 handleCallExpr( untypedExpr );604 }605 606 std::list< Expression * > * matches;607 private:608 const std::list< std::string > names;609 610 template< typename CallExpr >611 void handleCallExpr( CallExpr * expr ) {612 std::string fname = getFunctionName( expr );613 if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {614 matches->push_back( expr );615 }616 }617 };618 619 310 struct CallFinder_new final { 620 311 std::vector< const ast::Expr * > matches; … … 634 325 }; 635 326 636 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {637 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );638 finder.pass.matches = &matches;639 maybeAccept( stmt, finder );640 }641 642 327 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 643 328 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; … … 646 331 } 647 332 648 Expression * getCtorDtorCall( Statement * stmt ) {649 std::list< Expression * > matches;650 collectCtorDtorCalls( stmt, matches );651 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );652 return matches.size() == 1 ? matches.front() : nullptr;653 }654 655 333 namespace { 656 DeclarationWithType * getCalledFunction( Expression * expr );657 658 template<typename CallExpr>659 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {660 // (*f)(x) => should get "f"661 std::string name = getFunctionName( expr );662 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );663 assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );664 return getCalledFunction( expr->get_args().front() );665 }666 667 DeclarationWithType * getCalledFunction( Expression * expr ) {668 assert( expr );669 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {670 return varExpr->var;671 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {672 return memberExpr->member;673 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {674 return getCalledFunction( castExpr->arg );675 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {676 return handleDerefCalledFunction( untypedExpr );677 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {678 return handleDerefCalledFunction( appExpr );679 } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {680 return getCalledFunction( addrExpr->arg );681 } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {682 return getCalledFunction( commaExpr->arg2 );683 }684 return nullptr;685 }686 687 DeclarationWithType * getFunctionCore( const Expression * expr ) {688 if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {689 return getCalledFunction( appExpr->function );690 } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {691 return getCalledFunction( untyped->function );692 }693 assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );694 }695 }696 697 DeclarationWithType * getFunction( Expression * expr ) {698 return getFunctionCore( expr );699 }700 701 const DeclarationWithType * getFunction( const Expression * expr ) {702 return getFunctionCore( expr );703 }704 705 ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {706 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );707 if ( ! appExpr ) return nullptr;708 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );709 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );710 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor711 // will call all member dtors, and some members may have a user defined dtor.712 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;713 }714 715 namespace {716 template <typename Predicate>717 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {718 std::list< Expression * > callExprs;719 collectCtorDtorCalls( stmt, callExprs );720 return std::all_of( callExprs.begin(), callExprs.end(), pred);721 }722 723 334 template <typename Predicate> 724 335 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { … … 726 337 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 727 338 } 728 }729 730 bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {731 return allofCtorDtor( stmt, []( Expression * callExpr ){732 if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {733 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );734 assert( funcType );735 return funcType->get_parameters().size() == 1;736 }737 return false;738 });739 339 } 740 340 … … 749 349 return false; 750 350 }); 751 }752 753 bool isIntrinsicCallStmt( Statement * stmt ) {754 return allofCtorDtor( stmt, []( Expression * callExpr ) {755 return isIntrinsicCallExpr( callExpr );756 });757 }758 759 namespace {760 template<typename CallExpr>761 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {762 if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );763 for ( Expression *& arg : callExpr->get_args() ) {764 if ( pos == 0 ) return arg;765 pos--;766 }767 assert( false );768 }769 }770 771 Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {772 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {773 return callArg( appExpr, pos );774 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {775 return callArg( untypedExpr, pos );776 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {777 std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();778 assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );779 ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );780 TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );781 assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );782 return getCallArg( tuple->get_exprs().front(), pos );783 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {784 return getCallArg( copyCtor->callExpr, pos );785 } else {786 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );787 }788 }789 790 namespace {791 std::string funcName( Expression * func );792 793 template<typename CallExpr>794 std::string handleDerefName( CallExpr * expr ) {795 // (*f)(x) => should get name "f"796 std::string name = getFunctionName( expr );797 assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );798 assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );799 return funcName( expr->get_args().front() );800 }801 802 std::string funcName( Expression * func ) {803 if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {804 return nameExpr->get_name();805 } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {806 return varExpr->get_var()->get_name();807 } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {808 return funcName( castExpr->get_arg() );809 } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {810 return memberExpr->get_member()->get_name();811 } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {812 return funcName( memberExpr->get_member() );813 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {814 return handleDerefName( untypedExpr );815 } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {816 return handleDerefName( appExpr );817 } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {818 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );819 } else {820 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );821 }822 }823 }824 825 std::string getFunctionName( Expression * expr ) {826 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and827 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction828 // can't possibly do anything reasonable.829 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {830 return funcName( appExpr->get_function() );831 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {832 return funcName( untypedExpr->get_function() );833 } else {834 std::cerr << expr << std::endl;835 assertf( false, "Unexpected expression type passed to getFunctionName" );836 }837 }838 839 Type * getPointerBase( Type * type ) {840 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {841 return ptrType->get_base();842 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {843 return arrayType->get_base();844 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {845 return refType->get_base();846 } else {847 return nullptr;848 }849 }850 851 Type * isPointerType( Type * type ) {852 return getPointerBase( type ) ? type : nullptr;853 }854 855 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {856 static FunctionDecl * assign = nullptr;857 if ( ! assign ) {858 // temporary? Generate a fake assignment operator to represent bitwise assignments.859 // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.860 TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );861 assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );862 }863 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {864 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {865 dst = new AddressExpr( dst );866 }867 } else {868 dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );869 }870 if ( dynamic_cast< ReferenceType * >( src->result ) ) {871 for (int depth = src->result->referenceDepth(); depth > 0; depth--) {872 src = new AddressExpr( src );873 }874 }875 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );876 351 } 877 352 … … 905 380 return app; 906 381 } 907 908 struct ConstExprChecker : public WithShortCircuiting {909 // most expressions are not const expr910 void previsit( Expression * ) { isConstExpr = false; visit_children = false; }911 912 void previsit( AddressExpr *addressExpr ) {913 visit_children = false;914 915 // address of a variable or member expression is constexpr916 Expression * arg = addressExpr->get_arg();917 if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;918 }919 920 // these expressions may be const expr, depending on their children921 void previsit( SizeofExpr * ) {}922 void previsit( AlignofExpr * ) {}923 void previsit( UntypedOffsetofExpr * ) {}924 void previsit( OffsetofExpr * ) {}925 void previsit( OffsetPackExpr * ) {}926 void previsit( CommaExpr * ) {}927 void previsit( LogicalExpr * ) {}928 void previsit( ConditionalExpr * ) {}929 void previsit( CastExpr * ) {}930 void previsit( ConstantExpr * ) {}931 932 void previsit( VariableExpr * varExpr ) {933 visit_children = false;934 935 if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {936 long long int value;937 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {938 // enumerators are const expr939 return;940 }941 }942 isConstExpr = false;943 }944 945 bool isConstExpr = true;946 };947 382 948 383 struct ConstExprChecker_new : public ast::WithShortCircuiting { … … 989 424 }; 990 425 991 bool isConstExpr( Expression * expr ) {992 if ( expr ) {993 PassVisitor<ConstExprChecker> checker;994 expr->accept( checker );995 return checker.pass.isConstExpr;996 }997 return true;998 }999 1000 bool isConstExpr( Initializer * init ) {1001 if ( init ) {1002 PassVisitor<ConstExprChecker> checker;1003 init->accept( checker );1004 return checker.pass.isConstExpr;1005 } // if1006 // for all intents and purposes, no initializer means const expr1007 return true;1008 }1009 1010 426 bool isConstExpr( const ast::Expr * expr ) { 1011 427 if ( expr ) { … … 1027 443 } 1028 444 1029 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {1030 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );1031 if ( ! function ) return nullptr;1032 if ( function->name != fname ) return nullptr;1033 FunctionType * ftype = function->type;1034 if ( ftype->parameters.size() != 2 ) return nullptr;1035 1036 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );1037 Type * t2 = ftype->parameters.back()->get_type();1038 assert( t1 );1039 1040 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {1041 return function;1042 } else {1043 return nullptr;1044 }1045 }1046 1047 445 bool isAssignment( const ast::FunctionDecl * decl ) { 1048 446 return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl ); … … 1071 469 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 ); 1072 470 } 1073 1074 1075 const FunctionDecl * isAssignment( const Declaration * decl ) {1076 return isCopyFunction( decl, "?=?" );1077 }1078 const FunctionDecl * isDestructor( const Declaration * decl ) {1079 if ( CodeGen::isDestructor( decl->name ) ) {1080 return dynamic_cast< const FunctionDecl * >( decl );1081 }1082 return nullptr;1083 }1084 const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {1085 if ( CodeGen::isConstructor( decl->name ) ) {1086 if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {1087 if ( func->type->parameters.size() == 1 ) {1088 return func;1089 }1090 }1091 }1092 return nullptr;1093 }1094 const FunctionDecl * isCopyConstructor( const Declaration * decl ) {1095 return isCopyFunction( decl, "?{}" );1096 }1097 471 1098 472 #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message … … 1103 477 static const char * const data_section = ".data" ASM_COMMENT; 1104 478 static const char * const tlsd_section = ".tdata" ASM_COMMENT; 1105 void addDataSectionAttribute( ObjectDecl * objDecl ) {1106 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();1107 const char * section = is_tls ? tlsd_section : data_section;1108 objDecl->attributes.push_back(new Attribute("section", {1109 new ConstantExpr( Constant::from_string( section ) )1110 }));1111 }1112 479 1113 480 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { -
src/InitTweak/InitTweak.h
r0030b508 rfc12f05 22 22 23 23 #include "AST/Fwd.hpp" // for AST nodes 24 #include "SynTree/SynTree.h" // for Visitor Nodes25 24 26 25 // helper functions for initialization 27 26 namespace InitTweak { 28 const FunctionDecl * isAssignment( const Declaration * decl );29 const FunctionDecl * isDestructor( const Declaration * decl );30 const FunctionDecl * isDefaultConstructor( const Declaration * decl );31 const FunctionDecl * isCopyConstructor( const Declaration * decl );32 const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );33 27 bool isAssignment( const ast::FunctionDecl * decl ); 34 28 bool isDestructor( const ast::FunctionDecl * decl ); … … 38 32 39 33 /// returns the base type of the first parameter to a constructor/destructor/assignment function 40 Type * getTypeofThis( FunctionType * ftype );41 34 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 42 35 43 36 /// returns the first parameter of a constructor/destructor/assignment function 44 ObjectDecl * getParamThis( FunctionType * ftype );45 37 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 46 38 47 39 /// generate a bitwise assignment operation. 48 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );49 50 40 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 51 41 52 42 /// transform Initializer into an argument list that can be passed to a call expression 53 std::list< Expression * > makeInitList( Initializer * init );54 43 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ); 55 44 56 45 /// True if the resolver should try to construct dwt 57 bool tryConstruct( DeclarationWithType * dwt );58 46 bool tryConstruct( const ast::DeclWithType * dwt ); 59 47 60 48 /// True if the type can have a user-defined constructor 61 bool isConstructable( Type * t );62 49 bool isConstructable( const ast::Type * t ); 63 50 64 51 /// True if the Initializer contains designations 65 bool isDesignated( Initializer * init );66 52 bool isDesignated( const ast::Init * init ); 67 53 68 54 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 69 55 /// type, where the depth of its type is the number of nested ArrayTypes + 1 70 bool checkInitDepth( ObjectDecl * objDecl );71 56 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 72 73 /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)74 DeclarationWithType * getFunction( Expression * expr );75 const DeclarationWithType * getFunction( const Expression * expr );76 77 /// Non-Null if expr is a call expression whose target function is intrinsic78 ApplicationExpr * isIntrinsicCallExpr( Expression * expr );79 57 80 58 /// True if stmt is a call statement where the function called is intrinsic and takes one parameter. 81 59 /// Intended to be used for default ctor/dtor calls, but might have use elsewhere. 82 60 /// Currently has assertions that make it less than fully general. 83 bool isIntrinsicSingleArgCallStmt( Statement * stmt );84 61 bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ); 85 62 86 /// True if stmt is a call statement where the function called is intrinsic.87 bool isIntrinsicCallStmt( Statement * stmt );88 89 63 /// get all Ctor/Dtor call expressions from a Statement 90 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );91 64 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 92 65 93 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call94 Expression * getCtorDtorCall( Statement * stmt );95 96 /// returns the name of the function being called97 std::string getFunctionName( Expression * expr );98 99 /// returns the argument to a call expression in position N indexed from 0100 Expression *& getCallArg( Expression * callExpr, unsigned int pos );101 102 /// returns the base type of a PointerType or ArrayType, else returns NULL103 Type * getPointerBase( Type * );104 105 /// returns the argument if it is a PointerType or ArrayType, else returns NULL106 Type * isPointerType( Type * );107 108 66 /// returns true if expr is trivially a compile-time constant 109 bool isConstExpr( Expression * expr );110 bool isConstExpr( Initializer * init );111 112 67 bool isConstExpr( const ast::Expr * expr ); 113 68 bool isConstExpr( const ast::Init * init ); … … 122 77 /// .section .data#,"a" 123 78 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectionAttribute( ObjectDecl * objDecl );125 126 79 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 127 128 class InitExpander_old {129 public:130 // expand by stepping through init to get each list of arguments131 InitExpander_old( Initializer * init );132 133 // always expand to expr134 InitExpander_old( Expression * expr );135 136 // iterator-like interface137 std::list< Expression * > operator*();138 InitExpander_old & operator++();139 140 // builds statement which has the same semantics as a C-style list initializer141 // (for array initializers) using callExpr as the base expression to perform initialization142 Statement * buildListInit( UntypedExpr * callExpr );143 void addArrayIndex( Expression * index, Expression * dimension );144 void clearArrayIndices();145 bool addReference();146 147 class ExpanderImpl;148 149 typedef std::list< Expression * > IndexList;150 private:151 std::shared_ptr< ExpanderImpl > expander;152 std::list< Expression * > cur;153 154 // invariant: list of size 2N (elements come in pairs [index, dimension])155 IndexList indices;156 };157 80 158 81 class InitExpander_new { -
src/InitTweak/module.mk
r0030b508 rfc12f05 24 24 InitTweak/FixGlobalInit.cc \ 25 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \27 26 InitTweak/FixInit.h \ 28 27 InitTweak/FixInitNew.cpp -
src/MakeLibCfa.h
r0030b508 rfc12f05 24 24 25 25 namespace LibCfa { 26 void makeLibCfa( std::list< Declaration* > &prelude );27 26 void makeLibCfa( ast::TranslationUnit & translationUnit ); 28 27 } // namespace LibCfa -
src/Makefile.am
r0030b508 rfc12f05 22 22 CompilationState.cc \ 23 23 CompilationState.h \ 24 MakeLibCfa.cc \25 24 MakeLibCfaNew.cpp \ 26 25 MakeLibCfa.h … … 42 41 include AST/module.mk 43 42 include CodeGen/module.mk 44 include CodeTools/module.mk45 43 include Concurrency/module.mk 46 44 include Common/module.mk … … 51 49 include ResolvExpr/module.mk 52 50 include SymTab/module.mk 53 include SynTree/module.mk54 51 include Tuples/module.mk 55 52 include Validate/module.mk 56 53 include Virtual/module.mk 57 54 58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/ SynTree/Type.h55 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp 59 56 60 57 $(srcdir)/AST/Type.hpp : BasicTypes-gen.cc -
src/Parser/RunParser.cpp
r0030b508 rfc12f05 16 16 #include "RunParser.hpp" 17 17 18 #include "AST/Convert.hpp" // for convert19 18 #include "AST/TranslationUnit.hpp" // for TranslationUnit 20 #include "CodeTools/TrackLoc.h" // for fillLocations21 19 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 22 20 #include "Parser/DeclarationNode.h" // for DeclarationNode, buildList -
src/Parser/StatementNode.cc
r0030b508 rfc12f05 503 503 } // build_corun 504 504 505 ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) { 506 std::vector<ast::ptr<ast::Stmt>> astinit; // maybe empty 507 buildMoveList( forctl->init, astinit ); 508 509 ast::Expr * astcond = nullptr; // maybe empty 510 astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) ); 511 512 ast::Expr * astincr = nullptr; // maybe empty 513 astincr = maybeMoveBuild( forctl->change ); 514 delete forctl; 515 516 return new ast::CoforStmt( location, 517 std::move( astinit ), 518 astcond, 519 astincr, 520 buildMoveSingle( stmt ) 521 ); 522 } // build_cofor 523 505 524 // Local Variables: // 506 525 // tab-width: 4 // -
src/Parser/StatementNode.h
r0030b508 rfc12f05 106 106 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt ); 107 107 ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt ); 108 ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ); -
src/Parser/parser.yy
r0030b508 rfc12f05 48 48 using namespace std; 49 49 50 #include "SynTree/Type.h" // for Type51 50 #include "DeclarationNode.h" // for DeclarationNode, ... 52 51 #include "ExpressionNode.h" // for ExpressionNode, ... … … 58 57 #include "Common/SemanticError.h" // error_str 59 58 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 60 61 #include "SynTree/Attribute.h" // for Attribute62 59 63 60 // lex uses __null in a boolean context, it's fine. … … 1726 1723 cofor_statement: 1727 1724 COFOR '(' for_control_expression_list ')' statement 1728 { SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }1725 { $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); } 1729 1726 ; 1730 1727 … … 2169 2166 type_qualifier_name: 2170 2167 CONST 2171 { $$ = DeclarationNode::newTypeQualifier( Type::Const ); }2168 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); } 2172 2169 | RESTRICT 2173 { $$ = DeclarationNode::newTypeQualifier( Type::Restrict ); }2170 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); } 2174 2171 | VOLATILE 2175 { $$ = DeclarationNode::newTypeQualifier( Type::Volatile ); }2172 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); } 2176 2173 | ATOMIC 2177 { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); }2174 { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); } 2178 2175 | forall 2179 2176 { $$ = DeclarationNode::newForall( $1 ); } … … 2206 2203 storage_class: 2207 2204 EXTERN 2208 { $$ = DeclarationNode::newStorageClass( Type::Extern ); }2205 { $$ = DeclarationNode::newStorageClass( ast::Storage::Extern ); } 2209 2206 | STATIC 2210 { $$ = DeclarationNode::newStorageClass( Type::Static ); }2207 { $$ = DeclarationNode::newStorageClass( ast::Storage::Static ); } 2211 2208 | AUTO 2212 { $$ = DeclarationNode::newStorageClass( Type::Auto ); }2209 { $$ = DeclarationNode::newStorageClass( ast::Storage::Auto ); } 2213 2210 | REGISTER 2214 { $$ = DeclarationNode::newStorageClass( Type::Register ); }2211 { $$ = DeclarationNode::newStorageClass( ast::Storage::Register ); } 2215 2212 | THREADLOCALGCC // GCC 2216 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); }2213 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalGcc ); } 2217 2214 | THREADLOCALC11 // C11 2218 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); }2215 { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalC11 ); } 2219 2216 // Put function specifiers here to simplify parsing rules, but separate them semantically. 2220 2217 | INLINE // C99 2221 { $$ = DeclarationNode::newFuncSpecifier( Type::Inline ); }2218 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Inline ); } 2222 2219 | FORTRAN // C99 2223 { $$ = DeclarationNode::newFuncSpecifier( Type::Fortran ); }2220 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Fortran ); } 2224 2221 | NORETURN // C11 2225 { $$ = DeclarationNode::newFuncSpecifier( Type::Noreturn ); }2222 { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Noreturn ); } 2226 2223 ; 2227 2224 … … 3717 3714 { $$ = $1->addQualifiers( $2 ); } 3718 3715 | '&' MUTEX paren_identifier attribute_list_opt 3719 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }3716 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3720 3717 | identifier_parameter_ptr 3721 3718 | identifier_parameter_array attribute_list_opt … … 3767 3764 { $$ = $1->addQualifiers( $2 ); } 3768 3765 | '&' MUTEX typedef_name attribute_list_opt 3769 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }3766 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3770 3767 | type_parameter_ptr 3771 3768 | type_parameter_array attribute_list_opt … … 3941 3938 abstract_parameter_ptr 3942 3939 | '&' MUTEX attribute_list_opt 3943 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }3940 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); } 3944 3941 | abstract_parameter_array attribute_list_opt 3945 3942 { $$ = $1->addQualifiers( $2 ); } -
src/ResolvExpr/AdjustExprType.cc
r0030b508 rfc12f05 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "SymTab/Indexer.h" // for Indexer23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype24 #include "SynTree/Mutator.h" // for Mutator25 #include "SynTree/Type.h" // for PointerType, TypeInstType, Type26 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment27 21 28 22 namespace ResolvExpr { 29 30 namespace {31 class AdjustExprType_old final : public WithShortCircuiting {32 public:33 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );34 void premutate( VoidType * ) { visit_children = false; }35 void premutate( BasicType * ) { visit_children = false; }36 void premutate( PointerType * ) { visit_children = false; }37 void premutate( ArrayType * ) { visit_children = false; }38 void premutate( FunctionType * ) { visit_children = false; }39 void premutate( StructInstType * ) { visit_children = false; }40 void premutate( UnionInstType * ) { visit_children = false; }41 void premutate( EnumInstType * ) { visit_children = false; }42 void premutate( TraitInstType * ) { visit_children = false; }43 void premutate( TypeInstType * ) { visit_children = false; }44 void premutate( TupleType * ) { visit_children = false; }45 void premutate( VarArgsType * ) { visit_children = false; }46 void premutate( ZeroType * ) { visit_children = false; }47 void premutate( OneType * ) { visit_children = false; }48 49 Type * postmutate( ArrayType * arrayType );50 Type * postmutate( FunctionType * functionType );51 Type * postmutate( TypeInstType * aggregateUseType );52 53 private:54 const TypeEnvironment & env;55 const SymTab::Indexer & indexer;56 };57 58 AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )59 : env( env ), indexer( indexer ) {60 }61 62 Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {63 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };64 arrayType->base = nullptr;65 delete arrayType;66 return pointerType;67 }68 69 Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {70 return new PointerType{ Type::Qualifiers(), functionType };71 }72 73 Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {74 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {75 if ( eqvClass->data.kind == TypeDecl::Ftype ) {76 return new PointerType{ Type::Qualifiers(), typeInst };77 }78 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {79 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {80 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {81 return new PointerType{ Type::Qualifiers(), typeInst };82 } // if83 } // if84 } // if85 return typeInst;86 }87 } // anonymous namespace88 89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {90 PassVisitor<AdjustExprType_old> adjuster( env, indexer );91 Type * newType = type->acceptMutator( adjuster );92 type = newType;93 }94 95 void adjustExprType( Type *& type ) {96 TypeEnvironment env;97 SymTab::Indexer indexer;98 adjustExprType( type, env, indexer );99 }100 23 101 24 namespace { -
src/ResolvExpr/CandidateFinder.cpp
r0030b508 rfc12f05 57 57 58 58 /// Unique identifier for matching expression resolutions to their requesting expression 59 UniqueId globalResnSlot = 0;59 ast::UniqueId globalResnSlot = 0; 60 60 61 61 namespace { … … 686 686 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 687 687 // Set need bindings for any unbound assertions 688 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions688 ast::UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 689 689 for ( auto & assn : newCand->need ) { 690 690 // skip already-matched assertions -
src/ResolvExpr/CastCost.cc
r0030b508 rfc12f05 26 26 #include "ResolvExpr/ConversionCost.h" // for conversionCost 27 27 #include "ResolvExpr/PtrsCastable.hpp" // for ptrsCastable 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment, EqvClass29 28 #include "ResolvExpr/typeops.h" // for ptrsCastable 30 29 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 31 #include "SymTab/Indexer.h" // for Indexer32 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl33 #include "SynTree/Type.h" // for PointerType, Type, TypeInstType34 30 35 31 #if 0 … … 40 36 41 37 namespace ResolvExpr { 42 struct CastCost_old : public ConversionCost {43 public:44 CastCost_old( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );46 47 using ConversionCost::previsit;48 using ConversionCost::postvisit;49 void postvisit( const BasicType * basicType );50 void postvisit( const PointerType * pointerType );51 };52 53 Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,54 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {55 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {56 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {57 if ( eqvClass->type ) {58 return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );59 } else {60 return Cost::infinity;61 }62 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {63 // all typedefs should be gone by this point64 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );65 if ( type->base ) {66 return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;67 } // if68 } // if69 } // if70 71 PRINT(72 std::cerr << "castCost ::: src is ";73 src->print( std::cerr );74 std::cerr << std::endl << "dest is ";75 dest->print( std::cerr );76 std::cerr << std::endl << "env is" << std::endl;77 env.print( std::cerr, 8 );78 )79 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {88 return ptrsCastable( t1, t2, env, indexer );89 });90 } else {91 PassVisitor<CastCost_old> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))94 castCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 // xxx - why are we adding cost 0 here?100 return converter.pass.get_cost() + Cost::zero;101 } // if102 } // if103 }104 105 CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,106 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )107 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {108 }109 110 void CastCost_old::postvisit( const BasicType * basicType ) {111 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );112 if ( destAsPointer && basicType->isInteger() ) {113 // necessary for, e.g. unsigned long => void *114 cost = Cost::unsafe;115 } else {116 cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );117 } // if118 }119 120 void CastCost_old::postvisit( const PointerType * pointerType ) {121 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {122 if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {123 cost = Cost::safe;124 } else {125 TypeEnvironment newEnv( env );126 newEnv.add( pointerType->forall );127 newEnv.add( pointerType->base->forall );128 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );129 if ( castResult > 0 ) {130 cost = Cost::safe;131 } else if ( castResult < 0 ) {132 cost = Cost::infinity;133 } // if134 } // if135 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {136 if ( destAsBasic->isInteger() ) {137 // necessary for, e.g. void * => unsigned long138 cost = Cost::unsafe;139 } // if140 }141 }142 38 143 39 namespace { … … 200 96 } // anonymous namespace 201 97 202 203 204 98 Cost castCost( 205 99 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, -
src/ResolvExpr/CommonType.cc
r0030b508 rfc12f05 23 23 #include "AST/Pass.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h"26 #include "ResolvExpr/TypeEnvironment.h" // for OpenVarSet, AssertionSet27 #include "SymTab/Indexer.h" // for Indexer28 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl (ptr...29 #include "SynTree/Type.h" // for BasicType, BasicType::Kind::...30 #include "SynTree/Visitor.h" // for Visitor31 25 #include "Unify.h" // for unifyExact, WidenMode 32 26 #include "typeops.h" // for isFtype … … 41 35 42 36 namespace ResolvExpr { 43 struct CommonType_old : public WithShortCircuiting {44 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );45 Type * get_result() const { return result; }46 47 void previsit( BaseSyntaxNode * ) { visit_children = false; }48 49 void postvisit( VoidType * voidType );50 void postvisit( BasicType * basicType );51 void postvisit( PointerType * pointerType );52 void postvisit( ArrayType * arrayType );53 void postvisit( ReferenceType * refType );54 void postvisit( FunctionType * functionType );55 void postvisit( StructInstType * aggregateUseType );56 void postvisit( UnionInstType * aggregateUseType );57 void postvisit( EnumInstType * aggregateUseType );58 void postvisit( TraitInstType * aggregateUseType );59 void postvisit( TypeInstType * aggregateUseType );60 void postvisit( TupleType * tupleType );61 void postvisit( VarArgsType * varArgsType );62 void postvisit( ZeroType * zeroType );63 void postvisit( OneType * oneType );64 65 private:66 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );67 template< typename RefType > void handleRefType( RefType * inst, Type * other );68 69 Type * result;70 Type * type2; // inherited71 bool widenFirst, widenSecond;72 const SymTab::Indexer &indexer;73 TypeEnvironment &env;74 const OpenVarSet &openVars;75 };76 77 Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {78 Type * common = nullptr;79 AssertionSet have, need;80 OpenVarSet newOpen( openVars );81 // need unify to bind type variables82 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {83 PRINT(84 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;85 )86 if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {87 PRINT(88 std::cerr << "widen okay" << std::endl;89 )90 common->tq |= t1->tq;91 common->tq |= t2->tq;92 return common;93 }94 }95 PRINT(96 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;97 )98 return nullptr;99 }100 101 Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {102 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );103 104 int depth1 = type1->referenceDepth();105 int depth2 = type2->referenceDepth();106 if ( depth1 > 0 || depth2 > 0 ) {107 int diff = depth1-depth2;108 // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.109 // if ( diff > 1 || diff < -1 ) return nullptr;110 111 // special case where one type has a reference depth of 1 larger than the other112 if ( diff > 0 || diff < 0 ) {113 PRINT(114 std::cerr << "reference depth diff: " << diff << std::endl;115 )116 Type * result = nullptr;117 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );118 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );119 if ( diff > 0 ) {120 // deeper on the left121 assert( ref1 );122 result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );123 } else {124 // deeper on the right125 assert( ref2 );126 result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );127 }128 if ( result && ref1 ) {129 // formal is reference, so result should be reference130 PRINT(131 std::cerr << "formal is reference; result should be reference" << std::endl;132 )133 result = new ReferenceType( ref1->tq, result );134 }135 PRINT(136 std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;137 )138 return result;139 }140 // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.141 }142 143 type1->accept( visitor );144 Type * result = visitor.pass.get_result();145 if ( ! result ) {146 // this appears to be handling for opaque type declarations147 if ( widenSecond ) {148 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {149 if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {150 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );151 if ( type->get_base() ) {152 Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;153 AssertionSet have, need;154 OpenVarSet newOpen( openVars );155 type1->tq = Type::Qualifiers();156 type->get_base()->tq = tq1;157 if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {158 result = type1->clone();159 result->tq = tq1 | tq2;160 } // if161 type1->tq = tq1;162 type->get_base()->tq = Type::Qualifiers();163 } // if164 } // if165 } // if166 } // if167 } // if168 #ifdef DEBUG169 std::cerr << "============= commonType" << std::endl << "type1 is ";170 type1->print( std::cerr );171 std::cerr << " type2 is ";172 type2->print( std::cerr );173 if ( result ) {174 std::cerr << " common type is ";175 result->print( std::cerr );176 } else {177 std::cerr << " no common type";178 } // if179 std::cerr << std::endl;180 #endif181 return result;182 }183 37 184 38 // GENERATED START, DO NOT EDIT 185 39 // GENERATED BY BasicTypes-gen.cc 186 #define BT BasicType::187 static const B asicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor40 #define BT ast::BasicType:: 41 static const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor 188 42 /* B C SC UC SI SUI 189 43 I UI LI LUI LLI LLUI … … 485 339 // GENERATED END 486 340 static_assert( 487 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES *BasicType::NUMBER_OF_BASIC_TYPES,341 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES, 488 342 "Each basic type kind should have a corresponding row in the combined type matrix" 489 343 ); 490 491 CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )492 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {493 }494 495 void CommonType_old::postvisit( VoidType * ) {}496 497 void CommonType_old::postvisit( BasicType * basicType ) {498 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {499 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];500 if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {501 result = new BasicType( basicType->tq | otherBasic->tq, newType );502 } // if503 } else if ( dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {504 // use signed int in lieu of the enum/zero/one type505 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];506 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {507 result = new BasicType( basicType->tq | type2->tq, newType );508 } // if509 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {510 const EnumDecl* enumDecl = enumInst->baseEnum;511 if ( const Type* baseType = enumDecl->base ) {512 result = baseType->clone();513 } else {514 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];515 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {516 result = new BasicType( basicType->tq | type2->tq, newType );517 } // if518 }519 }520 }521 522 template< typename Pointer >523 void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {524 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {525 OpenVarSet::const_iterator entry = openVars.find( var->get_name() );526 if ( entry != openVars.end() ) {527 AssertionSet need, have;528 WidenMode widen( widenFirst, widenSecond );529 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;530 }531 }532 result = voidPointer->clone();533 result->tq |= otherPointer->tq;534 }535 536 void CommonType_old::postvisit( PointerType * pointerType ) {537 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {538 // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;539 if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {540 getCommonWithVoidPointer( otherPointer, pointerType );541 } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {542 getCommonWithVoidPointer( pointerType, otherPointer );543 } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )544 && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {545 // std::cerr << "middle case" << std::endl;546 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;547 pointerType->get_base()->tq = Type::Qualifiers();548 otherPointer->get_base()->tq = Type::Qualifiers();549 AssertionSet have, need;550 OpenVarSet newOpen( openVars );551 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {552 // std::cerr << "unifyExact success" << std::endl;553 if ( tq1 < tq2 ) {554 result = pointerType->clone();555 } else {556 result = otherPointer->clone();557 } // if558 strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;559 } else {560 /// std::cerr << "place for ptr-to-type" << std::endl;561 } // if562 pointerType->get_base()->tq = tq1;563 otherPointer->get_base()->tq = tq2;564 } // if565 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {566 result = pointerType->clone();567 result->tq |= type2->tq;568 } // if569 }570 571 void CommonType_old::postvisit( ArrayType * ) {}572 573 void CommonType_old::postvisit( ReferenceType * refType ) {574 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {575 // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;576 // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;577 if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {578 getCommonWithVoidPointer( otherRef, refType );579 } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {580 getCommonWithVoidPointer( refType, otherRef );581 } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )582 && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {583 // std::cerr << "middle case" << std::endl;584 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;585 refType->get_base()->tq = Type::Qualifiers();586 otherRef->get_base()->tq = Type::Qualifiers();587 AssertionSet have, need;588 OpenVarSet newOpen( openVars );589 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {590 if ( tq1 < tq2 ) {591 result = refType->clone();592 } else {593 result = otherRef->clone();594 } // if595 strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;596 } else {597 /// std::cerr << "place for ptr-to-type" << std::endl;598 } // if599 refType->get_base()->tq = tq1;600 otherRef->get_base()->tq = tq2;601 } // if602 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {603 result = refType->clone();604 result->tq |= type2->tq;605 } // if606 }607 608 void CommonType_old::postvisit( FunctionType * ) {}609 void CommonType_old::postvisit( StructInstType * ) {}610 void CommonType_old::postvisit( UnionInstType * ) {}611 612 void CommonType_old::postvisit( EnumInstType * enumInstType ) {613 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {614 // reuse BasicType, EnumInstType code by swapping type2 with enumInstType615 result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );616 } // if617 }618 619 void CommonType_old::postvisit( TraitInstType * ) {620 }621 622 void CommonType_old::postvisit( TypeInstType * inst ) {623 if ( widenFirst ) {624 const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );625 if ( nt ) {626 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );627 if ( type->get_base() ) {628 Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;629 AssertionSet have, need;630 OpenVarSet newOpen( openVars );631 type2->tq = Type::Qualifiers();632 type->get_base()->tq = tq1;633 if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {634 result = type2->clone();635 result->tq = tq1 | tq2;636 } // if637 type2->tq = tq2;638 type->get_base()->tq = Type::Qualifiers();639 } // if640 } // if641 } // if642 }643 644 void CommonType_old::postvisit( TupleType * ) {}645 void CommonType_old::postvisit( VarArgsType * ) {}646 647 void CommonType_old::postvisit( ZeroType * zeroType ) {648 if ( widenFirst ) {649 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {650 if ( widenSecond || zeroType->tq <= type2->tq ) {651 result = type2->clone();652 result->tq |= zeroType->tq;653 }654 } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {655 result = new BasicType( zeroType->tq, BasicType::SignedInt );656 result->tq |= type2->tq;657 }658 }659 }660 661 void CommonType_old::postvisit( OneType * oneType ) {662 if ( widenFirst ) {663 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {664 if ( widenSecond || oneType->tq <= type2->tq ) {665 result = type2->clone();666 result->tq |= oneType->tq;667 }668 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {669 result = new BasicType( oneType->tq, BasicType::SignedInt );670 result->tq |= type2->tq;671 }672 }673 }674 344 675 345 class CommonType_new final : public ast::WithShortCircuiting { … … 700 370 else if (!widen.first) kind = basic->kind; // widen.second 701 371 else if (!widen.second) kind = basic2->kind; 702 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];372 else kind = commonTypes[ basic->kind ][ basic2->kind ]; 703 373 // xxx - what does qualifiers even do here?? 704 374 if ( (basic->qualifiers >= basic2->qualifiers || widen.first) … … 719 389 } else { 720 390 #warning remove casts when `commonTypes` moved to new AST 721 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];391 ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ]; 722 392 if ( 723 393 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) -
src/ResolvExpr/CommonType.hpp
r0030b508 rfc12f05 18 18 #include "AST/Fwd.hpp" 19 19 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 20 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet21 20 #include "WidenMode.h" // for WidenMode 22 23 class Type;24 namespace SymTab {25 class Indexer;26 }27 21 28 22 namespace ResolvExpr { 29 23 30 Type * commonType(31 Type * type1, Type * type2, bool widenFirst, bool widenSecond,32 const SymTab::Indexer & indexer, TypeEnvironment & env,33 const OpenVarSet & openVars );34 24 ast::ptr< ast::Type > commonType( 35 25 const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, -
src/ResolvExpr/ConversionCost.cc
r0030b508 rfc12f05 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment24 23 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 25 24 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType29 30 25 31 26 namespace ResolvExpr { 32 #if 033 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 };34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 };35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 };36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 };37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 };38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 };39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 };40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 };41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 };42 #endif43 27 44 28 #if 0 … … 47 31 #define PRINT(x) 48 32 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) {52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; )54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {55 if ( eqvClass->type ) {56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );57 } else {58 return Cost::infinity;59 }60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {61 PRINT( std::cerr << " found" << std::endl; )62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );63 // all typedefs should be gone by this point64 assert( type );65 if ( type->base ) {66 return conversionCost( src, type->base, srcIsLvalue, indexer, env )67 + Cost::safe;68 } // if69 } // if70 PRINT( std::cerr << " not found" << std::endl; )71 } // if72 PRINT(73 std::cerr << "src is ";74 src->print( std::cerr );75 std::cerr << std::endl << "dest is ";76 dest->print( std::cerr );77 std::cerr << std::endl << "env is" << std::endl;78 env.print( std::cerr, 8 );79 )80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {81 PRINT( std::cerr << "compatible!" << std::endl; )82 return Cost::zero;83 } else if ( dynamic_cast< const VoidType * >( dest ) ) {84 return Cost::safe;85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){88 return ptrsAssignable( t1, t2, env );89 });90 } else {91 PassVisitor<ConversionCost> converter(92 dest, srcIsLvalue, indexer, env,93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))94 conversionCost );95 src->accept( converter );96 if ( converter.pass.get_cost() == Cost::infinity ) {97 return Cost::infinity;98 } else {99 return converter.pass.get_cost() + Cost::zero;100 } // if101 } // if102 }103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )107 if ( diff > 0 ) {108 // TODO: document this109 Cost cost = convertToReferenceCost(110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,111 diff-1, indexer, env, func );112 cost.incReference();113 return cost;114 } else if ( diff < -1 ) {115 // TODO: document this116 Cost cost = convertToReferenceCost(117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,118 diff+1, indexer, env, func );119 cost.incReference();120 return cost;121 } else if ( diff == 0 ) {122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references125 PRINT( std::cerr << "converting between references" << std::endl; )126 Type::Qualifiers tq1 = srcAsRef->base->tq;127 Type::Qualifiers tq2 = destAsRef->base->tq;128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )130 if ( tq1 == tq2 ) {131 // types are the same132 return Cost::zero;133 } else {134 // types are the same, except otherPointer has more qualifiers135 return Cost::safe;136 }137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )140 if ( assignResult > 0 ) {141 return Cost::safe;142 } else if ( assignResult < 0 ) {143 return Cost::unsafe;144 } // if145 } // if146 } else {147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )148 PassVisitor<ConversionCost> converter(149 dest, srcIsLvalue, indexer, env,150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))151 conversionCost );152 src->accept( converter );153 return converter.pass.get_cost();154 } // if155 } else {156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );157 assert( diff == -1 && destAsRef );158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {160 PRINT( std::cerr << "converting compatible base type" << std::endl; )161 if ( srcIsLvalue ) {162 PRINT(163 std::cerr << "lvalue to reference conversion" << std::endl;164 std::cerr << src << " => " << destAsRef << std::endl;165 )166 // lvalue-to-reference conversion: cv lvalue T => cv T &167 if ( src->tq == destAsRef->base->tq ) {168 return Cost::reference; // cost needs to be non-zero to add cast169 } if ( src->tq < destAsRef->base->tq ) {170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same171 } else {172 return Cost::unsafe;173 } // if174 } else if ( destAsRef->base->get_const() ) {175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )176 // rvalue-to-const-reference conversion: T => const T &177 return Cost::safe;178 } else {179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )180 // rvalue-to-reference conversion: T => T &181 return Cost::unsafe;182 } // if183 } // if184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )185 }186 return Cost::infinity;187 }188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )194 return cost;195 }196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {199 }200 33 201 34 // GENERATED START, DO NOT EDIT … … 226 59 // GENERATED START, DO NOT EDIT 227 60 // GENERATED BY BasicTypes-gen.cc 228 static const int costMatrix[ BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node61 static const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node 229 62 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 230 63 /* B */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17, 16, 18, 17, }, … … 268 101 // GENERATED END 269 102 static_assert( 270 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES *BasicType::NUMBER_OF_BASIC_TYPES,103 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES, 271 104 "Missing row in the cost matrix" 272 105 ); … … 274 107 // GENERATED START, DO NOT EDIT 275 108 // GENERATED BY BasicTypes-gen.cc 276 static const int signMatrix[ BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion109 static const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion 277 110 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 278 111 /* B */ { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, … … 315 148 // GENERATED END 316 149 static_assert( 317 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES *BasicType::NUMBER_OF_BASIC_TYPES,150 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES, 318 151 "Missing row in the sign matrix" 319 152 ); 320 321 void ConversionCost::postvisit( const VoidType * ) {322 cost = Cost::infinity;323 }324 325 // refactor for code resue326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {327 int tableResult = costMatrix[ src->kind ][ dest->kind ];328 if ( tableResult == -1 ) {329 cost = Cost::unsafe;330 } else {331 cost = Cost::zero;332 cost.incSafe( tableResult );333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] );334 } // if335 } // ConversionCost::conversionCostFromBasicToBasic336 337 void ConversionCost::postvisit(const BasicType * basicType) {338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {339 conversionCostFromBasicToBasic(basicType, destAsBasic);340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {341 const EnumDecl * base_enum = enumInst->baseEnum;342 if ( const Type * base = base_enum->base ) {343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);345 } else {346 cost = Cost::infinity;347 } // if348 } else {349 cost = Cost::unsafe;350 } // if351 } // if352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.353 }354 355 void ConversionCost::postvisit( const PointerType * pointerType ) {356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )358 Type::Qualifiers tq1 = pointerType->base->tq;359 Type::Qualifiers tq2 = destAsPtr->base->tq;360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )362 if ( tq1 == tq2 ) {363 // types are the same364 cost = Cost::zero;365 } else {366 // types are the same, except otherPointer has more qualifiers367 cost = Cost::safe;368 } // if369 } else {370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );371 PRINT( std::cerr << " :: " << assignResult << std::endl; )372 if ( assignResult > 0 && tq1 <= tq2 ) {373 // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?374 if ( tq1 == tq2 ) {375 cost = Cost::safe;376 } else if ( tq1 < tq2 ) {377 cost = Cost::safe+Cost::safe;378 }379 } else if ( assignResult < 0 ) {380 cost = Cost::unsafe;381 } // if382 // assignResult == 0 means Cost::Infinity383 } // if384 // case case for zero_t because it should not be possible to convert pointers to zero_t.385 } // if386 }387 388 void ConversionCost::postvisit( const ArrayType * ) {}389 390 void ConversionCost::postvisit( const ReferenceType * refType ) {391 // Note: dest can never be a reference, since it would have been caught in an earlier check392 assert( ! dynamic_cast< const ReferenceType * >( dest ) );393 // convert reference to rvalue: cv T1 & => T2394 // recursively compute conversion cost from T1 to T2.395 // cv can be safely dropped because of 'implicit dereference' behavior.396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );397 if ( refType->base->tq == dest->tq ) {398 cost.incReference(); // prefer exact qualifiers399 } else if ( refType->base->tq < dest->tq ) {400 cost.incSafe(); // then gaining qualifiers401 } else {402 cost.incUnsafe(); // lose qualifiers as last resort403 }404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )405 }406 407 void ConversionCost::postvisit( const FunctionType * ) {}408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) {410 const EnumDecl * enumDecl = enumInst -> baseEnum;411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );413 } else {414 static Type::Qualifiers q;415 static BasicType integer( q, BasicType::SignedInt );416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int417 } // if418 if ( cost < Cost::unsafe ) {419 cost.incSafe();420 } // if421 }422 423 void ConversionCost::postvisit( const TraitInstType * ) {}424 425 void ConversionCost::postvisit( const TypeInstType * inst ) {426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {429 if ( inst->name == destAsInst->name ) {430 cost = Cost::zero;431 }432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );434 // all typedefs should be gone by this point435 assert( type );436 if ( type->base ) {437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;438 } // if439 } // if440 }441 442 void ConversionCost::postvisit( const TupleType * tupleType ) {443 Cost c = Cost::zero;444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin();446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );449 if ( newCost == Cost::infinity ) {450 return;451 } // if452 c += newCost;453 } // while454 if ( destIt != destAsTuple->types.end() ) {455 cost = Cost::infinity;456 } else {457 cost = c;458 } // if459 } // if460 }461 462 void ConversionCost::postvisit( const VarArgsType * ) {463 if ( dynamic_cast< const VarArgsType * >( dest ) ) {464 cost = Cost::zero;465 }466 }467 468 void ConversionCost::postvisit( const ZeroType * ) {469 if ( dynamic_cast< const ZeroType * >( dest ) ) {470 cost = Cost::zero;471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];474 if ( tableResult == -1 ) {475 cost = Cost::unsafe;476 } else {477 cost = Cost::zero;478 cost.incSafe( tableResult + 1 );479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );480 } // if481 } else if ( dynamic_cast< const PointerType * >( dest ) ) {482 cost = Cost::zero;483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation484 } // if485 }486 487 void ConversionCost::postvisit( const OneType * ) {488 if ( dynamic_cast< const OneType * >( dest ) ) {489 cost = Cost::zero;490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];493 if ( tableResult == -1 ) {494 cost = Cost::unsafe;495 } else {496 cost = Cost::zero;497 cost.incSafe( tableResult + 1 );498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );499 } // if500 } // if501 }502 153 503 154 namespace { -
src/ResolvExpr/ConversionCost.h
r0030b508 rfc12f05 22 22 #include "AST/Fwd.hpp" 23 23 #include "AST/Pass.hpp" // for WithShortCircuiting 24 #include "Common/PassVisitor.h"25 #include "SynTree/Visitor.h" // for Visitor26 #include "SynTree/SynTree.h" // for Visitor Nodes27 24 28 25 namespace SymTab { … … 32 29 namespace ResolvExpr { 33 30 class TypeEnvironment; 34 35 Cost conversionCost(36 const Type * src, const Type * dest, bool srcIsLvalue,37 const SymTab::Indexer & indexer, const TypeEnvironment & env );38 39 typedef std::function<Cost(const Type *, const Type *, bool,40 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;41 42 struct ConversionCost : public WithShortCircuiting {43 public:44 ConversionCost( const Type * dest, bool srcIsLvalue,45 const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );46 47 Cost get_cost() const { return cost; }48 49 void previsit( const BaseSyntaxNode * ) { visit_children = false; }50 51 void postvisit( const VoidType * voidType );52 void postvisit( const BasicType * basicType );53 void postvisit( const PointerType * pointerType );54 void postvisit( const ArrayType * arrayType );55 void postvisit( const ReferenceType * refType );56 void postvisit( const FunctionType * functionType );57 void postvisit( const EnumInstType * aggregateUseType );58 void postvisit( const TraitInstType * aggregateUseType );59 void postvisit( const TypeInstType * aggregateUseType );60 void postvisit( const TupleType * tupleType );61 void postvisit( const VarArgsType * varArgsType );62 void postvisit( const ZeroType * zeroType );63 void postvisit( const OneType * oneType );64 protected:65 const Type * dest;66 bool srcIsLvalue;67 const SymTab::Indexer &indexer;68 Cost cost;69 const TypeEnvironment &env;70 CostFunction costFunc;71 private:72 // refactor for code resue73 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );74 };75 76 typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;77 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,78 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );79 31 80 32 // Some function pointer types, differ in return type. -
src/ResolvExpr/CurrentObject.cc
r0030b508 rfc12f05 33 33 #include "Common/utility.h" // for toString 34 34 #include "CurrentObject.h" 35 #include "SynTree/Constant.h" // for Constant36 #include "SynTree/Declaration.h" // for ObjectDecl, Declaration, Struc...37 #include "SynTree/Expression.h" // for InitAlternative, VariableExpr38 #include "SynTree/Initializer.h" // for Designation, operator<<39 #include "SynTree/Type.h" // for Type, StructInstType, UnionIns...40 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution41 35 42 36 #if 0 … … 45 39 #define PRINT(x) 46 40 #endif 47 48 namespace ResolvExpr {49 template< typename AggrInst >50 TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {51 assert( inst );52 assert( inst->get_baseParameters() );53 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();54 std::list< Expression * > typeSubs = inst->get_parameters();55 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );56 return subs;57 }58 59 TypeSubstitution makeGenericSubstitution( Type * type ) {60 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {61 return makeGenericSubstitution( inst );62 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {63 return makeGenericSubstitution( inst );64 } else {65 return TypeSubstitution();66 }67 }68 69 class MemberIterator {70 public:71 virtual ~MemberIterator() {}72 73 /// walks the current object using the given designators as a guide74 virtual void setPosition( std::list< Expression * > & designators ) = 0;75 76 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object77 virtual std::list<InitAlternative> operator*() const = 0;78 79 /// true if the iterator is not currently at the end80 virtual operator bool() const = 0;81 82 /// moves the iterator by one member in the current object83 virtual MemberIterator & bigStep() = 0;84 85 /// moves the iterator by one member in the current subobject86 virtual MemberIterator & smallStep() = 0;87 88 /// the type of the current object89 virtual Type * getType() = 0;90 91 /// the type of the current subobject92 virtual Type * getNext() = 0;93 94 /// printing for debug95 virtual void print( std::ostream & out, Indenter indent ) const = 0;96 97 /// helper for operator*; aggregates must add designator to each init alternative, but98 /// adding designators in operator* creates duplicates.99 virtual std::list<InitAlternative> first() const = 0; // should be protected100 };101 102 std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {103 Indenter indenter;104 it.print( out, indenter );105 return out;106 }107 108 /// create a new MemberIterator that traverses a type correctly109 MemberIterator * createMemberIterator( Type * type );110 111 /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry112 class SimpleIterator : public MemberIterator {113 public:114 SimpleIterator( Type * type ) : type( type ) {}115 116 virtual void setPosition( std::list< Expression * > & designators ) {117 assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error118 }119 120 virtual std::list<InitAlternative> operator*() const { return first(); }121 virtual operator bool() const { return type; }122 123 // big step is the same as small step124 virtual MemberIterator & bigStep() { return smallStep(); }125 virtual MemberIterator & smallStep() {126 type = nullptr; // type is nullified on increment since SimpleIterators do not have members127 return *this;128 }129 130 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {131 out << "SimpleIterator(" << type << ")";132 }133 134 virtual Type * getType() { return type; }135 virtual Type * getNext() { return type; }136 137 protected:138 virtual std::list<InitAlternative> first() const {139 if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };140 else return std::list<InitAlternative>{};141 }142 private:143 Type * type = nullptr;144 };145 146 class ArrayIterator : public MemberIterator {147 public:148 ArrayIterator( ArrayType * at ) : array( at ) {149 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )150 base = at->base;151 memberIter = createMemberIterator( base );152 if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );153 setSize( at->dimension );154 }155 156 ~ArrayIterator() {157 delete memberIter;158 }159 160 private:161 void setSize( Expression * expr ) {162 auto res = eval( expr );163 if (res.second) {164 size = res.first;165 } else {166 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );167 }168 }169 170 public:171 void setPosition( Expression * expr ) {172 // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions173 auto arg = eval( expr );174 index = arg.first;175 return;176 177 // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {178 // try {179 // index = constExpr->intValue();180 // } catch( SemanticErrorException & ) {181 // SemanticError( expr, "Constant expression of non-integral type in array designator: " );182 // }183 // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {184 // setPosition( castExpr->get_arg() );185 // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {186 // EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );187 // assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );188 // long long int value;189 // if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {190 // index = value;191 // }192 // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {193 // index = 0; // xxx - get actual sizeof/alignof value?194 // } else {195 // assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );196 // }197 }198 199 virtual void setPosition( std::list< Expression * > & designators ) {200 if ( ! designators.empty() ) {201 setPosition( designators.front() );202 designators.pop_front();203 memberIter->setPosition( designators );204 }205 }206 207 virtual std::list<InitAlternative> operator*() const {208 return first();209 }210 211 virtual operator bool() const { return index < size; }212 213 virtual MemberIterator & bigStep() {214 PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )215 ++index;216 delete memberIter;217 if ( index < size ) memberIter = createMemberIterator( base );218 else memberIter = nullptr;219 return *this;220 }221 222 virtual MemberIterator & smallStep() {223 PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )224 if ( memberIter ) {225 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )226 memberIter->smallStep();227 if ( *memberIter ) {228 PRINT( std::cerr << "has valid member iter" << std::endl; )229 return *this;230 }231 }232 return bigStep();233 }234 235 virtual Type * getType() { return array; }236 virtual Type * getNext() { return base; }237 238 virtual std::list<InitAlternative> first() const {239 PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )240 if ( memberIter && *memberIter ) {241 std::list<InitAlternative> ret = memberIter->first();242 for ( InitAlternative & alt : ret ) {243 alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );244 }245 return ret;246 }247 return std::list<InitAlternative>();248 }249 250 virtual void print( std::ostream & out, Indenter indent ) const {251 out << "ArrayIterator(Array of " << base << ")";252 if ( memberIter ) {253 Indenter childIndent = indent+1;254 out << std::endl << childIndent;255 memberIter->print( out, childIndent );256 }257 }258 259 private:260 ArrayType * array = nullptr;261 Type * base = nullptr;262 size_t index = 0;263 size_t size = 0;264 MemberIterator * memberIter = nullptr;265 };266 267 class AggregateIterator : public MemberIterator {268 public:269 typedef std::list<Declaration *> MemberList;270 typedef MemberList::const_iterator iterator;271 std::string kind = ""; // for debug272 std::string name;273 Type * inst = nullptr;274 const MemberList & members;275 iterator curMember;276 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning277 Type * curType = nullptr;278 MemberIterator * memberIter = nullptr;279 mutable TypeSubstitution sub;280 281 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {282 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )283 init();284 }285 286 virtual ~AggregateIterator() {287 delete memberIter;288 }289 290 bool init() {291 PRINT( std::cerr << "--init()--" << members.size() << std::endl; )292 if ( curMember != members.end() ) {293 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {294 PRINT( std::cerr << "incremented to field: " << field << std::endl; )295 curType = field->get_type();296 memberIter = createMemberIterator( curType );297 return true;298 }299 }300 return false;301 }302 303 virtual std::list<InitAlternative> operator*() const {304 if (memberIter && *memberIter) {305 std::list<InitAlternative> ret = memberIter->first();306 PRINT( std::cerr << "sub: " << sub << std::endl; )307 for ( InitAlternative & alt : ret ) {308 PRINT( std::cerr << "iterating and adding designators" << std::endl; )309 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );310 // need to substitute for generic types, so that casts are to concrete types311 PRINT( std::cerr << " type is: " << alt.type; )312 sub.apply( alt.type ); // also apply to designation??313 PRINT( std::cerr << " ==> " << alt.type << std::endl; )314 }315 return ret;316 }317 return std::list<InitAlternative>();318 }319 320 virtual void setPosition( std::list< Expression * > & designators ) {321 if ( ! designators.empty() ) {322 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {323 for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {324 if ( *curMember == varExpr->get_var() ) {325 designators.pop_front();326 delete memberIter;327 memberIter = createMemberIterator( varExpr->get_result() );328 curType = varExpr->get_result();329 atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??330 memberIter->setPosition( designators );331 return;332 } // if333 } // for334 assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );335 } else {336 assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );337 } // if338 } // if339 }340 341 virtual MemberIterator & smallStep() {342 PRINT( std::cerr << "smallStep in " << kind << std::endl; )343 atbegin = false;344 if ( memberIter ) {345 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )346 memberIter->smallStep();347 if ( *memberIter ) {348 PRINT( std::cerr << "success!" << std::endl; )349 return *this;350 }351 }352 return bigStep();353 }354 355 virtual Type * getType() { return inst; }356 virtual Type * getNext() {357 if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???358 return nullptr;359 }360 361 virtual std::list<InitAlternative> first() const {362 std::list<InitAlternative> ret;363 PRINT( std::cerr << "first " << kind << std::endl; )364 if ( memberIter && *memberIter ) { // might not need *memberIter??365 PRINT( std::cerr << "adding children" << std::endl; )366 ret = memberIter->first();367 for ( InitAlternative & alt : ret ) {368 PRINT( std::cerr << "iterating and adding designators" << std::endl; )369 alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );370 }371 }372 if ( atbegin ) {373 // xxx - what about case of empty struct??374 // only add self if at the very beginning of the structure375 PRINT( std::cerr << "adding self" << std::endl; )376 ret.push_front( { inst->clone(), new Designation( {} ) } );377 }378 return ret;379 }380 381 virtual void print( std::ostream & out, Indenter indent ) const {382 out << kind << "(" << name << ")";383 if ( memberIter ) {384 Indenter childIndent = indent+1;385 out << std::endl << childIndent;386 memberIter->print( out, childIndent );387 }388 }389 };390 391 class UnionIterator : public AggregateIterator {392 public:393 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}394 395 virtual operator bool() const { return (memberIter && *memberIter); }396 virtual MemberIterator & bigStep() {397 // unions only initialize one member398 PRINT( std::cerr << "bigStep in " << kind << std::endl; )399 atbegin = false;400 delete memberIter;401 memberIter = nullptr;402 curType = nullptr;403 curMember = members.end();404 return *this;405 }406 };407 408 class StructIterator : public AggregateIterator {409 public:410 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}411 412 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }413 414 virtual MemberIterator & bigStep() {415 PRINT( std::cerr << "bigStep in " << kind << std::endl; )416 atbegin = false;417 delete memberIter;418 memberIter = nullptr;419 curType = nullptr;420 for ( ; curMember != members.end(); ) {421 ++curMember;422 if ( init() ) {423 return *this;424 }425 }426 return *this;427 }428 };429 430 class TupleIterator : public AggregateIterator {431 public:432 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}433 434 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }435 436 virtual MemberIterator & bigStep() {437 PRINT( std::cerr << "bigStep in " << kind << std::endl; )438 atbegin = false;439 delete memberIter;440 memberIter = nullptr;441 curType = nullptr;442 for ( ; curMember != members.end(); ) {443 ++curMember;444 if ( init() ) {445 return *this;446 }447 }448 return *this;449 }450 };451 452 MemberIterator * createMemberIterator( Type * type ) {453 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {454 if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {455 return new StructIterator( sit );456 } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {457 return new UnionIterator( uit );458 } else {459 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );460 return new SimpleIterator( type );461 }462 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {463 return new ArrayIterator( at );464 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {465 return new TupleIterator( tt );466 } else {467 return new SimpleIterator( type );468 }469 }470 471 CurrentObject::CurrentObject() {}472 CurrentObject::CurrentObject( Type * type ) {473 objStack.push( new SimpleIterator( type ) );474 }475 476 477 void CurrentObject::setNext( Designation * designation ) {478 assertf( ! objStack.empty(), "obj stack empty in setNext" );479 PRINT( std::cerr << "____setNext" << designation << std::endl; )480 objStack.top()->setPosition( designation->get_designators() );481 }482 483 Designation * CurrentObject::findNext( Designation * designation ) {484 typedef std::list< Expression * > DesignatorChain;485 PRINT( std::cerr << "___findNext" << std::endl; )486 // find all the d's487 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;488 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;489 for ( Expression * expr : designation->get_designators() ) {490 PRINT( std::cerr << "____untyped: " << expr << std::endl; )491 std::list<DesignatorChain>::iterator dit = desigAlts.begin();492 if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {493 for ( Type * t : curTypes ) {494 assert( dit != desigAlts.end() );495 DesignatorChain & d = *dit;496 PRINT( std::cerr << "____actual: " << t << std::endl; )497 ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);498 std::list<Declaration *> members;499 if ( refType ) {500 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name501 // xxx - need to also include anonymous members in this somehow...502 for ( Declaration * mem: members ) {503 if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {504 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )505 DesignatorChain newD = d;506 newD.push_back( new VariableExpr( field ) );507 newDesigAlts.push_back( newD );508 newTypes.push_back( field->get_type() );509 } // if510 } // for511 } // if512 ++dit;513 } // for514 } else {515 for ( Type * t : curTypes ) {516 assert( dit != desigAlts.end() );517 DesignatorChain & d = *dit;518 if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {519 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )520 d.push_back( expr );521 newDesigAlts.push_back( d );522 newTypes.push_back( at->get_base() );523 }524 ++dit;525 } // for526 } // if527 desigAlts = newDesigAlts;528 newDesigAlts.clear();529 curTypes = newTypes;530 newTypes.clear();531 assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );532 } // for533 if ( desigAlts.size() > 1 ) {534 SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );535 } else if ( desigAlts.size() == 0 ) {536 SemanticError( designation, "No reasonable alternatives for designation: " );537 }538 DesignatorChain & d = desigAlts.back();539 PRINT( for ( Expression * expr : d ) {540 std::cerr << "____desig: " << expr << std::endl;541 } ) // for542 assertf( ! curTypes.empty(), "empty designator chosen");543 544 // set new designators545 assertf( ! objStack.empty(), "empty object stack when setting designation" );546 Designation * actualDesignation = new Designation( d );547 objStack.top()->setPosition( d ); // destroys d548 return actualDesignation;549 }550 551 void CurrentObject::increment() {552 PRINT( std::cerr << "____increment" << std::endl; )553 if ( ! objStack.empty() ) {554 PRINT( std::cerr << *objStack.top() << std::endl; )555 objStack.top()->smallStep();556 }557 }558 559 void CurrentObject::enterListInit() {560 PRINT( std::cerr << "____entering list init" << std::endl; )561 assertf( ! objStack.empty(), "empty obj stack entering list init" );562 Type * type = objStack.top()->getNext();563 if ( type ) {564 objStack.push( createMemberIterator( type ) );565 } else {566 assertf( false, "not sure about this case..." );567 }568 }569 570 void CurrentObject::exitListInit() {571 PRINT( std::cerr << "____exiting list init" << std::endl; )572 assertf( ! objStack.empty(), "objstack empty" );573 delete objStack.top();574 objStack.pop();575 if ( ! objStack.empty() ) {576 PRINT( std::cerr << *objStack.top() << std::endl; )577 objStack.top()->bigStep();578 }579 }580 581 std::list< InitAlternative > CurrentObject::getOptions() {582 PRINT( std::cerr << "____getting current options" << std::endl; )583 assertf( ! objStack.empty(), "objstack empty in getOptions" );584 return **objStack.top();585 }586 587 Type * CurrentObject::getCurrentType() {588 PRINT( std::cerr << "____getting current type" << std::endl; )589 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );590 return objStack.top()->getNext();591 }592 } // namespace ResolvExpr593 41 594 42 namespace ast { … … 1064 512 } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) { 1065 513 auto nexpr = dynamic_cast< const NameExpr *>( expr ); 1066 auto res = eval( nexpr );1067 514 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { 1068 515 if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) { … … 1070 517 d2.emplace_back( new VariableExpr{ expr->location, field } ); 1071 518 newDesigAlts.emplace_back( std::move( d2 ) ); 1072 // newTypes.emplace_back( field->type );1073 519 newTypes.emplace_back( at->base ); 1074 520 } 1075 521 } 1076 1077 // d.emplace_back( expr );1078 // newDesigAlts.emplace_back( d );1079 // newTypes.emplace_back( at->base );1080 522 } 1081 523 -
src/ResolvExpr/FindOpenVars.cc
r0030b508 rfc12f05 16 16 #include "FindOpenVars.h" 17 17 18 #include <list> // for _List_const_iterator, list<>::const...19 #include <map> // for map<>::mapped_type20 21 18 #include "AST/Pass.hpp" 22 19 #include "AST/Type.hpp" 23 20 #include "AST/TypeEnvironment.hpp" 24 #include "Common/PassVisitor.h"25 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ...26 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType27 21 28 22 #include <iostream> 29 23 30 24 namespace ResolvExpr { 31 struct FindOpenVars_old : public WithGuards {32 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );33 34 void previsit( const PointerType * pointerType );35 void previsit( const ArrayType * arrayType );36 void previsit( const FunctionType * functionType );37 void previsit( const TupleType * tupleType );38 39 void common_action( const Type *type );40 41 OpenVarSet &openVars, &closedVars;42 AssertionSet &needAssertions, &haveAssertions;43 bool nextIsOpen;44 };45 46 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {47 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );48 type->accept( finder );49 }50 51 FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )52 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {53 }54 55 void FindOpenVars_old::common_action( const Type * type ) {56 if ( nextIsOpen ) {57 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {58 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };59 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {60 needAssertions[ *assert ].isUsed = false;61 }62 /// cloneAll( (*i)->get_assertions(), needAssertions );63 /// needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );64 }65 } else {66 for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {67 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };68 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {69 haveAssertions[ *assert ].isUsed = false;70 }71 /// cloneAll( (*i)->get_assertions(), haveAssertions );72 /// haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );73 } // for74 } // if75 /// std::cerr << "type is ";76 /// type->print( std::cerr );77 /// std::cerr << std::endl << "need is" << std::endl;78 /// printAssertionSet( needAssertions, std::cerr );79 /// std::cerr << std::endl << "have is" << std::endl;80 /// printAssertionSet( haveAssertions, std::cerr );81 }82 83 void FindOpenVars_old::previsit(const PointerType * pointerType) {84 common_action( pointerType );85 }86 87 void FindOpenVars_old::previsit(const ArrayType * arrayType) {88 common_action( arrayType );89 }90 91 void FindOpenVars_old::previsit(const FunctionType * functionType) {92 common_action( functionType );93 nextIsOpen = ! nextIsOpen;94 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );95 }96 97 void FindOpenVars_old::previsit(const TupleType * tupleType) {98 common_action( tupleType );99 }100 25 101 26 namespace { -
src/ResolvExpr/FindOpenVars.h
r0030b508 rfc12f05 17 17 18 18 #include "AST/TypeEnvironment.hpp" // for AssertionSet, OpenVarSet 19 #include "ResolvExpr/TypeEnvironment.h" // for AssertionSet, OpenVarSet20 19 21 class Type;22 20 namespace ast { 23 21 class Type; … … 25 23 26 24 namespace ResolvExpr { 27 // Updates open and closed variables and their associated assertions28 void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );29 30 25 enum FirstMode { FirstClosed, FirstOpen }; 31 26 -
src/ResolvExpr/PolyCost.cc
r0030b508 rfc12f05 18 18 #include "AST/Type.hpp" 19 19 #include "AST/TypeEnvironment.hpp" 20 #include "Common/PassVisitor.h"21 #include "SymTab/Indexer.h" // for Indexer22 #include "SynTree/Type.h" // for TypeInstType, Type23 #include "TypeEnvironment.h" // for EqvClass, TypeEnvironment24 20 25 21 namespace ResolvExpr { 26 struct PolyCost {27 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );28 29 void previsit( TypeInstType * aggregateUseType );30 int result;31 const TypeEnvironment &tenv;32 const SymTab::Indexer &indexer;33 };34 35 int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {36 PassVisitor<PolyCost> coster( env, indexer );37 type->accept( coster );38 return (coster.pass.result > 0) ? 1 : 0;39 }40 41 PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {42 }43 44 void PolyCost::previsit(TypeInstType * typeInst) {45 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {46 if ( eqvClass->type ) {47 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {48 if ( indexer.lookupType( otherTypeInst->name ) ) {49 // bound to opaque type50 result += 1;51 } // if52 } else {53 // bound to concrete type54 result += 1;55 } // if56 } // if57 } // if58 }59 22 60 23 // TODO: When the old PolyCost is torn out get rid of the _new suffix. -
src/ResolvExpr/PtrsAssignable.cc
r0030b508 rfc12f05 19 19 #include "AST/Type.hpp" 20 20 #include "AST/TypeEnvironment.hpp" 21 #include "Common/PassVisitor.h"22 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment23 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType24 #include "SynTree/Visitor.h" // for Visitor25 26 21 27 22 namespace ResolvExpr { 28 struct PtrsAssignable : public WithShortCircuiting {29 PtrsAssignable( const Type * dest, const TypeEnvironment &env );30 31 int get_result() const { return result; }32 33 void previsit( const Type * ) { visit_children = false; }34 35 void postvisit( const VoidType * voidType );36 void postvisit( const BasicType * basicType );37 void postvisit( const PointerType * pointerType );38 void postvisit( const ArrayType * arrayType );39 void postvisit( const FunctionType * functionType );40 void postvisit( const StructInstType * inst );41 void postvisit( const UnionInstType * inst );42 void postvisit( const EnumInstType * inst );43 void postvisit( const TraitInstType * inst );44 void postvisit( const TypeInstType * inst );45 void postvisit( const TupleType * tupleType );46 void postvisit( const VarArgsType * varArgsType );47 void postvisit( const ZeroType * zeroType );48 void postvisit( const OneType * oneType );49 private:50 const Type * dest;51 int result;52 const TypeEnvironment &env;53 };54 55 int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {56 // std::cerr << "assignable: " << src << " | " << dest << std::endl;57 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {58 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {59 return ptrsAssignable( src, eqvClass->type, env );60 } // if61 } // if62 if ( dynamic_cast< const VoidType* >( dest ) ) {63 // void * = T * for any T is unsafe64 // xxx - this should be safe, but that currently breaks the build65 return -1;66 } else {67 PassVisitor<PtrsAssignable> ptrs( dest, env );68 src->accept( ptrs );69 return ptrs.pass.get_result();70 } // if71 }72 73 PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}74 75 void PtrsAssignable::postvisit( const VoidType * ) {76 // T * = void * is disallowed - this is a change from C, where any77 // void * can be assigned or passed to a non-void pointer without a cast.78 }79 80 void PtrsAssignable::postvisit( const BasicType * ) {}81 void PtrsAssignable::postvisit( const PointerType * ) {}82 void PtrsAssignable::postvisit( const ArrayType * ) {}83 void PtrsAssignable::postvisit( const FunctionType * ) {}84 85 void PtrsAssignable::postvisit( const StructInstType * ) {}86 void PtrsAssignable::postvisit( const UnionInstType * ) {}87 88 void PtrsAssignable::postvisit( const EnumInstType * ) {89 if ( dynamic_cast< const BasicType* >( dest ) ) {90 // int * = E *, etc. is safe. This isn't technically correct, as each91 // enum has one basic type that it is compatible with, an that type can92 // differ from enum to enum. Without replicating GCC's internal logic,93 // there is no way to know which type this particular enum is compatible94 // with, so punt on this for now.95 result = 1;96 }97 }98 99 void PtrsAssignable::postvisit( const TraitInstType * ) {}100 void PtrsAssignable::postvisit( const TypeInstType * inst ) {101 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {102 if ( eqvClass->type ) {103 // T * = S * for any S depends on the type bound to T104 result = ptrsAssignable( eqvClass->type, dest, env );105 }106 } // if107 }108 109 void PtrsAssignable::postvisit( const TupleType * ) {}110 void PtrsAssignable::postvisit( const VarArgsType * ) {}111 void PtrsAssignable::postvisit( const ZeroType * ) {}112 void PtrsAssignable::postvisit( const OneType * ) {}113 23 114 24 // TODO: Get rid of the `_new` suffix when the old version is removed. -
src/ResolvExpr/PtrsCastable.cc
r0030b508 rfc12f05 20 20 #include "AST/Type.hpp" 21 21 #include "AST/TypeEnvironment.hpp" 22 #include "Common/PassVisitor.h"23 22 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 24 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment25 #include "SymTab/Indexer.h" // for Indexer26 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Kind::Ftype27 #include "SynTree/Type.h" // for TypeInstType, Type, BasicType28 #include "SynTree/Visitor.h" // for Visitor29 23 30 24 namespace ResolvExpr { 31 struct PtrsCastable_old : public WithShortCircuiting {32 public:33 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );34 35 int get_result() const { return result; }36 37 void previsit( const Type * ) { visit_children = false; }38 39 void postvisit( const VoidType * voidType );40 void postvisit( const BasicType * basicType );41 void postvisit( const PointerType * pointerType );42 void postvisit( const ArrayType * arrayType );43 void postvisit( const FunctionType * functionType );44 void postvisit( const StructInstType * inst );45 void postvisit( const UnionInstType * inst );46 void postvisit( const EnumInstType * inst );47 void postvisit( const TraitInstType * inst );48 void postvisit( const TypeInstType * inst );49 void postvisit( const TupleType * tupleType );50 void postvisit( const VarArgsType * varArgsType );51 void postvisit( const ZeroType * zeroType );52 void postvisit( const OneType * oneType );53 private:54 const Type * dest;55 int result;56 const TypeEnvironment &env;57 const SymTab::Indexer &indexer;58 };59 60 namespace {61 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {62 if ( dynamic_cast< const FunctionType* >( src ) ) {63 return -1;64 } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {65 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {66 if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {67 if ( tyDecl->kind == TypeDecl::Ftype ) {68 return -1;69 } // if70 } //if71 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {72 if ( eqvClass->data.kind == TypeDecl::Ftype ) {73 return -1;74 } // if75 } // if76 } //if77 return 1;78 }79 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {80 return -1 * objectCast( src, env, indexer ); // reverse the sense of objectCast81 }82 }83 84 int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {85 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {86 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {87 // xxx - should this be ptrsCastable?88 return ptrsAssignable( src, eqvClass->type, env );89 } // if90 } // if91 if ( dynamic_cast< const VoidType* >( dest ) ) {92 return objectCast( src, env, indexer );93 } else {94 PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );95 src->accept( ptrs );96 return ptrs.pass.get_result();97 } // if98 }99 100 PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )101 : dest( dest ), result( 0 ), env( env ), indexer( indexer ) {102 }103 104 void PtrsCastable_old::postvisit( const VoidType * ) {105 result = objectCast( dest, env, indexer );106 }107 108 void PtrsCastable_old::postvisit( const BasicType * ) {109 result = objectCast( dest, env, indexer );110 }111 112 void PtrsCastable_old::postvisit( const PointerType * ) {113 result = objectCast( dest, env, indexer );114 }115 116 void PtrsCastable_old::postvisit( const ArrayType * ) {117 result = objectCast( dest, env, indexer );118 }119 120 void PtrsCastable_old::postvisit( const FunctionType * ) {121 // result = -1;122 result = functionCast( dest, env, indexer );123 }124 125 void PtrsCastable_old::postvisit( const StructInstType * ) {126 result = objectCast( dest, env, indexer );127 }128 129 void PtrsCastable_old::postvisit( const UnionInstType * ) {130 result = objectCast( dest, env, indexer );131 }132 133 void PtrsCastable_old::postvisit( const EnumInstType * ) {134 if ( dynamic_cast< const EnumInstType * >( dest ) ) {135 result = 1;136 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {137 if ( bt->kind == BasicType::SignedInt ) {138 result = 0;139 } else {140 result = 1;141 }142 } else {143 result = objectCast( dest, env, indexer );144 }145 }146 147 void PtrsCastable_old::postvisit( const TraitInstType * ) {}148 149 void PtrsCastable_old::postvisit( const TypeInstType *inst ) {150 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;151 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;152 }153 154 void PtrsCastable_old::postvisit( const TupleType * ) {155 result = objectCast( dest, env, indexer );156 }157 158 void PtrsCastable_old::postvisit( const VarArgsType * ) {159 result = objectCast( dest, env, indexer );160 }161 162 void PtrsCastable_old::postvisit( const ZeroType * ) {163 result = objectCast( dest, env, indexer );164 }165 166 void PtrsCastable_old::postvisit( const OneType * ) {167 result = objectCast( dest, env, indexer );168 }169 25 170 26 namespace { -
src/ResolvExpr/RenameVars.cc
r0030b508 rfc12f05 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 23 #include "Common/ScopedMap.h" 25 24 #include "Common/SemanticError.h" // for SemanticError 26 25 #include "RenameVars.h" 27 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...28 #include "SynTree/Expression.h" // for Expression29 #include "SynTree/Type.h" // for Type, TypeInstType, TraitInstType30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept31 26 32 27 #include "AST/Copy.hpp" … … 49 44 } 50 45 51 void rename( TypeInstType * type ) {52 auto it = nameMap.find( type->name );53 if ( it != nameMap.end() ) {54 type->name = it->second;55 }56 }57 58 46 void nextUsage() { 59 47 ++next_usage_id; 60 }61 62 void openLevel( Type * type ) {63 if ( ! type->forall.empty() ) {64 nameMap.beginScope();65 // renames all "forall" type names to `_${level}_${name}'66 for ( auto td : type->forall ) {67 std::ostringstream output;68 output << "_" << resetCount << "_" << level << "_" << td->name;69 std::string newname( output.str() );70 nameMap[ td->get_name() ] = newname;71 td->name = newname;72 // ditto for assertion names, the next level in73 level++;74 }75 }76 }77 78 void closeLevel( Type * type ) {79 if ( !type->forall.empty() ) {80 nameMap.endScope();81 }82 48 } 83 49 … … 135 101 RenamingData renaming; 136 102 137 struct RenameVars_old {138 void previsit( TypeInstType * instType ) {139 renaming.openLevel( (Type*)instType );140 renaming.rename( instType );141 }142 void previsit( Type * type ) {143 renaming.openLevel( type );144 }145 void postvisit( Type * type ) {146 renaming.closeLevel( type );147 }148 };149 150 103 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 151 104 RenameMode mode; … … 178 131 } // namespace 179 132 180 void renameTyVars( Type * t ) {181 PassVisitor<RenameVars_old> renamer;182 t->accept( renamer );183 }184 185 133 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 186 134 ast::Pass<RenameVars_new> renamer; -
src/ResolvExpr/RenameVars.h
r0030b508 rfc12f05 16 16 #pragma once 17 17 18 #include <list> // for list19 #include <map> // for map20 #include <string> // for string21 22 #include "SynTree/SynTree.h" // for Visitor Nodes23 #include "SynTree/Visitor.h" // for Visitor24 25 18 namespace ast { 26 19 class Type; … … 28 21 29 22 namespace ResolvExpr { 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID31 void renameTyVars( Type * );32 33 23 enum RenameMode { 34 24 GEN_USAGE, // for type in VariableExpr -
src/ResolvExpr/ResolveTypeof.cc
r0030b508 rfc12f05 24 24 #include "AST/Type.hpp" 25 25 #include "AST/TypeEnvironment.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/utility.h" // for copy 28 27 #include "InitTweak/InitTweak.h" // for isConstExpr … … 30 29 #include "Resolver.h" // for resolveInVoidContext 31 30 #include "SymTab/Mangler.h" 32 #include "SynTree/Expression.h" // for Expression33 #include "SynTree/Mutator.h" // for Mutator34 #include "SynTree/Type.h" // for TypeofType, Type35 36 namespace SymTab {37 class Indexer;38 } // namespace SymTab39 31 40 32 namespace ResolvExpr { 41 namespace {42 #if 043 void44 printAlts( const AltList &list, std::ostream &os, int indent = 0 )45 {46 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {47 i->print( os, indent );48 os << std::endl;49 }50 }51 #endif52 }53 54 class ResolveTypeof_old : public WithShortCircuiting {55 public:56 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}57 void premutate( TypeofType *typeofType );58 Type * postmutate( TypeofType *typeofType );59 60 private:61 const SymTab::Indexer &indexer;62 };63 64 Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {65 PassVisitor<ResolveTypeof_old> mutator( indexer );66 return type->acceptMutator( mutator );67 }68 69 void ResolveTypeof_old::premutate( TypeofType * ) {70 visit_children = false;71 }72 73 Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {74 #if 075 std::cerr << "resolving typeof: ";76 typeofType->print( std::cerr );77 std::cerr << std::endl;78 #endif79 // pass on null expression80 if ( ! typeofType->expr ) return typeofType;81 82 bool isBasetypeof = typeofType->is_basetypeof;83 auto oldQuals = typeofType->get_qualifiers().val;84 85 Type* newType;86 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {87 // typeof wrapping type88 newType = tyExpr->type;89 tyExpr->type = nullptr;90 delete tyExpr;91 } else {92 // typeof wrapping expression93 Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );94 assert( newExpr->result && ! newExpr->result->isVoid() );95 newType = newExpr->result;96 newExpr->result = nullptr;97 delete typeofType;98 delete newExpr;99 }100 101 // clear qualifiers for base, combine with typeoftype quals in any case102 if ( isBasetypeof ) {103 // replace basetypeof(<enum>) by int104 if ( dynamic_cast<EnumInstType*>(newType) ) {105 Type* newerType =106 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,107 newType->attributes };108 delete newType;109 newType = newerType;110 }111 newType->get_qualifiers().val112 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;113 } else {114 newType->get_qualifiers().val |= oldQuals;115 }116 117 return newType;118 }119 33 120 34 namespace { -
src/ResolvExpr/Resolver.cc
r0030b508 rfc12f05 19 19 #include <vector> // for vector 20 20 21 #include "Alternative.h" // for Alternative, AltList22 #include "AlternativeFinder.h" // for AlternativeFinder, resolveIn...23 21 #include "Candidate.hpp" 24 22 #include "CandidateFinder.hpp" … … 40 38 #include "Common/Eval.h" // for eval 41 39 #include "Common/Iterate.hpp" // for group_iterate 42 #include "Common/PassVisitor.h" // for PassVisitor43 40 #include "Common/SemanticError.h" // for SemanticError 44 41 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 45 42 #include "Common/ToString.hpp" // for toCString 43 #include "Common/UniqueName.h" // for UniqueName 46 44 #include "InitTweak/GenInit.h" 47 45 #include "InitTweak/InitTweak.h" // for isIntrinsicSingleArgCallStmt 48 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment49 #include "SymTab/Autogen.h" // for SizeType50 #include "SymTab/Indexer.h" // for Indexer51 46 #include "SymTab/Mangler.h" // for Mangler 52 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar...53 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr54 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit55 #include "SynTree/Statement.h" // for ForStmt, Statement, BranchStmt56 #include "SynTree/Type.h" // for Type, BasicType, PointerType57 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution58 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept59 47 #include "Tuples/Tuples.h" 60 48 #include "Validate/FindSpecialDecls.h" // for SizeType … … 63 51 64 52 namespace ResolvExpr { 65 struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {66 Resolver_old() {}67 Resolver_old( const SymTab::Indexer & other ) {68 indexer = other;69 }70 71 void previsit( FunctionDecl * functionDecl );72 void postvisit( FunctionDecl * functionDecl );73 void previsit( ObjectDecl * objectDecll );74 void previsit( EnumDecl * enumDecl );75 void previsit( StaticAssertDecl * assertDecl );76 77 void previsit( ArrayType * at );78 void previsit( PointerType * at );79 80 void previsit( ExprStmt * exprStmt );81 void previsit( AsmExpr * asmExpr );82 void previsit( AsmStmt * asmStmt );83 void previsit( IfStmt * ifStmt );84 void previsit( WhileDoStmt * whileDoStmt );85 void previsit( ForStmt * forStmt );86 void previsit( SwitchStmt * switchStmt );87 void previsit( CaseStmt * caseStmt );88 void previsit( BranchStmt * branchStmt );89 void previsit( ReturnStmt * returnStmt );90 void previsit( ThrowStmt * throwStmt );91 void previsit( CatchStmt * catchStmt );92 void postvisit( CatchStmt * catchStmt );93 void previsit( WaitForStmt * stmt );94 95 void previsit( SingleInit * singleInit );96 void previsit( ListInit * listInit );97 void previsit( ConstructorInit * ctorInit );98 private:99 typedef std::list< Initializer * >::iterator InitIterator;100 101 template< typename PtrType >102 void handlePtrType( PtrType * type );103 104 void fallbackInit( ConstructorInit * ctorInit );105 106 Type * functionReturn = nullptr;107 CurrentObject currentObject = nullptr;108 bool inEnumDecl = false;109 };110 111 struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {112 void previsit( FunctionDecl * );113 void previsit( WithStmt * );114 115 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );116 };117 118 void resolve( std::list< Declaration * > translationUnit ) {119 PassVisitor<Resolver_old> resolver;120 acceptAll( translationUnit, resolver );121 }122 123 void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {124 PassVisitor<Resolver_old> resolver( indexer );125 maybeAccept( decl, resolver );126 }127 128 namespace {129 struct DeleteFinder_old : public WithShortCircuiting {130 DeletedExpr * delExpr = nullptr;131 void previsit( DeletedExpr * expr ) {132 if ( delExpr ) visit_children = false;133 else delExpr = expr;134 }135 136 void previsit( Expression * ) {137 if ( delExpr ) visit_children = false;138 }139 };140 }141 142 DeletedExpr * findDeletedExpr( Expression * expr ) {143 PassVisitor<DeleteFinder_old> finder;144 expr->accept( finder );145 return finder.pass.delExpr;146 }147 148 namespace {149 struct StripCasts_old {150 Expression * postmutate( CastExpr * castExpr ) {151 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {152 // generated cast is to the same type as its argument, so it's unnecessary -- remove it153 Expression * expr = castExpr->arg;154 castExpr->arg = nullptr;155 std::swap( expr->env, castExpr->env );156 return expr;157 }158 return castExpr;159 }160 161 static void strip( Expression *& expr ) {162 PassVisitor<StripCasts_old> stripper;163 expr = expr->acceptMutator( stripper );164 }165 };166 167 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {168 expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;169 env.makeSubstitution( *expr->env );170 StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression171 }172 173 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {174 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {175 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {176 // cast is to the same type as its argument, so it's unnecessary -- remove it177 expr = castExpr->arg;178 castExpr->arg = nullptr;179 std::swap( expr->env, castExpr->env );180 delete castExpr;181 }182 }183 }184 } // namespace185 186 namespace {187 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {188 assertf( untyped, "expected a non-null expression." );189 190 // xxx - this isn't thread-safe, but should work until we parallelize the resolver191 static unsigned recursion_level = 0;192 193 ++recursion_level;194 TypeEnvironment env;195 AlternativeFinder finder( indexer, env );196 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );197 --recursion_level;198 199 #if 0200 if ( finder.get_alternatives().size() != 1 ) {201 std::cerr << "untyped expr is ";202 untyped->print( std::cerr );203 std::cerr << std::endl << "alternatives are:";204 for ( const Alternative & alt : finder.get_alternatives() ) {205 alt.print( std::cerr );206 } // for207 } // if208 #endif209 210 // produce filtered list of alternatives211 AltList candidates;212 for ( Alternative & alt : finder.get_alternatives() ) {213 if ( pred( alt ) ) {214 candidates.push_back( std::move( alt ) );215 }216 }217 218 // produce invalid error if no candidates219 if ( candidates.empty() ) {220 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );221 }222 223 // search for cheapest candidate224 AltList winners;225 bool seen_undeleted = false;226 for ( unsigned i = 0; i < candidates.size(); ++i ) {227 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );228 229 if ( c > 0 ) continue; // skip more expensive than winner230 231 if ( c < 0 ) {232 // reset on new cheapest233 seen_undeleted = ! findDeletedExpr( candidates[i].expr );234 winners.clear();235 } else /* if ( c == 0 ) */ {236 if ( findDeletedExpr( candidates[i].expr ) ) {237 // skip deleted expression if already seen one equivalent-cost not238 if ( seen_undeleted ) continue;239 } else if ( ! seen_undeleted ) {240 // replace list of equivalent-cost deleted expressions with one non-deleted241 winners.clear();242 seen_undeleted = true;243 }244 }245 246 winners.emplace_back( std::move( candidates[i] ) );247 }248 249 // promote alternative.cvtCost to .cost250 // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost251 for ( Alternative& winner : winners ) {252 winner.cost = winner.cvtCost;253 }254 255 // produce ambiguous errors, if applicable256 if ( winners.size() != 1 ) {257 std::ostringstream stream;258 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";259 untyped->print( stream );260 stream << " Alternatives are:\n";261 printAlts( winners, stream, 1 );262 SemanticError( untyped->location, stream.str() );263 }264 265 // single selected choice266 Alternative& choice = winners.front();267 268 // fail on only expression deleted269 if ( ! seen_undeleted ) {270 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );271 }272 273 // xxx - check for ambiguous expressions274 275 // output selected choice276 alt = std::move( choice );277 }278 279 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages280 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {281 if ( ! untyped ) return;282 Alternative choice;283 findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );284 finishExpr( choice.expr, choice.env, untyped->env );285 delete untyped;286 untyped = choice.expr;287 choice.expr = nullptr;288 }289 290 bool standardAlternativeFilter( const Alternative & ) {291 // currently don't need to filter, under normal circumstances.292 // in the future, this may be useful for removing deleted expressions293 return true;294 }295 } // namespace296 297 // used in resolveTypeof298 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {299 TypeEnvironment env;300 return resolveInVoidContext( expr, indexer, env );301 }302 303 Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {304 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0305 // interpretations, an exception has already been thrown.306 assertf( expr, "expected a non-null expression." );307 308 CastExpr * untyped = new CastExpr( expr ); // cast to void309 untyped->location = expr->location;310 311 // set up and resolve expression cast to void312 Alternative choice;313 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );314 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );315 assert( castExpr );316 env = std::move( choice.env );317 318 // clean up resolved expression319 Expression * ret = castExpr->arg;320 castExpr->arg = nullptr;321 322 // unlink the arg so that it isn't deleted twice at the end of the program323 untyped->arg = nullptr;324 return ret;325 }326 327 void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {328 resetTyVarRenaming();329 TypeEnvironment env;330 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );331 finishExpr( newExpr, env, untyped->env );332 delete untyped;333 untyped = newExpr;334 }335 336 void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {337 findKindExpression( untyped, indexer, "", standardAlternativeFilter );338 }339 340 void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {341 assert( untyped && type );342 // transfer location to generated cast for error purposes343 CodeLocation location = untyped->location;344 untyped = new CastExpr( untyped, type );345 untyped->location = location;346 findSingleExpression( untyped, indexer );347 removeExtraneousCast( untyped, indexer );348 }349 350 namespace {351 bool isIntegralType( const Alternative & alt ) {352 Type * type = alt.expr->result;353 if ( dynamic_cast< EnumInstType * >( type ) ) {354 return true;355 } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {356 return bt->isInteger();357 } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {358 return true;359 } else {360 return false;361 } // if362 }363 364 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {365 findKindExpression( untyped, indexer, "condition", isIntegralType );366 }367 }368 369 370 bool isStructOrUnion( const Alternative & alt ) {371 Type * t = alt.expr->result->stripReferences();372 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );373 }374 375 void resolveWithExprs( std::list< Declaration * > & translationUnit ) {376 PassVisitor<ResolveWithExprs> resolver;377 acceptAll( translationUnit, resolver );378 }379 380 void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {381 for ( Expression *& expr : withExprs ) {382 // only struct- and union-typed expressions are viable candidates383 findKindExpression( expr, indexer, "with statement", isStructOrUnion );384 385 // if with expression might be impure, create a temporary so that it is evaluated once386 if ( Tuples::maybeImpure( expr ) ) {387 static UniqueName tmpNamer( "_with_tmp_" );388 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );389 expr = new VariableExpr( tmp );390 newStmts.push_back( new DeclStmt( tmp ) );391 if ( InitTweak::isConstructable( tmp->type ) ) {392 // generate ctor/dtor and resolve them393 tmp->init = InitTweak::genCtorInit( tmp );394 tmp->accept( *visitor );395 }396 }397 }398 }399 400 void ResolveWithExprs::previsit( WithStmt * withStmt ) {401 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );402 }403 404 void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {405 {406 // resolve with-exprs with parameters in scope and add any newly generated declarations to the407 // front of the function body.408 auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );409 indexer.addFunctionType( functionDecl->type );410 std::list< Statement * > newStmts;411 resolveWithExprs( functionDecl->withExprs, newStmts );412 if ( functionDecl->statements ) {413 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );414 } else {415 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );416 }417 }418 }419 420 void Resolver_old::previsit( ObjectDecl * objectDecl ) {421 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that422 // class-variable initContext is changed multiple time because the LHS is analysed twice.423 // The second analysis changes initContext because of a function type can contain object424 // declarations in the return and parameter types. So each value of initContext is425 // retained, so the type on the first analysis is preserved and used for selecting the RHS.426 GuardValue( currentObject );427 currentObject = CurrentObject( objectDecl->get_type() );428 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {429 // enumerator initializers should not use the enum type to initialize, since430 // the enum type is still incomplete at this point. Use signed int instead.431 // TODO: BasicType::SignedInt may not longer be true432 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );433 }434 }435 436 template< typename PtrType >437 void Resolver_old::handlePtrType( PtrType * type ) {438 if ( type->get_dimension() ) {439 findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );440 }441 }442 443 void Resolver_old::previsit( ArrayType * at ) {444 handlePtrType( at );445 }446 447 void Resolver_old::previsit( PointerType * pt ) {448 handlePtrType( pt );449 }450 451 void Resolver_old::previsit( FunctionDecl * functionDecl ) {452 #if 0453 std::cerr << "resolver visiting functiondecl ";454 functionDecl->print( std::cerr );455 std::cerr << std::endl;456 #endif457 GuardValue( functionReturn );458 functionReturn = ResolvExpr::extractResultType( functionDecl->type );459 }460 461 void Resolver_old::postvisit( FunctionDecl * functionDecl ) {462 // default value expressions have an environment which shouldn't be there and trips up463 // later passes.464 // xxx - it might be necessary to somehow keep the information from this environment, but I465 // can't currently see how it's useful.466 for ( Declaration * d : functionDecl->type->parameters ) {467 if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {468 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {469 delete init->value->env;470 init->value->env = nullptr;471 }472 }473 }474 }475 476 void Resolver_old::previsit( EnumDecl * ) {477 // in case we decide to allow nested enums478 GuardValue( inEnumDecl );479 inEnumDecl = true;480 }481 482 void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {483 findIntegralExpression( assertDecl->condition, indexer );484 }485 486 void Resolver_old::previsit( ExprStmt * exprStmt ) {487 visit_children = false;488 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );489 findVoidExpression( exprStmt->expr, indexer );490 }491 492 void Resolver_old::previsit( AsmExpr * asmExpr ) {493 visit_children = false;494 findVoidExpression( asmExpr->operand, indexer );495 }496 497 void Resolver_old::previsit( AsmStmt * asmStmt ) {498 visit_children = false;499 acceptAll( asmStmt->get_input(), *visitor );500 acceptAll( asmStmt->get_output(), *visitor );501 }502 503 void Resolver_old::previsit( IfStmt * ifStmt ) {504 findIntegralExpression( ifStmt->condition, indexer );505 }506 507 void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {508 findIntegralExpression( whileDoStmt->condition, indexer );509 }510 511 void Resolver_old::previsit( ForStmt * forStmt ) {512 if ( forStmt->condition ) {513 findIntegralExpression( forStmt->condition, indexer );514 } // if515 516 if ( forStmt->increment ) {517 findVoidExpression( forStmt->increment, indexer );518 } // if519 }520 521 void Resolver_old::previsit( SwitchStmt * switchStmt ) {522 GuardValue( currentObject );523 findIntegralExpression( switchStmt->condition, indexer );524 525 currentObject = CurrentObject( switchStmt->condition->result );526 }527 528 void Resolver_old::previsit( CaseStmt * caseStmt ) {529 if ( caseStmt->condition ) {530 std::list< InitAlternative > initAlts = currentObject.getOptions();531 assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );532 // must remove cast from case statement because RangeExpr cannot be cast.533 Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );534 findSingleExpression( newExpr, indexer );535 // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.536 // Ideally we would perform the conversion internally here.537 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {538 newExpr = castExpr->arg;539 castExpr->arg = nullptr;540 std::swap( newExpr->env, castExpr->env );541 delete castExpr;542 }543 caseStmt->condition = newExpr;544 }545 }546 547 void Resolver_old::previsit( BranchStmt * branchStmt ) {548 visit_children = false;549 // must resolve the argument for a computed goto550 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement551 if ( branchStmt->computedTarget ) {552 // computed goto argument is void *553 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );554 } // if555 } // if556 }557 558 void Resolver_old::previsit( ReturnStmt * returnStmt ) {559 visit_children = false;560 if ( returnStmt->expr ) {561 findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );562 } // if563 }564 565 void Resolver_old::previsit( ThrowStmt * throwStmt ) {566 visit_children = false;567 // TODO: Replace *exception type with &exception type.568 if ( throwStmt->get_expr() ) {569 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );570 assert( exception_decl );571 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );572 findSingleExpression( throwStmt->expr, exceptType, indexer );573 }574 }575 576 void Resolver_old::previsit( CatchStmt * catchStmt ) {577 // Until we are very sure this invarent (ifs that move between passes have then)578 // holds, check it. This allows a check for when to decode the mangling.579 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {580 assert( ifStmt->then );581 }582 // Encode the catchStmt so the condition can see the declaration.583 if ( catchStmt->cond ) {584 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );585 catchStmt->cond = nullptr;586 catchStmt->body = ifStmt;587 }588 }589 590 void Resolver_old::postvisit( CatchStmt * catchStmt ) {591 // Decode the catchStmt so everything is stored properly.592 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );593 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {594 assert( ifStmt->condition );595 assert( ifStmt->else_ );596 catchStmt->cond = ifStmt->condition;597 catchStmt->body = ifStmt->else_;598 ifStmt->condition = nullptr;599 ifStmt->else_ = nullptr;600 delete ifStmt;601 }602 }603 604 53 template< typename iterator_t > 605 54 inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) { … … 610 59 return it != end; 611 60 } 612 613 void Resolver_old::previsit( WaitForStmt * stmt ) {614 visit_children = false;615 616 // Resolve all clauses first617 for( auto& clause : stmt->clauses ) {618 619 TypeEnvironment env;620 AlternativeFinder funcFinder( indexer, env );621 622 // Find all alternatives for a function in canonical form623 funcFinder.findWithAdjustment( clause.target.function );624 625 if ( funcFinder.get_alternatives().empty() ) {626 stringstream ss;627 ss << "Use of undeclared indentifier '";628 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;629 ss << "' in call to waitfor";630 SemanticError( stmt->location, ss.str() );631 }632 633 if(clause.target.arguments.empty()) {634 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");635 }636 637 // Find all alternatives for all arguments in canonical form638 std::vector< AlternativeFinder > argAlternatives;639 funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );640 641 // List all combinations of arguments642 std::vector< AltList > possibilities;643 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );644 645 AltList func_candidates;646 std::vector< AltList > args_candidates;647 648 // For every possible function :649 // try matching the arguments to the parameters650 // not the other way around because we have more arguments than parameters651 SemanticErrorException errors;652 for ( Alternative & func : funcFinder.get_alternatives() ) {653 try {654 PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );655 if( !pointer ) {656 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );657 }658 659 FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );660 if( !function ) {661 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );662 }663 664 665 {666 auto param = function->parameters.begin();667 auto param_end = function->parameters.end();668 669 if( !advance_to_mutex( param, param_end ) ) {670 SemanticError(function, "candidate function not viable: no mutex parameters\n");671 }672 }673 674 Alternative newFunc( func );675 // Strip reference from function676 referenceToRvalueConversion( newFunc.expr, newFunc.cost );677 678 // For all the set of arguments we have try to match it with the parameter of the current function alternative679 for ( auto & argsList : possibilities ) {680 681 try {682 // Declare data structures need for resolution683 OpenVarSet openVars;684 AssertionSet resultNeed, resultHave;685 TypeEnvironment resultEnv( func.env );686 makeUnifiableVars( function, openVars, resultNeed );687 // add all type variables as open variables now so that those not used in the parameter688 // list are still considered open.689 resultEnv.add( function->forall );690 691 // Load type variables from arguemnts into one shared space692 simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );693 694 // Make sure we don't widen any existing bindings695 resultEnv.forbidWidening();696 697 // Find any unbound type variables698 resultEnv.extractOpenVars( openVars );699 700 auto param = function->parameters.begin();701 auto param_end = function->parameters.end();702 703 int n_mutex_param = 0;704 705 // For every arguments of its set, check if it matches one of the parameter706 // The order is important707 for( auto & arg : argsList ) {708 709 // Ignore non-mutex arguments710 if( !advance_to_mutex( param, param_end ) ) {711 // We ran out of parameters but still have arguments712 // this function doesn't match713 SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));714 }715 716 n_mutex_param++;717 718 // Check if the argument matches the parameter type in the current scope719 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {720 // Type doesn't match721 stringstream ss;722 ss << "candidate function not viable: no known convertion from '";723 (*param)->get_type()->print( ss );724 ss << "' to '";725 arg.expr->get_result()->print( ss );726 ss << "' with env '";727 resultEnv.print(ss);728 ss << "'\n";729 SemanticError( function, ss.str() );730 }731 732 param++;733 }734 735 // All arguments match !736 737 // Check if parameters are missing738 if( advance_to_mutex( param, param_end ) ) {739 do {740 n_mutex_param++;741 param++;742 } while( advance_to_mutex( param, param_end ) );743 744 // We ran out of arguments but still have parameters left745 // this function doesn't match746 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));747 }748 749 // All parameters match !750 751 // Finish the expressions to tie in the proper environments752 finishExpr( newFunc.expr, resultEnv );753 for( Alternative & alt : argsList ) {754 finishExpr( alt.expr, resultEnv );755 }756 757 // This is a match store it and save it for later758 func_candidates.push_back( newFunc );759 args_candidates.push_back( argsList );760 761 }762 catch( SemanticErrorException & e ) {763 errors.append( e );764 }765 }766 }767 catch( SemanticErrorException & e ) {768 errors.append( e );769 }770 }771 772 // Make sure we got the right number of arguments773 if( func_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor" ); top.append( errors ); throw top; }774 if( args_candidates.empty() ) { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }775 if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor" ); top.append( errors ); throw top; }776 if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor" ); top.append( errors ); throw top; }777 // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.778 779 // Swap the results from the alternative with the unresolved values.780 // Alternatives will handle deletion on destruction781 std::swap( clause.target.function, func_candidates.front().expr );782 for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {783 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );784 }785 786 // Resolve the conditions as if it were an IfStmt787 // Resolve the statments normally788 findSingleExpression( clause.condition, this->indexer );789 clause.statement->accept( *visitor );790 }791 792 793 if( stmt->timeout.statement ) {794 // Resolve the timeout as an size_t for now795 // Resolve the conditions as if it were an IfStmt796 // Resolve the statments normally797 findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );798 findSingleExpression( stmt->timeout.condition, this->indexer );799 stmt->timeout.statement->accept( *visitor );800 }801 802 if( stmt->orelse.statement ) {803 // Resolve the conditions as if it were an IfStmt804 // Resolve the statments normally805 findSingleExpression( stmt->orelse.condition, this->indexer );806 stmt->orelse.statement->accept( *visitor );807 }808 }809 810 bool isCharType( Type * t ) {811 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {812 return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||813 bt->get_kind() == BasicType::UnsignedChar;814 }815 return false;816 }817 818 void Resolver_old::previsit( SingleInit * singleInit ) {819 visit_children = false;820 // resolve initialization using the possibilities as determined by the currentObject cursor821 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );822 findSingleExpression( newExpr, indexer );823 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );824 825 // move cursor to the object that is actually initialized826 currentObject.setNext( initExpr->get_designation() );827 828 // discard InitExpr wrapper and retain relevant pieces829 newExpr = initExpr->expr;830 initExpr->expr = nullptr;831 std::swap( initExpr->env, newExpr->env );832 // InitExpr may have inferParams in the case where the expression specializes a function833 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not834 // sufficient.835 newExpr->spliceInferParams( initExpr );836 delete initExpr;837 838 // get the actual object's type (may not exactly match what comes back from the resolver839 // due to conversions)840 Type * initContext = currentObject.getCurrentType();841 842 removeExtraneousCast( newExpr, indexer );843 844 // check if actual object's type is char[]845 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {846 if ( isCharType( at->get_base() ) ) {847 // check if the resolved type is char *848 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {849 if ( isCharType( pt->get_base() ) ) {850 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {851 // strip cast if we're initializing a char[] with a char *,852 // e.g. char x[] = "hello";853 newExpr = ce->get_arg();854 ce->set_arg( nullptr );855 std::swap( ce->env, newExpr->env );856 delete ce;857 }858 }859 }860 }861 }862 863 // set initializer expr to resolved express864 singleInit->value = newExpr;865 866 // move cursor to next object in preparation for next initializer867 currentObject.increment();868 }869 870 void Resolver_old::previsit( ListInit * listInit ) {871 visit_children = false;872 // move cursor into brace-enclosed initializer-list873 currentObject.enterListInit();874 // xxx - fix this so that the list isn't copied, iterator should be used to change current875 // element876 std::list<Designation *> newDesignations;877 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {878 // iterate designations and initializers in pairs, moving the cursor to the current879 // designated object and resolving the initializer against that object.880 Designation * des = std::get<0>(p);881 Initializer * init = std::get<1>(p);882 newDesignations.push_back( currentObject.findNext( des ) );883 init->accept( *visitor );884 }885 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list886 listInit->get_designations() = newDesignations; // xxx - memory management887 currentObject.exitListInit();888 889 // xxx - this part has not be folded into CurrentObject yet890 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {891 // Type * base = tt->get_baseType()->get_base();892 // if ( base ) {893 // // know the implementation type, so try using that as the initContext894 // ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );895 // currentObject = &tmpObj;896 // visit( listInit );897 // } else {898 // // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context899 // Parent::visit( listInit );900 // }901 // } else {902 }903 904 // ConstructorInit - fall back on C-style initializer905 void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {906 // could not find valid constructor, or found an intrinsic constructor907 // fall back on C-style initializer908 delete ctorInit->get_ctor();909 ctorInit->set_ctor( nullptr );910 delete ctorInit->get_dtor();911 ctorInit->set_dtor( nullptr );912 maybeAccept( ctorInit->get_init(), *visitor );913 }914 915 // needs to be callable from outside the resolver, so this is a standalone function916 void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {917 assert( ctorInit );918 PassVisitor<Resolver_old> resolver( indexer );919 ctorInit->accept( resolver );920 }921 922 void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {923 assert( stmtExpr );924 PassVisitor<Resolver_old> resolver( indexer );925 stmtExpr->accept( resolver );926 stmtExpr->computeResult();927 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?928 }929 930 void Resolver_old::previsit( ConstructorInit * ctorInit ) {931 visit_children = false;932 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit933 maybeAccept( ctorInit->ctor, *visitor );934 maybeAccept( ctorInit->dtor, *visitor );935 936 // found a constructor - can get rid of C-style initializer937 delete ctorInit->init;938 ctorInit->init = nullptr;939 940 // intrinsic single parameter constructors and destructors do nothing. Since this was941 // implicitly generated, there's no way for it to have side effects, so get rid of it942 // to clean up generated code.943 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {944 delete ctorInit->ctor;945 ctorInit->ctor = nullptr;946 }947 948 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {949 delete ctorInit->dtor;950 ctorInit->dtor = nullptr;951 }952 953 // xxx - todo -- what about arrays?954 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {955 // // can reduce the constructor down to a SingleInit using the956 // // second argument from the ctor call, since957 // delete ctorInit->get_ctor();958 // ctorInit->set_ctor( nullptr );959 960 // Expression * arg =961 // ctorInit->set_init( new SingleInit( arg ) );962 // }963 }964 965 ///////////////////////////////////////////////////////////////////////////966 //967 // *** NEW RESOLVER ***968 //969 ///////////////////////////////////////////////////////////////////////////970 61 971 62 namespace { -
src/ResolvExpr/SatisfyAssertions.cpp
r0030b508 rfc12f05 46 46 #include "SymTab/Mangler.h" 47 47 48 49 50 48 namespace ResolvExpr { 51 49 52 50 // in CandidateFinder.cpp; unique ID for assertion satisfaction 53 extern UniqueId globalResnSlot;51 extern ast::UniqueId globalResnSlot; 54 52 55 53 namespace { … … 298 296 if ( !expr->inferred.hasSlots() ) return expr; 299 297 // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 300 std::vector< UniqueId> missingSlots;298 std::vector<ast::UniqueId> missingSlots; 301 299 // find inferred parameters for resolution slots 302 300 ast::InferredParams * newInferred = new ast::InferredParams(); 303 for ( UniqueId slot : expr->inferred.resnSlots() ) {301 for ( ast::UniqueId slot : expr->inferred.resnSlots() ) { 304 302 // fail if no matching assertions found 305 303 auto it = inferred.find( slot ); -
src/ResolvExpr/SpecCost.cc
r0030b508 rfc12f05 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "Common/PassVisitor.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Expression.h"26 #include "SynTree/Type.h"27 23 28 24 namespace ResolvExpr { 29 30 /// Counts specializations in a type31 class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {32 int count = -1; ///< specialization count (-1 for none)33 34 public:35 int get_count() const { return count >= 0 ? count : 0; }36 37 // mark specialization of base type38 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }39 40 // mark specialization of base type41 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }42 43 // mark specialization of base type44 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }45 46 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }47 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }48 49 private:50 // takes minimum non-negative count over parameter/return list51 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {52 for ( DeclarationWithType* dwt : dwts ) {53 count = -1;54 maybeAccept( dwt->get_type(), *visitor );55 if ( count != -1 && count < mincount ) mincount = count;56 }57 }58 59 public:60 // take minimal specialization value over ->returnVals and ->parameters61 void previsit(FunctionType* fty) {62 int mincount = std::numeric_limits<int>::max();63 takeminover( mincount, fty->parameters );64 takeminover( mincount, fty->returnVals );65 // add another level to mincount if set66 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;67 // already visited children68 visit_children = false;69 }70 71 private:72 // returns minimum non-negative count + 1 over type parameters (-1 if none such)73 int minover( std::list<Expression*>& parms ) {74 int mincount = std::numeric_limits<int>::max();75 for ( Expression* parm : parms ) {76 count = -1;77 maybeAccept( parm->result, *visitor );78 if ( count != -1 && count < mincount ) mincount = count;79 }80 return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;81 }82 83 public:84 // look for polymorphic parameters85 void previsit(StructInstType* sty) {86 count = minover( sty->parameters );87 }88 89 // look for polymorphic parameters90 void previsit(UnionInstType* uty) {91 count = minover( uty->parameters );92 }93 94 // note polymorphic type (which may be specialized)95 // xxx - maybe account for open/closed type variables96 void postvisit(TypeInstType*) { count = 0; }97 98 // take minimal specialization over elements99 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize100 void previsit(TupleType* tty) {101 int mincount = std::numeric_limits<int>::max();102 for ( Type* ty : tty->types ) {103 count = -1;104 maybeAccept( ty, *visitor );105 if ( count != -1 && count < mincount ) mincount = count;106 }107 count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;108 visit_children = false;109 }110 };111 112 /// Returns the (negated) specialization cost for a given type113 int specCost( Type* ty ) {114 PassVisitor<CountSpecs> counter;115 maybeAccept( ty, *counter.pass.visitor );116 return counter.pass.get_count();117 }118 25 119 26 namespace { -
src/ResolvExpr/Unify.cc
r0030b508 rfc12f05 33 33 #include "AST/TypeEnvironment.hpp" 34 34 #include "Common/Eval.h" // for eval 35 #include "Common/PassVisitor.h" // for PassVisitor36 35 #include "CommonType.hpp" // for commonType 37 36 #include "FindOpenVars.h" // for findOpenVars 38 37 #include "SpecCost.hpp" // for SpecCost 39 #include "SynTree/LinkageSpec.h" // for C40 #include "SynTree/Constant.h" // for Constant41 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Declarati...42 #include "SynTree/Expression.h" // for TypeExpr, Expression, ConstantExpr43 #include "SynTree/Mutator.h" // for Mutator44 #include "SynTree/Type.h" // for Type, TypeInstType, FunctionType45 #include "SynTree/Visitor.h" // for Visitor46 38 #include "Tuples/Tuples.h" // for isTtype 47 #include "TypeEnvironment.h" // for EqvClass, AssertionSet, OpenVarSet48 39 #include "typeops.h" // for flatten, occurs 49 40 … … 52 43 } 53 44 54 namespace SymTab {55 class Indexer;56 } // namespace SymTab57 58 45 // #define DEBUG 59 46 60 47 namespace ResolvExpr { 61 62 // Template Helpers:63 template< typename Iterator1, typename Iterator2 >64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {65 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {66 Type *commonType = 0;67 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {68 return false;69 } // if70 commonTypes.push_back( commonType );71 } // for72 return ( list1Begin == list1End && list2Begin == list2End );73 }74 75 template< typename Iterator1, typename Iterator2 >76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {77 std::list< Type* > commonTypes;78 if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions, openVars, indexer, commonTypes ) ) {79 deleteAll( commonTypes );80 return true;81 } else {82 return false;83 } // if84 }85 86 struct Unify_old : public WithShortCircuiting {87 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );88 89 bool get_result() const { return result; }90 91 void previsit( BaseSyntaxNode * ) { visit_children = false; }92 93 void postvisit( VoidType * voidType );94 void postvisit( BasicType * basicType );95 void postvisit( PointerType * pointerType );96 void postvisit( ArrayType * arrayType );97 void postvisit( ReferenceType * refType );98 void postvisit( FunctionType * functionType );99 void postvisit( StructInstType * aggregateUseType );100 void postvisit( UnionInstType * aggregateUseType );101 void postvisit( EnumInstType * aggregateUseType );102 void postvisit( TraitInstType * aggregateUseType );103 void postvisit( TypeInstType * aggregateUseType );104 void postvisit( TupleType * tupleType );105 void postvisit( VarArgsType * varArgsType );106 void postvisit( ZeroType * zeroType );107 void postvisit( OneType * oneType );108 109 private:110 template< typename RefType > void handleRefType( RefType *inst, Type *other );111 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );112 113 bool result;114 Type *type2; // inherited115 TypeEnvironment &env;116 AssertionSet &needAssertions;117 AssertionSet &haveAssertions;118 const OpenVarSet &openVars;119 WidenMode widen;120 const SymTab::Indexer &indexer;121 };122 123 /// Attempts an inexact unification of type1 and type2.124 /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)125 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );126 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );127 128 bool unifyExact(129 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,130 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,131 WidenMode widen );132 133 bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {134 TypeEnvironment newEnv;135 OpenVarSet openVars, closedVars; // added closedVars136 AssertionSet needAssertions, haveAssertions;137 Type * newFirst = first->clone(), * newSecond = second->clone();138 env.apply( newFirst );139 env.apply( newSecond );140 141 // do we need to do this? Seems like we do, types should be able to be compatible if they142 // have free variables that can unify143 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );144 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );145 146 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );147 delete newFirst;148 delete newSecond;149 return result;150 }151 48 152 49 bool typesCompatible( … … 165 62 166 63 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); 167 }168 169 bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {170 TypeEnvironment newEnv;171 OpenVarSet openVars;172 AssertionSet needAssertions, haveAssertions;173 Type *newFirst = first->clone(), *newSecond = second->clone();174 env.apply( newFirst );175 env.apply( newSecond );176 newFirst->get_qualifiers() = Type::Qualifiers();177 newSecond->get_qualifiers() = Type::Qualifiers();178 179 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );180 delete newFirst;181 delete newSecond;182 return result;183 64 } 184 65 … … 218 99 subSecond, 219 100 newEnv, need, have, open, noWiden() ); 220 }221 222 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {223 OpenVarSet closedVars;224 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );225 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );226 Type *commonType = 0;227 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {228 if ( commonType ) {229 delete commonType;230 } // if231 return true;232 } else {233 return false;234 } // if235 }236 237 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {238 OpenVarSet closedVars;239 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );240 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );241 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );242 }243 244 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {245 #ifdef DEBUG246 TypeEnvironment debugEnv( env );247 #endif248 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {249 return false;250 }251 252 bool result;253 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );254 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );255 OpenVarSet::const_iterator entry1, entry2;256 if ( var1 ) {257 entry1 = openVars.find( var1->get_name() );258 } // if259 if ( var2 ) {260 entry2 = openVars.find( var2->get_name() );261 } // if262 bool isopen1 = var1 && ( entry1 != openVars.end() );263 bool isopen2 = var2 && ( entry2 != openVars.end() );264 265 if ( isopen1 && isopen2 ) {266 if ( entry1->second.kind != entry2->second.kind ) {267 result = false;268 } else {269 result = env.bindVarToVar(270 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,271 haveAssertions, openVars, widen, indexer );272 }273 } else if ( isopen1 ) {274 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );275 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?276 result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );277 } else {278 PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );279 type1->accept( comparator );280 result = comparator.pass.get_result();281 } // if282 #ifdef DEBUG283 std::cerr << "============ unifyExact" << std::endl;284 std::cerr << "type1 is ";285 type1->print( std::cerr );286 std::cerr << std::endl << "type2 is ";287 type2->print( std::cerr );288 std::cerr << std::endl << "openVars are ";289 printOpenVarSet( openVars, std::cerr, 8 );290 std::cerr << std::endl << "input env is " << std::endl;291 debugEnv.print( std::cerr, 8 );292 std::cerr << std::endl << "result env is " << std::endl;293 env.print( std::cerr, 8 );294 std::cerr << "result is " << result << std::endl;295 #endif296 return result;297 }298 299 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {300 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );301 }302 303 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {304 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();305 type1->get_qualifiers() = Type::Qualifiers();306 type2->get_qualifiers() = Type::Qualifiers();307 bool result;308 #ifdef DEBUG309 std::cerr << "unifyInexact type 1 is ";310 type1->print( std::cerr );311 std::cerr << " type 2 is ";312 type2->print( std::cerr );313 std::cerr << std::endl;314 #endif315 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {316 #ifdef DEBUG317 std::cerr << "unifyInexact: no exact unification found" << std::endl;318 #endif319 if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {320 common->tq = tq1.unify( tq2 );321 #ifdef DEBUG322 std::cerr << "unifyInexact: common type is ";323 common->print( std::cerr );324 std::cerr << std::endl;325 #endif326 result = true;327 } else {328 #ifdef DEBUG329 std::cerr << "unifyInexact: no common type found" << std::endl;330 #endif331 result = false;332 } // if333 } else {334 if ( tq1 != tq2 ) {335 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {336 common = type1->clone();337 common->tq = tq1.unify( tq2 );338 result = true;339 } else {340 result = false;341 } // if342 } else {343 common = type1->clone();344 common->tq = tq1.unify( tq2 );345 result = true;346 } // if347 } // if348 type1->get_qualifiers() = tq1;349 type2->get_qualifiers() = tq2;350 return result;351 }352 353 Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )354 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {355 }356 357 void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {358 result = dynamic_cast< VoidType* >( type2 );359 }360 361 void Unify_old::postvisit(BasicType *basicType) {362 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {363 result = basicType->get_kind() == otherBasic->get_kind();364 } // if365 }366 367 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {368 AssertionSet::iterator i = assertions.find( assert );369 if ( i != assertions.end() ) {370 i->second.isUsed = true;371 } // if372 }373 374 void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {375 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {376 for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {377 markAssertionSet( assertion1, *assert );378 markAssertionSet( assertion2, *assert );379 } // for380 } // for381 }382 383 void Unify_old::postvisit(PointerType *pointerType) {384 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {385 result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );386 markAssertions( haveAssertions, needAssertions, pointerType );387 markAssertions( haveAssertions, needAssertions, otherPointer );388 } // if389 }390 391 void Unify_old::postvisit(ReferenceType *refType) {392 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {393 result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );394 markAssertions( haveAssertions, needAssertions, refType );395 markAssertions( haveAssertions, needAssertions, otherRef );396 } // if397 }398 399 void Unify_old::postvisit(ArrayType *arrayType) {400 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );401 // to unify, array types must both be VLA or both not VLA402 // and must both have a dimension expression or not have a dimension403 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {404 405 if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&406 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {407 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );408 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );409 // see C11 Reference Manual 6.7.6.2.6410 // two array types with size specifiers that are integer constant expressions are411 // compatible if both size specifiers have the same constant value412 if ( ce1 && ce2 ) {413 Constant * c1 = ce1->get_constant();414 Constant * c2 = ce2->get_constant();415 416 if ( c1->get_value() != c2->get_value() ) {417 // does not unify if the dimension is different418 return;419 }420 }421 }422 423 result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );424 } // if425 }426 427 template< typename Iterator, typename Func >428 std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {429 std::list< Type * > types;430 for ( ; begin != end; ++begin ) {431 // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple432 flatten( toType( *begin ), back_inserter( types ) );433 }434 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );435 }436 437 template< typename Iterator1, typename Iterator2 >438 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {439 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };440 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {441 Type * t1 = (*list1Begin)->get_type();442 Type * t2 = (*list2Begin)->get_type();443 bool isTtype1 = Tuples::isTtype( t1 );444 bool isTtype2 = Tuples::isTtype( t2 );445 // xxx - assumes ttype must be last parameter446 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.447 if ( isTtype1 && ! isTtype2 ) {448 // combine all of the things in list2, then unify449 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );450 } else if ( isTtype2 && ! isTtype1 ) {451 // combine all of the things in list1, then unify452 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );453 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {454 return false;455 } // if456 } // for457 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype458 if ( list1Begin != list1End ) {459 // try unifying empty tuple type with ttype460 Type * t1 = (*list1Begin)->get_type();461 if ( Tuples::isTtype( t1 ) ) {462 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );463 } else return false;464 } else if ( list2Begin != list2End ) {465 // try unifying empty tuple type with ttype466 Type * t2 = (*list2Begin)->get_type();467 if ( Tuples::isTtype( t2 ) ) {468 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );469 } else return false;470 } else {471 return true;472 } // if473 }474 475 /// Finds ttypes and replaces them with their expansion, if known.476 /// This needs to be done so that satisfying ttype assertions is easier.477 /// If this isn't done then argument lists can have wildly different478 /// size and structure, when they should be compatible.479 struct TtypeExpander_old : public WithShortCircuiting {480 TypeEnvironment & tenv;481 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}482 void premutate( TypeInstType * ) { visit_children = false; }483 Type * postmutate( TypeInstType * typeInst ) {484 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {485 // expand ttype parameter into its actual type486 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {487 delete typeInst;488 return eqvClass->type->clone();489 }490 }491 return typeInst;492 }493 };494 495 /// flattens a list of declarations, so that each tuple type has a single declaration.496 /// makes use of TtypeExpander to ensure ttypes are flat as well.497 void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {498 dst.clear();499 for ( DeclarationWithType * dcl : src ) {500 PassVisitor<TtypeExpander_old> expander( env );501 dcl->acceptMutator( expander );502 std::list< Type * > types;503 flatten( dcl->get_type(), back_inserter( types ) );504 for ( Type * t : types ) {505 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.506 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.507 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);508 509 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );510 }511 delete dcl;512 }513 }514 515 void Unify_old::postvisit(FunctionType *functionType) {516 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );517 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {518 // flatten the parameter lists for both functions so that tuple structure519 // doesn't affect unification. Must be a clone so that the types don't change.520 std::unique_ptr<FunctionType> flatFunc( functionType->clone() );521 std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );522 flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );523 flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );524 525 // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors526 if (527 (flatFunc->parameters.size() == flatOther->parameters.size() &&528 flatFunc->returnVals.size() == flatOther->returnVals.size())529 || flatFunc->isTtype()530 || flatOther->isTtype()531 ) {532 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {533 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {534 535 // the original types must be used in mark assertions, since pointer comparisons are used536 markAssertions( haveAssertions, needAssertions, functionType );537 markAssertions( haveAssertions, needAssertions, otherFunction );538 539 result = true;540 } // if541 } // if542 } // if543 } // if544 }545 546 template< typename RefType >547 void Unify_old::handleRefType( RefType *inst, Type *other ) {548 // check that other type is compatible and named the same549 RefType *otherStruct = dynamic_cast< RefType* >( other );550 result = otherStruct && inst->name == otherStruct->name;551 }552 553 template< typename RefType >554 void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {555 // Check that other type is compatible and named the same556 handleRefType( inst, other );557 if ( ! result ) return;558 // Check that parameters of types unify, if any559 std::list< Expression* > params = inst->parameters;560 std::list< Expression* > otherParams = ((RefType*)other)->parameters;561 562 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();563 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {564 TypeExpr *param = dynamic_cast< TypeExpr* >(*it);565 assertf(param, "Aggregate parameters should be type expressions");566 TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);567 assertf(otherParam, "Aggregate parameters should be type expressions");568 569 Type* paramTy = param->get_type();570 Type* otherParamTy = otherParam->get_type();571 572 bool tupleParam = Tuples::isTtype( paramTy );573 bool otherTupleParam = Tuples::isTtype( otherParamTy );574 575 if ( tupleParam && otherTupleParam ) {576 ++it; ++jt; // skip ttype parameters for break577 } else if ( tupleParam ) {578 // bundle other parameters into tuple to match579 std::list< Type * > binderTypes;580 581 do {582 binderTypes.push_back( otherParam->get_type()->clone() );583 ++jt;584 585 if ( jt == otherParams.end() ) break;586 587 otherParam = dynamic_cast< TypeExpr* >(*jt);588 assertf(otherParam, "Aggregate parameters should be type expressions");589 } while (true);590 591 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };592 ++it; // skip ttype parameter for break593 } else if ( otherTupleParam ) {594 // bundle parameters into tuple to match other595 std::list< Type * > binderTypes;596 597 do {598 binderTypes.push_back( param->get_type()->clone() );599 ++it;600 601 if ( it == params.end() ) break;602 603 param = dynamic_cast< TypeExpr* >(*it);604 assertf(param, "Aggregate parameters should be type expressions");605 } while (true);606 607 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };608 ++jt; // skip ttype parameter for break609 }610 611 if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {612 result = false;613 return;614 }615 616 // ttype parameter should be last617 if ( tupleParam || otherTupleParam ) break;618 }619 result = ( it == params.end() && jt == otherParams.end() );620 }621 622 void Unify_old::postvisit(StructInstType *structInst) {623 handleGenericRefType( structInst, type2 );624 }625 626 void Unify_old::postvisit(UnionInstType *unionInst) {627 handleGenericRefType( unionInst, type2 );628 }629 630 void Unify_old::postvisit(EnumInstType *enumInst) {631 handleRefType( enumInst, type2 );632 }633 634 void Unify_old::postvisit(TraitInstType *contextInst) {635 handleRefType( contextInst, type2 );636 }637 638 void Unify_old::postvisit(TypeInstType *typeInst) {639 assert( openVars.find( typeInst->get_name() ) == openVars.end() );640 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );641 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {642 result = true;643 /// } else {644 /// NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );645 /// if ( nt ) {646 /// TypeDecl *type = dynamic_cast< TypeDecl* >( nt );647 /// assert( type );648 /// if ( type->get_base() ) {649 /// result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );650 /// }651 /// }652 } // if653 }654 655 template< typename Iterator1, typename Iterator2 >656 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {657 auto get_type = [](Type * t) { return t; };658 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {659 Type * t1 = *list1Begin;660 Type * t2 = *list2Begin;661 bool isTtype1 = Tuples::isTtype( t1 );662 bool isTtype2 = Tuples::isTtype( t2 );663 // xxx - assumes ttype must be last parameter664 // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.665 if ( isTtype1 && ! isTtype2 ) {666 // combine all of the things in list2, then unify667 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );668 } else if ( isTtype2 && ! isTtype1 ) {669 // combine all of the things in list1, then unify670 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );671 } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {672 return false;673 } // if674 675 } // for676 if ( list1Begin != list1End ) {677 // try unifying empty tuple type with ttype678 Type * t1 = *list1Begin;679 if ( Tuples::isTtype( t1 ) ) {680 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );681 } else return false;682 } else if ( list2Begin != list2End ) {683 // try unifying empty tuple type with ttype684 Type * t2 = *list2Begin;685 if ( Tuples::isTtype( t2 ) ) {686 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );687 } else return false;688 } else {689 return true;690 } // if691 }692 693 void Unify_old::postvisit(TupleType *tupleType) {694 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {695 std::unique_ptr<TupleType> flat1( tupleType->clone() );696 std::unique_ptr<TupleType> flat2( otherTuple->clone() );697 std::list<Type *> types1, types2;698 699 PassVisitor<TtypeExpander_old> expander( env );700 flat1->acceptMutator( expander );701 flat2->acceptMutator( expander );702 703 flatten( flat1.get(), back_inserter( types1 ) );704 flatten( flat2.get(), back_inserter( types2 ) );705 706 result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );707 } // if708 }709 710 void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {711 result = dynamic_cast< VarArgsType* >( type2 );712 }713 714 void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {715 result = dynamic_cast< ZeroType* >( type2 );716 }717 718 void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {719 result = dynamic_cast< OneType* >( type2 );720 }721 722 Type * extractResultType( FunctionType * function ) {723 if ( function->get_returnVals().size() == 0 ) {724 return new VoidType( Type::Qualifiers() );725 } else if ( function->get_returnVals().size() == 1 ) {726 return function->get_returnVals().front()->get_type()->clone();727 } else {728 std::list< Type * > types;729 for ( DeclarationWithType * decl : function->get_returnVals() ) {730 types.push_back( decl->get_type()->clone() );731 } // for732 return new TupleType( Type::Qualifiers(), types );733 }734 101 } 735 102 -
src/ResolvExpr/Unify.h
r0030b508 rfc12f05 20 20 #include "AST/Node.hpp" // for ptr 21 21 #include "AST/TypeEnvironment.hpp" // for TypeEnvironment, AssertionSet, OpenVarSet 22 #include "Common/utility.h" // for deleteAll23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data24 #include "TypeEnvironment.h" // for AssertionSet, OpenVarSet25 22 #include "WidenMode.h" // for WidenMode 26 27 class Type;28 class TypeInstType;29 namespace SymTab {30 class Indexer;31 }32 23 33 24 namespace ast { … … 37 28 38 29 namespace ResolvExpr { 39 40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );44 45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );47 48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {49 TypeEnvironment env;50 return typesCompatible( t1, t2, indexer, env );51 }52 53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {54 TypeEnvironment env;55 return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );56 }57 30 58 31 bool unify( … … 85 58 const ast::TypeEnvironment & env = {} ); 86 59 87 /// Creates the type represented by the list of returnVals in a FunctionType.88 /// The caller owns the return value.89 Type * extractResultType( FunctionType * functionType );90 60 /// Creates or extracts the type represented by returns in a `FunctionType`. 91 61 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ); -
src/ResolvExpr/module.mk
r0030b508 rfc12f05 18 18 ResolvExpr/AdjustExprType.cc \ 19 19 ResolvExpr/AdjustExprType.hpp \ 20 ResolvExpr/Alternative.cc \21 ResolvExpr/AlternativeFinder.cc \22 ResolvExpr/AlternativeFinder.h \23 ResolvExpr/Alternative.h \24 20 ResolvExpr/Candidate.cpp \ 25 21 ResolvExpr/CandidateFinder.cpp \ … … 35 31 ResolvExpr/CurrentObject.cc \ 36 32 ResolvExpr/CurrentObject.h \ 37 ResolvExpr/ExplodedActual.cc \38 ResolvExpr/ExplodedActual.h \39 33 ResolvExpr/ExplodedArg.cpp \ 40 34 ResolvExpr/ExplodedArg.hpp \ 41 35 ResolvExpr/FindOpenVars.cc \ 42 36 ResolvExpr/FindOpenVars.h \ 43 ResolvExpr/Occurs.cc \44 37 ResolvExpr/PolyCost.cc \ 45 38 ResolvExpr/PolyCost.hpp \ … … 50 43 ResolvExpr/RenameVars.cc \ 51 44 ResolvExpr/RenameVars.h \ 52 ResolvExpr/ResolveAssertions.cc \53 ResolvExpr/ResolveAssertions.h \54 45 ResolvExpr/Resolver.cc \ 55 46 ResolvExpr/Resolver.h \ … … 61 52 ResolvExpr/SpecCost.cc \ 62 53 ResolvExpr/SpecCost.hpp \ 63 ResolvExpr/TypeEnvironment.cc \64 ResolvExpr/TypeEnvironment.h \65 54 ResolvExpr/typeops.h \ 66 55 ResolvExpr/Unify.cc \ … … 69 58 70 59 SRC += $(SRC_RESOLVEXPR) \ 71 ResolvExpr/AlternativePrinter.cc \72 ResolvExpr/AlternativePrinter.h \73 60 ResolvExpr/CandidatePrinter.cpp \ 74 61 ResolvExpr/CandidatePrinter.hpp \ -
src/ResolvExpr/typeops.h
r0030b508 rfc12f05 19 19 20 20 #include "AST/Type.hpp" 21 #include "SynTree/Type.h"22 21 23 22 namespace SymTab { … … 52 51 std::copy( i.begin(), i.end(), inserter ); 53 52 *out++ = result; 54 }55 }56 57 // in Occurs.cc58 bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );59 // new AST version in TypeEnvironment.cpp (only place it was used in old AST)60 61 template<typename Iter>62 bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {63 while ( begin != end ) {64 if ( occurs( ty, *begin, env ) ) return true;65 ++begin;66 }67 return false;68 }69 70 /// flatten tuple type into list of types71 template< typename OutputIterator >72 void flatten( Type * type, OutputIterator out ) {73 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {74 for ( Type * t : tupleType->get_types() ) {75 flatten( t, out );76 }77 } else {78 *out++ = type->clone();79 53 } 80 54 } … … 120 94 return tupleFromTypes( tys.begin(), tys.end() ); 121 95 } 122 123 // in TypeEnvironment.cc124 bool isFtype( const Type * type );125 96 } // namespace ResolvExpr 126 97 -
src/SymTab/Demangle.cc
r0030b508 rfc12f05 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Jul 19 12:52:41 2018 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 11 21:28:27 202113 // Update Count : 1 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 6 15:59:00 2023 13 // Update Count : 12 14 14 // 15 15 … … 17 17 #include <sstream> 18 18 19 #include "AST/Pass.hpp" 20 #include "AST/Type.hpp" 19 21 #include "CodeGen/GenType.h" 20 #include "Co mmon/PassVisitor.h"22 #include "CodeGen/OperatorTable.h" 21 23 #include "Common/utility.h" // isPrefix 22 24 #include "Mangler.h" 23 #include "SynTree/Type.h"24 #include "SynTree/Declaration.h"25 25 26 26 #define DEBUG … … 31 31 #endif 32 32 33 namespace Mangle { 34 33 35 namespace { 34 struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting { 35 std::string typeString; 36 GenType( const std::string &typeString ); 37 38 void previsit( BaseSyntaxNode * ); 39 void postvisit( BaseSyntaxNode * ); 40 41 void postvisit( FunctionType * funcType ); 42 void postvisit( VoidType * voidType ); 43 void postvisit( BasicType * basicType ); 44 void postvisit( PointerType * pointerType ); 45 void postvisit( ArrayType * arrayType ); 46 void postvisit( ReferenceType * refType ); 47 void postvisit( StructInstType * structInst ); 48 void postvisit( UnionInstType * unionInst ); 49 void postvisit( EnumInstType * enumInst ); 50 void postvisit( TypeInstType * typeInst ); 51 void postvisit( TupleType * tupleType ); 52 void postvisit( VarArgsType * varArgsType ); 53 void postvisit( ZeroType * zeroType ); 54 void postvisit( OneType * oneType ); 55 void postvisit( GlobalScopeType * globalType ); 56 void postvisit( QualifiedType * qualType ); 57 58 private: 59 void handleQualifiers( Type *type ); 60 std::string handleGeneric( ReferenceToType * refType ); 61 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ); 62 }; 63 64 std::string genDemangleType( Type * type, const std::string & baseString ) { 65 PassVisitor<GenType> gt( baseString ); 66 assert( type ); 67 type->accept( gt ); 68 return gt.pass.typeString; 69 } 70 71 GenType::GenType( const std::string &typeString ) : typeString( typeString ) {} 72 73 // *** BaseSyntaxNode 74 void GenType::previsit( BaseSyntaxNode * ) { 75 // turn off automatic recursion for all nodes, to allow each visitor to 76 // precisely control the order in which its children are visited. 77 visit_children = false; 78 } 79 80 void GenType::postvisit( BaseSyntaxNode * node ) { 81 std::stringstream ss; 82 node->print( ss ); 83 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() ); 84 } 85 86 void GenType::postvisit( VoidType * voidType ) { 87 typeString = "void " + typeString; 88 handleQualifiers( voidType ); 89 } 90 91 void GenType::postvisit( BasicType * basicType ) { 92 BasicType::Kind kind = basicType->kind; 93 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES ); 94 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString; 95 handleQualifiers( basicType ); 96 } 97 98 void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) { 99 std::ostringstream os; 100 if ( typeString != "" ) { 101 if ( typeString[ 0 ] == '*' ) { 102 os << "(" << typeString << ")"; 103 } else { 104 os << typeString; 105 } // if 106 } // if 107 os << "["; 108 109 if ( qualifiers.is_const ) { 110 os << "const "; 111 } // if 112 if ( qualifiers.is_volatile ) { 113 os << "volatile "; 114 } // if 115 if ( qualifiers.is_restrict ) { 116 os << "__restrict "; 117 } // if 118 if ( qualifiers.is_atomic ) { 119 os << "_Atomic "; 120 } // if 121 if ( dimension != 0 ) { 122 // TODO: ??? 123 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 124 // dimension->accept( cg ); 125 } else if ( isVarLen ) { 126 // no dimension expression on a VLA means it came in with the * token 127 os << "*"; 128 } // if 129 os << "]"; 130 131 typeString = os.str(); 132 133 base->accept( *visitor ); 134 } 135 136 void GenType::postvisit( PointerType * pointerType ) { 137 assert( pointerType->base != 0); 138 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) { 139 assert(false); 140 genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() ); 141 } else { 142 handleQualifiers( pointerType ); 143 if ( typeString[ 0 ] == '?' ) { 144 typeString = "* " + typeString; 145 } else { 146 typeString = "*" + typeString; 147 } // if 148 pointerType->base->accept( *visitor ); 149 } // if 150 } 151 152 void GenType::postvisit( ArrayType * arrayType ) { 153 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() ); 154 } 155 156 void GenType::postvisit( ReferenceType * refType ) { 157 assert( false ); 158 assert( refType->base != 0); 159 handleQualifiers( refType ); 160 typeString = "&" + typeString; 161 refType->base->accept( *visitor ); 162 } 163 164 void GenType::postvisit( FunctionType * funcType ) { 165 std::ostringstream os; 166 167 if ( typeString != "" ) { 168 if ( typeString[0] == '*' ) { 169 os << "(" << typeString << ")"; 170 } else { 171 os << typeString; 172 } // if 173 } // if 174 175 /************* parameters ***************/ 176 const std::list<DeclarationWithType *> &pars = funcType->parameters; 177 178 if ( pars.empty() ) { 179 if ( funcType->get_isVarArgs() ) { 180 os << "()"; 181 } else { 182 os << "(void)"; 183 } // if 184 } else { 185 os << "(" ; 186 187 unsigned int i = 0; 188 for (DeclarationWithType * p : pars) { 189 os << genDemangleType( p->get_type(), "" ); 190 if (++i != pars.size()) os << ", "; 191 } 192 193 if ( funcType->get_isVarArgs() ) { 194 os << ", ..."; 195 } // if 196 os << ")"; 197 } // if 198 199 typeString = os.str(); 200 201 if ( funcType->returnVals.size() == 0 ) { 202 typeString += ": void"; 203 } else { 204 typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), ""); 205 } // if 206 207 // add forall 208 if( ! funcType->forall.empty() ) { 209 std::ostringstream os; 210 os << "forall("; 211 unsigned int i = 0; 212 for ( auto td : funcType->forall ) { 213 os << td->typeString() << " " << td->name; 214 if (! td->assertions.empty()) { 215 os << " | { "; 216 unsigned int j = 0; 217 for (DeclarationWithType * assert : td->assertions) { 218 os << genDemangleType(assert->get_type(), assert->name); 219 if (++j != td->assertions.size()) os << ", "; 220 } 221 os << "}"; 222 } 223 if (++i != funcType->forall.size()) os << ", "; 224 } 225 os << ")"; 226 typeString = typeString + " -> " + os.str(); 36 37 struct Demangler { 38 private: 39 std::string str; 40 size_t index = 0; 41 using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>; 42 std::vector<std::pair<std::string, Parser>> parsers; 43 public: 44 Demangler( const std::string & str ); 45 46 bool done() const { return str.size() <= index; } 47 char cur() const { assert( !done() ); return str[index]; } 48 bool expect( char ch ) { return str[index++] == ch; } 49 50 bool isPrefix( const std::string & pref ); 51 bool extractNumber( size_t & out ); 52 bool extractName( std::string & out ); 53 bool stripMangleName( std::string & name ); 54 55 ast::Type * parseFunction( ast::CV::Qualifiers tq ); 56 ast::Type * parseTuple( ast::CV::Qualifiers tq ); 57 ast::Type * parsePointer( ast::CV::Qualifiers tq ); 58 ast::Type * parseArray( ast::CV::Qualifiers tq ); 59 ast::Type * parseStruct( ast::CV::Qualifiers tq ); 60 ast::Type * parseUnion( ast::CV::Qualifiers tq ); 61 ast::Type * parseEnum( ast::CV::Qualifiers tq ); 62 ast::Type * parseType( ast::CV::Qualifiers tq ); 63 ast::Type * parseZero( ast::CV::Qualifiers tq ); 64 ast::Type * parseOne( ast::CV::Qualifiers tq ); 65 66 ast::Type * parseType(); 67 bool parse( std::string & name, ast::Type *& type ); 68 }; 69 70 Demangler::Demangler(const std::string & str) : str(str) { 71 for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 72 parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) { 73 PRINT( std::cerr << "basic type: " << k << std::endl; ) 74 return new ast::BasicType( (ast::BasicType::Kind)k, tq ); 75 }); 76 } 77 78 for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) { 79 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 80 static_assert( 81 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS, 82 "Each type variable kind should have a demangle name prefix" 83 ); 84 parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * { 85 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 86 size_t N; 87 if (!extractNumber(N)) return nullptr; 88 return new ast::TypeInstType( 89 toString(typeVariableNames[k], N), 90 (ast::TypeDecl::Kind)k, 91 tq ); 92 }); 93 } 94 95 parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); }); 96 parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); }); 97 parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); }); 98 parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); }); 99 parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); }); 100 parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); }); 101 parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); }); 102 parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); }); 103 parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); }); 104 parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); }); 105 parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); }); 106 } 107 108 bool Demangler::extractNumber( size_t & out ) { 109 std::stringstream numss; 110 if ( str.size() <= index ) return false; 111 while ( isdigit( str[index] ) ) { 112 numss << str[index]; 113 ++index; 114 if ( str.size() == index ) break; 115 } 116 if ( !(numss >> out) ) return false; 117 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 118 return true; 119 } 120 121 bool Demangler::extractName( std::string & out ) { 122 size_t len; 123 if ( !extractNumber(len) ) return false; 124 if ( str.size() < index + len ) return false; 125 out = str.substr( index, len ); 126 index += len; 127 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 128 return true; 129 } 130 131 bool Demangler::isPrefix( const std::string & pref ) { 132 // Wraps the utility isPrefix function. 133 if ( ::isPrefix( str, pref, index ) ) { 134 index += pref.size(); 135 return true; 136 } 137 return false; 138 } 139 140 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 141 bool Demangler::stripMangleName( std::string & name ) { 142 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 143 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 144 if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false; 145 146 if (!extractName(name)) return false; 147 148 // Find bounds for type. 149 PRINT( std::cerr << index << " " << str.size() << std::endl; ) 150 PRINT( std::cerr << "["); 151 while (isdigit(str.back())) { 152 PRINT(std::cerr << "."); 153 str.pop_back(); 154 if (str.size() <= index) return false; 155 } 156 PRINT( std::cerr << "]" << std::endl ); 157 if (str.back() != '_') return false; 158 str.pop_back(); 159 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; ) 160 return index < str.size(); 161 } 162 163 ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) { 164 PRINT( std::cerr << "function..." << std::endl; ) 165 if ( done() ) return nullptr; 166 ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq ); 167 std::unique_ptr<ast::Type> manager( ftype ); 168 ast::Type * retVal = parseType(); 169 if ( !retVal ) return nullptr; 170 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 171 ftype->returns.emplace_back( retVal ); 172 if ( done() || !expect('_') ) return nullptr; 173 while ( !done() ) { 174 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 175 if ( cur() == '_' ) return manager.release(); 176 ast::Type * param = parseType(); 177 if ( !param ) return nullptr; 178 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 179 ftype->params.emplace_back( param ); 180 } 181 return nullptr; 182 } 183 184 ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) { 185 PRINT( std::cerr << "tuple..." << std::endl; ) 186 std::vector<ast::ptr<ast::Type>> types; 187 size_t ncomponents; 188 if ( !extractNumber(ncomponents) ) return nullptr; 189 for ( size_t i = 0; i < ncomponents; ++i ) { 190 if ( done() ) return nullptr; 191 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 192 ast::Type * t = parseType(); 193 if ( !t ) return nullptr; 194 PRINT( std::cerr << "with type : " << t << std::endl; ) 195 types.push_back( t ); 196 } 197 return new ast::TupleType( std::move( types ), tq ); 198 } 199 200 ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) { 201 PRINT( std::cerr << "pointer..." << std::endl; ) 202 ast::Type * t = parseType(); 203 if ( !t ) return nullptr; 204 return new ast::PointerType( t, tq ); 205 } 206 207 ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) { 208 PRINT( std::cerr << "array..." << std::endl; ) 209 size_t length; 210 if ( !extractNumber(length) ) return nullptr; 211 ast::Type * t = parseType(); 212 if ( !t ) return nullptr; 213 return new ast::ArrayType( 214 t, 215 ast::ConstantExpr::from_ulong( CodeLocation(), length ), 216 ast::FixedLen, 217 ast::DynamicDim, 218 tq ); 219 } 220 221 ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) { 222 PRINT( std::cerr << "struct..." << std::endl; ) 223 std::string name; 224 if ( !extractName(name) ) return nullptr; 225 return new ast::StructInstType( name, tq ); 226 } 227 228 ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) { 229 PRINT( std::cerr << "union..." << std::endl; ) 230 std::string name; 231 if ( !extractName(name) ) return nullptr; 232 return new ast::UnionInstType( name, tq ); 233 } 234 235 ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) { 236 PRINT( std::cerr << "enum..." << std::endl; ) 237 std::string name; 238 if ( !extractName(name) ) return nullptr; 239 return new ast::EnumInstType( name, tq ); 240 } 241 242 ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) { 243 PRINT( std::cerr << "type..." << std::endl; ) 244 std::string name; 245 if ( !extractName(name) ) return nullptr; 246 PRINT( std::cerr << "typename..." << name << std::endl; ) 247 return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq ); 248 } 249 250 ast::Type * Demangler::parseType() { 251 if (done()) return nullptr; 252 253 if (isPrefix(Encoding::forall)) { 254 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 255 size_t dcount, fcount, vcount, acount; 256 if ( !extractNumber(dcount) ) return nullptr; 257 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 258 if ( !expect('_') ) return nullptr; 259 if ( !extractNumber(fcount) ) return nullptr; 260 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 261 if ( !expect('_')) return nullptr; 262 if ( !extractNumber(vcount)) return nullptr; 263 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 264 if ( !expect('_') ) return nullptr; 265 if ( !extractNumber(acount) ) return nullptr; 266 PRINT( std::cerr << acount << " assertions" << std::endl; ) 267 if ( !expect('_') ) return nullptr; 268 for ( size_t i = 0 ; i < acount ; ++i ) { 269 // TODO: need to recursively parse assertions, but for now just return nullptr so that 270 // demangler does not crash if there are assertions 271 return nullptr; 227 272 } 228 } 229 230 std::string GenType::handleGeneric( ReferenceToType * refType ) { 231 if ( ! refType->parameters.empty() ) { 232 std::ostringstream os; 233 // TODO: ??? 234 // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks ); 235 os << "("; 236 // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() ); 237 os << ") "; 238 return os.str(); 239 } 240 return ""; 241 } 242 243 void GenType::postvisit( StructInstType * structInst ) { 244 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString; 245 handleQualifiers( structInst ); 246 } 247 248 void GenType::postvisit( UnionInstType * unionInst ) { 249 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString; 250 handleQualifiers( unionInst ); 251 } 252 253 void GenType::postvisit( EnumInstType * enumInst ) { 254 typeString = "enum " + enumInst->name + " " + typeString; 255 handleQualifiers( enumInst ); 256 } 257 258 void GenType::postvisit( TypeInstType * typeInst ) { 259 typeString = typeInst->name + " " + typeString; 260 handleQualifiers( typeInst ); 261 } 262 263 void GenType::postvisit( TupleType * tupleType ) { 264 unsigned int i = 0; 265 std::ostringstream os; 266 os << "["; 267 for ( Type * t : *tupleType ) { 268 i++; 269 os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", "); 270 } 271 os << "] "; 272 typeString = os.str() + typeString; 273 } 274 275 void GenType::postvisit( VarArgsType * varArgsType ) { 276 typeString = "__builtin_va_list " + typeString; 277 handleQualifiers( varArgsType ); 278 } 279 280 void GenType::postvisit( ZeroType * zeroType ) { 281 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 282 typeString = "zero_t " + typeString; 283 handleQualifiers( zeroType ); 284 } 285 286 void GenType::postvisit( OneType * oneType ) { 287 // ideally these wouldn't hit codegen at all, but should be safe to make them ints 288 typeString = "one_t " + typeString; 289 handleQualifiers( oneType ); 290 } 291 292 void GenType::postvisit( GlobalScopeType * globalType ) { 293 handleQualifiers( globalType ); 294 } 295 296 void GenType::postvisit( QualifiedType * qualType ) { 297 std::ostringstream os; 298 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString; 299 typeString = os.str(); 300 handleQualifiers( qualType ); 301 } 302 303 void GenType::handleQualifiers( Type * type ) { 304 if ( type->get_const() ) { 305 typeString = "const " + typeString; 306 } // if 307 if ( type->get_volatile() ) { 308 typeString = "volatile " + typeString; 309 } // if 310 if ( type->get_restrict() ) { 311 typeString = "__restrict " + typeString; 312 } // if 313 if ( type->get_atomic() ) { 314 typeString = "_Atomic " + typeString; 315 } // if 316 } 317 } 318 319 320 namespace SymTab { 321 namespace Mangler { 322 namespace { 323 struct StringView { 324 private: 325 std::string str; 326 size_t idx = 0; 327 // typedef Type * (StringView::*parser)(Type::Qualifiers); 328 typedef std::function<Type * (Type::Qualifiers)> parser; 329 std::vector<std::pair<std::string, parser>> parsers; 330 public: 331 StringView(const std::string & str); 332 333 bool done() const { return idx >= str.size(); } 334 char cur() const { assert(! done()); return str[idx]; } 335 336 bool expect(char ch) { return str[idx++] == ch; } 337 void next(size_t inc = 1) { idx += inc; } 338 339 /// determines if `pref` is a prefix of `str` 340 bool isPrefix(const std::string & pref); 341 bool extractNumber(size_t & out); 342 bool extractName(std::string & out); 343 bool stripMangleName(std::string & name); 344 345 Type * parseFunction(Type::Qualifiers tq); 346 Type * parseTuple(Type::Qualifiers tq); 347 Type * parseVoid(Type::Qualifiers tq); 348 Type * parsePointer(Type::Qualifiers tq); 349 Type * parseArray(Type::Qualifiers tq); 350 Type * parseStruct(Type::Qualifiers tq); 351 Type * parseUnion(Type::Qualifiers tq); 352 Type * parseEnum(Type::Qualifiers tq); 353 Type * parseType(Type::Qualifiers tq); 354 355 Type * parseType(); 356 bool parse(std::string & name, Type *& type); 357 }; 358 359 StringView::StringView(const std::string & str) : str(str) { 360 // basic types 361 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) { 362 parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) { 363 PRINT( std::cerr << "basic type: " << k << std::endl; ) 364 return new BasicType(tq, (BasicType::Kind)k); 365 }); 366 } 367 // type variable types 368 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) { 369 static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", }; 370 static_assert( 371 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS, 372 "Each type variable kind should have a demangle name prefix" 373 ); 374 parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * { 375 PRINT( std::cerr << "type variable type: " << k << std::endl; ) 376 size_t N; 377 if (! extractNumber(N)) return nullptr; 378 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype); 379 }); 380 } 381 // everything else 382 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); }); 383 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); }); 384 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); }); 385 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); }); 386 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); }); 387 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); }); 388 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); }); 389 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); }); 390 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); }); 391 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); }); 392 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); }); 393 } 394 395 bool StringView::extractNumber(size_t & out) { 396 std::stringstream numss; 397 if (idx >= str.size()) return false; 398 while (isdigit(str[idx])) { 399 numss << str[idx]; 400 ++idx; 401 if (idx == str.size()) break; 402 } 403 if (! (numss >> out)) return false; 404 PRINT( std::cerr << "extractNumber success: " << out << std::endl; ) 405 return true; 406 } 407 408 bool StringView::extractName(std::string & out) { 409 size_t len; 410 if (! extractNumber(len)) return false; 411 if (idx+len > str.size()) return false; 412 out = str.substr(idx, len); 413 idx += len; 414 PRINT( std::cerr << "extractName success: " << out << std::endl; ) 415 return true; 416 } 417 418 bool StringView::isPrefix(const std::string & pref) { 419 // if ( pref.size() > str.size()-idx ) return false; 420 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) ); 421 // if (its.first == pref.end()) { 422 // idx += pref.size(); 423 // return true; 424 // } 425 426 // This update is untested because there are no tests for this code. 427 if ( ::isPrefix( str, pref, idx ) ) { 428 idx += pref.size(); 429 return true; 430 } 431 return false; 432 } 433 434 // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise 435 bool StringView::stripMangleName(std::string & name) { 436 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 437 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 438 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false; 439 440 // get name 441 if (! extractName(name)) return false; 442 443 // find bounds for type 444 PRINT( std::cerr << idx << " " << str.size() << std::endl; ) 445 PRINT( std::cerr << "["); 446 while (isdigit(str.back())) { 447 PRINT(std::cerr << "."); 448 str.pop_back(); 449 if (str.size() <= idx) return false; 450 } 451 PRINT( std::cerr << "]" << std::endl ); 452 if (str.back() != '_') return false; 453 str.pop_back(); 454 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; ) 455 return str.size() > idx; 456 } 457 458 Type * StringView::parseFunction(Type::Qualifiers tq) { 459 PRINT( std::cerr << "function..." << std::endl; ) 460 if (done()) return nullptr; 461 FunctionType * ftype = new FunctionType( tq, false ); 462 std::unique_ptr<Type> manager(ftype); 463 Type * retVal = parseType(); 464 if (! retVal) return nullptr; 465 PRINT( std::cerr << "with return type: " << retVal << std::endl; ) 466 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr)); 467 if (done() || ! expect('_')) return nullptr; 468 while (! done()) { 469 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 470 if (cur() == '_') return manager.release(); 471 Type * param = parseType(); 472 if (! param) return nullptr; 473 PRINT( std::cerr << "with parameter : " << param << std::endl; ) 474 ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr)); 475 } 476 return nullptr; 477 } 478 479 Type * StringView::parseTuple(Type::Qualifiers tq) { 480 PRINT( std::cerr << "tuple..." << std::endl; ) 481 std::list< Type * > types; 482 size_t ncomponents; 483 if (! extractNumber(ncomponents)) return nullptr; 484 for (size_t i = 0; i < ncomponents; ++i) { 485 // TODO: delete all on return 486 if (done()) return nullptr; 487 PRINT( std::cerr << "got ch: " << cur() << std::endl; ) 488 Type * t = parseType(); 489 if (! t) return nullptr; 490 PRINT( std::cerr << "with type : " << t << std::endl; ) 491 types.push_back(t); 492 } 493 return new TupleType( tq, types ); 494 } 495 496 Type * StringView::parseVoid(Type::Qualifiers tq) { 497 return new VoidType( tq ); 498 } 499 500 Type * StringView::parsePointer(Type::Qualifiers tq) { 501 PRINT( std::cerr << "pointer..." << std::endl; ) 502 Type * t = parseType(); 503 if (! t) return nullptr; 504 return new PointerType( tq, t ); 505 } 506 507 Type * StringView::parseArray(Type::Qualifiers tq) { 508 PRINT( std::cerr << "array..." << std::endl; ) 509 size_t length; 510 if (! extractNumber(length)) return nullptr; 511 Type * t = parseType(); 512 if (! t) return nullptr; 513 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false ); 514 } 515 516 Type * StringView::parseStruct(Type::Qualifiers tq) { 517 PRINT( std::cerr << "struct..." << std::endl; ) 518 std::string name; 519 if (! extractName(name)) return nullptr; 520 return new StructInstType(tq, name); 521 } 522 523 Type * StringView::parseUnion(Type::Qualifiers tq) { 524 PRINT( std::cerr << "union..." << std::endl; ) 525 std::string name; 526 if (! extractName(name)) return nullptr; 527 return new UnionInstType(tq, name); 528 } 529 530 Type * StringView::parseEnum(Type::Qualifiers tq) { 531 PRINT( std::cerr << "enum..." << std::endl; ) 532 std::string name; 533 if (! extractName(name)) return nullptr; 534 return new EnumInstType(tq, name); 535 } 536 537 Type * StringView::parseType(Type::Qualifiers tq) { 538 PRINT( std::cerr << "type..." << std::endl; ) 539 std::string name; 540 if (! extractName(name)) return nullptr; 541 PRINT( std::cerr << "typename..." << name << std::endl; ) 542 return new TypeInstType(tq, name, false); 543 } 544 545 Type * StringView::parseType() { 546 if (done()) return nullptr; 547 548 std::list<TypeDecl *> forall; 549 if (isPrefix(Encoding::forall)) { 550 PRINT( std::cerr << "polymorphic with..." << std::endl; ) 551 size_t dcount, fcount, vcount, acount; 552 if (! extractNumber(dcount)) return nullptr; 553 PRINT( std::cerr << dcount << " dtypes" << std::endl; ) 554 if (! expect('_')) return nullptr; 555 if (! extractNumber(fcount)) return nullptr; 556 PRINT( std::cerr << fcount << " ftypes" << std::endl; ) 557 if (! expect('_')) return nullptr; 558 if (! extractNumber(vcount)) return nullptr; 559 PRINT( std::cerr << vcount << " ttypes" << std::endl; ) 560 if (! expect('_')) return nullptr; 561 if (! extractNumber(acount)) return nullptr; 562 PRINT( std::cerr << acount << " assertions" << std::endl; ) 563 if (! expect('_')) return nullptr; 564 for (size_t i = 0; i < acount; ++i) { 565 // TODO: need to recursively parse assertions, but for now just return nullptr so that 566 // demangler does not crash if there are assertions 567 return nullptr; 568 } 569 if (! expect('_')) return nullptr; 570 } 571 572 // qualifiers 573 Type::Qualifiers tq; 574 while (true) { 575 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 576 return isPrefix(val.second); 577 }); 578 if (qual == Encoding::qualifiers.end()) break; 579 tq |= qual->first; 580 } 581 582 // find the correct type parser and use it 583 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) { 584 return isPrefix(p.first); 585 }); 586 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx); 587 Type * ret = iter->second(tq); 588 if (! ret) return nullptr; 589 ret->forall = std::move(forall); 590 return ret; 591 } 592 593 bool StringView::parse(std::string & name, Type *& type) { 594 if (! stripMangleName(name)) return false; 595 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 596 Type * t = parseType(); 597 if (! t) return false; 598 type = t; 599 return true; 600 } 601 602 std::string demangle(const std::string & mangleName) { 603 SymTab::Mangler::StringView view(mangleName); 604 std::string name; 605 Type * type = nullptr; 606 if (! view.parse(name, type)) return mangleName; 607 std::unique_ptr<Type> manager(type); 608 return genDemangleType(type, name); 609 } 610 } // namespace 611 } // namespace Mangler 612 } // namespace SymTab 273 if ( !expect('_') ) return nullptr; 274 } 275 276 ast::CV::Qualifiers tq; 277 while (true) { 278 auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) { 279 return isPrefix(val.second); 280 }); 281 if (qual == Encoding::qualifiers.end()) break; 282 tq |= qual->first; 283 } 284 285 // Find the correct type parser and then apply it. 286 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) { 287 return isPrefix(p.first); 288 }); 289 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index); 290 ast::Type * ret = iter->second(tq); 291 if ( !ret ) return nullptr; 292 return ret; 293 } 294 295 bool Demangler::parse( std::string & name, ast::Type *& type) { 296 if ( !stripMangleName(name) ) return false; 297 PRINT( std::cerr << "stripped name: " << name << std::endl; ) 298 ast::Type * t = parseType(); 299 if ( !t ) return false; 300 type = t; 301 return true; 302 } 303 304 std::string demangle( const std::string & mangleName ) { 305 using namespace CodeGen; 306 Demangler demangler( mangleName ); 307 std::string name; 308 ast::Type * type = nullptr; 309 if ( !demangler.parse( name, type ) ) return mangleName; 310 ast::readonly<ast::Type> roType = type; 311 if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName; 312 return genType( type, name, Options( false, false, false, false ) ); 313 } 314 315 } // namespace 316 317 } // namespace Mangle 613 318 614 319 extern "C" { 615 320 char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) { 616 const std::string & demangleName = SymTab::Mangler::demangle(mangleName);321 const std::string & demangleName = Mangle::demangle(mangleName); 617 322 return strdup(demangleName.c_str()); 618 323 } -
src/SymTab/Demangle.h
r0030b508 rfc12f05 10 10 // Created On : Fri May 13 10:11:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri May 13 10:30:00 202213 // Update Count : 012 // Last Modified On : Mon Nov 6 15:48:00 2023 13 // Update Count : 1 14 14 // 15 15 … … 17 17 18 18 extern "C" { 19 /// Main interface to the demangler as a utility. 20 /// Caller must free the returned string. 19 21 char * cforall_demangle(const char *, int); 20 22 } -
src/SymTab/FixFunction.cc
r0030b508 rfc12f05 22 22 #include "AST/Type.hpp" 23 23 #include "Common/utility.h" // for copy 24 #include "SynTree/Declaration.h" // for FunctionDecl, ObjectDecl, Declarati...25 #include "SynTree/Expression.h" // for Expression26 #include "SynTree/Type.h" // for ArrayType, PointerType, Type, Basic...27 24 28 25 namespace SymTab { 29 class FixFunction_old : public WithShortCircuiting {30 typedef Mutator Parent;31 public:32 FixFunction_old() : isVoid( false ) {}33 34 void premutate(FunctionDecl *functionDecl);35 DeclarationWithType* postmutate(FunctionDecl *functionDecl);36 37 Type * postmutate(ArrayType * arrayType);38 39 void premutate(ArrayType * arrayType);40 void premutate(VoidType * voidType);41 void premutate(BasicType * basicType);42 void premutate(PointerType * pointerType);43 void premutate(StructInstType * aggregateUseType);44 void premutate(UnionInstType * aggregateUseType);45 void premutate(EnumInstType * aggregateUseType);46 void premutate(TraitInstType * aggregateUseType);47 void premutate(TypeInstType * aggregateUseType);48 void premutate(TupleType * tupleType);49 void premutate(VarArgsType * varArgsType);50 void premutate(ZeroType * zeroType);51 void premutate(OneType * oneType);52 53 bool isVoid;54 };55 56 DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) {57 // can't delete function type because it may contain assertions, so transfer ownership to new object58 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );59 pointer->location = functionDecl->location;60 functionDecl->attributes.clear();61 functionDecl->type = nullptr;62 delete functionDecl;63 return pointer;64 }65 66 // xxx - this passes on void[], e.g.67 // void foo(void [10]);68 // does not cause an error69 70 Type * FixFunction_old::postmutate(ArrayType *arrayType) {71 // need to recursively mutate the base type in order for multi-dimensional arrays to work.72 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );73 pointerType->location = arrayType->location;74 arrayType->base = nullptr;75 arrayType->dimension = nullptr;76 delete arrayType;77 return pointerType;78 }79 80 void FixFunction_old::premutate(VoidType *) {81 isVoid = true;82 }83 84 void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; }85 void FixFunction_old::premutate(ArrayType *) { visit_children = false; }86 void FixFunction_old::premutate(BasicType *) { visit_children = false; }87 void FixFunction_old::premutate(PointerType *) { visit_children = false; }88 void FixFunction_old::premutate(StructInstType *) { visit_children = false; }89 void FixFunction_old::premutate(UnionInstType *) { visit_children = false; }90 void FixFunction_old::premutate(EnumInstType *) { visit_children = false; }91 void FixFunction_old::premutate(TraitInstType *) { visit_children = false; }92 void FixFunction_old::premutate(TypeInstType *) { visit_children = false; }93 void FixFunction_old::premutate(TupleType *) { visit_children = false; }94 void FixFunction_old::premutate(VarArgsType *) { visit_children = false; }95 void FixFunction_old::premutate(ZeroType *) { visit_children = false; }96 void FixFunction_old::premutate(OneType *) { visit_children = false; }97 98 bool fixFunction( DeclarationWithType *& dwt ) {99 PassVisitor<FixFunction_old> fixer;100 dwt = dwt->acceptMutator( fixer );101 return fixer.pass.isVoid;102 }103 26 104 27 namespace { -
src/SymTab/FixFunction.h
r0030b508 rfc12f05 16 16 #pragma once 17 17 18 #include "Common/PassVisitor.h" // for PassVisitor19 #include "SynTree/SynTree.h" // for Types20 21 18 namespace ast { 22 19 class DeclWithType; … … 25 22 26 23 namespace SymTab { 27 /// Replaces function and array types by equivalent pointer types. Returns true if type is28 /// void29 bool fixFunction( DeclarationWithType *& );30 31 24 /// Returns declaration with function and array types replaced by equivalent pointer types. 32 25 /// Sets isVoid to true if type is void -
src/SymTab/Mangler.cc
r0030b508 rfc12f05 22 22 #include <string> // for string, char_traits, operator<< 23 23 24 #include "AST/Pass.hpp" 24 25 #include "CodeGen/OperatorTable.h" // for OperatorInfo, operatorLookup 25 #include "Common/PassVisitor.h"26 26 #include "Common/ToString.hpp" // for toCString 27 27 #include "Common/SemanticError.h" // for SemanticError 28 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment29 #include "SynTree/LinkageSpec.h" // for Spec, isOverridable, AutoGen, Int...30 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType31 #include "SynTree/Expression.h" // for TypeExpr, Expression, operator<<32 #include "SynTree/Type.h" // for Type, ReferenceToType, Type::Fora...33 34 #include "AST/Pass.hpp"35 36 namespace SymTab {37 namespace Mangler {38 namespace {39 /// Mangles names to a unique C identifier40 struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards {41 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams );42 Mangler_old( const Mangler_old & ) = delete;43 44 void previsit( const BaseSyntaxNode * ) { visit_children = false; }45 46 void postvisit( const ObjectDecl * declaration );47 void postvisit( const FunctionDecl * declaration );48 void postvisit( const TypeDecl * declaration );49 50 void postvisit( const VoidType * voidType );51 void postvisit( const BasicType * basicType );52 void postvisit( const PointerType * pointerType );53 void postvisit( const ArrayType * arrayType );54 void postvisit( const ReferenceType * refType );55 void postvisit( const FunctionType * functionType );56 void postvisit( const StructInstType * aggregateUseType );57 void postvisit( const UnionInstType * aggregateUseType );58 void postvisit( const EnumInstType * aggregateUseType );59 void postvisit( const TypeInstType * aggregateUseType );60 void postvisit( const TraitInstType * inst );61 void postvisit( const TupleType * tupleType );62 void postvisit( const VarArgsType * varArgsType );63 void postvisit( const ZeroType * zeroType );64 void postvisit( const OneType * oneType );65 void postvisit( const QualifiedType * qualType );66 67 std::string get_mangleName() { return mangleName; }68 private:69 std::string mangleName; ///< Mangled name being constructed70 typedef std::map< std::string, std::pair< int, int > > VarMapType;71 VarMapType varNums; ///< Map of type variables to indices72 int nextVarNum; ///< Next type variable index73 bool isTopLevel; ///< Is the Mangler at the top level74 bool mangleOverridable; ///< Specially mangle overridable built-in methods75 bool typeMode; ///< Produce a unique mangled name for a type76 bool mangleGenericParams; ///< Include generic parameters in name mangling if true77 bool inFunctionType = false; ///< Include type qualifiers if false.78 bool inQualifiedType = false; ///< Add start/end delimiters around qualified type79 80 public:81 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,82 int nextVarNum, const VarMapType& varNums );83 84 private:85 void mangleDecl( const DeclarationWithType * declaration );86 void mangleRef( const ReferenceToType * refType, std::string prefix );87 88 void printQualifiers( const Type *type );89 }; // Mangler_old90 } // namespace91 92 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {93 PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams );94 maybeAccept( decl, mangler );95 return mangler.pass.get_mangleName();96 }97 98 std::string mangleType( const Type * ty ) {99 PassVisitor<Mangler_old> mangler( false, true, true );100 maybeAccept( ty, mangler );101 return mangler.pass.get_mangleName();102 }103 104 std::string mangleConcrete( const Type * ty ) {105 PassVisitor<Mangler_old> mangler( false, false, false );106 maybeAccept( ty, mangler );107 return mangler.pass.get_mangleName();108 }109 110 namespace {111 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams )112 : nextVarNum( 0 ), isTopLevel( true ),113 mangleOverridable( mangleOverridable ), typeMode( typeMode ),114 mangleGenericParams( mangleGenericParams ) {}115 116 Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,117 int nextVarNum, const VarMapType& varNums )118 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),119 mangleOverridable( mangleOverridable ), typeMode( typeMode ),120 mangleGenericParams( mangleGenericParams ) {}121 122 void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) {123 bool wasTopLevel = isTopLevel;124 if ( isTopLevel ) {125 varNums.clear();126 nextVarNum = 0;127 isTopLevel = false;128 } // if129 mangleName += Encoding::manglePrefix;130 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );131 if ( opInfo ) {132 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;133 } else {134 mangleName += std::to_string( declaration->name.size() ) + declaration->name;135 } // if136 maybeAccept( declaration->get_type(), *visitor );137 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {138 // want to be able to override autogenerated and intrinsic routines,139 // so they need a different name mangling140 if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {141 mangleName += Encoding::autogen;142 } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {143 mangleName += Encoding::intrinsic;144 } else {145 // if we add another kind of overridable function, this has to change146 assert( false && "unknown overrideable linkage" );147 } // if148 }149 isTopLevel = wasTopLevel;150 }151 152 void Mangler_old::postvisit( const ObjectDecl * declaration ) {153 mangleDecl( declaration );154 }155 156 void Mangler_old::postvisit( const FunctionDecl * declaration ) {157 mangleDecl( declaration );158 }159 160 void Mangler_old::postvisit( const VoidType * voidType ) {161 printQualifiers( voidType );162 mangleName += Encoding::void_t;163 }164 165 void Mangler_old::postvisit( const BasicType * basicType ) {166 printQualifiers( basicType );167 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );168 mangleName += Encoding::basicTypes[ basicType->kind ];169 }170 171 void Mangler_old::postvisit( const PointerType * pointerType ) {172 printQualifiers( pointerType );173 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers174 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;175 maybeAccept( pointerType->base, *visitor );176 }177 178 void Mangler_old::postvisit( const ArrayType * arrayType ) {179 // TODO: encode dimension180 printQualifiers( arrayType );181 mangleName += Encoding::array + "0";182 maybeAccept( arrayType->base, *visitor );183 }184 185 void Mangler_old::postvisit( const ReferenceType * refType ) {186 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.187 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),188 // by pretending every reference type is a function parameter.189 GuardValue( inFunctionType );190 inFunctionType = true;191 printQualifiers( refType );192 maybeAccept( refType->base, *visitor );193 }194 195 namespace {196 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {197 std::list< Type* > ret;198 std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),199 std::mem_fun( &DeclarationWithType::get_type ) );200 return ret;201 }202 }203 204 void Mangler_old::postvisit( const FunctionType * functionType ) {205 printQualifiers( functionType );206 mangleName += Encoding::function;207 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,208 // since qualifiers on outermost parameter type do not differentiate function types, e.g.,209 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different210 GuardValue( inFunctionType );211 inFunctionType = true;212 std::list< Type* > returnTypes = getTypes( functionType->returnVals );213 if (returnTypes.empty()) mangleName += Encoding::void_t;214 else acceptAll( returnTypes, *visitor );215 mangleName += "_";216 std::list< Type* > paramTypes = getTypes( functionType->parameters );217 acceptAll( paramTypes, *visitor );218 mangleName += "_";219 }220 221 void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) {222 printQualifiers( refType );223 224 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;225 226 if ( mangleGenericParams ) {227 const std::list< Expression* > & params = refType->parameters;228 if ( ! params.empty() ) {229 mangleName += "_";230 for ( const Expression * param : params ) {231 const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );232 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));233 maybeAccept( paramType->type, *visitor );234 }235 mangleName += "_";236 }237 }238 }239 240 void Mangler_old::postvisit( const StructInstType * aggregateUseType ) {241 mangleRef( aggregateUseType, Encoding::struct_t );242 }243 244 void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) {245 mangleRef( aggregateUseType, Encoding::union_t );246 }247 248 void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) {249 mangleRef( aggregateUseType, Encoding::enum_t );250 }251 252 void Mangler_old::postvisit( const TypeInstType * typeInst ) {253 VarMapType::iterator varNum = varNums.find( typeInst->get_name() );254 if ( varNum == varNums.end() ) {255 mangleRef( typeInst, Encoding::type );256 } else {257 printQualifiers( typeInst );258 // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.259 // forall(dtype T) void f(T);260 // forall(dtype S) void f(S);261 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they262 // are first found and prefixing with the appropriate encoding for the type class.263 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );264 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );265 } // if266 }267 268 void Mangler_old::postvisit( const TraitInstType * inst ) {269 printQualifiers( inst );270 mangleName += std::to_string( inst->name.size() ) + inst->name;271 }272 273 void Mangler_old::postvisit( const TupleType * tupleType ) {274 printQualifiers( tupleType );275 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );276 acceptAll( tupleType->types, *visitor );277 }278 279 void Mangler_old::postvisit( const VarArgsType * varArgsType ) {280 printQualifiers( varArgsType );281 static const std::string vargs = "__builtin_va_list";282 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;283 }284 285 void Mangler_old::postvisit( const ZeroType * ) {286 mangleName += Encoding::zero;287 }288 289 void Mangler_old::postvisit( const OneType * ) {290 mangleName += Encoding::one;291 }292 293 void Mangler_old::postvisit( const QualifiedType * qualType ) {294 bool inqual = inQualifiedType;295 if (! inqual ) {296 // N marks the start of a qualified type297 inQualifiedType = true;298 mangleName += Encoding::qualifiedTypeStart;299 }300 maybeAccept( qualType->parent, *visitor );301 maybeAccept( qualType->child, *visitor );302 if ( ! inqual ) {303 // E marks the end of a qualified type304 inQualifiedType = false;305 mangleName += Encoding::qualifiedTypeEnd;306 }307 }308 309 void Mangler_old::postvisit( const TypeDecl * decl ) {310 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be311 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.312 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply313 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed314 // aside from the assert false.315 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl));316 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );317 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;318 }319 320 __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {321 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {322 os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;323 } // for324 }325 326 void Mangler_old::printQualifiers( const Type * type ) {327 // skip if not including qualifiers328 if ( typeMode ) return;329 if ( ! type->forall.empty() ) {330 std::list< std::string > assertionNames;331 int dcount = 0, fcount = 0, vcount = 0, acount = 0;332 mangleName += Encoding::forall;333 for ( const TypeDecl * i : type->forall ) {334 switch ( i->kind ) {335 case TypeDecl::Dtype:336 dcount++;337 break;338 case TypeDecl::Ftype:339 fcount++;340 break;341 case TypeDecl::Ttype:342 vcount++;343 break;344 default:345 assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() );346 } // switch347 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind );348 for ( const DeclarationWithType * assert : i->assertions ) {349 PassVisitor<Mangler_old> sub_mangler(350 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );351 assert->accept( sub_mangler );352 assertionNames.push_back( sub_mangler.pass.get_mangleName() );353 acount++;354 } // for355 } // for356 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";357 for(const auto & a : assertionNames) mangleName += a;358 // std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );359 mangleName += "_";360 } // if361 if ( ! inFunctionType ) {362 // these qualifiers do not distinguish the outermost type of a function parameter363 if ( type->get_const() ) {364 mangleName += Encoding::qualifiers.at(Type::Const);365 } // if366 if ( type->get_volatile() ) {367 mangleName += Encoding::qualifiers.at(Type::Volatile);368 } // if369 // Removed due to restrict not affecting function compatibility in GCC370 // if ( type->get_isRestrict() ) {371 // mangleName += "E";372 // } // if373 if ( type->get_atomic() ) {374 mangleName += Encoding::qualifiers.at(Type::Atomic);375 } // if376 }377 if ( type->get_mutex() ) {378 mangleName += Encoding::qualifiers.at(Type::Mutex);379 } // if380 if ( inFunctionType ) {381 // turn off inFunctionType so that types can be differentiated for nested qualifiers382 GuardValue( inFunctionType );383 inFunctionType = false;384 }385 }386 } // namespace387 } // namespace Mangler388 } // namespace SymTab389 28 390 29 namespace Mangle { … … 476 115 mangleName += std::to_string( decl->name.size() ) + decl->name; 477 116 } // if 478 maybeAccept( decl->get_type(),*visitor );117 decl->get_type()->accept( *visitor ); 479 118 if ( mangleOverridable && decl->linkage.is_overrideable ) { 480 119 // want to be able to override autogenerated and intrinsic routines, … … 522 161 printQualifiers( arrayType ); 523 162 mangleName += Encoding::array + "0"; 524 maybeAccept( arrayType->base.get(),*visitor );163 arrayType->base->accept( *visitor ); 525 164 } 526 165 … … 532 171 inFunctionType = true; 533 172 printQualifiers( refType ); 534 maybeAccept( refType->base.get(),*visitor );173 refType->base->accept( *visitor ); 535 174 } 536 175 … … 561 200 auto paramType = dynamic_cast< const ast::TypeExpr * >( param ); 562 201 assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param)); 563 maybeAccept( paramType->type.get(),*visitor );202 paramType->type->accept( *visitor ); 564 203 } 565 204 mangleName += "_"; … … 590 229 // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they 591 230 // are first found and prefixing with the appropriate encoding for the type class. 592 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );231 assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 593 232 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 594 233 } // if … … 622 261 void Mangler_new::postvisit( const ast::QualifiedType * qualType ) { 623 262 bool inqual = inQualifiedType; 624 if ( !inqual ) {263 if ( !inqual ) { 625 264 // N marks the start of a qualified type 626 265 inQualifiedType = true; 627 266 mangleName += Encoding::qualifiedTypeStart; 628 267 } 629 maybeAccept( qualType->parent.get(),*visitor );630 maybeAccept( qualType->child.get(),*visitor );631 if ( ! 268 qualType->parent->accept( *visitor ); 269 qualType->child->accept( *visitor ); 270 if ( !inqual ) { 632 271 // E marks the end of a qualified type 633 272 inQualifiedType = false; … … 691 330 // these qualifiers do not distinguish the outermost type of a function parameter 692 331 if ( type->is_const() ) { 693 mangleName += Encoding::qualifiers.at( Type::Const);332 mangleName += Encoding::qualifiers.at( ast::CV::Const ); 694 333 } // if 695 334 if ( type->is_volatile() ) { 696 mangleName += Encoding::qualifiers.at( Type::Volatile);335 mangleName += Encoding::qualifiers.at( ast::CV::Volatile ); 697 336 } // if 698 337 // Removed due to restrict not affecting function compatibility in GCC … … 701 340 // } // if 702 341 if ( type->is_atomic() ) { 703 mangleName += Encoding::qualifiers.at( Type::Atomic);342 mangleName += Encoding::qualifiers.at( ast::CV::Atomic ); 704 343 } // if 705 344 } 706 345 if ( type->is_mutex() ) { 707 mangleName += Encoding::qualifiers.at( Type::Mutex);346 mangleName += Encoding::qualifiers.at( ast::CV::Mutex ); 708 347 } // if 709 348 if ( inFunctionType ) { -
src/SymTab/Mangler.h
r0030b508 rfc12f05 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "SynTree/SynTree.h" // for Types25 #include "SynTree/Visitor.h" // for Visitor, maybeAccept26 24 27 25 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling … … 35 33 class Node; 36 34 } 37 namespace ResolvExpr {38 class TypeEnvironment;39 }40 35 41 36 namespace SymTab { 42 37 namespace Mangler { 43 /// Mangle syntax tree object; primary interface to clients44 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );45 46 /// Mangle a type name; secondary interface47 std::string mangleType( const Type * ty );48 /// Mangle ignoring generic type parameters49 std::string mangleConcrete( const Type * ty );50 51 38 namespace Encoding { 52 39 extern const std::string manglePrefix; -
src/SymTab/ManglerCommon.cc
r0030b508 rfc12f05 15 15 16 16 #include "Mangler.h" 17 #include "SynTree/Type.h" 18 #include "SynTree/Declaration.h" 17 18 #include "AST/Decl.hpp" 19 #include "AST/Type.hpp" 19 20 20 21 namespace SymTab { … … 39 40 // - "Di" char32_t 40 41 // - "Ds" char16_t 41 const std::string basicTypes[ BasicType::NUMBER_OF_BASIC_TYPES] = {42 const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = { 42 43 "b", // _Bool 43 44 "c", // char … … 79 80 // GENERATED END 80 81 static_assert( 81 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,82 sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES, 82 83 "Each basic type kind should have a corresponding mangler letter" 83 84 ); 84 85 85 86 const std::map<int, std::string> qualifiers = { 86 { Type::Const, "K" },87 { Type::Volatile, "V" },88 { Type::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA89 { Type::Mutex, "X" },87 { ast::CV::Const, "K" }, 88 { ast::CV::Volatile, "V" }, 89 { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA 90 { ast::CV::Mutex, "X" }, 90 91 }; 91 92 … … 111 112 }; 112 113 static_assert( 113 sizeof(typeVariables) / sizeof(typeVariables[0]) == TypeDecl::NUMBER_OF_KINDS,114 sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS, 114 115 "Each type variable kind should have a corresponding mangler prefix" 115 116 ); -
src/SymTab/demangler.cc
r0030b508 rfc12f05 2 2 #include <iostream> 3 3 #include <fstream> 4 using namespace std;5 4 6 void f(const std::string & mangleName) {5 void demangleAndPrint(const std::string & mangleName) { 7 6 char * demangleName = cforall_demangle(mangleName.c_str(), 0); 8 cout << mangleName << " => " << std::flush << demangleName <<endl;7 std::cout << mangleName << " => " << demangleName << std::endl; 9 8 free(demangleName); 10 9 } 11 10 12 int main() { 13 ifstream in("in-demangle.txt"); 11 int main(int argc, char * argv[]) { 12 char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt"; 13 std::ifstream in(fileName); 14 14 15 std::string line; 15 while (getline(in, line)) { 16 if (line.empty()) { cout << "=================================" << endl; continue; } 17 else if (line[0] == '#') continue; 18 f(line); 16 while (std::getline(in, line)) { 17 if (line.empty()) { 18 std::cout << "=================================" << std::endl; 19 } else if (line[0] == '#') { 20 continue; 21 } else { 22 demangleAndPrint(line); 23 } 19 24 } 20 25 } -
src/SymTab/module.mk
r0030b508 rfc12f05 16 16 17 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \19 SymTab/Autogen.h \20 18 SymTab/FixFunction.cc \ 21 19 SymTab/FixFunction.h \ 22 20 SymTab/GenImplicitCall.cpp \ 23 21 SymTab/GenImplicitCall.hpp \ 24 SymTab/Indexer.cc \25 SymTab/Indexer.h \26 22 SymTab/Mangler.cc \ 27 23 SymTab/ManglerCommon.cc \ 28 SymTab/Mangler.h \ 29 SymTab/ValidateType.cc \ 30 SymTab/ValidateType.h 24 SymTab/Mangler.h 31 25 32 SRC += $(SRC_SYMTAB) \ 33 SymTab/Validate.cc \ 34 SymTab/Validate.h 26 SRC += $(SRC_SYMTAB) 35 27 36 28 SRCDEMANGLE += $(SRC_SYMTAB) \ -
src/Tuples/Explode.cc
r0030b508 rfc12f05 15 15 16 16 #include "Explode.h" 17 #include <list> // for list18 17 19 18 #include "AST/Pass.hpp" // for Pass 20 #include "SynTree/Mutator.h" // for Mutator21 #include "Common/PassVisitor.h" // for PassVisitor22 19 23 20 namespace Tuples { 24 namespace {25 // remove one level of reference from a reference type -- may be useful elsewhere.26 Type * getReferenceBase( Type * t ) {27 if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {28 return refType->get_base();29 } else {30 // for the moment, I want to know immediately if a non-reference type is ever passed in here.31 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );32 return nullptr;33 }34 }35 36 struct CastExploder {37 bool castAdded = false;38 bool foundUniqueExpr = false;39 Expression * applyCast( Expression * expr, bool first = true ) {40 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){41 foundUniqueExpr = true;42 std::list< Expression * > exprs;43 for ( Expression *& expr : tupleExpr->get_exprs() ) {44 // move cast into tuple exprs45 exprs.push_back( applyCast( expr, false ) );46 }47 // want the top-level expression to be cast to reference type, but not nested48 // tuple expressions49 if ( first ) {50 castAdded = true;51 Expression * tupleExpr = new TupleExpr( exprs );52 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );53 } else {54 return new TupleExpr( exprs );55 }56 }57 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {58 // don't need to cast reference type to another reference type59 return expr->clone();60 } else {61 // anything else should be cast to reference as normal62 castAdded = true;63 return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );64 }65 }66 67 Expression * postmutate( UniqueExpr * uniqueExpr ) {68 // move cast into unique expr so that the unique expr has type T& rather than69 // type T. In particular, this transformation helps with generating the70 // correct code for reference-cast member tuple expressions, since the result71 // should now be a tuple of references rather than a reference to a tuple.72 // Still, this code is a bit awkward, and could use some improvement.73 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );74 delete uniqueExpr;75 if ( castAdded ) {76 // if a cast was added by applyCast, then unique expr now has one more layer of reference77 // than it had coming into this function. To ensure types still match correctly, need to cast78 // to reference base so that outer expressions are still correct.79 castAdded = false;80 Type * toType = getReferenceBase( newUniqueExpr->result );81 return new CastExpr( newUniqueExpr, toType->clone() );82 }83 return newUniqueExpr;84 }85 86 87 Expression * postmutate( TupleIndexExpr * tupleExpr ) {88 // tuple index expr needs to be rebuilt to ensure that the type of the89 // field is consistent with the type of the tuple expr, since the field90 // may have changed from type T to T&.91 Expression * expr = tupleExpr->get_tuple();92 tupleExpr->set_tuple( nullptr );93 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );94 delete tupleExpr;95 return ret;96 }97 };98 } // namespace99 100 Expression * distributeReference( Expression * expr ) {101 PassVisitor<CastExploder> exploder;102 expr = expr->acceptMutator( exploder );103 if ( ! exploder.pass.foundUniqueExpr ) {104 // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate105 expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );106 }107 return expr;108 }109 21 110 22 namespace { -
src/Tuples/Explode.h
r0030b508 rfc12f05 20 20 21 21 #include "AST/Expr.hpp" 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList23 22 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual25 23 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr27 #include "SynTree/Type.h" // for TupleType, Type28 24 #include "Tuples.h" // for maybeImpure 29 25 … … 32 28 } 33 29 34 namespace SymTab {35 class Indexer;36 } // namespace SymTab37 38 30 namespace Tuples { 39 Expression * distributeReference( Expression * );40 41 static inline CastExpr * isReferenceCast( Expression * expr ) {42 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {43 if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {44 return castExpr;45 }46 }47 return nullptr;48 }49 50 /// Append alternative to an OutputIterator of Alternatives51 template<typename OutputIterator>52 void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,53 const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,54 const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {55 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };56 }57 58 /// Append alternative to an ExplodedActual59 static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,60 const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,61 const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {62 ea.exprs.emplace_back( expr );63 /// xxx -- merge environment, openVars, need, cost?64 }65 66 /// helper function used by explode67 template< typename Output >68 void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,69 const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {70 if ( isTupleAssign ) {71 // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components72 if ( CastExpr * castExpr = isReferenceCast( expr ) ) {73 ResolvExpr::AltList alts;74 explodeUnique(75 castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );76 for ( ResolvExpr::Alternative & alt : alts ) {77 // distribute reference cast over all components78 append( std::forward<Output>(out), distributeReference( alt.release_expr() ),79 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );80 }81 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)82 return;83 }84 }85 Type * res = expr->get_result()->stripReferences();86 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {87 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {88 // can open tuple expr and dump its exploded components89 for ( Expression * expr : tupleExpr->get_exprs() ) {90 explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );91 }92 } else {93 // tuple type, but not tuple expr - recursively index into its components.94 // if expr type is reference, convert to value type95 Expression * arg = expr->clone();96 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {97 // expressions which may contain side effects require a single unique instance of the expression.98 arg = new UniqueExpr( arg );99 }100 // cast reference to value type to facilitate further explosion101 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {102 arg = new CastExpr( arg, tupleType->clone() );103 }104 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {105 TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );106 explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );107 delete idx;108 }109 delete arg;110 }111 } else {112 // atomic (non-tuple) type - output a clone of the expression in a new alternative113 append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,114 alt.cost, alt.cvtCost );115 }116 }117 118 /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type119 template< typename Output >120 void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,121 Output&& out, bool isTupleAssign = false ) {122 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );123 }124 125 // explode list of alternatives126 template< typename AltIterator, typename Output >127 void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,128 Output&& out, bool isTupleAssign = false ) {129 for ( ; altBegin != altEnd; ++altBegin ) {130 explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );131 }132 }133 134 template< typename Output >135 void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,136 bool isTupleAssign = false ) {137 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );138 }139 31 140 32 const ast::Expr * distributeReference( const ast::Expr * ); -
src/Tuples/TupleAssignment.cc
r0030b508 rfc12f05 28 28 #include "AST/TypeEnvironment.hpp" 29 29 #include "CodeGen/OperatorTable.h" 30 #include "Common/PassVisitor.h"31 30 #include "Common/UniqueName.h" // for UniqueName 32 31 #include "Common/utility.h" // for splice, zipWith … … 34 33 #include "InitTweak/GenInit.h" // for genCtorInit 35 34 #include "InitTweak/InitTweak.h" // for getPointerBase, isAssignment 36 #include "ResolvExpr/Alternative.h" // for AltList, Alternative37 #include "ResolvExpr/AlternativeFinder.h" // for AlternativeFinder, simpleC...38 35 #include "ResolvExpr/Cost.h" // for Cost 39 36 #include "ResolvExpr/Resolver.h" // for resolveCtorInit 40 #include "ResolvExpr/TypeEnvironment.h" // for TypeEnvironment41 37 #include "ResolvExpr/typeops.h" // for combos 42 #include "SynTree/LinkageSpec.h" // for Cforall43 #include "SynTree/Declaration.h" // for ObjectDecl44 #include "SynTree/Expression.h" // for Expression, CastExpr, Name...45 #include "SynTree/Initializer.h" // for ConstructorInit, SingleInit46 #include "SynTree/Statement.h" // for ExprStmt47 #include "SynTree/Type.h" // for Type, Type::Qualifiers48 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution49 #include "SynTree/Visitor.h" // for Visitor50 38 51 39 #if 0 … … 56 44 57 45 namespace Tuples { 58 class TupleAssignSpotter_old {59 public:60 // dispatcher for Tuple (multiple and mass) assignment operations61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );63 64 private:65 void match();66 67 struct Matcher {68 public:69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,70 const ResolvExpr::AltList& rhs );71 virtual ~Matcher() {}72 73 virtual void match( std::list< Expression * > &out ) = 0;74 ObjectDecl * newObject( UniqueName & namer, Expression * expr );75 76 void combineState( const ResolvExpr::Alternative& alt ) {77 compositeEnv.simpleCombine( alt.env );78 ResolvExpr::mergeOpenVars( openVars, alt.openVars );79 cloneAll( alt.need, need );80 }81 82 void combineState( const ResolvExpr::AltList& alts ) {83 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }84 }85 86 ResolvExpr::AltList lhs, rhs;87 TupleAssignSpotter_old &spotter;88 ResolvExpr::Cost baseCost;89 std::list< ObjectDecl * > tmpDecls;90 ResolvExpr::TypeEnvironment compositeEnv;91 ResolvExpr::OpenVarSet openVars;92 ResolvExpr::AssertionSet need;93 };94 95 struct MassAssignMatcher : public Matcher {96 public:97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}99 virtual void match( std::list< Expression * > &out );100 };101 102 struct MultipleAssignMatcher : public Matcher {103 public:104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}106 virtual void match( std::list< Expression * > &out );107 };108 109 ResolvExpr::AlternativeFinder ¤tFinder;110 std::string fname;111 std::unique_ptr< Matcher > matcher;112 };113 114 /// true if expr is an expression of tuple type115 bool isTuple( Expression *expr ) {116 if ( ! expr ) return false;117 assert( expr->result );118 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );119 }120 121 template< typename AltIter >122 bool isMultAssign( AltIter begin, AltIter end ) {123 // multiple assignment if more than one alternative in the range or if124 // the alternative is a tuple125 if ( begin == end ) return false;126 if ( isTuple( begin->expr ) ) return true;127 return ++begin != end;128 }129 130 bool refToTuple( Expression *expr ) {131 assert( expr->get_result() );132 // also check for function returning tuple of reference types133 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {134 return refToTuple( castExpr->get_arg() );135 } else {136 return isTuple( expr );137 }138 return false;139 }140 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,142 std::vector<ResolvExpr::AlternativeFinder> &args ) {143 TupleAssignSpotter_old spotter( currentFinder );144 spotter.spot( expr, args );145 }146 147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )148 : currentFinder(f) {}149 150 void TupleAssignSpotter_old::spot( UntypedExpr * expr,151 std::vector<ResolvExpr::AlternativeFinder> &args ) {152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {153 if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {154 fname = op->get_name();155 156 // AlternativeFinder will naturally handle this case case, if it's legal157 if ( args.size() == 0 ) return;158 159 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote160 // the function, in which case AlternativeFinder will handle it normally161 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;162 163 // look over all possible left-hand-sides164 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {165 // skip non-tuple LHS166 if ( ! refToTuple(lhsAlt.expr) ) continue;167 168 // explode is aware of casts - ensure every LHS expression is sent into explode169 // with a reference cast170 // xxx - this seems to change the alternatives before the normal171 // AlternativeFinder flow; maybe this is desired?172 if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {173 lhsAlt.expr = new CastExpr( lhsAlt.expr,174 new ReferenceType( Type::Qualifiers(),175 lhsAlt.expr->result->clone() ) );176 }177 178 // explode the LHS so that each field of a tuple-valued-expr is assigned179 ResolvExpr::AltList lhs;180 explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );181 for ( ResolvExpr::Alternative& alt : lhs ) {182 // each LHS value must be a reference - some come in with a cast expression,183 // if not just cast to reference here184 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {185 alt.expr = new CastExpr( alt.expr,186 new ReferenceType( Type::Qualifiers(),187 alt.expr->get_result()->clone() ) );188 }189 }190 191 if ( args.size() == 1 ) {192 // mass default-initialization/destruction193 ResolvExpr::AltList rhs{};194 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );195 match();196 } else if ( args.size() > 2 ) {197 // expand all possible RHS possibilities198 // TODO build iterative version of this instead of using combos199 std::vector< ResolvExpr::AltList > rhsAlts;200 combos( std::next(args.begin(), 1), args.end(),201 std::back_inserter( rhsAlts ) );202 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {203 // multiple assignment204 ResolvExpr::AltList rhs;205 explode( rhsAlt, currentFinder.get_indexer(),206 std::back_inserter(rhs), true );207 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );208 match();209 }210 } else {211 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {212 ResolvExpr::AltList rhs;213 if ( isTuple(rhsAlt.expr) ) {214 // multiple assignment215 explode( rhsAlt, currentFinder.get_indexer(),216 std::back_inserter(rhs), true );217 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );218 } else {219 // mass assignment220 rhs.push_back( rhsAlt );221 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );222 }223 match();224 }225 }226 }227 }228 }229 }230 231 void TupleAssignSpotter_old::match() {232 assert ( matcher != 0 );233 234 std::list< Expression * > new_assigns;235 matcher->match( new_assigns );236 237 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {238 // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.239 // if not the empty tuple case, return early so that no new alternatives are generated.240 if ( new_assigns.empty() ) return;241 }242 ResolvExpr::AltList current;243 // now resolve new assignments244 for ( std::list< Expression * >::iterator i = new_assigns.begin();245 i != new_assigns.end(); ++i ) {246 PRINT(247 std::cerr << "== resolving tuple assign ==" << std::endl;248 std::cerr << *i << std::endl;249 )250 251 ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),252 matcher->compositeEnv };253 254 try {255 finder.findWithAdjustment(*i);256 } catch (...) {257 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid258 }259 // prune expressions that don't coincide with260 ResolvExpr::AltList alts = finder.get_alternatives();261 assert( alts.size() == 1 );262 assert( alts.front().expr != 0 );263 current.push_back( alts.front() );264 }265 266 // extract expressions from the assignment alternatives to produce a list of assignments267 // that together form a single alternative268 std::list< Expression *> solved_assigns;269 for ( ResolvExpr::Alternative & alt : current ) {270 solved_assigns.push_back( alt.expr->clone() );271 matcher->combineState( alt );272 }273 274 // xxx -- was push_front275 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{276 new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,277 matcher->openVars,278 ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),279 ResolvExpr::sumCost( current ) + matcher->baseCost } );280 }281 282 TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )284 : lhs(lhs), rhs(rhs), spotter(spotter),285 baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {286 combineState( lhs );287 combineState( rhs );288 }289 290 UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {291 assert( left );292 std::list< Expression * > args;293 args.push_back( new VariableExpr( left ) );294 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );295 if ( right ) args.push_back( new VariableExpr( right ) );296 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {297 args.front() = new AddressExpr( args.front() );298 if ( right ) args.back() = new AddressExpr( args.back() );299 return new UntypedExpr( new NameExpr( "?=?" ), args );300 } else {301 return new UntypedExpr( new NameExpr( fname ), args );302 }303 }304 305 // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv306 // xxx - maybe this should happen in alternative finder for every StmtExpr?307 struct EnvRemover {308 void previsit( ExprStmt * stmt ) {309 assert( compositeEnv );310 if ( stmt->expr->env ) {311 compositeEnv->add( *stmt->expr->env );312 delete stmt->expr->env;313 stmt->expr->env = nullptr;314 }315 }316 317 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;318 };319 320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {321 assert( expr->result && ! expr->get_result()->isVoid() );322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );323 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.324 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {325 ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );326 ret->init = ctorInit;327 ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object328 PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs329 rm.pass.compositeEnv = &compositeEnv;330 ctorInit->accept( rm );331 }332 PRINT( std::cerr << "new object: " << ret << std::endl; )333 return ret;334 }335 336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {337 static UniqueName lhsNamer( "__massassign_L" );338 static UniqueName rhsNamer( "__massassign_R" );339 // empty tuple case falls into this matcher, hence the second part of the assert340 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );341 342 // xxx - may need to split this up into multiple declarations, because potential conversion to references343 // probably should not reference local variable - see MultipleAssignMatcher::match344 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;345 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {346 // create a temporary object for each value in the lhs and create a call involving the rhs347 ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );348 out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );349 tmpDecls.push_back( ltmp );350 }351 if ( rtmp ) tmpDecls.push_back( rtmp );352 }353 354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {355 static UniqueName lhsNamer( "__multassign_L" );356 static UniqueName rhsNamer( "__multassign_R" );357 358 if ( lhs.size() == rhs.size() ) {359 // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls360 std::list< ObjectDecl * > ltmp;361 std::list< ObjectDecl * > rtmp;362 for ( auto p : group_iterate( lhs, rhs ) ) {363 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);364 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);365 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.366 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );367 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );368 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );369 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );370 out.push_back( createFunc(spotter.fname, lobj, robj) );371 ltmp.push_back( lobj );372 rtmp.push_back( robj );373 374 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment375 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };376 finder.findWithAdjustment( rhsAlt.expr );377 assert( finder.get_alternatives().size() == 1 );378 compositeEnv = std::move( finder.get_alternatives().front().env );379 }380 tmpDecls.splice( tmpDecls.end(), ltmp );381 tmpDecls.splice( tmpDecls.end(), rtmp );382 }383 }384 46 385 47 namespace { -
src/Tuples/TupleExpansion.cc
r0030b508 rfc12f05 23 23 #include "AST/Node.hpp" 24 24 #include "AST/Type.hpp" 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu...26 25 #include "Common/ScopedMap.h" // for ScopedMap 27 26 #include "Common/utility.h" // for CodeLocation 28 27 #include "InitTweak/InitTweak.h" // for getFunction 29 #include "SynTree/LinkageSpec.h" // for Spec, C, Intrinsic30 #include "SynTree/Constant.h" // for Constant31 #include "SynTree/Declaration.h" // for StructDecl, DeclarationWithType32 #include "SynTree/Expression.h" // for UntypedMemberExpr, Expression, Uniq...33 #include "SynTree/Label.h" // for operator==, Label34 #include "SynTree/Mutator.h" // for Mutator35 #include "SynTree/Type.h" // for Type, Type::Qualifiers, TupleType36 #include "SynTree/Visitor.h" // for Visitor37 28 #include "Tuples.h" 38 29 39 class CompoundStmt; 40 class TypeSubstitution; 30 namespace Tuples { 41 31 42 namespace Tuples {43 namespace {44 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {45 void premutate( UntypedMemberExpr * ) { visit_children = false; }46 Expression * postmutate( UntypedMemberExpr * memberExpr );47 };48 49 struct UniqueExprExpander final : public WithDeclsToAdd {50 Expression * postmutate( UniqueExpr * unqExpr );51 52 std::map< int, Expression * > decls; // not vector, because order added may not be increasing order53 54 ~UniqueExprExpander() {55 for ( std::pair<const int, Expression *> & p : decls ) {56 delete p.second;57 }58 }59 };60 61 struct TupleAssignExpander {62 Expression * postmutate( TupleAssignExpr * tupleExpr );63 };64 65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {66 Type * postmutate( TupleType * tupleType );67 68 void premutate( CompoundStmt * ) {69 GuardScope( typeMap );70 }71 private:72 ScopedMap< int, StructDecl * > typeMap;73 };74 75 struct TupleIndexExpander {76 Expression * postmutate( TupleIndexExpr * tupleExpr );77 };78 79 struct TupleExprExpander final {80 Expression * postmutate( TupleExpr * tupleExpr );81 };82 }83 84 void expandMemberTuples( std::list< Declaration * > & translationUnit ) {85 PassVisitor<MemberTupleExpander> expander;86 mutateAll( translationUnit, expander );87 }88 89 void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {90 PassVisitor<UniqueExprExpander> unqExpander;91 mutateAll( translationUnit, unqExpander );92 }93 94 void expandTuples( std::list< Declaration * > & translationUnit ) {95 PassVisitor<TupleAssignExpander> assnExpander;96 mutateAll( translationUnit, assnExpander );97 98 PassVisitor<TupleTypeReplacer> replacer;99 mutateAll( translationUnit, replacer );100 101 PassVisitor<TupleIndexExpander> idxExpander;102 mutateAll( translationUnit, idxExpander );103 104 PassVisitor<TupleExprExpander> exprExpander;105 mutateAll( translationUnit, exprExpander );106 }107 108 namespace {109 /// given a expression representing the member and an expression representing the aggregate,110 /// reconstructs a flattened UntypedMemberExpr with the right precedence111 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {112 if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {113 // construct a new UntypedMemberExpr with the correct structure , and recursively114 // expand that member expression.115 PassVisitor<MemberTupleExpander> expander;116 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );117 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );118 inner->location = newMemberExpr->location = loc;119 memberExpr->member = nullptr;120 memberExpr->aggregate = nullptr;121 delete memberExpr;122 return newMemberExpr->acceptMutator( expander );123 } else {124 // not a member expression, so there is nothing to do but attach and return125 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );126 newMemberExpr->location = loc;127 return newMemberExpr;128 }129 }130 }131 132 Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {133 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {134 Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );135 // aggregate expressions which might be impure must be wrapped in unique expressions136 if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );137 for ( Expression *& expr : tupleExpr->exprs ) {138 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );139 expr->location = memberExpr->location;140 }141 delete aggr;142 tupleExpr->location = memberExpr->location;143 return tupleExpr;144 } else {145 // there may be a tuple expr buried in the aggregate146 // xxx - this is a memory leak147 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );148 newMemberExpr->location = memberExpr->location;149 return newMemberExpr;150 }151 }152 153 Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {154 const int id = unqExpr->get_id();155 156 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,157 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.158 if ( ! decls.count( id ) ) {159 Expression * assignUnq;160 Expression * var = unqExpr->get_var();161 if ( unqExpr->get_object() ) {162 // an object was generated to represent this unique expression -- it should be added to the list of declarations now163 declsToAddBefore.push_back( unqExpr->get_object() );164 unqExpr->set_object( nullptr );165 // steal the expr from the unqExpr166 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );167 unqExpr->set_expr( nullptr );168 } else {169 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit170 Expression * expr = unqExpr->get_expr();171 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );172 assignUnq = commaExpr->get_arg1();173 commaExpr->set_arg1( nullptr );174 }175 ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),176 new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );177 declsToAddBefore.push_back( finished );178 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))179 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.180 Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );181 ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),182 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );183 condExpr->set_result( var->get_result()->clone() );184 condExpr->set_env( maybeClone( unqExpr->get_env() ) );185 decls[id] = condExpr;186 }187 delete unqExpr;188 return decls[id]->clone();189 }190 191 Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {192 StmtExpr * ret = assnExpr->get_stmtExpr();193 assnExpr->set_stmtExpr( nullptr );194 // move env to StmtExpr195 ret->set_env( assnExpr->get_env() );196 assnExpr->set_env( nullptr );197 delete assnExpr;198 return ret;199 }200 201 Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {202 unsigned tupleSize = tupleType->size();203 if ( ! typeMap.count( tupleSize ) ) {204 // generate struct type to replace tuple type based on the number of components in the tuple205 StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );206 decl->location = tupleType->location;207 decl->set_body( true );208 for ( size_t i = 0; i < tupleSize; ++i ) {209 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );210 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );211 decl->get_parameters().push_back( tyParam );212 }213 if ( tupleSize == 0 ) {214 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.215 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );216 }217 typeMap[tupleSize] = decl;218 declsToAddBefore.push_back( decl );219 }220 Type::Qualifiers qualifiers = tupleType->get_qualifiers();221 222 StructDecl * decl = typeMap[tupleSize];223 StructInstType * newType = new StructInstType( qualifiers, decl );224 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {225 Type * t = std::get<0>(p);226 newType->get_parameters().push_back( new TypeExpr( t->clone() ) );227 }228 delete tupleType;229 return newType;230 }231 232 Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {233 Expression * tuple = tupleExpr->tuple;234 assert( tuple );235 tupleExpr->tuple = nullptr;236 unsigned int idx = tupleExpr->index;237 TypeSubstitution * env = tupleExpr->env;238 tupleExpr->env = nullptr;239 delete tupleExpr;240 241 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {242 if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {243 // optimization: definitely pure tuple expr => can reduce to the only relevant component.244 assert( tupleExpr->exprs.size() > idx );245 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);246 Expression * ret = expr;247 ret->env = env;248 expr = nullptr; // remove from list so it can safely be deleted249 delete tupleExpr;250 return ret;251 }252 }253 254 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );255 StructDecl * structDecl = type->baseStruct;256 assert( structDecl->members.size() > idx );257 Declaration * member = *std::next(structDecl->members.begin(), idx);258 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );259 memExpr->env = env;260 return memExpr;261 }262 263 Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {264 if ( result->isVoid() ) {265 // void result - don't need to produce a value for cascading - just output a chain of comma exprs266 assert( ! exprs.empty() );267 std::list< Expression * >::const_iterator iter = exprs.begin();268 Expression * expr = new CastExpr( *iter++ );269 for ( ; iter != exprs.end(); ++iter ) {270 expr = new CommaExpr( expr, new CastExpr( *iter ) );271 }272 expr->set_env( env );273 return expr;274 } else {275 // typed tuple expression - produce a compound literal which performs each of the expressions276 // as a distinct part of its initializer - the produced compound literal may be used as part of277 // another expression278 std::list< Initializer * > inits;279 for ( Expression * expr : exprs ) {280 inits.push_back( new SingleInit( expr ) );281 }282 Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );283 expr->set_env( env );284 return expr;285 }286 }287 288 Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {289 Type * result = tupleExpr->get_result();290 std::list< Expression * > exprs = tupleExpr->get_exprs();291 assert( result );292 TypeSubstitution * env = tupleExpr->get_env();293 294 // remove data from shell and delete it295 tupleExpr->set_result( nullptr );296 tupleExpr->get_exprs().clear();297 tupleExpr->set_env( nullptr );298 delete tupleExpr;299 300 return replaceTupleExpr( result, exprs, env );301 }302 303 Type * makeTupleType( const std::list< Expression * > & exprs ) {304 // produce the TupleType which aggregates the types of the exprs305 std::list< Type * > types;306 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );307 for ( Expression * expr : exprs ) {308 assert( expr->get_result() );309 if ( expr->get_result()->isVoid() ) {310 // if the type of any expr is void, the type of the entire tuple is void311 return new VoidType( Type::Qualifiers() );312 }313 Type * type = expr->get_result()->clone();314 types.push_back( type );315 // the qualifiers on the tuple type are the qualifiers that exist on all component types316 qualifiers &= type->get_qualifiers();317 } // for318 if ( exprs.empty() ) qualifiers = Type::Qualifiers();319 return new TupleType( qualifiers, types );320 }321 32 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) { 322 33 // produce the TupleType which aggregates the types of the exprs … … 341 52 } 342 53 343 TypeInstType * isTtype( Type * type ) {344 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {345 if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {346 return inst;347 }348 }349 return nullptr;350 }351 352 const TypeInstType * isTtype( const Type * type ) {353 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {354 if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {355 return inst;356 }357 }358 return nullptr;359 }360 361 54 const ast::TypeInstType * isTtype( const ast::Type * type ) { 362 55 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { -
src/Tuples/Tuples.cc
r0030b508 rfc12f05 19 19 #include "AST/Inspect.hpp" 20 20 #include "AST/LinkageSpec.hpp" 21 #include "Common/PassVisitor.h"22 21 #include "InitTweak/InitTweak.h" 23 22 … … 25 24 26 25 namespace { 27 /// Checks if impurity (read: side-effects) may exist in a piece of code.28 /// Currently gives a very crude approximation, wherein any function29 /// call expression means the code may be impure.30 struct ImpurityDetector_old : public WithShortCircuiting {31 bool const ignoreUnique;32 bool maybeImpure;33 34 ImpurityDetector_old( bool ignoreUnique ) :35 ignoreUnique( ignoreUnique ), maybeImpure( false )36 {}37 38 void previsit( const ApplicationExpr * appExpr ) {39 visit_children = false;40 if ( const DeclarationWithType * function =41 InitTweak::getFunction( appExpr ) ) {42 if ( function->linkage == LinkageSpec::Intrinsic ) {43 if ( function->name == "*?" || function->name == "?[?]" ) {44 // intrinsic dereference, subscript are pure,45 // but need to recursively look for impurity46 visit_children = true;47 return;48 }49 }50 }51 maybeImpure = true;52 }53 54 void previsit( const UntypedExpr * ) {55 maybeImpure = true;56 visit_children = false;57 }58 59 void previsit( const UniqueExpr * ) {60 if ( ignoreUnique ) {61 // bottom out at unique expression.62 // The existence of a unique expression doesn't change the purity of an expression.63 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.64 visit_children = false;65 return;66 }67 }68 };69 70 bool detectImpurity( const Expression * expr, bool ignoreUnique ) {71 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );72 expr->accept( detector );73 return detector.pass.maybeImpure;74 }75 26 76 27 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives … … 110 61 } 111 62 112 bool maybeImpure( const Expression * expr ) {113 return detectImpurity( expr, false );114 }115 116 bool maybeImpureIgnoreUnique( const Expression * expr ) {117 return detectImpurity( expr, true );118 }119 120 63 } // namespace Tuples 121 64 -
src/Tuples/Tuples.h
r0030b508 rfc12f05 21 21 #include "AST/Fwd.hpp" 22 22 #include "AST/Node.hpp" 23 #include "SynTree/Expression.h"24 #include "SynTree/Declaration.h"25 #include "SynTree/Type.h"26 27 #include "ResolvExpr/AlternativeFinder.h"28 23 #include "ResolvExpr/CandidateFinder.hpp" 29 24 30 25 namespace Tuples { 31 26 // TupleAssignment.cc 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,33 std::vector< ResolvExpr::AlternativeFinder >& args );34 27 void handleTupleAssignment( 35 28 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, … … 38 31 // TupleExpansion.cc 39 32 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate 40 void expandMemberTuples( std::list< Declaration * > & translationUnit );41 33 void expandMemberTuples( ast::TranslationUnit & translationUnit ); 42 34 43 35 /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc. 44 void expandTuples( std::list< Declaration * > & translationUnit );45 36 void expandTuples( ast::TranslationUnit & translaionUnit ); 46 37 47 38 /// replaces UniqueExprs with a temporary variable and one call 48 void expandUniqueExpr( std::list< Declaration * > & translationUnit );49 39 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 50 40 51 41 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 52 Type * makeTupleType( const std::list< Expression * > & exprs );53 42 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 54 43 55 44 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 56 TypeInstType * isTtype( Type * type );57 const TypeInstType * isTtype( const Type * type );58 45 const ast::TypeInstType * isTtype( const ast::Type * type ); 59 46 60 47 /// returns true if the expression may contain side-effects. 61 bool maybeImpure( const Expression * expr );62 48 bool maybeImpure( const ast::Expr * expr ); 63 49 64 50 /// Returns true if the expression may contain side-effect, 65 51 /// ignoring the presence of unique expressions. 66 bool maybeImpureIgnoreUnique( const Expression * expr );67 52 bool maybeImpureIgnoreUnique( const ast::Expr * expr ); 68 53 } // namespace Tuples -
src/Validate/FindSpecialDecls.h
r0030b508 rfc12f05 16 16 #pragma once 17 17 18 #include <list> // for list19 20 class Declaration;21 class FunctionDecl;22 class StructDecl;23 class Type;24 25 18 namespace ast { 26 19 class TranslationUnit; … … 28 21 29 22 namespace Validate { 30 /// size_t type - set when size_t typedef is seen. Useful in a few places,31 /// such as in determining array dimension type32 extern Type * SizeType;33 34 /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.35 /// Useful for creating dereference ApplicationExprs without a full resolver pass.36 extern FunctionDecl * dereferenceOperator;37 38 /// special built-in functions and data structures necessary for destructor generation39 extern StructDecl * dtorStruct;40 extern FunctionDecl * dtorStructDestroy;41 42 /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.43 void findSpecialDecls( std::list< Declaration * > & translationUnit );44 23 45 24 /// Find and remember some of the special declarations that are useful for -
src/Validate/FixReturnTypes.cpp
r0030b508 rfc12f05 19 19 #include "AST/Pass.hpp" 20 20 #include "AST/Type.hpp" 21 #include "CodeGen/CodeGenerator .h"21 #include "CodeGen/CodeGeneratorNew.hpp" 22 22 #include "ResolvExpr/Unify.h" 23 23 -
src/Validate/module.mk
r0030b508 rfc12f05 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \19 18 Validate/FindSpecialDecls.h 20 19 … … 37 36 Validate/GenericParameter.cpp \ 38 37 Validate/GenericParameter.hpp \ 39 Validate/HandleAttributes.cc \40 Validate/HandleAttributes.h \41 38 Validate/HoistStruct.cpp \ 42 39 Validate/HoistStruct.hpp \ -
src/Virtual/ExpandCasts.cc
r0030b508 rfc12f05 24 24 #include "AST/Expr.hpp" 25 25 #include "AST/Pass.hpp" 26 #include "Common/PassVisitor.h" // for PassVisitor27 26 #include "Common/ScopedMap.h" // for ScopedMap 28 27 #include "Common/SemanticError.h" // for SemanticError 29 28 #include "SymTab/Mangler.h" // for mangleType 30 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl31 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address...32 #include "SynTree/Mutator.h" // for mutateAll33 #include "SynTree/Type.h" // for Type, PointerType, StructInstType34 #include "SynTree/Visitor.h" // for acceptAll35 29 36 30 namespace Virtual { … … 43 37 } 44 38 45 bool is_type_id_object( const ObjectDecl * objectDecl ) {46 const std::string & objectName = objectDecl->name;47 return is_prefix( "__cfatid_", objectName );48 }49 50 39 bool is_type_id_object( const ast::ObjectDecl * decl ) { 51 40 return is_prefix( "__cfatid_", decl->name ); … … 55 44 56 45 /// Maps virtual table types the instance for that type. 57 class VirtualTableMap final {58 ScopedMap<std::string, ObjectDecl *> vtable_instances;59 public:60 void enterScope() {61 vtable_instances.beginScope();62 }63 void leaveScope() {64 vtable_instances.endScope();65 }66 67 ObjectDecl * insert( ObjectDecl * vtableDecl ) {68 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );69 ObjectDecl *& value = vtable_instances[ mangledName ];70 if ( value ) {71 if ( vtableDecl->storageClasses.is_extern ) {72 return nullptr;73 } else if ( ! value->storageClasses.is_extern ) {74 return value;75 }76 }77 value = vtableDecl;78 return nullptr;79 }80 81 ObjectDecl * lookup( const Type * vtableType ) {82 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );83 const auto it = vtable_instances.find( mangledName );84 return ( vtable_instances.end() == it ) ? nullptr : it->second;85 }86 };87 88 class VirtualCastCore {89 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {90 Type * type = new StructInstType(91 Type::Qualifiers( Type::Const ), pvt_decl );92 for (int i = 0 ; i < level_of_indirection ; ++i) {93 type = new PointerType( noQualifiers, type );94 }95 return new CastExpr( expr, type );96 }97 98 public:99 VirtualCastCore() :100 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )101 {}102 103 void premutate( FunctionDecl * functionDecl );104 void premutate( StructDecl * structDecl );105 void premutate( ObjectDecl * objectDecl );106 107 Expression * postmutate( VirtualCastExpr * castExpr );108 109 VirtualTableMap indexer;110 private:111 FunctionDecl *vcast_decl;112 StructDecl *pvt_decl;113 };114 115 void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {116 if ( (! vcast_decl) &&117 functionDecl->get_name() == "__cfavir_virtual_cast" ) {118 vcast_decl = functionDecl;119 }120 }121 122 void VirtualCastCore::premutate( StructDecl * structDecl ) {123 if ( pvt_decl || ! structDecl->has_body() ) {124 return;125 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {126 pvt_decl = structDecl;127 }128 }129 130 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {131 if ( is_type_id_object( objectDecl ) ) {132 // Multiple definitions should be fine because of linkonce.133 indexer.insert( objectDecl );134 }135 }136 137 /// Better error locations for generated casts.138 CodeLocation castLocation( const VirtualCastExpr * castExpr ) {139 if ( castExpr->location.isSet() ) {140 return castExpr->location;141 } else if ( castExpr->arg->location.isSet() ) {142 return castExpr->arg->location;143 } else if ( castExpr->result->location.isSet() ) {144 return castExpr->result->location;145 } else {146 return CodeLocation();147 }148 }149 150 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {151 SemanticError( castLocation( castExpr ), message );152 }153 154 /// Get the base type from a pointer or reference.155 const Type * getBaseType( const Type * type ) {156 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {157 return target->base;158 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {159 return target->base;160 } else {161 return nullptr;162 }163 }164 165 /* Attempt to follow the "head" field of the structure to get the...166 * Returns nullptr on error, otherwise owner must free returned node.167 */168 StructInstType * followHeadPointerType(169 const StructInstType * oldType,170 const std::string& fieldName,171 const CodeLocation& errorLocation ) {172 173 // First section of the function is all about trying to fill this variable in.174 StructInstType * newType = nullptr;175 {176 const StructDecl * oldDecl = oldType->baseStruct;177 assert( oldDecl );178 179 // Helper function for throwing semantic errors.180 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {181 const std::string& context = "While following head pointer of " +182 oldDecl->name + " named '" + fieldName + "': ";183 SemanticError( errorLocation, context + message );184 };185 186 if ( oldDecl->members.empty() ) {187 throwError( "Type has no fields." );188 }189 const Declaration * memberDecl = oldDecl->members.front();190 assert( memberDecl );191 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );192 assert( fieldDecl );193 if ( fieldName != fieldDecl->name ) {194 throwError( "Head field did not have expected name." );195 }196 197 const Type * fieldType = fieldDecl->type;198 if ( nullptr == fieldType ) {199 throwError( "Could not get head field." );200 }201 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );202 if ( nullptr == ptrType ) {203 throwError( "First field is not a pointer type." );204 }205 assert( ptrType->base );206 newType = dynamic_cast<StructInstType *>( ptrType->base );207 if ( nullptr == newType ) {208 throwError( "First field does not point to a structure type." );209 }210 }211 212 // Now we can look into copying it.213 newType = newType->clone();214 if ( ! oldType->parameters.empty() ) {215 deleteAll( newType->parameters );216 newType->parameters.clear();217 cloneAll( oldType->parameters, newType->parameters );218 }219 return newType;220 }221 222 /// Get the type-id type from a virtual type.223 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {224 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );225 if ( nullptr == typeInst ) {226 return nullptr;227 }228 StructInstType * tableInst =229 followHeadPointerType( typeInst, "virtual_table", errorLocation );230 if ( nullptr == tableInst ) {231 return nullptr;232 }233 StructInstType * typeIdInst =234 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );235 delete tableInst;236 return typeIdInst;237 }238 239 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {240 assertf( castExpr->result, "Virtual Cast target not found before expansion." );241 242 assert( vcast_decl );243 assert( pvt_decl );244 245 const Type * base_type = getBaseType( castExpr->result );246 if ( nullptr == base_type ) {247 castError( castExpr, "Virtual cast target must be a pointer or reference type." );248 }249 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );250 if ( nullptr == type_id_type ) {251 castError( castExpr, "Ill formed virtual cast target type." );252 }253 ObjectDecl * type_id = indexer.lookup( type_id_type );254 delete type_id_type;255 if ( nullptr == type_id ) {256 castError( castExpr, "Virtual cast does not target a virtual type." );257 }258 259 Expression * result = new CastExpr(260 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {261 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),262 cast_to_type_id( castExpr->get_arg(), 2 ),263 } ),264 castExpr->get_result()->clone()265 );266 267 castExpr->set_arg( nullptr );268 castExpr->set_result( nullptr );269 delete castExpr;270 return result;271 }272 46 273 47 /// Better error locations for generated casts. … … 494 268 } // namespace 495 269 496 void expandCasts( std::list< Declaration * > & translationUnit ) {497 PassVisitor<VirtualCastCore> translator;498 mutateAll( translationUnit, translator );499 }500 501 270 void expandCasts( ast::TranslationUnit & translationUnit ) { 502 271 ast::Pass<ExpandCastsCore>::run( translationUnit ); -
src/Virtual/Tables.cc
r0030b508 rfc12f05 21 21 #include "AST/Stmt.hpp" 22 22 #include "AST/Type.hpp" 23 #include <SynTree/Attribute.h>24 #include <SynTree/Declaration.h>25 #include <SynTree/Expression.h>26 #include <SynTree/Statement.h>27 #include <SynTree/Type.h>28 23 29 24 namespace Virtual { … … 65 60 return 17 < name.size() && '_' == name[0] && 66 61 std::string("_vtable_instance") == name.substr(1, name.size() - 17); 67 }68 69 static ObjectDecl * makeVtableDeclaration(70 std::string const & name,71 StructInstType * type, Initializer * init ) {72 Type::StorageClasses storage = noStorageClasses;73 if ( nullptr == init ) {74 storage.is_extern = true;75 }76 return new ObjectDecl(77 name,78 storage,79 LinkageSpec::Cforall,80 nullptr,81 type,82 init83 );84 62 } 85 63 … … 101 79 } 102 80 103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {104 assert( type );105 return makeVtableDeclaration( name, type, nullptr );106 }107 108 81 ast::ObjectDecl * makeVtableForward( 109 82 CodeLocation const & location, std::string const & name, … … 111 84 assert( vtableType ); 112 85 return makeVtableDeclaration( location, name, vtableType, nullptr ); 113 }114 115 ObjectDecl * makeVtableInstance(116 std::string const & name, StructInstType * vtableType,117 Type * objectType, Initializer * init ) {118 assert( vtableType );119 assert( objectType );120 StructDecl * vtableStruct = vtableType->baseStruct;121 // Build the initialization122 if ( nullptr == init ) {123 std::list< Initializer * > inits;124 125 // This is going to have to be run before the resolver to connect expressions.126 for ( auto field : vtableStruct->members ) {127 if ( std::string( "parent" ) == field->name ) {128 // This will not work with polymorphic state.129 auto oField = strict_dynamic_cast< ObjectDecl * >( field );130 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );131 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );132 std::string const & parentInstance = instanceName( parentType->name );133 inits.push_back(134 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );135 } else if ( std::string( "__cfavir_typeid" ) == field->name ) {136 std::string const & baseType = baseTypeName( vtableType->name );137 std::string const & typeId = typeIdName( baseType );138 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );139 } else if ( std::string( "size" ) == field->name ) {140 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );141 } else if ( std::string( "align" ) == field->name ) {142 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );143 } else {144 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );145 }146 }147 init = new ListInit( inits );148 // This should initialize everything except the parent pointer, the149 // size-of and align-of fields. These should be inserted.150 } else {151 assert(false);152 }153 return makeVtableDeclaration( name, vtableType, init );154 86 } 155 87 … … 224 156 } 225 157 226 FunctionDecl * makeGetExceptionForward(227 Type * vtableType, Type * exceptType ) {228 assert( vtableType );229 assert( exceptType );230 FunctionType * type = new FunctionType( noQualifiers, false );231 vtableType->tq.is_const = true;232 type->returnVals.push_back( new ObjectDecl(233 "_retvalue",234 noStorageClasses,235 LinkageSpec::Cforall,236 nullptr,237 new ReferenceType( noQualifiers, vtableType ),238 nullptr,239 { new Attribute("unused") }240 ) );241 type->parameters.push_back( new ObjectDecl(242 "__unused",243 noStorageClasses,244 LinkageSpec::Cforall,245 nullptr,246 new PointerType( noQualifiers, exceptType ),247 nullptr,248 { new Attribute("unused") }249 ) );250 return new FunctionDecl(251 functionName,252 noStorageClasses,253 LinkageSpec::Cforall,254 type,255 nullptr256 );257 }258 259 158 ast::FunctionDecl * makeGetExceptionForward( 260 159 CodeLocation const & location, … … 284 183 } 285 184 286 FunctionDecl * makeGetExceptionFunction(287 ObjectDecl * vtableInstance, Type * exceptType ) {288 assert( vtableInstance );289 assert( exceptType );290 FunctionDecl * func = makeGetExceptionForward(291 vtableInstance->type->clone(), exceptType );292 func->statements = new CompoundStmt( {293 new ReturnStmt( new VariableExpr( vtableInstance ) ),294 } );295 return func;296 }297 298 185 ast::FunctionDecl * makeGetExceptionFunction( 299 186 CodeLocation const & location, … … 307 194 } ); 308 195 return func; 309 }310 311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {312 assert( typeIdType );313 StructInstType * type = typeIdType->clone();314 type->tq.is_const = true;315 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );316 return new ObjectDecl(317 typeid_name,318 noStorageClasses,319 LinkageSpec::Cforall,320 /* bitfieldWidth */ nullptr,321 type,322 new ListInit( { new SingleInit(323 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )324 ) } ),325 { new Attribute( "cfa_linkonce", {} ) },326 noFuncSpecifiers327 );328 196 } 329 197 -
src/Virtual/Tables.h
r0030b508 rfc12f05 18 18 #include <string> 19 19 #include "AST/Fwd.hpp" 20 class Declaration;21 class Expression;22 class FunctionDecl;23 class Initializer;24 class ObjectDecl;25 class StructDecl;26 class StructInstType;27 class Type;28 20 29 21 namespace Virtual { … … 37 29 bool isVTableInstanceName( std::string const & name ); 38 30 39 ObjectDecl * makeVtableForward(40 std::string const & name, StructInstType * vtableType );41 31 /* Create a forward declaration of a vtable of the given type. 42 32 * vtableType node is consumed. … … 46 36 ast::StructInstType const * vtableType ); 47 37 48 ObjectDecl * makeVtableInstance(49 std::string const & name,50 StructInstType * vtableType, Type * objectType,51 Initializer * init = nullptr );52 38 /* Create an initialized definition of a vtable. 53 39 * vtableType and init (if provided) nodes are consumed. … … 61 47 62 48 // Some special code for how exceptions interact with virtual tables. 63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType ); 49 64 50 /* Create a forward declaration of the exception virtual function 65 51 * linking the vtableType to the exceptType. Both nodes are consumed. … … 70 56 ast::Type const * exceptType ); 71 57 72 FunctionDecl * makeGetExceptionFunction(73 ObjectDecl * vtableInstance, Type * exceptType );74 58 /* Create the definition of the exception virtual function. 75 59 * exceptType node is consumed. … … 79 63 ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ); 80 64 81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );82 65 /* Build an instance of the type-id from the type of the type-id. 83 66 * TODO: Should take the parent type. Currently locked to the exception_t. -
src/main.cc
r0030b508 rfc12f05 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Sep 28 22:28:45202313 // Update Count : 6 8712 // Last Modified On : Wed Nov 1 21:12:58 2023 13 // Update Count : 690 14 14 // 15 15 … … 29 29 #include <string> // for char_traits, operator<< 30 30 31 #include "AST/Convert.hpp"32 31 #include "AST/Pass.hpp" // for pass_visitor_stats 32 #include "AST/Print.hpp" // for printAll 33 33 #include "AST/TranslationUnit.hpp" // for TranslationUnit 34 34 #include "AST/Util.hpp" // for checkInvariants … … 39 39 #include "CodeGen/Generate.h" // for generate 40 40 #include "CodeGen/LinkOnce.h" // for translateLinkOnce 41 #include "CodeTools/TrackLoc.h" // for fillLocations42 41 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 43 42 #include "Common/DeclStats.hpp" // for printDeclStats … … 65 64 #include "ResolvExpr/EraseWith.hpp" // for eraseWith 66 65 #include "ResolvExpr/Resolver.h" // for resolve 67 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic68 #include "SynTree/Declaration.h" // for Declaration69 66 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 70 67 #include "Validate/Autogen.hpp" // for autogenerateRoutines … … 94 91 using namespace Stats::Counters; 95 92 { 96 static auto group = build<CounterGroup>( "Pass Visitor " );93 static auto group = build<CounterGroup>( "Pass Visitor Template" ); 97 94 auto pass = build<CounterGroup>( name, group ); 98 pass_visitor_stats.depth = 0; 99 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 100 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 101 } 102 { 103 static auto group = build<CounterGroup>( "Syntax Node" ); 104 auto pass = build<CounterGroup>( name, group ); 105 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass ); 95 ast::pass_visitor_stats.depth = 0; 96 ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass ); 97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass ); 106 98 } 107 99 } … … 132 124 133 125 static void parse_cmdline( int argc, char * argv[] ); 134 static void dump( list< Declaration * > & translationUnit, ostream & out = cout );135 126 static void dump( ast::TranslationUnit && transUnit, ostream & out = cout ); 136 127 … … 246 237 FILE * input; // use FILE rather than istream because yyin is FILE 247 238 ostream * output = & cout; 248 list< Declaration * > translationUnit;249 239 ast::TranslationUnit transUnit; 250 240 … … 260 250 261 251 parse_cmdline( argc, argv ); // process command-line arguments 262 CodeGen::FixMain::setReplaceMain( !nomainp );263 252 264 253 if ( waiting_for_gdb ) { … … 290 279 291 280 // Read to gcc builtins, if not generating the cfa library 292 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf ").c_str(), "r" );281 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" ); 293 282 assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" ); 294 283 parse( gcc_builtins, ast::Linkage::Compiler ); 295 284 296 285 // read the extra prelude in, if not generating the cfa library 297 FILE * extras = fopen( (PreludeDirector + "/extras.cf ").c_str(), "r" );286 FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" ); 298 287 assertf( extras, "cannot open extras.cf\n" ); 299 288 parse( extras, ast::Linkage::BuiltinC ); … … 306 295 307 296 // Read to cfa builtins, if not generating the cfa library 308 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf ").c_str(), "r" );297 FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" ); 309 298 assertf( builtins, "cannot open builtins.cf\n" ); 310 299 parse( builtins, ast::Linkage::BuiltinCFA ); … … 319 308 320 309 Stats::Time::StopBlock(); 321 322 if (Stats::Counters::enabled) {323 ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");324 ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");325 }326 310 327 311 PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit ); … … 409 393 PASS( "Translate Tries", ControlStruct::translateTries, transUnit ); 410 394 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit ); 395 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp ); 411 396 412 397 // Needs to happen before tuple types are expanded. … … 427 412 PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit ); 428 413 429 translationUnit = convert( std::move( transUnit ) );430 431 414 // Code has been lowered to C, now we can start generation. 432 415 433 DUMP( bcodegenp, translationUnit);416 DUMP( bcodegenp, std::move( transUnit ) ); 434 417 435 418 if ( optind < argc ) { // any commands after the flags and input file ? => output file name … … 437 420 } // if 438 421 439 CodeTools::fillLocations( translationUnit ); 440 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ); 441 442 CodeGen::FixMain::fix( translationUnit, *output, 443 (PreludeDirector + "/bootloader.c").c_str() ); 422 PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false ); 423 CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() ); 424 444 425 if ( output != &cout ) { 445 426 delete output; … … 448 429 if ( errorp ) { 449 430 cerr << "---AST at error:---" << endl; 450 // We check which section the errors came from without looking at 451 // transUnit because std::move means it could look like anything. 452 if ( !translationUnit.empty() ) { 453 dump( translationUnit, cerr ); 454 } else { 455 dump( std::move( transUnit ), cerr ); 456 } 431 dump( std::move( transUnit ), cerr ); 457 432 cerr << endl << "---End of AST, begin error message:---\n" << endl; 458 433 } // if … … 480 455 } // try 481 456 482 deleteAll( translationUnit );483 457 Stats::print(); 484 458 return EXIT_SUCCESS; … … 710 684 } // parse_cmdline 711 685 712 static bool notPrelude( Declaration * decl ) { 713 return ! LinkageSpec::isBuiltin( decl->get_linkage() ); 714 } // notPrelude 715 716 static void dump( list< Declaration * > & translationUnit, ostream & out ) { 717 list< Declaration * > decls; 718 686 static bool notPrelude( ast::ptr<ast::Decl> & decl ) { 687 return !decl->linkage.is_builtin; 688 } 689 690 static void dump( ast::TranslationUnit && unit, std::ostream & out ) { 691 // May filter out all prelude declarations. 719 692 if ( genproto ) { 720 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude ); 693 std::list<ast::ptr<ast::Decl>> decls; 694 std::copy_if( unit.decls.begin(), unit.decls.end(), 695 std::back_inserter( decls ), notPrelude ); 696 decls.swap( unit.decls ); 697 } 698 699 // May print as full dump or as code generation. 700 if ( codegenp ) { 701 CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false ); 721 702 } else { 722 decls = translationUnit; 723 } // if 724 725 // depending on commandline options, either generate code or dump the AST 726 if ( codegenp ) { 727 CodeGen::generate( decls, out, ! genproto, prettycodegenp ); 728 } else { 729 printAll( decls, out ); 730 } // if 731 deleteAll( translationUnit ); 732 } // dump 733 734 static void dump( ast::TranslationUnit && transUnit, ostream & out ) { 735 std::list< Declaration * > translationUnit = convert( std::move( transUnit ) ); 736 dump( translationUnit, out ); 703 ast::printAll( out, unit.decls ); 704 } 737 705 } 738 706 -
tests/collections/.expect/string-istream-manip.txt
r0030b508 rfc12f05 69 69 13 wwwwwwww 70 70 14 cccc 71 15 71 15 q 72 72 1 yyyyyyyyyyyyyyyyyyyy 73 73 2 abcxxx … … 84 84 13 wwwwwwww 85 85 14 cccc 86 15 86 15 q -
tests/collections/string-istream-manip.cfa
r0030b508 rfc12f05 38 38 void echoTillX(const char * casename) { 39 39 string s; 40 do { 40 // loop assumes behaviour not tested until main-case #15: 41 // on reading nothing, the prior string value is left alone 42 do { 43 s = ""; 41 44 forceStringHeapFreeSpaceTo(9); 42 45 sin | s; … … 54 57 string s; 55 58 do { 59 s = ""; 56 60 sin | plainjane( s ); 57 61 sout | casename | s; … … 68 72 string_res s; 69 73 do { 74 s = ""; 70 75 sin | plainjane( s ); 71 76 sout | casename | s; … … 82 87 string s; 83 88 do { 89 s = ""; 84 90 sin | skip("-\n"); 85 91 sin | incl( ".:|# x", s ); … … 97 103 string s; 98 104 do { 105 s = ""; 99 106 sin | skip("-\n"); 100 107 sin | excl( "-\n", s ); … … 113 120 string s; 114 121 do { 122 s = ""; 115 123 sin | getline( s ); 116 124 sout | casename | s; … … 127 135 string s; 128 136 do { 137 s = ""; 129 138 sin | getline( s, '@' ); 130 139 sout | casename | s; -
tests/concurrency/actors/.expect/dynamic.txt
r0030b508 rfc12f05 1 1 starting 2 2 started 3 stopping4 3 Done 5 4 stopped -
tests/concurrency/actors/.expect/static.txt
r0030b508 rfc12f05 1 1 starting 2 2 started 3 stopping4 3 Done 5 4 stopped -
tests/concurrency/actors/dynamic.cfa
r0030b508 rfc12f05 58 58 *d_actor | *d_msg; 59 59 60 sout | "stopping";61 62 60 stop_actor_system(); 63 61 -
tests/concurrency/actors/static.cfa
r0030b508 rfc12f05 55 55 actor | msg; 56 56 57 sout | "stopping";58 59 57 stop_actor_system(); 60 58 -
tests/concurrency/cofor.cfa
r0030b508 rfc12f05 1 1 #include <cofor.hfa> 2 3 2 4 3 void add_num( long * total, long val ) { __atomic_fetch_add( total, (long)val, __ATOMIC_SEQ_CST ); } … … 8 7 processor p[4]; 9 8 long total = 0; 10 COFOR( i, 0, 10, __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); ); 9 cofor( i; 10 ) { 10 __atomic_fetch_add( &total, i, __ATOMIC_SEQ_CST ); 11 } 11 12 { 12 13 corun; // does nothing -
tests/concurrency/waitfor/parse.cfa
r0030b508 rfc12f05 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 10 22:52:18202313 // Update Count : 6 412 // Last Modified On : Wed Nov 1 07:28:19 2023 13 // Update Count : 65 14 14 // 15 15 … … 258 258 // Local Variables: // 259 259 // tab-width: 4 // 260 // compile-command: "cfa waitfor.cfa" //260 // compile-command: "cfa parse.cfa" // 261 261 // End: // -
tests/concurrency/waituntil/channel_close.cfa
r0030b508 rfc12f05 26 26 for( ;; ) { 27 27 if ( useAnd ) { 28 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }29 and waituntil( (in2 << B) ) { assert( B_removes == in2 ); B_removes++; removes++; }28 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; } 29 and waituntil( (in2 << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( B_removes == in2 ); B_removes++; removes++; } 30 30 continue; 31 31 } 32 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }33 or waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; }32 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; } 33 or waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); ( B_removes == in ); B_removes++; removes++; } 34 34 } 35 35 } catchResume ( channel_closed * e ) {} // continue to remove until would block … … 37 37 try { 38 38 for( ;; ) 39 waituntil( (in << A) ) { assert( A_removes == in ); A_removes++; removes++; }39 waituntil( (in << A) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( A_removes == in ); A_removes++; removes++; } 40 40 } catchResume ( channel_closed * e ) {} // continue to remove until would block 41 41 catch ( channel_closed * e ) {} 42 42 try { 43 43 for( ;; ) 44 waituntil( (in << B) ) { assert( B_removes == in ); B_removes++; removes++; }44 waituntil( (in << B) ) { __atomic_thread_fence( __ATOMIC_SEQ_CST ); assert( B_removes == in ); B_removes++; removes++; } 45 45 } catchResume ( channel_closed * e ) {} // continue to remove until would block 46 46 catch ( channel_closed * e ) {} -
tests/genericUnion.cfa
r0030b508 rfc12f05 10 10 // Created On : Tue Dec 25 14:42:46 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 25 14:46:33 201813 // Update Count : 212 // Last Modified On : Fri Oct 20 09:13:26 2023 13 // Update Count : 15 14 14 // 15 15 16 #include <fstream.hfa> 16 17 #include <limits.hfa> 17 18 18 forall( T)19 forall( T ) 19 20 union ByteView { 20 21 T val; … … 23 24 24 25 forall(T) 25 void print( ByteView(T) x) {26 for ( int i = 0; i < sizeof(int); i++) {// want to change to sizeof(T)27 printf("%02x", x.bytes[i] & 0xff);26 void print( ByteView(T) x ) { 27 for ( i; sizeof(int) ) { // want to change to sizeof(T) 28 sout | nobase( pad0( wd( 2, hex( x.bytes[i] & 0xff ) ) ) ) | nosep; 28 29 } 29 30 } 30 31 31 32 forall(T) 32 void f( ByteView(T) x, T val) {33 print( x);34 printf(" ");33 void f( ByteView(T) x, T val ) { 34 print( x ); 35 sout | " "; 35 36 x.val = val; 36 print( x);37 printf("\n");37 print( x ); 38 sout | nl; 38 39 } 39 40 40 41 int main() { 42 sout | nlOff; 41 43 ByteView(unsigned) u = { 0 }; 42 44 ByteView(int) i = { 0 }; 43 f( u, MAX);44 f( i, -1);45 f( u, MAX ); 46 f( i, -1 ); 45 47 } 46 48 -
tests/io/.expect/manipulatorsInput.arm64.txt
r0030b508 rfc12f05 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsInput.x64.txt
r0030b508 rfc12f05 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsInput.x86.txt
r0030b508 rfc12f05 24 24 3 abcxxx 25 25 4 aaaaaaaa 26 5 aaaaaaaa26 5 27 27 6 aabbccbb 28 28 7 dddwww 29 8 dddwww30 9 dddwww29 8 30 9 31 31 10 aaaaaaaa 32 32 11 wwwwwwww 33 12 wwwwwwww34 13 wwwwwwww33 12 34 13 35 35 14 cccc 36 36 15 -
tests/io/.expect/manipulatorsOutput4.txt
r0030b508 rfc12f05 225 225 -1.55051464826854e+28 -15.5051e27 -15.5051e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 -0015.505e27 -0015.505e27 -15.50515e27 -15.50515e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 -15.505e27 -15.505e27 -15.50515e27 -15.50515e27 226 226 -6.51216152272788e+29 -651.216e27 -651.216e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 -00651.22e27 -00651.22e27 -651.21615e27 -651.21615e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 -651.22e27 -651.22e27 -651.21615e27 -651.21615e27 227 0 1 1 1.0 1 228 1 2 2 2.0 2 229 2 4 4 4.0 4 230 3 8 8 8.0 8 231 4 16 16 16.0 16 232 5 32 32 32.0 32 233 6 64 64 64.0 64 234 7 128 128 128.0 128 235 8 256 256 256.0 256 236 9 512 512 512.0 512 237 10 1024 1.024K 1.0K 1K 238 11 2048 2.048K 2.0K 2K 239 12 4096 4.096K 4.1K 4K 240 13 8192 8.192K 8.2K 8K 241 14 16384 16.384K 16.4K 16K 242 15 32768 32.768K 32.8K 33K 243 16 65536 65.536K 65.5K 66K 244 17 131072 131.072K 131.1K 131K 245 18 262144 262.144K 262.1K 262K 246 19 524288 524.288K 524.3K 524K 247 20 1048576 1.04858M 1.0M 1M 248 21 2097152 2.09715M 2.1M 2M 249 22 4194304 4.1943M 4.2M 4M 250 23 8388608 8.38861M 8.4M 8M 251 24 16777216 16.7772M 16.8M 17M 252 25 33554432 33.5544M 33.6M 34M 253 26 67108864 67.1089M 67.1M 67M 254 27 134217728 134.218M 134.2M 134M 255 28 268435456 268.435M 268.4M 268M 256 29 536870912 536.871M 536.9M 537M 257 30 1073741824 1.07374G 1.1G 1G 258 31 2147483648 2.14748G 2.1G 2G -
tests/io/manipulatorsOutput4.cfa
r0030b508 rfc12f05 7 7 // Created On : Tue Apr 13 17:55:02 2021 8 8 // Last Modified By : Peter A. Buhr 9 // Last Modified On : Tue Apr 13 18:00:33 202110 // Update Count : 49 // Last Modified On : Tue Oct 17 08:37:42 2023 10 // Update Count : 5 11 11 // 12 12 … … 42 42 | left(ws(12,5, eng(w) )) | left(sign(ws(12,5, eng(w) ))) | left(wd(12,5, eng(w) )) | left(sign(wd(12,5, eng(w) ))) | left(pad0(ws(12,5, eng(w) ))) | left(pad0(sign(ws(12,5, eng(w) )))) | left(pad0(wd(12,5, eng(w) ))) | left(pad0(sign(wd(12,5, eng(w) )))); 43 43 } // for 44 45 for ( exp; sizeof(int) * 8 ) { 46 size_t pow2 = 1z << exp; 47 sout | exp | pow2 | unit(eng(pow2)) | wd(0,1, unit(eng( pow2 ))) | wd(0,0, unit(eng(pow2))); 48 } // for 44 49 } // main 45 50
Note:
See TracChangeset
for help on using the changeset viewer.