Changeset 63be3387
- Timestamp:
- Nov 14, 2022, 11:52:44 AM (3 years ago)
- Branches:
- ADT, ast-experimental, master
- Children:
- 7d9598d8
- Parents:
- b77f0e1 (diff), 19a8c40 (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:
-
- 27 added
- 2 deleted
- 72 edited
Legend:
- Unmodified
- Added
- Removed
-
benchmark/io/http/worker.hfa
rb77f0e1 r63be3387 2 2 3 3 #include <iofwd.hfa> 4 #include < queueLockFree.hfa>4 #include <containers/lockfree.hfa> 5 5 #include <thread.hfa> 6 6 -
doc/theses/mike_brooks_MMath/programs/hello-md.cfa
rb77f0e1 r63be3387 1 1 #include "array.hfa" 2 3 4 trait ix( C &, E &, ztype(N) ) {5 E & ?[?]( C &, ptrdiff_t );6 void __taglen( tag(C), tag(N) );7 };8 9 forall( ztype(Zn), ztype(S), Timmed &, Tbase & )10 void __taglen( tag(arpk(Zn, S, Timmed, Tbase)), tag(Zn) ) {}11 2 12 3 … … 38 29 39 30 40 forall( ztype( N ) ) 31 32 33 34 35 36 37 38 39 40 forall( [N] ) 41 41 void print1d_cstyle( array(float, N) & c ); 42 42 43 forall( C &, ztype( N ) | ix( C, float, N ) )43 forall( [N], C & | ar( C, float, N ) ) 44 44 void print1d( C & c ); 45 45 … … 58 58 59 59 60 forall( ztype( N ))60 forall( [N] ) 61 61 void print1d_cstyle( array(float, N) & c ) { 62 for( i; z(N)) {62 for( i; N ) { 63 63 printf("%.1f ", c[i]); 64 64 } … … 78 78 79 79 80 forall( C &, ztype( N ) | ix( C, float, N ) )80 forall( [N], C & | ar( C, float, N ) ) 81 81 void print1d( C & c ) { 82 for( i; z(N)) {82 for( i; N ) { 83 83 printf("%.1f ", c[i]); 84 84 } … … 99 99 100 100 101 void fill( array(float, Z(5), Z(7)) & a ) {101 void fill( array(float, 5, 7) & a ) { 102 102 for ( i; (ptrdiff_t) 5 ) { 103 103 for ( j; 7 ) { 104 a[ [i,j]] = 1.0 * i + 0.1 * j;105 printf("%.1f ", a[ [i,j]]);104 a[i,j] = 1.0 * i + 0.1 * j; 105 printf("%.1f ", a[i,j]); 106 106 } 107 107 printf("\n"); … … 118 118 119 119 120 array( float, Z(5), Z(7)) a;120 array( float, 5, 7 ) a; 121 121 fill(a); 122 122 /* … … 148 148 149 149 150 print1d( a[ [ 2, all ]] ); // 2.0 2.1 2.2 2.3 2.4 2.5 2.6151 print1d( a[ [ all, 3 ]] ); // 0.3 1.3 2.3 3.3 4.3150 print1d( a[ 2, all ] ); // 2.0 2.1 2.2 2.3 2.4 2.5 2.6 151 print1d( a[ all, 3 ] ); // 0.3 1.3 2.3 3.3 4.3 152 152 153 153 154 154 155 print1d_cstyle( a[ [ 2, all ]] );155 print1d_cstyle( a[ 2, all ] ); 156 156 157 157 … … 161 161 162 162 163 #ifdef SHOW ERR1163 #ifdef SHOW_ERROR_1 164 164 165 print1d_cstyle( a[ [ all, 2 ]] ); // bad165 print1d_cstyle( a[ all, 2 ] ); // bad 166 166 167 167 #endif -
doc/theses/thierry_delisle_PhD/thesis/text/front.tex
rb77f0e1 r63be3387 161 161 Thanks to Andrew Beach, Michael Brooks, Colby Parsons, Mubeen Zulfiqar, Fangren Yu and Jiada Liang for their work on the \CFA project as well as all the discussions which have helped me concretize the ideas in this thesis. 162 162 163 Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science and the corporate partnership with Huawei Ltd.163 Finally, I acknowledge that this has been possible thanks to the financial help offered by the David R. Cheriton School of Computer Science, the corporate partnership with Huawei Ltd. and the Natural Sciences and Engineering Research Council. 164 164 \cleardoublepage 165 165 -
libcfa/src/Makefile.am
rb77f0e1 r63be3387 62 62 containers/array.hfa \ 63 63 containers/list.hfa \ 64 containers/queueLockFree.hfa \ 65 containers/stackLockFree.hfa \ 64 containers/lockfree.hfa \ 66 65 containers/string_sharectx.hfa \ 67 66 containers/vector2.hfa \ … … 112 111 concurrency/invoke.h \ 113 112 concurrency/future.hfa \ 113 concurrency/once.hfa \ 114 114 concurrency/kernel/fwd.hfa \ 115 115 concurrency/mutex_stmt.hfa … … 127 127 128 128 thread_libsrc = ${inst_thread_headers_src} ${inst_thread_headers_src:.hfa=.cfa} \ 129 interpose_thread.cfa \ 129 130 bits/signal.hfa \ 130 131 concurrency/clib/cfathread.cfa \ … … 145 146 concurrency/stats.cfa \ 146 147 concurrency/stats.hfa \ 147 concurrency/stats.hfa 148 concurrency/stats.hfa \ 149 concurrency/pthread.cfa 148 150 149 151 else -
libcfa/src/bits/containers.hfa
rb77f0e1 r63be3387 152 152 153 153 void append( __queue(T) & this, T * val ) with(this) { 154 verify(get_next( *val ) == 0p); 154 155 verify(this.tail != 0p); 155 156 verify(*this.tail == 1p); -
libcfa/src/bits/defs.hfa
rb77f0e1 r63be3387 30 30 #ifdef __cforall 31 31 #define __cfa_anonymous_object(x) inline struct x 32 #define __cfa_dlink(x) inline dlink(x)33 32 #else 34 33 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object 35 #define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute36 34 #endif 37 35 -
libcfa/src/concurrency/clib/cfathread.cfa
rb77f0e1 r63be3387 172 172 173 173 pthread_attr_t attr; 174 if (int ret = pthread_attr_init(&attr); 0 != ret) {174 if (int ret = __cfaabi_pthread_attr_init(&attr); 0 != ret) { 175 175 abort | "failed to create master epoll thread attr: " | ret | strerror(ret); 176 176 } 177 177 178 if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {178 if (int ret = __cfaabi_pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) { 179 179 abort | "failed to create master epoll thread: " | ret | strerror(ret); 180 180 } -
libcfa/src/concurrency/invoke.h
rb77f0e1 r63be3387 146 146 147 147 // Link lists fields 148 // instrusive link field for threads 148 // instrusive link field for threads in the ready-queue 149 149 struct __thread_desc_link { 150 150 struct thread$ * next; 151 151 volatile unsigned long long ts; 152 152 }; 153 154 // Link lists fields 155 // instrusive link field for threads in the user_link/cltr_link 156 struct __thread_user_link { 157 #ifdef __cforall 158 inline dlink(thread$); 159 #else 160 struct thread$ * next; struct thread$ * back; 161 #endif 162 }; 163 _Static_assert(sizeof(struct __thread_user_link) == 2 * sizeof(struct thread$ *), "__thread_user_link should be consistent in C and Cforall"); 153 164 154 165 struct thread$ { … … 159 170 // Link lists fields 160 171 // instrusive link field for threads 161 struct __thread_desc_link link;172 struct __thread_desc_link rdy_link; 162 173 163 174 // current execution status for coroutine … … 195 206 struct __monitor_group_t monitors; 196 207 197 // used to put threads on dlistdata structure198 __cfa_dlink(thread$);199 200 struct { 201 struct thread$ * next;202 struct thread$ * prev;203 } node;208 // intrusive link fields, used for locks, monitors and any user defined data structure 209 // default link fields for dlist 210 struct __thread_user_link user_link; 211 212 // secondary intrusive link fields, used for global cluster list 213 // default link fields for dlist 214 struct __thread_user_link cltr_link; 204 215 205 216 // used to store state between clh lock/unlock … … 214 225 215 226 #if defined( __CFA_WITH_VERIFY__ ) 227 struct processor * volatile executing; 216 228 void * canary; 217 229 #endif 218 230 }; 219 #ifdef __cforall 220 P9_EMBEDDED( thread$, dlink(thread$) ) 221 #endif 231 222 232 // Wrapper for gdb 223 233 struct cfathread_thread_t { struct thread$ debug; }; … … 231 241 #ifdef __cforall 232 242 extern "Cforall" { 243 static inline thread$ * volatile & ?`next ( thread$ * this ) { 244 return this->user_link.next; 245 } 233 246 234 247 static inline thread$ *& get_next( thread$ & this ) __attribute__((const)) { 235 return this.link.next; 236 } 237 238 static inline [thread$ *&, thread$ *& ] __get( thread$ & this ) __attribute__((const)) { 239 return this.node.[next, prev]; 240 } 248 return this.user_link.next; 249 } 250 251 static inline tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) { 252 dlink(thread$) & b = this.user_link; 253 tytagref( dlink(thread$), dlink(thread$) ) result = { b }; 254 return result; 255 } 256 257 static inline tytagref(struct __thread_user_link, dlink(thread$)) ?`inner( struct thread$ & this ) { 258 struct __thread_user_link & ib = this.cltr_link; 259 dlink(thread$) & b = ib`inner; 260 tytagref(struct __thread_user_link, dlink(thread$)) result = { b }; 261 return result; 262 } 263 264 P9_EMBEDDED(struct __thread_user_link, dlink(thread$)) 241 265 242 266 static inline void ?{}(__monitor_group_t & this) { -
libcfa/src/concurrency/io.cfa
rb77f0e1 r63be3387 610 610 if( we ) { 611 611 sigval_t value = { PREEMPT_IO }; 612 pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);612 __cfaabi_pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value); 613 613 } 614 614 … … 639 639 } 640 640 } 641 642 #if defined(CFA_WITH_IO_URING_IDLE)643 bool __kernel_read(struct processor * proc, io_future_t & future, iovec & iov, int fd) {644 io_context$ * ctx = proc->io.ctx;645 /* paranoid */ verify( ! __preemption_enabled() );646 /* paranoid */ verify( proc == __cfaabi_tls.this_processor );647 /* paranoid */ verify( ctx );648 649 __u32 idx;650 struct io_uring_sqe * sqe;651 652 // We can proceed to the fast path653 if( !__alloc(ctx, &idx, 1) ) {654 /* paranoid */ verify( false ); // for now check if this happens, next time just abort the sleep.655 return false;656 }657 658 // Allocation was successful659 __fill( &sqe, 1, &idx, ctx );660 661 sqe->user_data = (uintptr_t)&future;662 sqe->flags = 0;663 sqe->fd = fd;664 sqe->off = 0;665 sqe->ioprio = 0;666 sqe->fsync_flags = 0;667 sqe->__pad2[0] = 0;668 sqe->__pad2[1] = 0;669 sqe->__pad2[2] = 0;670 671 #if defined(CFA_HAVE_IORING_OP_READ)672 sqe->opcode = IORING_OP_READ;673 sqe->addr = (uint64_t)iov.iov_base;674 sqe->len = iov.iov_len;675 #elif defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV)676 sqe->opcode = IORING_OP_READV;677 sqe->addr = (uintptr_t)&iov;678 sqe->len = 1;679 #else680 #error CFA_WITH_IO_URING_IDLE but none of CFA_HAVE_READV, CFA_HAVE_IORING_OP_READV or CFA_HAVE_IORING_OP_READ defined681 #endif682 683 asm volatile("": : :"memory");684 685 /* paranoid */ verify( sqe->user_data == (uintptr_t)&future );686 __submit_only( ctx, &idx, 1 );687 688 /* paranoid */ verify( proc == __cfaabi_tls.this_processor );689 /* paranoid */ verify( ! __preemption_enabled() );690 691 return true;692 }693 694 void __cfa_io_idle( struct processor * proc ) {695 iovec iov;696 __atomic_acquire( &proc->io.ctx->cq.lock );697 698 __attribute__((used)) volatile bool was_reset = false;699 700 with( proc->idle_wctx) {701 702 // Do we already have a pending read703 if(available(*ftr)) {704 // There is no pending read, we need to add one705 reset(*ftr);706 707 iov.iov_base = rdbuf;708 iov.iov_len = sizeof(eventfd_t);709 __kernel_read(proc, *ftr, iov, evfd );710 ftr->result = 0xDEADDEAD;711 *((eventfd_t *)rdbuf) = 0xDEADDEADDEADDEAD;712 was_reset = true;713 }714 }715 716 if( !__atomic_load_n( &proc->do_terminate, __ATOMIC_SEQ_CST ) ) {717 __ioarbiter_flush( *proc->io.ctx );718 proc->idle_wctx.sleep_time = rdtscl();719 ioring_syscsll( *proc->io.ctx, 1, IORING_ENTER_GETEVENTS);720 }721 722 ready_schedule_lock();723 __cfa_do_drain( proc->io.ctx, proc->cltr );724 ready_schedule_unlock();725 726 asm volatile ("" :: "m" (was_reset));727 }728 #endif729 641 #endif -
libcfa/src/concurrency/io/setup.cfa
rb77f0e1 r63be3387 34 34 bool __cfa_io_flush( processor * proc ) { return false; } 35 35 bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1))) { return false; } 36 void __cfa_io_idle ( processor * ) __attribute__((nonnull (1))) {}37 36 void __cfa_io_stop ( processor * proc ) {} 38 37 … … 317 316 } 318 317 319 //=============================================================================================320 // I/O Context Sleep321 //=============================================================================================322 // static inline void __epoll_ctl(io_context$ & ctx, int op, const char * error) {323 // struct epoll_event ev;324 // ev.events = EPOLLIN | EPOLLONESHOT;325 // ev.data.u64 = (__u64)&ctx;326 // int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev);327 // if (ret < 0) {328 // abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );329 // }330 // }331 332 // static void __epoll_register(io_context$ & ctx) {333 // __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");334 // }335 336 // static void __epoll_unregister(io_context$ & ctx) {337 // // Read the current epoch so we know when to stop338 // size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);339 340 // // Remove the fd from the iopoller341 // __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");342 343 // // Notify the io poller thread of the shutdown344 // iopoll.run = false;345 // sigval val = { 1 };346 // pthread_sigqueue( iopoll.thrd, SIGUSR1, val );347 348 // // Make sure all this is done349 // __atomic_thread_fence(__ATOMIC_SEQ_CST);350 351 // // Wait for the next epoch352 // while(curr == iopoll.epoch && !iopoll.stopped) Pause();353 // }354 355 // void __ioctx_prepare_block(io_context$ & ctx) {356 // __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx);357 // __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");358 // }359 360 318 361 319 //============================================================================================= -
libcfa/src/concurrency/kernel.cfa
rb77f0e1 r63be3387 138 138 extern bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1))); 139 139 extern bool __cfa_io_flush( processor * ) __attribute__((nonnull (1))); 140 extern void __cfa_io_idle( processor * ) __attribute__((nonnull (1))); 141 142 #if defined(CFA_WITH_IO_URING_IDLE) 143 extern bool __kernel_read(processor * proc, io_future_t & future, iovec &, int fd); 144 #endif 140 145 141 146 142 extern void __disable_interrupts_hard(); … … 162 158 verify(this); 163 159 164 /* paranoid */ verify( this->idle_wctx.ftr != 0p );165 /* paranoid */ verify( this->idle_wctx.rdbuf != 0p );166 167 // used for idle sleep when io_uring is present168 // mark it as already fulfilled so we know if there is a pending request or not169 this->idle_wctx.ftr->self.ptr = 1p;170 171 160 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 172 161 #if !defined(__CFA_NO_STATISTICS__) … … 291 280 /* paranoid */ verify( ! __preemption_enabled() ); 292 281 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); 293 /* paranoid */ verifyf( thrd_dst-> link.next == 0p, "Expected null got %p", thrd_dst->link.next );282 /* paranoid */ verifyf( thrd_dst->rdy_link.next == 0p, "Expected null got %p", thrd_dst->rdy_link.next ); 294 283 __builtin_prefetch( thrd_dst->context.SP ); 295 284 … … 321 310 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 322 311 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor 312 /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, this, __ATOMIC_SEQ_CST) == 0p ); 323 313 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 324 314 … … 332 322 333 323 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 324 /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, 0p, __ATOMIC_SEQ_CST) == this ); 334 325 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); 335 326 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); 327 /* paranoid */ verify( thrd_dst->state != Halted ); 336 328 /* paranoid */ verify( thrd_dst->context.SP ); 337 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );338 329 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst ); 339 330 /* paranoid */ verify( ! __preemption_enabled() ); … … 452 443 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted ); 453 444 /* paranoid */ #endif 454 /* paranoid */ verifyf( thrd-> link.next == 0p, "Expected null got %p", thrd->link.next );445 /* paranoid */ verifyf( thrd->rdy_link.next == 0p, "Expected null got %p", thrd->rdy_link.next ); 455 446 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 456 447 … … 600 591 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : thread$ %p has been corrupted.\n StackPointer too small.\n", thrd ); 601 592 602 thrd->state = Halting;603 593 if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); } 604 594 if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); } 605 595 if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); } 596 597 thrd->state = Halting; 598 thrd->ticket = TICKET_DEAD; 606 599 607 600 // Leave the thread … … 624 617 // If that is the case, abandon the preemption. 625 618 bool preempted = false; 626 if(thrd-> link.next == 0p) {619 if(thrd->rdy_link.next == 0p) { 627 620 preempted = true; 628 621 thrd->preempted = reason; … … 726 719 727 720 728 #if !defined(CFA_WITH_IO_URING_IDLE) 729 #if !defined(__CFA_NO_STATISTICS__) 730 if(this->print_halts) { 731 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 721 #if !defined(__CFA_NO_STATISTICS__) 722 if(this->print_halts) { 723 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 724 } 725 #endif 726 727 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 728 729 { 730 eventfd_t val; 731 ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) ); 732 if(ret < 0) { 733 switch((int)errno) { 734 case EAGAIN: 735 #if EAGAIN != EWOULDBLOCK 736 case EWOULDBLOCK: 737 #endif 738 case EINTR: 739 // No need to do anything special here, just assume it's a legitimate wake-up 740 break; 741 default: 742 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 732 743 } 733 #endif 734 735 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 736 737 { 738 eventfd_t val; 739 ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) ); 740 if(ret < 0) { 741 switch((int)errno) { 742 case EAGAIN: 743 #if EAGAIN != EWOULDBLOCK 744 case EWOULDBLOCK: 745 #endif 746 case EINTR: 747 // No need to do anything special here, just assume it's a legitimate wake-up 748 break; 749 default: 750 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 751 } 752 } 753 } 754 755 #if !defined(__CFA_NO_STATISTICS__) 756 if(this->print_halts) { 757 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 758 } 759 #endif 760 #else 761 __cfa_io_idle( this ); 744 } 745 } 746 747 #if !defined(__CFA_NO_STATISTICS__) 748 if(this->print_halts) { 749 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 750 } 762 751 #endif 763 752 } … … 775 764 insert_first(this.idles, proc); 776 765 766 // update the pointer to the head wait context, which should now point to this proc. 777 767 __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST); 778 768 unlock( this ); … … 791 781 792 782 { 783 // update the pointer to the head wait context 793 784 struct __fd_waitctx * wctx = 0; 794 785 if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx; -
libcfa/src/concurrency/kernel.hfa
rb77f0e1 r63be3387 64 64 // 1 - means the proc should wake-up immediately 65 65 // FD - means the proc is going asleep and should be woken by writing to the FD. 66 // The FD value should always be the evfd field just below. 66 67 volatile int sem; 67 68 … … 69 70 int evfd; 70 71 71 // buffer into which the proc will read from evfd 72 // unused if not using io_uring for idle sleep 73 void * rdbuf; 74 75 // future use to track the read of the eventfd 76 // unused if not using io_uring for idle sleep 77 io_future_t * ftr; 78 72 // Used for debugging, should be removed eventually. 79 73 volatile unsigned long long wake__time; 80 74 volatile unsigned long long sleep_time; … … 160 154 // P9_EMBEDDED( processor, dlink(processor) ) 161 155 static inline tytagref( dlink(processor), dlink(processor) ) ?`inner( processor & this ) { 162 163 164 156 dlink(processor) & b = this.link; 157 tytagref( dlink(processor), dlink(processor) ) result = { b }; 158 return result; 165 159 } 166 160 … … 256 250 // List of threads 257 251 __spinlock_t thread_list_lock; 258 __dllist_t(struct thread$) threads;252 dlist(struct thread$, struct __thread_user_link) threads; 259 253 unsigned int nthreads; 260 254 … … 269 263 io_context_params params; 270 264 } io; 265 266 struct { 267 struct processor ** procs; 268 unsigned cnt; 269 } managed; 271 270 272 271 #if !defined(__CFA_NO_STATISTICS__) … … 298 297 static inline struct cluster * active_cluster () { return publicTLS_get( this_processor )->cltr; } 299 298 299 // set the number of internal processors 300 // these processors are in addition to any explicitly declared processors 301 unsigned set_concurrency( cluster & this, unsigned new_count ); 302 300 303 #if !defined(__CFA_NO_STATISTICS__) 301 304 void print_stats_now( cluster & this, int flags ); -
libcfa/src/concurrency/kernel/cluster.cfa
rb77f0e1 r63be3387 483 483 484 484 // We add a boat-load of assertions here because the anchor code is very fragile 485 /* paranoid */ _Static_assert( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );486 /* paranoid */ verify( offsetof( thread$, link ) == nested_offsetof(__intrusive_lane_t, l.anchor) );487 /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, link )) == (uintptr_t)(&this.l.anchor) );488 /* paranoid */ verify( &mock_head(this)-> link.next == &this.l.anchor.next );489 /* paranoid */ verify( &mock_head(this)-> link.ts == &this.l.anchor.ts );490 /* paranoid */ verify( mock_head(this)-> link.next == 0p );491 /* paranoid */ verify( mock_head(this)-> link.ts == MAX );485 /* paranoid */ _Static_assert( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) ); 486 /* paranoid */ verify( offsetof( thread$, rdy_link ) == nested_offsetof(__intrusive_lane_t, l.anchor) ); 487 /* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, rdy_link )) == (uintptr_t)(&this.l.anchor) ); 488 /* paranoid */ verify( &mock_head(this)->rdy_link.next == &this.l.anchor.next ); 489 /* paranoid */ verify( &mock_head(this)->rdy_link.ts == &this.l.anchor.ts ); 490 /* paranoid */ verify( mock_head(this)->rdy_link.next == 0p ); 491 /* paranoid */ verify( mock_head(this)->rdy_link.ts == MAX ); 492 492 /* paranoid */ verify( mock_head(this) == this.l.prev ); 493 493 /* paranoid */ verify( __alignof__(__intrusive_lane_t) == 64 ); -
libcfa/src/concurrency/kernel/private.hfa
rb77f0e1 r63be3387 20 20 #endif 21 21 22 #include <signal.h> 23 22 24 #include "kernel.hfa" 23 25 #include "thread.hfa" … … 39 41 } 40 42 41 // Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call42 // #define CFA_WANT_IO_URING_IDLE43 44 // Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call45 #if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)46 #if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV))47 #define CFA_WITH_IO_URING_IDLE48 #endif49 #endif50 51 43 // #define READYQ_USE_LINEAR_AVG 52 44 #define READYQ_USE_LOGDBL_AVG … … 63 55 #endif 64 56 57 extern "C" { 58 __attribute__((visibility("protected"))) int __cfaabi_pthread_create(pthread_t *_thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 59 __attribute__((visibility("protected"))) int __cfaabi_pthread_join(pthread_t _thread, void **retval); 60 __attribute__((visibility("protected"))) pthread_t __cfaabi_pthread_self(void); 61 __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_init(pthread_attr_t *attr); 62 __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_destroy(pthread_attr_t *attr); 63 __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_setstack( pthread_attr_t *attr, void *stackaddr, size_t stacksize ); 64 __attribute__((visibility("protected"))) int __cfaabi_pthread_attr_getstacksize( const pthread_attr_t *attr, size_t *stacksize ); 65 __attribute__((visibility("protected"))) int __cfaabi_pthread_sigqueue(pthread_t _thread, int sig, const union sigval value); 66 __attribute__((visibility("protected"))) int __cfaabi_pthread_sigmask( int how, const sigset_t *set, sigset_t *oset); 67 } 68 65 69 //----------------------------------------------------------------------------- 66 70 // Scheduler … … 153 157 #define TICKET_RUNNING ( 0) // thread is running 154 158 #define TICKET_UNBLOCK ( 1) // thread should ignore next block 159 #define TICKET_DEAD (0xDEAD) // thread should never be unparked 155 160 156 161 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/kernel/startup.cfa
rb77f0e1 r63be3387 16 16 #define __cforall_thread__ 17 17 #define _GNU_SOURCE 18 19 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ 18 20 19 21 // C Includes … … 113 115 KERNEL_STORAGE(thread$, mainThread); 114 116 KERNEL_STORAGE(__stack_t, mainThreadCtx); 115 // KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);116 KERNEL_STORAGE(eventfd_t, mainIdleEventFd);117 KERNEL_STORAGE(io_future_t, mainIdleFuture);118 117 #if !defined(__CFA_NO_STATISTICS__) 119 118 KERNEL_STORAGE(__stats_t, mainProcStats); … … 222 221 ( this.runner ){}; 223 222 init( this, "Main Processor", *mainCluster, 0p ); 224 kernel_thread = pthread_self();223 kernel_thread = __cfaabi_pthread_self(); 225 224 226 225 runner{ &this }; … … 232 231 mainProcessor = (processor *)&storage_mainProcessor; 233 232 (*mainProcessor){}; 234 235 mainProcessor->idle_wctx.rdbuf = &storage_mainIdleEventFd;236 mainProcessor->idle_wctx.ftr = (io_future_t*)&storage_mainIdleFuture;237 /* paranoid */ verify( sizeof(storage_mainIdleEventFd) == sizeof(eventfd_t) );238 233 239 234 __cfa_io_start( mainProcessor ); … … 283 278 } 284 279 280 extern "C"{ 281 void pthread_delete_kernel_threads_(); 282 } 283 284 285 285 static void __kernel_shutdown(void) { 286 286 if(!cfa_main_returned) return; 287 288 //delete kernel threads for pthread_concurrency 289 pthread_delete_kernel_threads_(); 290 287 291 /* paranoid */ verify( __preemption_enabled() ); 288 292 disable_interrupts(); … … 327 331 328 332 /* paranoid */ verify( this.do_terminate == true ); 329 __cfa abi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner);333 __cfadbg_print_safe(runtime_core, "Kernel : destroyed main processor context %p\n", &runner); 330 334 } 331 335 … … 373 377 register_tls( proc ); 374 378 375 // used for idle sleep when io_uring is present376 io_future_t future;377 eventfd_t idle_buf;378 proc->idle_wctx.ftr = &future;379 proc->idle_wctx.rdbuf = &idle_buf;380 381 382 379 // SKULLDUGGERY: We want to create a context for the processor coroutine 383 380 // which is needed for the 2-step context switch. However, there is no reason … … 388 385 (proc->runner){ proc, &info }; 389 386 390 __cfa abi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);387 __cfadbg_print_safe(runtime_core, "Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 391 388 392 389 //Set global state … … 514 511 self_mon.recursion = 1; 515 512 self_mon_p = &self_mon; 516 link.next = 0p;517 link.ts = MAX;513 rdy_link.next = 0p; 514 rdy_link.ts = MAX; 518 515 preferred = ready_queue_new_preferred(); 519 516 last_proc = 0p; 520 517 random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl(); 521 518 #if defined( __CFA_WITH_VERIFY__ ) 519 executing = 0p; 522 520 canary = 0x0D15EA5E0D15EA5Ep; 523 521 #endif 524 522 525 node.next = 0p;526 node.prev = 0p;527 523 doregister(curr_cluster, this); 528 524 … … 647 643 #endif 648 644 649 threads{ __get};645 threads{}; 650 646 651 647 io.arbiter = create(); 652 648 io.params = io_params; 649 650 managed.procs = 0p; 651 managed.cnt = 0; 653 652 654 653 doregister(this); … … 667 666 668 667 void ^?{}(cluster & this) libcfa_public { 668 set_concurrency( this, 0 ); 669 669 670 destroy(this.io.arbiter); 670 671 … … 722 723 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 723 724 cltr->nthreads += 1; 724 push_front(cltr->threads, thrd);725 insert_first(cltr->threads, thrd); 725 726 unlock (cltr->thread_list_lock); 726 727 } … … 728 729 void unregister( cluster * cltr, thread$ & thrd ) { 729 730 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 730 remove(cltr->threads, thrd ); 731 cltr->nthreads -= 1; 731 { 732 tytagref( dlink(thread$), dlink(thread$) ) ?`inner( thread$ & this ) = void; 733 with( DLINK_VIA( thread$, struct __thread_user_link ) ) 734 remove( thrd ); 735 cltr->nthreads -= 1; 736 } 732 737 unlock(cltr->thread_list_lock); 733 738 } … … 777 782 pthread_attr_t attr; 778 783 779 check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute784 check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute 780 785 781 786 size_t stacksize = max( PTHREAD_STACK_MIN, DEFAULT_STACK_SIZE ); … … 804 809 #endif 805 810 806 check( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );807 check( pthread_create( pthread, &attr, start, arg ), "pthread_create" );811 check( __cfaabi_pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" ); 812 check( __cfaabi_pthread_create( pthread, &attr, start, arg ), "pthread_create" ); 808 813 return stack; 809 814 } 810 815 811 816 void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ) { 812 int err = pthread_join( pthread, retval );817 int err = __cfaabi_pthread_join( pthread, retval ); 813 818 if( err != 0 ) abort("KERNEL ERROR: joining pthread %p caused error %s\n", (void*)pthread, strerror(err)); 814 819 … … 816 821 pthread_attr_t attr; 817 822 818 check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute823 check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute 819 824 820 825 size_t stacksize; 821 826 // default stack size, normally defined by shell limit 822 check( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );827 check( __cfaabi_pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" ); 823 828 assert( stacksize >= PTHREAD_STACK_MIN ); 824 829 stacksize += __page_size; … … 838 843 } 839 844 845 unsigned set_concurrency( cluster & this, unsigned new ) libcfa_public { 846 unsigned old = this.managed.cnt; 847 848 __cfadbg_print_safe(runtime_core, "Kernel : resizing cluster from %u to %u\n", old, (unsigned)new); 849 850 // Delete all the old unneeded procs 851 if(old > new) for(i; (unsigned)new ~ old) { 852 __cfadbg_print_safe(runtime_core, "Kernel : destroying %u\n", i); 853 delete( this.managed.procs[i] ); 854 } 855 856 // Allocate new array (uses realloc and memcpies the data) 857 this.managed.procs = alloc( new, this.managed.procs`realloc ); 858 this.managed.cnt = new; 859 860 // Create the desired new procs 861 if(old < new) for(i; old ~ new) { 862 __cfadbg_print_safe(runtime_core, "Kernel : constructing %u\n", i); 863 (*(this.managed.procs[i] = alloc())){ this }; 864 } 865 866 // return the old count 867 return old; 868 } 869 840 870 #if defined(__CFA_WITH_VERIFY__) 841 871 static bool verify_fwd_bck_rng(void) { -
libcfa/src/concurrency/locks.hfa
rb77f0e1 r63be3387 21 21 22 22 #include "bits/weakso_locks.hfa" 23 #include "containers/ queueLockFree.hfa"23 #include "containers/lockfree.hfa" 24 24 #include "containers/list.hfa" 25 25 … … 498 498 } 499 499 500 static inline size_t on_wait(simple_owner_lock & this) with(this) { 500 static inline size_t on_wait(simple_owner_lock & this) with(this) { 501 501 lock( lock __cfaabi_dbg_ctx2 ); 502 502 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); -
libcfa/src/concurrency/monitor.cfa
rb77f0e1 r63be3387 122 122 123 123 // Some one else has the monitor, wait in line for it 124 /* paranoid */ verify( thrd-> link.next == 0p );124 /* paranoid */ verify( thrd->user_link.next == 0p ); 125 125 append( this->entry_queue, thrd ); 126 /* paranoid */ verify( thrd-> link.next == 1p );126 /* paranoid */ verify( thrd->user_link.next == 1p ); 127 127 128 128 unlock( this->lock ); … … 233 233 234 234 // Some one else has the monitor, wait in line for it 235 /* paranoid */ verify( thrd-> link.next == 0p );235 /* paranoid */ verify( thrd->user_link.next == 0p ); 236 236 append( this->entry_queue, thrd ); 237 /* paranoid */ verify( thrd-> link.next == 1p );237 /* paranoid */ verify( thrd->user_link.next == 1p ); 238 238 unlock( this->lock ); 239 239 … … 791 791 thread$ * new_owner = pop_head( this->entry_queue ); 792 792 /* paranoid */ verifyf( !this->owner || active_thread() == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", active_thread(), this->owner, this->recursion, this ); 793 /* paranoid */ verify( !new_owner || new_owner-> link.next == 0p );793 /* paranoid */ verify( !new_owner || new_owner->user_link.next == 0p ); 794 794 __set_owner( this, new_owner ); 795 795 … … 935 935 __queue_t(thread$) & entry_queue = monitors[0]->entry_queue; 936 936 937 #if defined( __CFA_WITH_VERIFY__ ) 938 thread$ * last = 0p; 939 #endif 937 940 // For each thread in the entry-queue 938 941 for( thread$ ** thrd_it = &entry_queue.head; 939 942 (*thrd_it) != 1p; 940 thrd_it = & (*thrd_it)->link.next943 thrd_it = &get_next(**thrd_it) 941 944 ) { 945 thread$ * curr = *thrd_it; 946 947 /* paranoid */ verifyf( !last || last->user_link.next == curr, "search not making progress, from %p (%p) to %p", last, last->user_link.next, curr ); 948 /* paranoid */ verifyf( curr != last, "search not making progress, from %p to %p", last, curr ); 949 942 950 // For each acceptable check if it matches 943 951 int i = 0; … … 946 954 for( __acceptable_t * it = begin; it != end; it++, i++ ) { 947 955 // Check if we have a match 948 if( *it == (*thrd_it)->monitors ) {956 if( *it == curr->monitors ) { 949 957 950 958 // If we have a match return it … … 953 961 } 954 962 } 963 964 #if defined( __CFA_WITH_VERIFY__ ) 965 last = curr; 966 #endif 955 967 } 956 968 … … 1025 1037 1026 1038 // Some one else has the monitor, wait in line for it 1027 /* paranoid */ verify( thrd-> link.next == 0p );1039 /* paranoid */ verify( thrd->user_link.next == 0p ); 1028 1040 append( this->entry_queue, thrd ); 1029 /* paranoid */ verify( thrd-> link.next == 1p );1041 /* paranoid */ verify( thrd->user_link.next == 1p ); 1030 1042 1031 1043 unlock( this->lock ); -
libcfa/src/concurrency/preemption.cfa
rb77f0e1 r63be3387 352 352 sigset_t oldset; 353 353 int ret; 354 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary354 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 355 355 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 356 356 … … 385 385 sigaddset( &mask, sig ); 386 386 387 if ( pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {387 if ( __cfaabi_pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) { 388 388 abort( "internal error, pthread_sigmask" ); 389 389 } … … 396 396 sigaddset( &mask, sig ); 397 397 398 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {398 if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 399 399 abort( "internal error, pthread_sigmask" ); 400 400 } … … 404 404 static void preempt( processor * this ) { 405 405 sigval_t value = { PREEMPT_NORMAL }; 406 pthread_sigqueue( this->kernel_thread, SIGUSR1, value );406 __cfaabi_pthread_sigqueue( this->kernel_thread, SIGUSR1, value ); 407 407 } 408 408 … … 415 415 sigset_t oldset; 416 416 int ret; 417 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary417 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 418 418 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 419 419 … … 434 434 sigset_t oldset; 435 435 int ret; 436 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary436 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 437 437 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 438 438 … … 505 505 sigval val; 506 506 val.sival_int = 0; 507 pthread_sigqueue( alarm_thread, SIGALRM, val );507 __cfaabi_pthread_sigqueue( alarm_thread, SIGALRM, val ); 508 508 509 509 // Wait for the preemption thread to finish … … 579 579 static_assert( sizeof( sigset_t ) == sizeof( cxt->uc_sigmask ), "Expected cxt->uc_sigmask to be of sigset_t" ); 580 580 #endif 581 if ( pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {581 if ( __cfaabi_pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) { 582 582 abort( "internal error, sigprocmask" ); 583 583 } … … 607 607 sigset_t mask; 608 608 sigfillset(&mask); 609 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {609 if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 610 610 abort( "internal error, pthread_sigmask" ); 611 611 } -
libcfa/src/concurrency/ready_subqueue.hfa
rb77f0e1 r63be3387 25 25 static inline thread$ * mock_head(const __intrusive_lane_t & this) { 26 26 thread$ * rhead = (thread$ *)( 27 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, link )27 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, rdy_link ) 28 28 ); 29 29 return rhead; … … 34 34 static inline void push( __intrusive_lane_t & this, thread$ * node ) { 35 35 /* paranoid */ verify( this.l.lock ); 36 /* paranoid */ verify( node-> link.next == 0p );37 /* paranoid */ verify( __atomic_load_n(&node-> link.ts, __ATOMIC_RELAXED) == MAX );38 /* paranoid */ verify( this.l.prev-> link.next == 0p );39 /* paranoid */ verify( __atomic_load_n(&this.l.prev-> link.ts, __ATOMIC_RELAXED) == MAX );36 /* paranoid */ verify( node->rdy_link.next == 0p ); 37 /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED) == MAX ); 38 /* paranoid */ verify( this.l.prev->rdy_link.next == 0p ); 39 /* paranoid */ verify( __atomic_load_n(&this.l.prev->rdy_link.ts, __ATOMIC_RELAXED) == MAX ); 40 40 if( this.l.anchor.next == 0p ) { 41 41 /* paranoid */ verify( this.l.anchor.next == 0p ); … … 51 51 52 52 // Get the relevant nodes locally 53 this.l.prev-> link.next = node;54 __atomic_store_n(&this.l.prev-> link.ts, rdtscl(), __ATOMIC_RELAXED);53 this.l.prev->rdy_link.next = node; 54 __atomic_store_n(&this.l.prev->rdy_link.ts, rdtscl(), __ATOMIC_RELAXED); 55 55 this.l.prev = node; 56 56 #if !defined(__CFA_NO_STATISTICS__) … … 70 70 // Get the relevant nodes locally 71 71 thread$ * node = this.l.anchor.next; 72 this.l.anchor.next = node-> link.next;73 __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node-> link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);72 this.l.anchor.next = node->rdy_link.next; 73 __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node->rdy_link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED); 74 74 bool is_empty = this.l.anchor.next == 0p; 75 node-> link.next = 0p;76 __atomic_store_n(&node-> link.ts, ULLONG_MAX, __ATOMIC_RELAXED);75 node->rdy_link.next = 0p; 76 __atomic_store_n(&node->rdy_link.ts, ULLONG_MAX, __ATOMIC_RELAXED); 77 77 #if !defined(__CFA_NO_STATISTICS__) 78 78 this.l.cnt--; … … 83 83 84 84 unsigned long long ats = __atomic_load_n(&this.l.anchor.ts, __ATOMIC_RELAXED); 85 /* paranoid */ verify( node-> link.next == 0p );86 /* paranoid */ verify( __atomic_load_n(&node-> link.ts , __ATOMIC_RELAXED) == MAX );87 /* paranoid */ verify( __atomic_load_n(&node-> link.ts , __ATOMIC_RELAXED) != 0 );85 /* paranoid */ verify( node->rdy_link.next == 0p ); 86 /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) == MAX ); 87 /* paranoid */ verify( __atomic_load_n(&node->rdy_link.ts , __ATOMIC_RELAXED) != 0 ); 88 88 /* paranoid */ verify( ats != 0 ); 89 89 /* paranoid */ verify( (ats == MAX) == is_empty ); -
libcfa/src/concurrency/thread.cfa
rb77f0e1 r63be3387 44 44 self_mon_p = &self_mon; 45 45 curr_cluster = &cl; 46 link.next = 0p;47 link.ts = MAX;46 rdy_link.next = 0p; 47 rdy_link.ts = MAX; 48 48 preferred = ready_queue_new_preferred(); 49 49 last_proc = 0p; 50 50 random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl(); 51 51 #if defined( __CFA_WITH_VERIFY__ ) 52 executing = 0p; 52 53 canary = 0x0D15EA5E0D15EA5Ep; 53 54 #endif 54 55 node.next = 0p;56 node.prev = 0p;57 55 58 56 clh_node = malloc( ); … … 177 175 178 176 //----------------------------------------------------------------------------- 177 bool migrate( thread$ * thrd, struct cluster & cl ) { 178 179 monitor$ * tmon = get_monitor(thrd); 180 monitor$ * __monitors[] = { tmon }; 181 monitor_guard_t __guard = { __monitors, 1 }; 182 183 184 { 185 // if nothing needs to be done, return false 186 if( thrd->curr_cluster == &cl ) return false; 187 188 // are we migrating ourself? 189 const bool local = thrd == active_thread(); 190 191 /* paranoid */ verify( !local || &cl != active_cluster() ); 192 /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() ); 193 /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr ); 194 /* paranoid */ verify( local || tmon->signal_stack.top->owner->waiting_thread == thrd ); 195 /* paranoid */ verify( local || tmon->signal_stack.top ); 196 197 // make sure we aren't interrupted while doing this 198 // not as important if we aren't local 199 disable_interrupts(); 200 201 // actually move the thread 202 unregister( thrd->curr_cluster, *thrd ); 203 thrd->curr_cluster = &cl; 204 doregister( thrd->curr_cluster, *thrd ); 205 206 // restore interrupts 207 enable_interrupts(); 208 209 // if this is the local thread, we are still running on the old cluster 210 if(local) yield(); 211 212 /* paranoid */ verify( !local || &cl == active_cluster() ); 213 /* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() ); 214 /* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr ); 215 /* paranoid */ verify( local || tmon->signal_stack.top ); 216 /* paranoid */ verify( local || tmon->signal_stack.top->owner->waiting_thread == thrd ); 217 218 return true; 219 } 220 } 221 222 //----------------------------------------------------------------------------- 179 223 #define GENERATOR LCG 180 224 -
libcfa/src/concurrency/thread.hfa
rb77f0e1 r63be3387 132 132 133 133 //---------- 134 // misc 135 bool migrate( thread$ * thrd, struct cluster & cl ); 136 137 forall( T & | is_thread(T) ) 138 static inline bool migrate( T & mutex thrd, struct cluster & cl ) { return migrate( &(thread&)thrd, cl ); } 139 140 141 //---------- 134 142 // prng 135 143 static inline { -
libcfa/src/containers/array.hfa
rb77f0e1 r63be3387 1 #pragma once 2 1 3 #include <assert.h> 2 4 … … 18 20 // About the choice of integral types offered as subscript overloads: 19 21 // Intent is to cover these use cases: 22 // a[0] // i : zero_t 23 // a[1] // i : one_t 24 // a[2] // i : int 20 25 // float foo( ptrdiff_t i ) { return a[i]; } // i : ptrdiff_t 26 // float foo( size_t i ) { return a[i]; } // i : size_t 21 27 // forall( [N] ) ... for( i; N ) { total += a[i]; } // i : typeof( sizeof(42) ) 22 28 // for( i; 5 ) { total += a[i]; } // i : int 29 // 23 30 // It gets complicated by: 24 31 // - CFA does overloading on concrete types, like int and unsigned int, not on typedefed … … 28 35 // should give them type size_t. 29 36 // 30 // gcc -m32 cfa -m32 given bug gcc -m64 37 // gcc -m32 cfa -m32 given bug gcc -m64 (and cfa) 31 38 // ptrdiff_t int int long int 32 39 // size_t unsigned int unsigned int unsigned long int 33 40 // typeof( sizeof(42) ) unsigned int unsigned long int unsigned long int 34 41 // int int int int 42 // 43 // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int} 44 // 45 // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t) 46 // because assertion satisfaction requires types to match exacly. Both higher-dimensional 47 // subscripting and operations on slices use asserted subscript operators. The test case 48 // array-container/array-sbscr-cases covers the combinations. Mike beleives that commenting out 49 // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit. 50 // Mike is open to being shown a smaller set of overloads that still passes the test. 51 52 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) { 53 assert( 0 < N ); 54 return (Timmed &) a.strides[0]; 55 } 56 57 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) { 58 assert( 1 < N ); 59 return (Timmed &) a.strides[1]; 60 } 35 61 36 62 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) { … … 77 103 return N; 78 104 } 105 106 static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {} 79 107 80 108 // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa) … … 156 184 #endif 157 185 186 // Available for users to work around Trac #265 187 // If `a[...0...]` isn't working, try `a[...ix0...]` instead. 188 189 #define ix0 ((ptrdiff_t)0) 190 191 192 158 193 // 159 194 // Rotation … … 185 220 // 186 221 187 trait ar(A &, Tv &) { 188 Tv& ?[?]( A&, ptrdiff_t ); 189 size_t ?`len( A& ); 190 }; 222 // desired: 223 // trait ar(A &, Tv &, [N]) { 224 // Tv& ?[?]( A&, zero_t ); 225 // Tv& ?[?]( A&, one_t ); 226 // Tv& ?[?]( A&, int ); 227 // ... 228 // size_t ?`len( A& ); 229 // void __taglen( tag(C), tag(N) ); 230 // }; 231 232 // working around N's not being accepted as arguments to traits 233 234 #define ar(A, Tv, N) { \ 235 Tv& ?[?]( A&, zero_t ); \ 236 Tv& ?[?]( A&, one_t ); \ 237 Tv& ?[?]( A&, int ); \ 238 Tv& ?[?]( A&, unsigned int ); \ 239 Tv& ?[?]( A&, long int ); \ 240 Tv& ?[?]( A&, unsigned long int ); \ 241 size_t ?`len( A& ); \ 242 void __taglen( tag(A), tag(N) ); \ 243 } -
libcfa/src/heap.cfa
rb77f0e1 r63be3387 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Oct 13 22:21:52202213 // Update Count : 15 5712 // Last Modified On : Sun Oct 30 20:56:20 2022 13 // Update Count : 1584 14 14 // 15 15 … … 43 43 44 44 #define FASTLOOKUP // use O(1) table lookup from allocation size to bucket size 45 #define RETURNSPIN // toggle spinlock / lockfree stack46 45 #define OWNERSHIP // return freed memory to owner thread 46 #define RETURNSPIN // toggle spinlock / lockfree queue 47 #if ! defined( OWNERSHIP ) && defined( RETURNSPIN ) 48 #warning "RETURNSPIN is ignored without OWNERSHIP; suggest commenting out RETURNSPIN" 49 #endif // ! OWNERSHIP && RETURNSPIN 47 50 48 51 #define CACHE_ALIGN 64 … … 109 112 110 113 111 //######################### Spin Lock ######################### 114 //######################### Helpers ######################### 115 116 117 // generic Bsearchl does not inline, so substitute with hand-coded binary-search. 118 inline __attribute__((always_inline)) 119 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) { 120 size_t l = 0, m, h = dim; 121 while ( l < h ) { 122 m = (l + h) / 2; 123 if ( (unsigned int &)(vals[m]) < key ) { // cast away const 124 l = m + 1; 125 } else { 126 h = m; 127 } // if 128 } // while 129 return l; 130 } // Bsearchl 112 131 113 132 … … 206 225 207 226 208 #define SPINLOCK 0209 #define LOCKFREE 1210 #define BUCKETLOCK SPINLOCK211 #if BUCKETLOCK == SPINLOCK212 #elif BUCKETLOCK == LOCKFREE213 #include <stackLockFree.hfa>214 #else215 #error undefined lock type for bucket lock216 #endif // LOCKFREE217 218 227 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage. 219 228 // Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined. … … 232 241 void * home; // allocated block points back to home locations (must overlay alignment) 233 242 size_t blockSize; // size for munmap (must overlay alignment) 234 #if BUCKETLOCK == SPINLOCK235 243 Storage * next; // freed block points to next freed block of same size 236 #endif // SPINLOCK237 244 }; 238 245 size_t size; // allocation size in bytes 239 246 }; 240 #if BUCKETLOCK == LOCKFREE241 Link(Storage) next; // freed block points next freed block of same size (double-wide)242 #endif // LOCKFREE243 247 }; 244 248 } real; // RealHeader … … 259 263 struct __attribute__(( aligned (8) )) FreeHeader { 260 264 size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list 261 #if BUCKETLOCK == SPINLOCK262 265 #ifdef OWNERSHIP 263 266 #ifdef RETURNSPIN … … 266 269 Storage * returnList; // other thread return list 267 270 #endif // OWNERSHIP 271 268 272 Storage * freeList; // thread free list 269 #else270 StackLF(Storage) freeList;271 #endif // BUCKETLOCK272 273 Heap * homeManager; // heap owner (free storage to bucket, from bucket to heap) 273 274 }; // FreeHeader … … 290 291 #endif // __STATISTICS__ 291 292 }; // Heap 292 293 #if BUCKETLOCK == LOCKFREE294 inline __attribute__((always_inline))295 static {296 Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; }297 void ?{}( Heap.FreeHeader & ) {}298 void ^?{}( Heap.FreeHeader & ) {}299 } // distribution300 #endif // LOCKFREE301 293 302 294 … … 385 377 386 378 387 // generic Bsearchl does not inline, so substitute with hand-coded binary-search.388 inline __attribute__((always_inline))389 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) {390 size_t l = 0, m, h = dim;391 while ( l < h ) {392 m = (l + h) / 2;393 if ( (unsigned int &)(vals[m]) < key ) { // cast away const394 l = m + 1;395 } else {396 h = m;397 } // if398 } // while399 return l;400 } // Bsearchl401 402 403 379 void heapMasterCtor() with( heapMaster ) { 404 380 // Singleton pattern to initialize heap master … … 409 385 __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC; 410 386 411 ?{}( extLock );412 ?{}( mgrLock );387 extLock = 0; 388 mgrLock = 0; 413 389 414 390 char * end = (char *)sbrk( 0 ); … … 497 473 #ifdef OWNERSHIP 498 474 #ifdef RETURNSPIN 499 ?{}( freeLists[j].returnLock ); 475 freeLists[j].returnLock = 0; 476 freeLists[j].returnList = 0p; 500 477 #endif // RETURNSPIN 501 freeLists[j].returnList = 0p;502 478 #endif // OWNERSHIP 479 503 480 freeLists[j].freeList = 0p; 504 481 freeLists[j].homeManager = heap; 505 482 freeLists[j].blockSize = bucketSizes[j]; 506 483 } // for 507 484 508 485 heapBuffer = 0p; 509 486 heapReserve = 0; … … 522 499 if ( unlikely( ! heapMasterBootFlag ) ) heapMasterCtor(); 523 500 524 lock( heapMaster.mgrLock ); // protect heapMaster counters501 lock( heapMaster.mgrLock ); // protect heapMaster counters 525 502 526 503 // get storage for heap manager … … 710 687 // find the closest bucket size less than or equal to the mmapStart size 711 688 maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search 689 712 690 verify( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 713 691 verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? … … 832 810 833 811 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() ); 834 // Do not call abort or strerror( errno ) as they may call malloc.835 812 if ( unlikely( sbrk( increase ) == (void *)-1 ) ) { // failed, no memory ? 836 813 unlock( extLock ); 837 abort( NO_MEMORY_MSG, size ); // no memory814 abort( NO_MEMORY_MSG, size ); // give up 838 815 } // if 839 816 … … 971 948 #endif // __STATISTICS__ 972 949 973 // Spin until the lock is acquired for this particular size of block.974 975 #if BUCKETLOCK == SPINLOCK976 950 block = freeHead->freeList; // remove node from stack 977 #else978 block = pop( freeHead->freeList );979 #endif // BUCKETLOCK980 951 if ( unlikely( block == 0p ) ) { // no free block ? 952 // Freelist for this size is empty, so check return list (OWNERSHIP), carve it out of the heap, if there 953 // is enough left, or get some more heap storage and carve it off. 981 954 #ifdef OWNERSHIP 982 // Freelist for that size is empty, so carve it out of the heap, if there is enough left, or get some more 983 // and then carve it off. 984 #ifdef RETURNSPIN 985 #if BUCKETLOCK == SPINLOCK 986 lock( freeHead->returnLock ); 987 block = freeHead->returnList; 988 freeHead->returnList = 0p; 989 unlock( freeHead->returnLock ); 990 #else 991 block = __atomic_exchange_n( &freeHead->returnList, nullptr, __ATOMIC_SEQ_CST ); 992 #endif // RETURNSPIN 993 994 if ( likely( block == 0p ) ) { // return list also empty? 955 if ( unlikely( freeHead->returnList ) ) { // race, get next time if lose race 956 #ifdef RETURNSPIN 957 lock( freeHead->returnLock ); 958 block = freeHead->returnList; 959 freeHead->returnList = 0p; 960 unlock( freeHead->returnLock ); 961 #else 962 block = __atomic_exchange_n( &freeHead->returnList, 0p, __ATOMIC_SEQ_CST ); 963 #endif // RETURNSPIN 964 965 verify( block ); 966 #ifdef __STATISTICS__ 967 stats.return_pulls += 1; 968 #endif // __STATISTICS__ 969 970 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 971 972 freeHead->freeList = block->header.kind.real.next; // merge returnList into freeHead 973 } else { 995 974 #endif // OWNERSHIP 996 975 // Do not leave kernel thread as manager_extend accesses heapManager. … … 1002 981 1003 982 #ifdef __CFA_DEBUG__ 1004 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024bytes.983 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. 1005 984 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) ); 1006 985 #endif // __CFA_DEBUG__ 1007 #endif // BUCKETLOCK1008 986 #ifdef OWNERSHIP 1009 } else { // merge returnList into freeHead1010 #ifdef __STATISTICS__1011 stats.return_pulls += 1;1012 #endif // __STATISTICS__1013 1014 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED.1015 1016 freeHead->freeList = block->header.kind.real.next;1017 987 } // if 1018 988 #endif // OWNERSHIP … … 1026 996 if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p; 1027 997 tsize = ceiling2( tsize, __page_size ); // must be multiple of page size 998 1028 999 #ifdef __STATISTICS__ 1029 1000 stats.counters[STAT_NAME].alloc += tsize; … … 1042 1013 if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory 1043 1014 // Do not call strerror( errno ) as it may call malloc. 1044 abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno ); 1015 abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", 1016 size, heapMaster.mmapStart, errno ); 1045 1017 } // if 1046 1018 block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap 1047 1019 1048 1020 #ifdef __CFA_DEBUG__ 1049 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes. The rest of1050 // the storage set to 0 by mmap.1021 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. The 1022 // rest of the storage set to 0 by mmap. 1051 1023 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) ); 1052 1024 #endif // __CFA_DEBUG__ … … 1126 1098 #endif // __CFA_DEBUG__ 1127 1099 1100 #ifdef OWNERSHIP 1128 1101 if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread 1129 1102 header->kind.real.next = freeHead->freeList; // push on stack … … 1132 1105 verify( heapManager ); 1133 1106 1134 #ifdef OWNERSHIP1135 1107 #ifdef RETURNSPIN 1136 1108 lock( freeHead->returnLock ); … … 1141 1113 header->kind.real.next = freeHead->returnList; // link new node to top node 1142 1114 // CAS resets header->kind.real.next = freeHead->returnList on failure 1143 while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header,1115 while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header, 1144 1116 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ); 1145 1117 #endif // RETURNSPIN 1146 1147 #else // no OWNERSHIP 1148 1149 freeHead = &heap->freeLists[ClearStickyBits( header->kind.real.home ) - &freeHead->homeManager->freeLists[0]]; 1150 header->kind.real.next = freeHead->freeList; // push on stack 1151 freeHead->freeList = (Heap.Storage *)header; 1152 #endif // ! OWNERSHIP 1153 1154 #ifdef __U_STATISTICS__ 1155 stats.return_pushes += 1; 1156 stats.return_storage_request += rsize; 1157 stats.return_storage_alloc += size; 1158 #endif // __U_STATISTICS__ 1159 1160 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1161 } // if 1118 } // if 1119 1120 #else // no OWNERSHIP 1121 1122 // kind.real.home is address in owner thread's freeLists, so compute the equivalent position in this thread's freeList. 1123 freeHead = &freeLists[ClearStickyBits( (Heap.FreeHeader *)(header->kind.real.home) ) - &freeHead->homeManager->freeLists[0]]; 1124 header->kind.real.next = freeHead->freeList; // push on stack 1125 freeHead->freeList = (Heap.Storage *)header; 1126 #endif // ! OWNERSHIP 1127 1128 #ifdef __U_STATISTICS__ 1129 stats.return_pushes += 1; 1130 stats.return_storage_request += rsize; 1131 stats.return_storage_alloc += size; 1132 #endif // __U_STATISTICS__ 1133 1134 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1162 1135 } // if 1163 1136 … … 1186 1159 #endif // __STATISTICS__ 1187 1160 1188 #if BUCKETLOCK == SPINLOCK1189 1161 for ( Heap.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 1190 #else1191 for(;;) {1192 // for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {1193 // for ( Heap.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {1194 // Heap.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`1195 // typeof(p) temp = (( p )`next)->top; // FIX ME: direct assignent fails, initialization works`1196 // p = temp;1197 #endif // BUCKETLOCK1198 1162 total += size; 1199 1163 #ifdef __STATISTICS__ -
libcfa/src/interpose.cfa
rb77f0e1 r63be3387 42 42 43 43 typedef void (* generic_fptr_t)(void); 44 static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) { 45 const char * error; 46 47 union { generic_fptr_t fptr; void * ptr; } originalFunc; 48 49 #if defined( _GNU_SOURCE ) 50 if ( version ) { 51 originalFunc.ptr = dlvsym( library, symbol, version ); 52 } else { 53 originalFunc.ptr = dlsym( library, symbol ); 54 } 55 #else 56 originalFunc.ptr = dlsym( library, symbol ); 57 #endif // _GNU_SOURCE 58 59 error = dlerror(); 60 if ( error ) abort( "interpose_symbol : internal error, %s\n", error ); 61 62 return originalFunc.fptr; 63 } 64 44 65 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 45 66 const char * error; 46 67 47 68 static void * library; 69 static void * pthread_library; 48 70 if ( ! library ) { 49 71 #if defined( RTLD_NEXT ) … … 58 80 #endif 59 81 } // if 60 61 union { generic_fptr_t fptr; void * ptr; } originalFunc; 62 63 #if defined( _GNU_SOURCE ) 64 if ( version ) { 65 originalFunc.ptr = dlvsym( library, symbol, version ); 66 } else { 67 originalFunc.ptr = dlsym( library, symbol ); 68 } 69 #else 70 originalFunc.ptr = dlsym( library, symbol ); 71 #endif // _GNU_SOURCE 72 73 error = dlerror(); 74 if ( error ) abort( "interpose_symbol : internal error, %s\n", error ); 75 76 return originalFunc.fptr; 82 if ( ! pthread_library ) { 83 #if defined( RTLD_NEXT ) 84 pthread_library = RTLD_NEXT; 85 #else 86 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 87 pthread_library = dlopen( "libpthread.so", RTLD_LAZY ); 88 error = dlerror(); 89 if ( error ) { 90 abort( "interpose_symbol : failed to open libpthread, %s\n", error ); 91 } 92 #endif 93 } // if 94 95 return do_interpose_symbol(library, symbol, version); 77 96 } 78 97 … … 97 116 98 117 extern "C" { 118 void __cfathreadabi_interpose_startup( generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ) ) __attribute__((weak)); 99 119 void __cfaabi_interpose_startup( void ) { 100 120 const char *version = 0p; … … 108 128 INTERPOSE_LIBC( exit , version ); 109 129 #pragma GCC diagnostic pop 130 131 if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol ); 110 132 111 133 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because -
src/AST/Convert.cpp
rb77f0e1 r63be3387 234 234 } 235 235 return declWithTypePostamble( decl, node ); 236 } 237 238 // InlineMemberDecl vanish after EnumAndPointerDecay pass so no necessary to implement NewToOld 239 const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final { 240 assert( false ); 241 (void) node; 242 return nullptr; 236 243 } 237 244 … … 1614 1621 { old->get_funcSpec().val } 1615 1622 ); 1616 decl->enumInLine = old->enumInLine;1617 1623 cache.emplace(old, decl); 1618 1624 assert(cache.find( old ) != cache.end()); … … 1859 1865 decl->uniqueId = old->uniqueId; 1860 1866 decl->storage = { old->storageClasses.val }; 1867 1868 this->node = decl; 1869 } 1870 1871 virtual void visit( const InlineMemberDecl * old ) override final { 1872 if ( inCache( old ) ) { 1873 return; 1874 } 1875 auto&& type = GET_ACCEPT_1(type, Type); 1876 auto&& attr = GET_ACCEPT_V(attributes, Attribute); 1877 1878 auto decl = new ast::InlineMemberDecl( 1879 old->location, 1880 old->name, 1881 type, 1882 { old->get_storageClasses().val }, 1883 { old->linkage.val }, 1884 std::move(attr), 1885 { old->get_funcSpec().val } 1886 ); 1887 cache.emplace(old, decl); 1888 assert(cache.find( old ) != cache.end()); 1889 decl->scopeLevel = old->scopeLevel; 1890 decl->mangleName = old->mangleName; 1891 decl->isDeleted = old->isDeleted; 1892 decl->asmName = GET_ACCEPT_1(asmName, Expr); 1893 decl->uniqueId = old->uniqueId; 1894 decl->extension = old->extension; 1861 1895 1862 1896 this->node = decl; -
src/AST/Decl.hpp
rb77f0e1 r63be3387 105 105 ptr<Init> init; 106 106 ptr<Expr> bitfieldWidth; 107 bool enumInLine = false; // enum inline is not a real object declaration.108 // It is a place holder for a set of enum value (ObjectDecl)109 bool importValue = false; // if the value copied from somewhere else110 107 111 108 ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type, … … 400 397 }; 401 398 399 /// Static Assertion `_Static_assert( ... , ... );` 402 400 class StaticAssertDecl : public Decl { 403 401 public: … … 411 409 private: 412 410 StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); } 411 MUTATE_FRIEND 412 }; 413 414 /// Inline Member Declaration `inline TypeName;` 415 class InlineMemberDecl final : public DeclWithType { 416 public: 417 ptr<Type> type; 418 419 InlineMemberDecl( const CodeLocation & loc, const std::string & name, const Type * type, 420 Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall, 421 std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {} ) 422 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ) {} 423 424 const Type * get_type() const override { return type; } 425 void set_type( const Type * ty ) override { type = ty; } 426 427 const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); } 428 private: 429 InlineMemberDecl * clone() const override { return new InlineMemberDecl{ *this }; } 413 430 MUTATE_FRIEND 414 431 }; -
src/AST/Fwd.hpp
rb77f0e1 r63be3387 37 37 class DirectiveDecl; 38 38 class StaticAssertDecl; 39 class InlineMemberDecl; 39 40 40 41 class Stmt; -
src/AST/Pass.hpp
rb77f0e1 r63be3387 141 141 const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) override final; 142 142 const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) override final; 143 const ast::DeclWithType * visit( const ast::InlineMemberDecl * ) override final; 143 144 const ast::CompoundStmt * visit( const ast::CompoundStmt * ) override final; 144 145 const ast::Stmt * visit( const ast::ExprStmt * ) override final; -
src/AST/Pass.impl.hpp
rb77f0e1 r63be3387 617 617 maybe_accept( node, &FunctionDecl::returns ); 618 618 maybe_accept( node, &FunctionDecl::type ); 619 maybe_accept( node, &FunctionDecl::attributes ); 619 620 // First remember that we are now within a function. 620 621 ValueGuard< bool > oldInFunction( inFunction ); … … 625 626 atFunctionTop = true; 626 627 maybe_accept( node, &FunctionDecl::stmts ); 627 maybe_accept( node, &FunctionDecl::attributes );628 628 } 629 629 } … … 800 800 801 801 VISIT_END( StaticAssertDecl, node ); 802 } 803 804 //-------------------------------------------------------------------------- 805 // InlineMemberDecl 806 template< typename core_t > 807 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::InlineMemberDecl * node ) { 808 VISIT_START( node ); 809 810 if ( __visit_children() ) { 811 { 812 guard_symtab guard { *this }; 813 maybe_accept( node, &InlineMemberDecl::type ); 814 } 815 } 816 817 VISIT_END( DeclWithType, node ); 802 818 } 803 819 -
src/AST/Print.cpp
rb77f0e1 r63be3387 398 398 virtual const ast::Decl * visit( const ast::StructDecl * node ) override final { 399 399 print(node); 400 return node; 401 } 402 403 virtual const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final { 404 os << "inline "; 405 if ( ! node->name.empty() ) os << node->name; 406 400 407 return node; 401 408 } -
src/AST/Type.cpp
rb77f0e1 r63be3387 147 147 // --- TypeInstType 148 148 149 bool TypeInstType::operator==( const TypeInstType & other ) const { 150 return base == other.base 151 && formal_usage == other.formal_usage 152 && expr_id == other.expr_id; 153 } 154 149 155 TypeInstType::TypeInstType( const TypeDecl * b, 150 156 CV::Qualifiers q, std::vector<ptr<Attribute>> && as ) … … 157 163 158 164 bool TypeInstType::isComplete() const { return base->sized; } 165 166 std::string TypeInstType::TypeEnvKey::typeString() const { 167 return std::string("_") + std::to_string(formal_usage) 168 + "_" + std::to_string(expr_id) + "_" + base->name; 169 } 170 171 bool TypeInstType::TypeEnvKey::operator==( 172 const TypeInstType::TypeEnvKey & other ) const { 173 return base == other.base 174 && formal_usage == other.formal_usage 175 && expr_id == other.expr_id; 176 } 177 178 bool TypeInstType::TypeEnvKey::operator<( 179 const TypeInstType::TypeEnvKey & other ) const { 180 // TypeEnvKey ordering is an arbitrary total ordering. 181 // It doesn't mean anything but allows for a sorting. 182 if ( base < other.base ) { 183 return true; 184 } else if ( other.base < base ) { 185 return false; 186 } else if ( formal_usage < other.formal_usage ) { 187 return true; 188 } else if ( other.formal_usage < formal_usage ) { 189 return false; 190 } else { 191 return expr_id < other.expr_id; 192 } 193 } 159 194 160 195 // --- TupleType -
src/AST/Type.hpp
rb77f0e1 r63be3387 408 408 409 409 TypeEnvKey() = default; 410 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {} 411 TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {} 412 std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; } 413 bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; } 410 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0) 411 : base(base), formal_usage(formal_usage), expr_id(expr_id) {} 412 TypeEnvKey(const TypeInstType & inst) 413 : base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {} 414 std::string typeString() const; 415 bool operator==(const TypeEnvKey & other) const; 416 bool operator<(const TypeEnvKey & other) const; 414 417 }; 415 418 416 bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }419 bool operator==(const TypeInstType & other) const; 417 420 418 421 TypeInstType( -
src/AST/Visitor.hpp
rb77f0e1 r63be3387 33 33 virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) = 0; 34 34 virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) = 0; 35 virtual const ast::DeclWithType * visit( const ast::InlineMemberDecl * ) = 0; 35 36 virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * ) = 0; 36 37 virtual const ast::Stmt * visit( const ast::ExprStmt * ) = 0; -
src/Common/CodeLocationTools.cpp
rb77f0e1 r63be3387 111 111 macro(DirectiveDecl, DirectiveDecl) \ 112 112 macro(StaticAssertDecl, StaticAssertDecl) \ 113 macro(InlineMemberDecl, DeclWithType) \ 113 114 macro(CompoundStmt, CompoundStmt) \ 114 115 macro(ExprStmt, Stmt) \ -
src/Common/PassVisitor.h
rb77f0e1 r63be3387 81 81 virtual void visit( StaticAssertDecl * assertDecl ) override final; 82 82 virtual void visit( const StaticAssertDecl * assertDecl ) override final; 83 virtual void visit( InlineMemberDecl * valueDecl ) override final; 84 virtual void visit( const InlineMemberDecl * valueDecl ) override final; 83 85 84 86 virtual void visit( CompoundStmt * compoundStmt ) override final; … … 273 275 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final; 274 276 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final; 277 virtual DeclarationWithType * mutate( InlineMemberDecl * valueDecl ) override final; 275 278 276 279 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override final; -
src/Common/PassVisitor.impl.h
rb77f0e1 r63be3387 607 607 indexerAddId( &func ); 608 608 maybeMutate_impl( node->type, *this ); 609 maybeMutate_impl( node->attributes, *this ); 609 610 // First remember that we are now within a function. 610 611 ValueGuard< bool > oldInFunction( inFunction ); … … 615 616 atFunctionTop = true; 616 617 maybeMutate_impl( node->statements, *this ); 617 maybeMutate_impl( node->attributes, *this );618 618 } 619 619 } … … 1044 1044 1045 1045 MUTATE_END( StaticAssertDecl, node ); 1046 } 1047 1048 //-------------------------------------------------------------------------- 1049 // InlineMemberDecl 1050 template< typename pass_type > 1051 void PassVisitor< pass_type >::visit( InlineMemberDecl * node ) { 1052 VISIT_START( node ); 1053 1054 maybeAccept_impl( node->type, *this ); 1055 1056 VISIT_END( node ); 1057 } 1058 1059 template< typename pass_type > 1060 void PassVisitor< pass_type >::visit( const InlineMemberDecl * node ) { 1061 VISIT_START( node ); 1062 1063 maybeAccept_impl( node->type, *this ); 1064 1065 VISIT_END( node ); 1066 } 1067 1068 template< typename pass_type > 1069 DeclarationWithType * PassVisitor< pass_type >::mutate( InlineMemberDecl * node ) { 1070 MUTATE_START( node ); 1071 1072 maybeMutate_impl( node->type, *this ); 1073 1074 MUTATE_END( DeclarationWithType, node ); 1046 1075 } 1047 1076 -
src/Common/utility.h
rb77f0e1 r63be3387 452 452 453 453 // ----------------------------------------------------------------------------- 454 // Helper struct and function to support 455 // for ( val : group_iterate( container1, container2, ... ) ) {} 456 // syntax to have a for each that iterates multiple containers of the same length 457 // TODO: update to use variadic arguments 458 459 template< typename T1, typename T2 > 460 struct group_iterate_t { 461 private: 462 std::tuple<T1, T2> args; 454 // Helper struct and function to support: 455 // for ( auto val : group_iterate( container1, container2, ... ) ) { ... } 456 // This iteraters through multiple containers of the same size. 457 458 template<typename... Args> 459 class group_iterate_t { 460 using Iterables = std::tuple<Args...>; 461 Iterables iterables; 462 463 // Getting the iterator and value types this way preserves const. 464 template<size_t I> using Iter = decltype(std::get<I>(iterables).begin()); 465 template<size_t I> using Data = decltype(*std::get<I>(iterables).begin()); 466 template<typename> struct base_iterator; 467 468 // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1` 469 // into a pack. These are the indexes into the tuples, so unpacking can 470 // go over each element of the tuple. 471 // The std::integer_sequence is just used to build that sequence. 472 // A library reference will probably explain it better than I can. 473 template<std::size_t... Indices> 474 struct base_iterator<std::integer_sequence<std::size_t, Indices...>> { 475 using value_type = std::tuple< Data<Indices>... >; 476 std::tuple<Iter<Indices>...> iterators; 477 478 base_iterator( Iter<Indices>... is ) : iterators( is... ) {} 479 base_iterator operator++() { 480 return base_iterator( ++std::get<Indices>( iterators )... ); 481 } 482 bool operator!=( const base_iterator& other ) const { 483 return iterators != other.iterators; 484 } 485 value_type operator*() const { 486 return std::tie( *std::get<Indices>( iterators )... ); 487 } 488 489 static base_iterator make_begin( Iterables & data ) { 490 return base_iterator( std::get<Indices>( data ).begin()... ); 491 } 492 static base_iterator make_end( Iterables & data ) { 493 return base_iterator( std::get<Indices>( data ).end()... ); 494 } 495 }; 496 463 497 public: 464 group_iterate_t( bool skipBoundsCheck, const T1 & v1, const T2 & v2 ) : args(v1, v2) { 465 assertf(skipBoundsCheck || v1.size() == v2.size(), "group iteration requires containers of the same size: <%zd, %zd>.", v1.size(), v2.size()); 466 }; 467 468 typedef std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin())> value_type; 469 typedef decltype(std::get<0>(args).begin()) T1Iter; 470 typedef decltype(std::get<1>(args).begin()) T2Iter; 471 472 struct iterator { 473 typedef std::tuple<T1Iter, T2Iter> IterTuple; 474 IterTuple it; 475 iterator( T1Iter i1, T2Iter i2 ) : it( i1, i2 ) {} 476 iterator operator++() { 477 return iterator( ++std::get<0>(it), ++std::get<1>(it) ); 478 } 479 bool operator!=( const iterator &other ) const { return it != other.it; } 480 value_type operator*() const { return std::tie( *std::get<0>(it), *std::get<1>(it) ); } 481 }; 482 483 iterator begin() { return iterator( std::get<0>(args).begin(), std::get<1>(args).begin() ); } 484 iterator end() { return iterator( std::get<0>(args).end(), std::get<1>(args).end() ); } 485 }; 486 487 /// performs bounds check to ensure that all arguments are of the same length. 498 group_iterate_t( const Args &... args ) : iterables( args... ) {} 499 500 using iterator = base_iterator<decltype( 501 std::make_integer_sequence<std::size_t, sizeof...(Args)>())>; 502 503 iterator begin() { return iterator::make_begin( iterables ); } 504 iterator end() { return iterator::make_end( iterables ); } 505 }; 506 507 // Helpers for the bounds checks (the non-varatic part of group_iterate): 508 static inline void runGroupBoundsCheck(size_t size0, size_t size1) { 509 assertf( size0 == size1, 510 "group iteration requires containers of the same size: <%zd, %zd>.", 511 size0, size1 ); 512 } 513 514 static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) { 515 assertf( size0 == size1 && size1 == size2, 516 "group iteration requires containers of the same size: <%zd, %zd, %zd>.", 517 size0, size1, size2 ); 518 } 519 520 /// Performs bounds check to ensure that all arguments are of the same length. 488 521 template< typename... Args > 489 522 group_iterate_t<Args...> group_iterate( Args &&... args ) { 490 return group_iterate_t<Args...>(false, std::forward<Args>( args )...); 491 } 492 493 /// does not perform a bounds check - requires user to ensure that iteration terminates when appropriate. 523 runGroupBoundsCheck( args.size()... ); 524 return group_iterate_t<Args...>( std::forward<Args>( args )... ); 525 } 526 527 /// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate. 494 528 template< typename... Args > 495 529 group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) { 496 return group_iterate_t<Args...>( true, std::forward<Args>( args )...);530 return group_iterate_t<Args...>( std::forward<Args>( args )... ); 497 531 } 498 532 -
src/GenPoly/Box.cc
rb77f0e1 r63be3387 58 58 namespace GenPoly { 59 59 namespace { 60 FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );60 FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars ); 61 61 62 62 class BoxPass { … … 68 68 /// Adds layout-generation functions to polymorphic types. 69 69 class LayoutFunctionBuilder final : public WithDeclsToAdd, public WithVisitorRef<LayoutFunctionBuilder>, public WithShortCircuiting { 70 // Current level of nested functions:71 unsigned int functionNesting = 0;72 70 public: 73 void previsit( FunctionDecl *functionDecl );74 71 void previsit( StructDecl *structDecl ); 75 72 void previsit( UnionDecl *unionDecl ); … … 100 97 void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ); 101 98 /// passes extra type parameters into a polymorphic function application 102 void passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ); 99 /// Returns an iterator to the first argument after the added 100 /// arguments, which are added at the beginning. 101 std::list< Expression *>::iterator passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ); 103 102 /// wraps a function application with a new temporary for the out-parameter return value 104 Expression *addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg ); 105 /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment 106 void replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params ); 107 /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete). 108 /// If `doClone` is set to false, will not clone interior types 109 Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true ); 103 /// The new out-parameter is the new first parameter. 104 Expression *addRetParam( ApplicationExpr *appExpr, Type *retType ); 110 105 /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value 111 Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg ); 112 Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ); 113 void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars ); 114 void boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ); 115 void addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ); 106 Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType ); 107 /// Converts a function call into a call of the adapter with the 108 /// original function as the first argument (all other arguments 109 /// are pushed back). May adjust return value. 110 Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function ); 111 /// Modifies the `arg`, replacing it with a boxed expression 112 /// that matches `formal` under the current TyVarMap. 113 void boxParam( Expression *&arg, Type *formal, const TyVarMap &exprTyVars ); 114 /// Box an argument of `appExpr` for each parameter in `function` 115 /// starting at `arg`. 116 /// `exprTyVars` is the function's type variables. 117 void boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ); 118 /// Boxes each assertion and inserts them into `appExpr` at 119 /// `arg`. `exprTyVars` is the function's type variables. 120 void addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ); 116 121 /// Stores assignment operators from assertion list in local map of assignment operations 117 122 void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars ); 118 FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ); 123 /// Creates an adapter definition from `adaptee` to `realType`, using 124 /// `mangleName` as the base name for the adapter. `tyVars` is the map of 125 /// type variables for the function type of the adapted expression. 126 FunctionDecl *makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ); 119 127 /// Replaces intrinsic operator functions with their arithmetic desugaring 120 128 Expression *handleIntrinsics( ApplicationExpr *appExpr ); … … 182 190 ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 ); 183 191 /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns 184 bool findGeneric( Type *ty );192 bool findGeneric( Type const *ty ); 185 193 /// adds type parameters to the layout call; will generate the appropriate parameters if needed 186 194 void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ); … … 221 229 } // anonymous namespace 222 230 223 /// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging224 template< typename MutatorType >225 inline void mutateTranslationUnit( std::list< Declaration* > &translationUnit, MutatorType &mutator ) {226 bool seenIntrinsic = false;227 SemanticErrorException errors;228 for ( typename std::list< Declaration* >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {229 try {230 if ( *i ) {231 if ( (*i)->get_linkage() == LinkageSpec::Intrinsic ) {232 seenIntrinsic = true;233 } else if ( seenIntrinsic ) {234 seenIntrinsic = false; // break on this line when debugging for end of prelude235 }236 237 *i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) );238 assert( *i );239 } // if240 } catch( SemanticErrorException &e ) {241 errors.append( e );242 } // try243 } // for244 if ( ! errors.isEmpty() ) {245 throw errors;246 } // if247 }248 249 231 void box( std::list< Declaration *>& translationUnit ) { 250 232 PassVisitor<LayoutFunctionBuilder> layoutBuilder; … … 263 245 ////////////////////////////////// LayoutFunctionBuilder //////////////////////////////////////////// 264 246 265 void LayoutFunctionBuilder::previsit( FunctionDecl *functionDecl ) {266 visit_children = false;267 maybeAccept( functionDecl->get_functionType(), *visitor );268 ++functionNesting;269 maybeAccept( functionDecl->get_statements(), *visitor );270 --functionNesting;271 }272 273 247 /// Get a list of type declarations that will affect a layout function 274 248 std::list< TypeDecl* > takeOtypeOnly( std::list< TypeDecl* > &decls ) { 275 249 std::list< TypeDecl * > otypeDecls; 276 250 277 for ( std::list< TypeDecl* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl) {278 if ( (*decl)->isComplete() ) {279 otypeDecls.push_back( *decl );251 for ( TypeDecl * const decl : decls ) { 252 if ( decl->isComplete() ) { 253 otypeDecls.push_back( decl ); 280 254 } 281 255 } … … 288 262 BasicType sizeAlignType( Type::Qualifiers(), BasicType::LongUnsignedInt ); 289 263 290 for ( std::list< TypeDecl* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param) {291 TypeInstType paramType( Type::Qualifiers(), (*param)->get_name(), *param );264 for ( TypeDecl * const param : otypeParams ) { 265 TypeInstType paramType( Type::Qualifiers(), param->get_name(), param ); 292 266 std::string paramName = mangleType( ¶mType ); 293 267 layoutFnType->get_parameters().push_back( new ObjectDecl( sizeofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) ); … … 297 271 298 272 /// Builds a layout function declaration 299 FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, unsigned int functionNesting, FunctionType *layoutFnType ) {273 FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, bool isInFunction, FunctionType *layoutFnType ) { 300 274 // Routines at global scope marked "static" to prevent multiple definitions is separate translation units 301 275 // because each unit generates copies of the default routines for each aggregate. 302 276 FunctionDecl *layoutDecl = new FunctionDecl( layoutofName( typeDecl ), 303 functionNesting > 0? Type::StorageClasses() : Type::StorageClasses( Type::Static ),277 isInFunction ? Type::StorageClasses() : Type::StorageClasses( Type::Static ), 304 278 LinkageSpec::AutoGen, layoutFnType, new CompoundStmt(), 305 279 std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ); 306 280 layoutDecl->fixUniqueId(); 307 281 return layoutDecl; 308 }309 310 /// Makes a unary operation311 Expression *makeOp( const std::string &name, Expression *arg ) {312 UntypedExpr *expr = new UntypedExpr( new NameExpr( name ) );313 expr->args.push_back( arg );314 return expr;315 282 } 316 283 … … 380 347 381 348 // build function decl 382 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, functionNesting, layoutFnType );349 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, isInFunction(), layoutFnType ); 383 350 384 351 // calculate struct layout in function body … … 387 354 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) ); 388 355 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 389 unsigned long n_members = 0; 390 bool firstMember = true; 391 for ( Declaration* member : structDecl->get_members() ) { 392 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member ); 356 for ( auto index_member : enumerate( structDecl->members ) ) { 357 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( index_member.val ); 393 358 assert( dwt ); 394 359 Type *memberType = dwt->get_type(); 395 360 396 if ( firstMember ) { 397 firstMember = false; 398 } else { 361 if ( 0 < index_member.idx ) { 399 362 // make sure all members after the first (automatically aligned at 0) are properly padded for alignment 400 363 addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), new AlignofExpr( memberType->clone() ) ) ); … … 402 365 403 366 // place current size in the current offset index 404 addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( n_members) ) ),367 addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( index_member.idx ) ) ), 405 368 derefVar( sizeParam ) ) ); 406 ++n_members;407 369 408 370 // add member size to current size … … 439 401 440 402 // build function decl 441 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, functionNesting, layoutFnType );403 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, isInFunction(), layoutFnType ); 442 404 443 405 // calculate union layout in function body 444 406 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 445 407 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 446 for ( std::list< Declaration* >::const_iterator member = unionDecl->get_members().begin(); member != unionDecl->get_members().end(); ++member) {447 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member );408 for ( Declaration * const member : unionDecl->members ) { 409 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member ); 448 410 assert( dwt ); 449 411 Type *memberType = dwt->get_type(); … … 464 426 465 427 namespace { 466 std::string makePolyMonoSuffix( FunctionType * function, const TyVarMap &tyVars ) {428 std::string makePolyMonoSuffix( FunctionType const * function, const TyVarMap &tyVars ) { 467 429 std::stringstream name; 468 430 … … 473 435 // to take those polymorphic types as pointers. Therefore, there can be two different functions 474 436 // with the same mangled name, so we need to further mangle the names. 475 for ( std::list< DeclarationWithType *>::iterator retval = function->get_returnVals().begin(); retval != function->get_returnVals().end(); ++retval) {476 if ( isPolyType( (*retval)->get_type(), tyVars ) ) {437 for ( DeclarationWithType const * const ret : function->returnVals ) { 438 if ( isPolyType( ret->get_type(), tyVars ) ) { 477 439 name << "P"; 478 440 } else { … … 481 443 } 482 444 name << "_"; 483 std::list< DeclarationWithType *> ¶mList = function->get_parameters(); 484 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { 485 if ( isPolyType( (*arg)->get_type(), tyVars ) ) { 445 for ( DeclarationWithType const * const arg : function->parameters ) { 446 if ( isPolyType( arg->get_type(), tyVars ) ) { 486 447 name << "P"; 487 448 } else { … … 492 453 } 493 454 494 std::string mangleAdapterName( FunctionType * function, const TyVarMap &tyVars ) {455 std::string mangleAdapterName( FunctionType const * function, const TyVarMap &tyVars ) { 495 456 return SymTab::Mangler::mangle( function ) + makePolyMonoSuffix( function, tyVars ); 496 457 } … … 499 460 return "_adapter" + mangleName; 500 461 } 462 463 /// Replaces a polymorphic type with its concrete equivalant under the current environment (returns itself if concrete). 464 /// If `doClone` is set to false, will not clone interior types 465 Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true ); 501 466 502 467 Pass1::Pass1() : tempNamer( "_temp" ) {} … … 524 489 525 490 std::list< DeclarationWithType *> ¶mList = functionType->parameters; 526 std::list< FunctionType *> functions;527 for ( Type ::ForallList::iterator tyVar = functionType->forall.begin(); tyVar != functionType->forall.end(); ++tyVar) {528 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert) {529 findFunction( (*assert)->get_type(), functions, scopeTyVars, needsAdapter );491 std::list< FunctionType const *> functions; 492 for ( TypeDecl * const tyVar : functionType->forall ) { 493 for ( DeclarationWithType * const assert : tyVar->assertions ) { 494 findFunction( assert->get_type(), functions, scopeTyVars, needsAdapter ); 530 495 } // for 531 496 } // for 532 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg) {533 findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter );497 for ( DeclarationWithType * const arg : paramList ) { 498 findFunction( arg->get_type(), functions, scopeTyVars, needsAdapter ); 534 499 } // for 535 500 536 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType) {537 std::string mangleName = mangleAdapterName( *funType, scopeTyVars );501 for ( FunctionType const * const funType : functions ) { 502 std::string mangleName = mangleAdapterName( funType, scopeTyVars ); 538 503 if ( adapters.find( mangleName ) == adapters.end() ) { 539 504 std::string adapterName = makeAdapterName( mangleName ); 540 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), nullptr ) ) );505 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), nullptr ) ) ); 541 506 } // if 542 507 } // for … … 593 558 } 594 559 595 void Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) { 560 std::list< Expression *>::iterator Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, const TyVarMap &exprTyVars ) { 561 assert( env ); 562 std::list< Expression *>::iterator arg = appExpr->args.begin(); 596 563 // pass size/align for type variables 597 for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm) {564 for ( std::pair<std::string, TypeDecl::Data> const & tyParam : exprTyVars ) { 598 565 ResolvExpr::EqvClass eqvClass; 599 assert( env ); 600 if ( tyParm->second.isComplete ) { 601 Type *concrete = env->lookup( tyParm->first ); 602 if ( concrete ) { 603 arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) ); 604 arg++; 605 arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) ); 606 arg++; 607 } else { 608 // xxx - should this be an assertion? 609 SemanticError( appExpr, toString( *env, "\nunbound type variable: ", tyParm->first, " in application " ) ); 610 } // if 566 if ( tyParam.second.isComplete ) { 567 Type *concrete = env->lookup( tyParam.first ); 568 // If there is an unbound type variable, it should have detected already. 569 assertf( concrete, "Unbound type variable: %s in: %s", 570 toCString( tyParam.first ), toCString( *env ) ); 571 572 arg = appExpr->get_args().insert( arg, new SizeofExpr( concrete->clone() ) ); 573 arg++; 574 arg = appExpr->get_args().insert( arg, new AlignofExpr( concrete->clone() ) ); 575 arg++; 611 576 } // if 612 577 } // for 613 578 614 579 // add size/align for generic types to parameter list 615 if ( ! appExpr->get_function()->result ) return ;580 if ( ! appExpr->get_function()->result ) return arg; 616 581 FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() ); 617 582 assert( funcType ); 618 583 584 // These iterators don't advance in unison. 619 585 std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); 620 586 std::list< Expression* >::const_iterator fnArg = arg; … … 623 589 // a polymorphic return type may need to be added to the argument list 624 590 if ( polyRetType ) { 625 Type *concRetType = replaceWithConcrete( appExpr, polyRetType);591 Type *concRetType = replaceWithConcrete( polyRetType, env ); 626 592 passArgTypeVars( appExpr, polyRetType, concRetType, arg, exprTyVars, seenTypes ); 627 593 ++fnArg; // skip the return parameter in the argument list … … 634 600 passArgTypeVars( appExpr, (*fnParm)->get_type(), argType, arg, exprTyVars, seenTypes ); 635 601 } 602 return arg; 636 603 } 637 604 … … 642 609 } 643 610 644 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType , std::list< Expression *>::iterator &arg) {611 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType ) { 645 612 // Create temporary to hold return value of polymorphic function and produce that temporary as a result 646 613 // using a comma expression. … … 662 629 paramExpr = new AddressExpr( paramExpr ); 663 630 } // if 664 arg = appExpr->args.insert( arg, paramExpr ); // add argument to function call665 a rg++;631 // Add argument to function call. 632 appExpr->args.push_front( paramExpr ); 666 633 // Build a comma expression to call the function and emulate a normal return. 667 634 CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr ); … … 671 638 } 672 639 673 void Pass1::replaceParametersWithConcrete( ApplicationExpr *appExpr, std::list< Expression* >& params ) { 674 for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) { 675 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param ); 640 /// Replaces all the type parameters of a generic type with their concrete equivalents under the current environment 641 void replaceParametersWithConcrete( std::list< Expression* >& params, TypeSubstitution const * env ) { 642 for ( Expression * const param : params ) { 643 TypeExpr *paramType = dynamic_cast< TypeExpr* >( param ); 676 644 assertf(paramType, "Aggregate parameters should be type expressions"); 677 paramType->set_type( replaceWithConcrete( appExpr, paramType->get_type(), false ) ); 678 } 679 } 680 681 Type *Pass1::replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone ) { 645 paramType->set_type( replaceWithConcrete( paramType->get_type(), env, false ) ); 646 } 647 } 648 649 // See forward definition. 650 Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone ) { 651 assert( env ); 682 652 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 683 653 Type *concrete = env->lookup( typeInst->get_name() ); … … 690 660 structType = structType->clone(); 691 661 } 692 replaceParametersWithConcrete( appExpr, structType->get_parameters());662 replaceParametersWithConcrete( structType->get_parameters(), env ); 693 663 return structType; 694 664 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { … … 696 666 unionType = unionType->clone(); 697 667 } 698 replaceParametersWithConcrete( appExpr, unionType->get_parameters());668 replaceParametersWithConcrete( unionType->get_parameters(), env ); 699 669 return unionType; 700 670 } … … 702 672 } 703 673 704 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) { 705 assert( env ); 706 Type *concrete = replaceWithConcrete( appExpr, dynType ); 674 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) { 675 Type *concrete = replaceWithConcrete( dynType, env ); 707 676 // add out-parameter for return value 708 return addRetParam( appExpr, concrete , arg);709 } 710 711 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function , std::list< Expression *>::iterator &arg, const TyVarMap &tyVars) {677 return addRetParam( appExpr, concrete ); 678 } 679 680 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) { 712 681 Expression *ret = appExpr; 713 682 // if ( ! function->get_returnVals().empty() && isPolyType( function->get_returnVals().front()->get_type(), tyVars ) ) { 714 if ( isDynRet( function, tyVars ) ) {715 ret = addRetParam( appExpr, function->returnVals.front()->get_type() , arg);683 if ( isDynRet( function, scopeTyVars ) ) { 684 ret = addRetParam( appExpr, function->returnVals.front()->get_type() ); 716 685 } // if 717 std::string mangleName = mangleAdapterName( function, tyVars );686 std::string mangleName = mangleAdapterName( function, scopeTyVars ); 718 687 std::string adapterName = makeAdapterName( mangleName ); 719 688 … … 724 693 725 694 return ret; 726 }727 728 void Pass1::boxParam( Type *param, Expression *&arg, const TyVarMap &exprTyVars ) {729 assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() );730 if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return;731 732 if ( arg->get_lvalue() ) {733 // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.734 // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {735 // if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){736 // // temporary hack - don't box arrays, because &arr is not the same as &arr[0]737 // return;738 // }739 // }740 arg = generalizedLvalue( new AddressExpr( arg ) );741 if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {742 // silence warnings by casting boxed parameters when the actual type does not match up with the formal type.743 arg = new CastExpr( arg, param->clone() );744 }745 } else {746 // use type computed in unification to declare boxed variables747 Type * newType = param->clone();748 if ( env ) env->apply( newType );749 ObjectDecl *newObj = ObjectDecl::newObject( tempNamer.newName(), newType, nullptr );750 newObj->get_type()->get_qualifiers() = Type::Qualifiers(); // TODO: is this right???751 stmtsToAddBefore.push_back( new DeclStmt( newObj ) );752 UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); // TODO: why doesn't this just use initialization syntax?753 assign->get_args().push_back( new VariableExpr( newObj ) );754 assign->get_args().push_back( arg );755 stmtsToAddBefore.push_back( new ExprStmt( assign ) );756 arg = new AddressExpr( new VariableExpr( newObj ) );757 } // if758 695 } 759 696 … … 791 728 } 792 729 793 void Pass1::boxParams( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) { 794 for ( std::list< DeclarationWithType *>::const_iterator param = function->get_parameters().begin(); param != function->parameters.end(); ++param, ++arg ) { 795 assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( *param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() ); 796 addCast( *arg, (*param)->get_type(), exprTyVars ); 797 boxParam( (*param)->get_type(), *arg, exprTyVars ); 730 void Pass1::boxParam( Expression *&arg, Type *param, const TyVarMap &exprTyVars ) { 731 assertf( arg->result, "arg does not have result: %s", toString( arg ).c_str() ); 732 addCast( arg, param, exprTyVars ); 733 if ( ! needsBoxing( param, arg->result, exprTyVars, env ) ) return; 734 735 if ( arg->get_lvalue() ) { 736 // argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations. 737 // if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) { 738 // if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){ 739 // // temporary hack - don't box arrays, because &arr is not the same as &arr[0] 740 // return; 741 // } 742 // } 743 arg = generalizedLvalue( new AddressExpr( arg ) ); 744 if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) { 745 // silence warnings by casting boxed parameters when the actual type does not match up with the formal type. 746 arg = new CastExpr( arg, param->clone() ); 747 } 748 } else { 749 // use type computed in unification to declare boxed variables 750 Type * newType = param->clone(); 751 if ( env ) env->apply( newType ); 752 ObjectDecl *newObj = makeTemporary( newType ); 753 // TODO: is this right??? (Why wouldn't it be?) 754 newObj->get_type()->get_qualifiers() = Type::Qualifiers(); 755 // TODO: why doesn't this just use initialization syntax? 756 // (Possibly to ensure code is run at the right time.) 757 UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); 758 assign->get_args().push_back( new VariableExpr( newObj ) ); 759 assign->get_args().push_back( arg ); 760 stmtsToAddBefore.push_back( new ExprStmt( assign ) ); 761 arg = new AddressExpr( new VariableExpr( newObj ) ); 762 } // if 763 } 764 765 void Pass1::boxParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *function, const TyVarMap &exprTyVars ) { 766 for ( DeclarationWithType * param : function->parameters ) { 767 assertf( arg != appExpr->args.end(), "boxParams: missing argument for param %s to %s in %s", toString( param ).c_str(), toString( function ).c_str(), toString( appExpr ).c_str() ); 768 boxParam( *arg, param->get_type(), exprTyVars ); 769 ++arg; 798 770 } // for 799 771 } 800 772 801 void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) {773 void Pass1::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) { 802 774 std::list< Expression *>::iterator cur = arg; 803 for ( Type ::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar) {804 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->assertions.begin(); assert != (*tyVar)->assertions.end(); ++assert) {805 InferredParams::const_iterator inferParam = appExpr->inferParams.find( (*assert)->get_uniqueId() );806 assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( *assert ).c_str(), toString( appExpr ).c_str() );775 for ( TypeDecl * const tyVar : functionType->forall ) { 776 for ( DeclarationWithType * const assert : tyVar->assertions ) { 777 InferredParams::const_iterator inferParam = appExpr->inferParams.find( assert->get_uniqueId() ); 778 assertf( inferParam != appExpr->inferParams.end(), "addInferredParams missing inferred parameter: %s in: %s", toString( assert ).c_str(), toString( appExpr ).c_str() ); 807 779 Expression *newExpr = inferParam->second.expr->clone(); 808 addCast( newExpr, (*assert)->get_type(), tyVars ); 809 boxParam( (*assert)->get_type(), newExpr, tyVars ); 780 boxParam( newExpr, assert->get_type(), tyVars ); 810 781 appExpr->get_args().insert( cur, newExpr ); 811 782 } // for … … 824 795 } 825 796 826 FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars ) {797 FunctionType *makeAdapterType( FunctionType const *adaptee, const TyVarMap &tyVars ) { 827 798 // actually make the adapter type 828 799 FunctionType *adapter = adaptee->clone(); … … 834 805 } 835 806 836 Expression *makeAdapterArg( DeclarationWithType *param, DeclarationWithType *arg, DeclarationWithType *realParam, const TyVarMap &tyVars ) { 807 Expression *makeAdapterArg( 808 DeclarationWithType *param, 809 DeclarationWithType const *arg, 810 DeclarationWithType const *realParam, 811 const TyVarMap &tyVars ) { 837 812 assert( param ); 838 813 assert( arg ); 839 if ( isPolyType( realParam->get_type(), tyVars ) ) { 840 if ( ! isPolyType( arg->get_type() ) ) { 841 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) ); 842 deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) ); 843 deref->result = arg->get_type()->clone(); 844 return deref; 845 } // if 814 if ( isPolyType( realParam->get_type(), tyVars ) 815 && ! isPolyType( arg->get_type() ) ) { 816 UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) ); 817 deref->args.push_back( new CastExpr( new VariableExpr( param ), new PointerType( Type::Qualifiers(), arg->get_type()->clone() ) ) ); 818 deref->result = arg->get_type()->clone(); 819 return deref; 846 820 } // if 847 821 return new VariableExpr( param ); 848 822 } 849 823 850 void addAdapterParams( ApplicationExpr *adapteeApp, std::list< DeclarationWithType *>::iterator arg, std::list< DeclarationWithType *>::iterator param, std::list< DeclarationWithType *>::iterator paramEnd, std::list< DeclarationWithType *>::iterator realParam, const TyVarMap &tyVars ) { 824 void addAdapterParams( 825 ApplicationExpr *adapteeApp, 826 std::list< DeclarationWithType *>::const_iterator arg, 827 std::list< DeclarationWithType *>::const_iterator param, 828 std::list< DeclarationWithType *>::const_iterator paramEnd, 829 std::list< DeclarationWithType *>::const_iterator realParam, 830 const TyVarMap &tyVars ) { 851 831 UniqueName paramNamer( "_p" ); 852 832 for ( ; param != paramEnd; ++param, ++arg, ++realParam ) { … … 859 839 } 860 840 861 FunctionDecl *Pass1::makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {841 FunctionDecl *Pass1::makeAdapter( FunctionType const *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) { 862 842 FunctionType *adapterType = makeAdapterType( adaptee, tyVars ); 863 843 adapterType = ScrubTyVars::scrub( adapterType, tyVars ); … … 876 856 Statement *bodyStmt; 877 857 878 Type::ForallList::iterator tyArg = realType->get_forall().begin(); 879 Type::ForallList::iterator tyParam = adapterType->get_forall().begin(); 880 Type::ForallList::iterator realTyParam = adaptee->get_forall().begin(); 881 for ( ; tyParam != adapterType->get_forall().end(); ++tyArg, ++tyParam, ++realTyParam ) { 882 assert( tyArg != realType->get_forall().end() ); 883 std::list< DeclarationWithType *>::iterator assertArg = (*tyArg)->get_assertions().begin(); 884 std::list< DeclarationWithType *>::iterator assertParam = (*tyParam)->get_assertions().begin(); 885 std::list< DeclarationWithType *>::iterator realAssertParam = (*realTyParam)->get_assertions().begin(); 886 for ( ; assertParam != (*tyParam)->get_assertions().end(); ++assertArg, ++assertParam, ++realAssertParam ) { 887 assert( assertArg != (*tyArg)->get_assertions().end() ); 888 adapteeApp->get_args().push_back( makeAdapterArg( *assertParam, *assertArg, *realAssertParam, tyVars ) ); 858 for ( auto tys : group_iterate( realType->forall, adapterType->forall, adaptee->forall ) ) { 859 TypeDecl * tyArg = std::get<0>( tys ); 860 TypeDecl * tyParam = std::get<1>( tys ); 861 TypeDecl * realTyParam = std::get<2>( tys ); 862 for ( auto asserts : group_iterate( tyArg->assertions, tyParam->assertions, realTyParam->assertions ) ) { 863 DeclarationWithType * assertArg = std::get<0>( asserts ); 864 DeclarationWithType * assertParam = std::get<1>( asserts ); 865 DeclarationWithType * realAssertParam = std::get<2>( asserts ); 866 adapteeApp->args.push_back( makeAdapterArg( assertParam, assertArg, realAssertParam, tyVars ) ); 889 867 } // for 890 868 } // for 891 869 892 std::list< DeclarationWithType *>:: iterator arg = realType->get_parameters().begin();893 std::list< DeclarationWithType *>:: iterator param = adapterType->get_parameters().begin();894 std::list< DeclarationWithType *>:: iterator realParam = adaptee->get_parameters().begin();870 std::list< DeclarationWithType *>::const_iterator arg = realType->parameters.begin(); 871 std::list< DeclarationWithType *>::const_iterator param = adapterType->parameters.begin(); 872 std::list< DeclarationWithType *>::const_iterator realParam = adaptee->parameters.begin(); 895 873 param++; // skip adaptee parameter in the adapter type 896 874 if ( realType->get_returnVals().empty() ) { … … 898 876 addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars ); 899 877 bodyStmt = new ExprStmt( adapteeApp ); 900 } else if ( isDynType( adaptee-> get_returnVals().front()->get_type(), tyVars ) ) {878 } else if ( isDynType( adaptee->returnVals.front()->get_type(), tyVars ) ) { 901 879 // return type T 902 880 if ( (*param)->get_name() == "" ) { … … 923 901 void Pass1::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) { 924 902 // collect a list of function types passed as parameters or implicit parameters (assertions) 925 std::list< DeclarationWithType *> ¶mList = functionType->get_parameters(); 926 std::list< FunctionType *> functions; 927 for ( Type::ForallList::iterator tyVar = functionType->get_forall().begin(); tyVar != functionType->get_forall().end(); ++tyVar ) { 928 for ( std::list< DeclarationWithType *>::iterator assert = (*tyVar)->get_assertions().begin(); assert != (*tyVar)->get_assertions().end(); ++assert ) { 929 findFunction( (*assert)->get_type(), functions, exprTyVars, needsAdapter ); 903 std::list<FunctionType const *> functions; 904 for ( TypeDecl * const tyVar : functionType->get_forall() ) { 905 for ( DeclarationWithType * const assert : tyVar->get_assertions() ) { 906 findFunction( assert->get_type(), functions, exprTyVars, needsAdapter ); 930 907 } // for 931 908 } // for 932 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg) {933 findFunction( (*arg)->get_type(), functions, exprTyVars, needsAdapter );909 for ( DeclarationWithType * const arg : functionType->get_parameters() ) { 910 findFunction( arg->get_type(), functions, exprTyVars, needsAdapter ); 934 911 } // for 935 912 … … 938 915 std::set< std::string > adaptersDone; 939 916 940 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType) {941 FunctionType *originalFunction = (*funType)->clone();942 FunctionType *realFunction = (*funType)->clone();917 for ( FunctionType const * const funType : functions ) { 918 FunctionType *originalFunction = funType->clone(); 919 FunctionType *realFunction = funType->clone(); 943 920 std::string mangleName = SymTab::Mangler::mangle( realFunction ); 944 921 … … 958 935 if ( adapter == adapters.end() ) { 959 936 // adapter has not been created yet in the current scope, so define it 960 FunctionDecl *newAdapter = makeAdapter( *funType, realFunction, mangleName, exprTyVars );937 FunctionDecl *newAdapter = makeAdapter( funType, realFunction, mangleName, exprTyVars ); 961 938 std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) ); 962 939 adapter = answer.first; … … 972 949 973 950 Expression *makeIncrDecrExpr( ApplicationExpr *appExpr, Type *polyType, bool isIncr ) { 974 NameExpr *opExpr; 975 if ( isIncr ) { 976 opExpr = new NameExpr( "?+=?" ); 977 } else { 978 opExpr = new NameExpr( "?-=?" ); 979 } // if 951 NameExpr *opExpr = new NameExpr( ( isIncr ) ? "?+=?" : "?-=?" ); 980 952 UntypedExpr *addAssign = new UntypedExpr( opExpr ); 981 953 if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) { … … 1120 1092 Expression *Pass1::postmutate( ApplicationExpr *appExpr ) { 1121 1093 // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl; 1122 // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i) {1123 // std::cerr << i->first << " ";1094 // for ( auto tyVar : scopeTyVars ) { 1095 // std::cerr << tyVar.first << " "; 1124 1096 // } 1125 1097 // std::cerr << "\n"; … … 1134 1106 1135 1107 Expression *ret = appExpr; 1136 1137 std::list< Expression *>::iterator arg = appExpr->get_args().begin();1138 1108 std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin(); 1139 1109 … … 1156 1126 // std::cerr << "dynRetType: " << dynRetType << std::endl; 1157 1127 Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result(); 1158 ret = addDynRetParam( appExpr, concRetType , arg); // xxx - used to use dynRetType instead of concRetType1128 ret = addDynRetParam( appExpr, concRetType ); // xxx - used to use dynRetType instead of concRetType 1159 1129 } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...? 1160 1130 // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed. … … 1164 1134 // std::cerr << *env << std::endl; 1165 1135 // change the application so it calls the adapter rather than the passed function 1166 ret = applyAdapter( appExpr, function , arg, scopeTyVars);1136 ret = applyAdapter( appExpr, function ); 1167 1137 } // if 1168 arg = appExpr->get_args().begin(); 1169 1170 Type *concRetType = replaceWithConcrete( appExpr, dynRetType );1171 passTypeVars( appExpr, concRetType, arg, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's)1172 addInferredParams( appExpr, function, arg, exprTyVars );1173 1174 arg = paramBegin;1175 1176 boxParams( appExpr, function, arg, exprTyVars ); 1138 1139 Type *concRetType = replaceWithConcrete( dynRetType, env ); 1140 std::list< Expression *>::iterator arg = 1141 passTypeVars( appExpr, concRetType, exprTyVars ); // xxx - used to use dynRetType instead of concRetType; this changed so that the correct type paramaters are passed for return types (it should be the concrete type's parameters, not the formal type's) 1142 addInferredParams( appExpr, arg, function, exprTyVars ); 1143 1144 // This needs to point at the original first argument. 1145 boxParams( appExpr, paramBegin, function, exprTyVars ); 1146 1177 1147 passAdapters( appExpr, function, exprTyVars ); 1178 1148 … … 1180 1150 } 1181 1151 1182 Expression * Pass1::postmutate( UntypedExpr *expr) {1152 bool isPolyDeref( UntypedExpr const * expr, TyVarMap const & scopeTyVars, TypeSubstitution const * env ) { 1183 1153 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) { 1184 if ( NameExpr *name = dynamic_cast< NameExpr*>( expr->function ) ) {1154 if ( auto name = dynamic_cast<NameExpr const *>( expr->function ) ) { 1185 1155 if ( name->name == "*?" ) { 1186 Expression *ret = expr->args.front(); 1187 expr->args.clear(); 1188 delete expr; 1189 return ret; 1156 return true; 1190 1157 } // if 1191 1158 } // if 1192 1159 } // if 1160 return false; 1161 } 1162 1163 Expression * Pass1::postmutate( UntypedExpr *expr ) { 1164 if ( isPolyDeref( expr, scopeTyVars, env ) ) { 1165 Expression *ret = expr->args.front(); 1166 expr->args.clear(); 1167 delete expr; 1168 return ret; 1169 } 1193 1170 return expr; 1194 1171 } … … 1200 1177 bool needs = false; 1201 1178 if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) { 1202 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) { 1203 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) { 1204 if ( name->name == "*?" ) { 1205 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) { 1206 assert( appExpr->function->result ); 1207 FunctionType *function = getFunctionType( appExpr->function->result ); 1208 assert( function ); 1209 needs = needsAdapter( function, scopeTyVars ); 1210 } // if 1211 } // if 1179 if ( isPolyDeref( expr, scopeTyVars, env ) ) { 1180 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) { 1181 assert( appExpr->function->result ); 1182 FunctionType *function = getFunctionType( appExpr->function->result ); 1183 assert( function ); 1184 needs = needsAdapter( function, scopeTyVars ); 1212 1185 } // if 1213 1186 } // if … … 1260 1233 void Pass2::addAdapters( FunctionType *functionType ) { 1261 1234 std::list< DeclarationWithType *> ¶mList = functionType->parameters; 1262 std::list< FunctionType *> functions;1263 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg) {1264 Type *orig = (*arg)->get_type();1235 std::list< FunctionType const *> functions; 1236 for ( DeclarationWithType * const arg : functionType->parameters ) { 1237 Type *orig = arg->get_type(); 1265 1238 findAndReplaceFunction( orig, functions, scopeTyVars, needsAdapter ); 1266 (*arg)->set_type( orig );1239 arg->set_type( orig ); 1267 1240 } 1268 1241 std::set< std::string > adaptersDone; 1269 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType) {1270 std::string mangleName = mangleAdapterName( *funType, scopeTyVars );1242 for ( FunctionType const * const funType : functions ) { 1243 std::string mangleName = mangleAdapterName( funType, scopeTyVars ); 1271 1244 if ( adaptersDone.find( mangleName ) == adaptersDone.end() ) { 1272 1245 std::string adapterName = makeAdapterName( mangleName ); 1273 1246 // adapter may not be used in body, pass along with unused attribute. 1274 paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );1247 paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) ); 1275 1248 adaptersDone.insert( adaptersDone.begin(), mangleName ); 1276 1249 } … … 1349 1322 ObjectDecl newPtr( "", Type::StorageClasses(), LinkageSpec::C, 0, 1350 1323 new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 ); 1351 for ( Type ::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm) {1324 for ( TypeDecl * const tyParam : funcType->get_forall() ) { 1352 1325 ObjectDecl *sizeParm, *alignParm; 1353 1326 // add all size and alignment parameters to parameter list 1354 if ( (*tyParm)->isComplete() ) {1355 TypeInstType parmType( Type::Qualifiers(), (*tyParm)->get_name(), *tyParm );1327 if ( tyParam->isComplete() ) { 1328 TypeInstType parmType( Type::Qualifiers(), tyParam->get_name(), tyParam ); 1356 1329 std::string parmName = mangleType( &parmType ); 1357 1330 … … 1367 1340 } 1368 1341 // move all assertions into parameter list 1369 for ( std::list< DeclarationWithType *>::iterator assert = (*tyParm)->get_assertions().begin(); assert != (*tyParm)->get_assertions().end(); ++assert) {1342 for ( DeclarationWithType * const assert : tyParam->get_assertions() ) { 1370 1343 // assertion parameters may not be used in body, pass along with unused attribute. 1371 (*assert)->get_attributes().push_back( new Attribute( "unused" ) );1372 inferredParams.push_back( *assert );1373 } 1374 (*tyParm)->get_assertions().clear();1344 assert->get_attributes().push_back( new Attribute( "unused" ) ); 1345 inferredParams.push_back( assert ); 1346 } 1347 tyParam->get_assertions().clear(); 1375 1348 } 1376 1349 1377 1350 // add size/align for generic parameter types to parameter list 1378 1351 std::set< std::string > seenTypes; // sizeofName for generic types we've seen 1379 for ( std::list< DeclarationWithType* >::const_iterator fnParm = last; fnParm != funcType->get_parameters().end(); ++fnParm) {1380 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );1352 for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) { 1353 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars ); 1381 1354 if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) { 1382 1355 std::string typeName = mangleType( polyType ); … … 1482 1455 1483 1456 if(!expect_func_type) { 1484 GuardAction( [this]() {1485 knownLayouts.endScope();1486 knownOffsets.endScope();1487 });1488 1457 // If this is the first function type we see 1489 1458 // Then it's the type of the declaration and we care about it 1490 knownLayouts.beginScope(); 1491 knownOffsets.beginScope(); 1459 GuardScope( *this ); 1492 1460 } 1493 1461 … … 1497 1465 1498 1466 // make sure that any type information passed into the function is accounted for 1499 for ( std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); fnParm != funcType->get_parameters().end(); ++fnParm) {1467 for ( DeclarationWithType * const fnParam : funcType->get_parameters() ) { 1500 1468 // condition here duplicates that in Pass2::mutate( FunctionType* ) 1501 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars );1469 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars ); 1502 1470 if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) { 1503 1471 knownLayouts.insert( mangleType( polyType ) ); … … 1507 1475 1508 1476 /// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T] 1509 Type * polyToMonoType( Type * declType ) {1477 Type * polyToMonoType( Type const * declType ) { 1510 1478 Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char); 1511 1479 Expression * size = new NameExpr( sizeofName( mangleType(declType) ) ); … … 1572 1540 /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present 1573 1541 long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) { 1574 long i = 0; 1575 for(std::list< Declaration* >::const_iterator decl = baseDecls.begin(); decl != baseDecls.end(); ++decl, ++i ) { 1576 if ( memberDecl->get_name() != (*decl)->get_name() ) 1542 for ( auto pair : enumerate( baseDecls ) ) { 1543 Declaration * decl = pair.val; 1544 size_t i = pair.idx; 1545 if ( memberDecl->get_name() != decl->get_name() ) 1577 1546 continue; 1578 1547 1579 1548 if ( memberDecl->get_name().empty() ) { 1580 1549 // plan-9 field: match on unique_id 1581 if ( memberDecl->get_uniqueId() == (*decl)->get_uniqueId() )1550 if ( memberDecl->get_uniqueId() == decl->get_uniqueId() ) 1582 1551 return i; 1583 1552 else … … 1585 1554 } 1586 1555 1587 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( *decl );1556 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl ); 1588 1557 1589 1558 if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) { … … 1603 1572 1604 1573 /// Returns an index expression into the offset array for a type 1605 Expression *makeOffsetIndex( Type *objectType, long i ) {1574 Expression *makeOffsetIndex( Type const *objectType, long i ) { 1606 1575 ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) ); 1607 1576 UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) ); … … 1696 1665 1697 1666 void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) { 1698 for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param) {1699 if ( findGeneric( *param ) ) {1667 for ( Type * const param : otypeParams ) { 1668 if ( findGeneric( param ) ) { 1700 1669 // push size/align vars for a generic parameter back 1701 std::string paramName = mangleType( *param );1670 std::string paramName = mangleType( param ); 1702 1671 layoutCall->get_args().push_back( new NameExpr( sizeofName( paramName ) ) ); 1703 1672 layoutCall->get_args().push_back( new NameExpr( alignofName( paramName ) ) ); 1704 1673 } else { 1705 layoutCall->get_args().push_back( new SizeofExpr( (*param)->clone() ) );1706 layoutCall->get_args().push_back( new AlignofExpr( (*param)->clone() ) );1674 layoutCall->get_args().push_back( new SizeofExpr( param->clone() ) ); 1675 layoutCall->get_args().push_back( new AlignofExpr( param->clone() ) ); 1707 1676 } 1708 1677 } … … 1710 1679 1711 1680 /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list 1712 bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* >&typeParams, std::list< Type* > &out ) {1681 bool findGenericParams( std::list< TypeDecl* > const &baseParams, std::list< Expression* > const &typeParams, std::list< Type* > &out ) { 1713 1682 bool hasDynamicLayout = false; 1714 1683 1715 std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();1716 std::list< Expression* >::const_iterator typeParam = typeParams.begin();1717 for ( ; baseParam != baseParams.end() && typeParam != typeParams.end(); ++baseParam, ++typeParam ) {1684 for ( auto paramPair : group_iterate( baseParams, typeParams ) ) { 1685 TypeDecl * baseParam = std::get<0>( paramPair ); 1686 Expression * typeParam = std::get<1>( paramPair ); 1718 1687 // skip non-otype parameters 1719 if ( ! (*baseParam)->isComplete() ) continue;1720 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam );1688 if ( ! baseParam->isComplete() ) continue; 1689 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( typeParam ); 1721 1690 assert( typeExpr && "all otype parameters should be type expressions" ); 1722 1691 … … 1725 1694 if ( isPolyType( type ) ) hasDynamicLayout = true; 1726 1695 } 1727 assert( baseParam == baseParams.end() && typeParam == typeParams.end() );1728 1696 1729 1697 return hasDynamicLayout; 1730 1698 } 1731 1699 1732 bool PolyGenericCalculator::findGeneric( Type *ty ) {1700 bool PolyGenericCalculator::findGeneric( Type const *ty ) { 1733 1701 ty = replaceTypeInst( ty, env ); 1734 1702 1735 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {1703 if ( auto typeInst = dynamic_cast< TypeInstType const * >( ty ) ) { 1736 1704 if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) { 1737 1705 // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set … … 1739 1707 } 1740 1708 return false; 1741 } else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) {1709 } else if ( auto structTy = dynamic_cast< StructInstType const * >( ty ) ) { 1742 1710 // check if this type already has a layout generated for it 1743 1711 std::string typeName = mangleType( ty ); … … 1746 1714 // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized 1747 1715 std::list< Type* > otypeParams; 1748 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy-> get_parameters(), otypeParams ) ) return false;1716 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->parameters, otypeParams ) ) return false; 1749 1717 1750 1718 // insert local variables for layout and generate call to layout function … … 1776 1744 1777 1745 return true; 1778 } else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {1746 } else if ( auto unionTy = dynamic_cast< UnionInstType const * >( ty ) ) { 1779 1747 // check if this type already has a layout generated for it 1780 1748 std::string typeName = mangleType( ty ); … … 1783 1751 // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized 1784 1752 std::list< Type* > otypeParams; 1785 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy-> get_parameters(), otypeParams ) ) return false;1753 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->parameters, otypeParams ) ) return false; 1786 1754 1787 1755 // insert local variables for layout and generate call to layout function … … 1881 1849 // build initializer list for offset array 1882 1850 std::list< Initializer* > inits; 1883 for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) { 1884 if ( DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( *member ) ) { 1885 inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) ); 1886 } else { 1887 assertf( false, "Requesting offset of Non-DWT member: %s", toString( *member ).c_str() ); 1888 } 1851 for ( Declaration * const member : baseMembers ) { 1852 DeclarationWithType *memberDecl = dynamic_cast< DeclarationWithType* >( member ); 1853 assertf( memberDecl, "Requesting offset of Non-DWT member: %s", toString( member ).c_str() ); 1854 inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) ); 1889 1855 } 1890 1856 … … 1965 1931 // compile-command: "make install" // 1966 1932 // End: // 1933 -
src/GenPoly/FindFunction.cc
rb77f0e1 r63be3387 29 29 class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting { 30 30 public: 31 FindFunction( std::list< FunctionType * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );31 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate ); 32 32 33 33 void premutate( FunctionType * functionType ); … … 37 37 void handleForall( const Type::ForallList &forall ); 38 38 39 std::list< FunctionType * > &functions;39 std::list< FunctionType const * > & functions; 40 40 TyVarMap tyVars; 41 41 bool replaceMode; … … 43 43 }; 44 44 45 void findFunction( Type *type, std::list< FunctionType * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {45 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) { 46 46 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate ); 47 47 type->acceptMutator( finder ); 48 48 } 49 49 50 void findAndReplaceFunction( Type *&type, std::list< FunctionType * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {50 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) { 51 51 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate ); 52 52 type = type->acceptMutator( finder ); 53 53 } 54 54 55 FindFunction::FindFunction( std::list< FunctionType * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )55 FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate ) 56 56 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) { 57 57 } -
src/GenPoly/FindFunction.h
rb77f0e1 r63be3387 27 27 28 28 /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions` 29 void findFunction( Type *type, std::list< FunctionType * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );29 void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 30 30 /// like `findFunction`, but also replaces the function type with void ()(void) 31 void findAndReplaceFunction( Type *&type, std::list< FunctionType * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );31 void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 32 32 } // namespace GenPoly 33 33 -
src/GenPoly/GenPoly.cc
rb77f0e1 r63be3387 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 7 15:25:00 202213 // Update Count : 1 612 // Last Modified On : Mon Oct 24 15:19:00 2022 13 // Update Count : 17 14 14 // 15 15 … … 118 118 } 119 119 120 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) { 121 if ( ! env ) return type; 122 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) { 123 Type *newType = env->lookup( typeInst->get_name() ); 124 if ( newType ) return newType; 125 } 126 return type; 127 } 128 120 129 const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { 121 130 if (!env) return type; 122 if ( auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {131 if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>(type) ) { 123 132 auto newType = env->lookup(typeInst); 124 133 if (newType) return newType; … … 194 203 195 204 if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { 196 if ( typeVars.find( inst->typeString()) != typeVars.end() ) return type;205 if ( typeVars.find( *inst ) != typeVars.end() ) return type; 197 206 } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) { 198 207 return isPolyType( array->base, subst ); … … 227 236 228 237 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) { 229 auto var = typeVars.find( inst->name);238 auto var = typeVars.find( *inst ); 230 239 if ( var != typeVars.end() && var->second.isComplete ) { 231 240 return inst; 232 241 } 233 242 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) { … … 784 793 785 794 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) { 786 typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) );795 typeVars.insert( *type, ast::TypeDecl::Data( type->base ) ); 787 796 } 788 797 … … 816 825 } 817 826 818 void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ) {819 for ( auto const & pair : typeVars ) {820 os << pair.first << " (" << pair.second << ") ";821 } // for822 os << std::endl;823 }824 825 827 } // namespace GenPoly 826 828 -
src/GenPoly/GenPoly.h
rb77f0e1 r63be3387 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 7 15:06:00 202213 // Update Count : 912 // Last Modified On : Mon Oct 24 15:18:00 2022 13 // Update Count : 11 14 14 // 15 15 … … 22 22 #include "AST/Decl.hpp" // for TypeDecl::Data 23 23 #include "AST/Fwd.hpp" // for ApplicationExpr, BaseInstType, Func... 24 #include "AST/Type.hpp" // for TypeInstType::TypeEnvKey 24 25 #include "SymTab/Mangler.h" // for Mangler 25 26 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type... … … 28 29 namespace GenPoly { 29 30 30 // TODO Via some tricks this works for ast::TypeDecl::Data as well.31 31 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 32 using TypeVarMap = ErasableScopedMap< std::string, ast::TypeDecl::Data >;32 using TypeVarMap = ErasableScopedMap< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >; 33 33 34 34 /// Replaces a TypeInstType by its referrent in the environment, if applicable 35 35 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); 36 const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ); 37 const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * ); 36 38 37 39 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided … … 53 55 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 54 56 ReferenceToType *isDynRet( FunctionType *function ); 57 const ast::BaseInstType *isDynRet( const ast::FunctionType * func ); 55 58 56 59 /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type … … 112 115 /// Prints type variable map 113 116 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ); 114 void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars );115 117 116 118 /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType(). 117 inline std::string mangleType( Type *ty ) { return SymTab::Mangler::mangleType( ty ); }119 inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); } 118 120 119 121 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 128 130 /// Gets the name of the layout function for a given aggregate type, given its declaration 129 131 inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); } 132 inline std::string layoutofName( ast::AggregateDecl const * decl ) { 133 return std::string( "_layoutof_" ) + decl->name; 134 } 130 135 131 136 } // namespace GenPoly -
src/GenPoly/InstantiateGenericNew.cpp
rb77f0e1 r63be3387 10 10 // Created On : Tue Aug 16 10:51:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Sep 13 16:03:00 202213 // Update Count : 012 // Last Modified On : Mon Oct 31 16:48:00 2022 13 // Update Count : 1 14 14 // 15 15 … … 378 378 // Ptr(int) p; 379 379 // int i; 380 // The original expression: 380 381 // p.x = &i; 381 // becomes 382 // int *& _dtype_static_member_0 = (int **)&p.x; 383 // _dtype_static_member_0 = &i; 382 // Becomes the expression/declaration: 383 // int *& _dtype_static_member_0; 384 // (_dtype_static_member_0 = (int**)&p.x, 385 // _dtype_static_member_0) = &i; 386 387 // The declaration is simple: 384 388 static UniqueName tmpNamer( "_dtype_static_member_" ); 385 ast::Expr * init = new ast::CastExpr( location,386 new ast::AddressExpr( location, memberExpr ),387 new ast::PointerType( ast::deepCopy( concType ) ),388 ast::ExplicitCast389 );390 389 ast::ObjectDecl * tmp = new ast::ObjectDecl( location, 391 390 tmpNamer.newName(), 392 391 new ast::ReferenceType( concType ), 393 n ew ast::SingleInit( location, init ),392 nullptr, 394 393 ast::Storage::Classes(), 395 394 ast::Linkage::C 396 395 ); 397 396 stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) ); 398 return new ast::VariableExpr( location, tmp ); 397 398 // The expression is more complex, uses references and reference / 399 // pointer parity. But breaking it up risks reordering. 400 return new ast::CommaExpr( location, 401 ast::UntypedExpr::createAssign( location, 402 new ast::VariableExpr( location, tmp ), 403 new ast::CastExpr( location, 404 new ast::AddressExpr( location, memberExpr ), 405 new ast::PointerType( ast::deepCopy( concType ) ), 406 ast::ExplicitCast 407 ) 408 ), 409 new ast::VariableExpr( location, tmp ) 410 ); 399 411 } else { 400 412 // Here, it can simply add a cast to actual types. … … 476 488 }; 477 489 478 // I think this and the UnionInstType can be made into a template function.479 490 ast::Type const * GenericInstantiator::postvisit( 480 491 ast::StructInstType const * inst ) { -
src/GenPoly/ScrubTyVars.cc
rb77f0e1 r63be3387 20 20 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 21 21 #include "ScrubTyVars.h" 22 #include "SymTab/Mangler.h" // for mangle , typeMode22 #include "SymTab/Mangler.h" // for mangleType 23 23 #include "SynTree/Declaration.h" // for TypeDecl, TypeDecl::Data, Typ... 24 24 #include "SynTree/Expression.h" // for Expression (ptr only), NameExpr … … 195 195 } 196 196 197 auto typeVar = typeVars->find( type->name );197 auto typeVar = typeVars->find( *type ); 198 198 if ( typeVar == typeVars->end() ) { 199 199 return type; … … 227 227 if ( dynType ) { 228 228 return new ast::NameExpr( expr->location, 229 sizeofName( Mangle::mangle ( dynType, Mangle::typeMode()) ) );229 sizeofName( Mangle::mangleType( dynType ) ) ); 230 230 } else { 231 231 return expr; … … 237 237 if ( dynType ) { 238 238 return new ast::NameExpr( expr->location, 239 alignofName( Mangle::mangle ( dynType, Mangle::typeMode()) ) );239 alignofName( Mangle::mangleType( dynType ) ) ); 240 240 } else { 241 241 return expr; -
src/Parser/DeclarationNode.cc
rb77f0e1 r63be3387 27 27 #include "SynTree/LinkageSpec.h" // for Spec, linkageName, Cforall 28 28 #include "SynTree/Attribute.h" // for Attribute 29 #include "SynTree/Declaration.h" // for TypeDecl, ObjectDecl, Declaration29 #include "SynTree/Declaration.h" // for TypeDecl, ObjectDecl, InlineMemberDecl, Declaration 30 30 #include "SynTree/Expression.h" // for Expression, ConstantExpr 31 31 #include "SynTree/Statement.h" // for AsmStmt … … 1165 1165 SemanticError( this, "invalid function specifier for " ); 1166 1166 } // if 1167 if ( enumInLine ) { 1168 return new InlineMemberDecl( *name, storageClasses, linkage, nullptr ); 1169 } // if 1167 1170 assertf( name, "ObjectDecl must a have name\n" ); 1168 1171 return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension ); -
src/Parser/ExpressionNode.cc
rb77f0e1 r63be3387 519 519 } 520 520 } 521 auto ret = new QualifiedNameExpr( newDecl, name->name ); 522 if ( auto e = dynamic_cast<EnumDecl*>(newDecl) ) { 523 auto enumInst = new EnumInstType( Type::Qualifiers(), e ); 524 auto obj = new ObjectDecl( name->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, enumInst, nullptr ); 525 } 526 return ret; 521 return new QualifiedNameExpr( newDecl, name->name ); 527 522 } 528 523 -
src/Parser/ParseNode.h
rb77f0e1 r63be3387 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Oct 18 16:22:15202213 // Update Count : 93 712 // Last Modified On : Wed Nov 2 21:27:07 2022 13 // Update Count : 939 14 14 // 15 15 … … 168 168 Ctor, Dtor, 169 169 }; // OperKinds 170 171 enum class EnumHiding { Visible, Hide }; 170 172 171 173 struct LabelNode { -
src/Parser/TypeData.cc
rb77f0e1 r63be3387 925 925 for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) { 926 926 if ( cur->enumInLine ) { 927 // Tell the compiler this is a inline value placeholder 928 ObjectDecl * member = dynamic_cast< ObjectDecl* >(* members); 929 member->enumInLine = true; 930 } 931 if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) { 927 // Do Nothing 928 } else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) { 932 929 SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." ); 933 930 } else if ( cur->has_enumeratorValue() ) { -
src/Parser/parser.yy
rb77f0e1 r63be3387 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Oct 14 14:04:43202213 // Update Count : 5 75112 // Last Modified On : Wed Nov 2 21:31:21 2022 13 // Update Count : 5810 14 14 // 15 15 … … 278 278 279 279 // Types declaration for productions 280 280 281 %union { 281 282 Token tok; … … 290 291 CondCtl * ifctl; 291 292 ForCtrl * fctl; 292 enumOperKinds compop;293 OperKinds compop; 293 294 LabelNode * label; 294 295 InitializerNode * in; … … 296 297 std::string * str; 297 298 bool flag; 299 EnumHiding hide; 298 300 CatchStmt::Kind catch_kind; 299 301 GenericExpr * genexpr; … … 364 366 %type<constant> string_literal 365 367 %type<str> string_literal_list 368 369 %type<hide> hide_opt visible_hide_opt 366 370 367 371 // expressions … … 2553 2557 | ENUM attribute_list_opt identifier 2554 2558 { typedefTable.makeTypedef( *$3 ); } 2555 '{' enumerator_list comma_opt '}'2556 { $$ = DeclarationNode::newEnum( $3, $6, true, false )->addQualifiers( $2 ); }2559 hide_opt '{' enumerator_list comma_opt '}' 2560 { $$ = DeclarationNode::newEnum( $3, $7, true, false )->addQualifiers( $2 ); } 2557 2561 | ENUM attribute_list_opt typedef_name // unqualified type name 2558 '{' enumerator_list comma_opt '}'2559 { $$ = DeclarationNode::newEnum( $3->name, $ 5, true, false )->addQualifiers( $2 ); }2562 hide_opt '{' enumerator_list comma_opt '}' 2563 { $$ = DeclarationNode::newEnum( $3->name, $6, true, false )->addQualifiers( $2 ); } 2560 2564 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2561 2565 { … … 2574 2578 typedefTable.makeTypedef( *$6 ); 2575 2579 } 2576 '{' enumerator_list comma_opt '}'2577 { 2578 $$ = DeclarationNode::newEnum( $6, $1 0, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );2580 hide_opt '{' enumerator_list comma_opt '}' 2581 { 2582 $$ = DeclarationNode::newEnum( $6, $11, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2579 2583 } 2580 2584 | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt 2581 '{' enumerator_list comma_opt '}' 2582 { 2583 $$ = DeclarationNode::newEnum( $5, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 ); 2584 } 2585 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' 2586 { 2587 $$ = DeclarationNode::newEnum( $6->name, $9, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2588 } 2589 | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' 2590 { 2591 $$ = DeclarationNode::newEnum( $5->name, $8, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 ); 2585 hide_opt '{' enumerator_list comma_opt '}' 2586 { 2587 $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 ); 2588 } 2589 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt 2590 hide_opt '{' enumerator_list comma_opt '}' 2591 { 2592 $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2593 } 2594 | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt 2595 hide_opt '{' enumerator_list comma_opt '}' 2596 { 2597 $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr )->addQualifiers( $4 )->addQualifiers( $6 ); 2592 2598 } 2593 2599 | enum_type_nobody 2600 ; 2601 2602 hide_opt: 2603 // empty 2604 { $$ = EnumHiding::Visible; } 2605 | '!' 2606 { $$ = EnumHiding::Hide; } 2594 2607 ; 2595 2608 … … 2602 2615 2603 2616 enumerator_list: 2604 identifier_or_type_name enumerator_value_opt2605 { $$ = DeclarationNode::newEnumValueGeneric( $ 1, $2); }2617 visible_hide_opt identifier_or_type_name enumerator_value_opt 2618 { $$ = DeclarationNode::newEnumValueGeneric( $2, $3 ); } 2606 2619 | INLINE type_name 2607 2620 { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); } 2608 | enumerator_list ',' identifier_or_type_name enumerator_value_opt2609 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $ 3, $4) ); }2621 | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt 2622 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); } 2610 2623 | enumerator_list ',' INLINE type_name enumerator_value_opt 2611 2624 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); } 2625 ; 2626 2627 visible_hide_opt: 2628 hide_opt 2629 | '^' 2630 { $$ = EnumHiding::Visible; } 2612 2631 ; 2613 2632 -
src/ResolvExpr/CommonType.cc
rb77f0e1 r63be3387 991 991 add_qualifiers( result, type2->qualifiers ); 992 992 } else { 993 // xxx - does unifying a ref with typed enumInst makes sense?994 993 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 995 994 result = commonType( type2, ref, tenv, need, have, open, widen, symtab ); … … 1010 1009 1011 1010 void postvisit( const ast::EnumInstType * enumInst ) { 1012 // reuse BasicType/EnumInstType common type by swapping1013 // xxx - is this already handled by unify?1014 1011 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 1015 1012 result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab); -
src/ResolvExpr/ConversionCost.cc
rb77f0e1 r63be3387 720 720 costCalc( baseType, dst, srcIsLvalue, symtab, env ); 721 721 } else { 722 (void)enumInstType;723 722 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 724 723 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); -
src/ResolvExpr/SatisfyAssertions.cpp
rb77f0e1 r63be3387 268 268 ast::ptr< ast::Type > resType = cand.expr->result; 269 269 cand.env.apply( resType ); 270 return Mangle::mangle ( resType, Mangle::typeMode());270 return Mangle::mangleType( resType ); 271 271 } 272 272 -
src/SymTab/Mangler.cc
rb77f0e1 r63be3387 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:40:29 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 11 21:56:06 202113 // Update Count : 7 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 21 16:18:00 2022 13 // Update Count : 75 14 14 // 15 15 #include "Mangler.h" … … 418 418 void postvisit( const ast::QualifiedType * qualType ); 419 419 420 std::string get_mangleName() { return mangleName; } 420 /// The result is the current constructed mangled name. 421 std::string result() const { return mangleName; } 421 422 private: 422 423 std::string mangleName; ///< Mangled name being constructed … … 444 445 } // namespace 445 446 446 447 447 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) { 448 ast::Pass<Mangler_new> mangler( mode ); 449 maybeAccept( decl, mangler ); 450 return mangler.core.get_mangleName(); 448 return ast::Pass<Mangler_new>::read( decl, mode ); 451 449 } 452 450 … … 689 687 } // for 690 688 for ( auto & assert : ptype->assertions ) { 691 ast::Pass<Mangler_new> sub_mangler( 692 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 693 assert->var->accept( sub_mangler ); 694 assertionNames.push_back( sub_mangler.core.get_mangleName() ); 689 assertionNames.push_back( ast::Pass<Mangler_new>::read( 690 assert->var.get(), 691 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); 695 692 acount++; 696 693 } // for -
src/SymTab/Mangler.h
rb77f0e1 r63be3387 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:44:03 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:45:30 201713 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Oct 27 11:58:00 2022 13 // Update Count : 16 14 14 // 15 15 … … 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "AST/Fwd.hpp"25 24 #include "SynTree/SynTree.h" // for Types 26 25 #include "SynTree/Visitor.h" // for Visitor, maybeAccept … … 33 32 // * Currently name compression is not implemented. 34 33 34 namespace ast { 35 class Node; 36 } 35 37 namespace ResolvExpr { 36 38 class TypeEnvironment; … … 101 103 using Mode = bitfield<mangle_flags>; 102 104 103 static inline Mode typeMode() { return NoOverrideable | Type; } 105 /// Mangle declaration name. 106 std::string mangle( const ast::Node * decl, Mode mode = {} ); 104 107 105 /// Mangle declaration name 106 std::string mangle( const ast::Node * decl, Mode mode = {} ); 108 /// Most common mangle configuration for types. 109 static inline std::string mangleType( const ast::Node * type ) { 110 return mangle( type, { NoOverrideable | Type } ); 111 } 107 112 108 113 namespace Encoding { -
src/SymTab/Validate.cc
rb77f0e1 r63be3387 47 47 #include <utility> // for pair 48 48 49 #include "AST/Chain.hpp"50 #include "AST/Decl.hpp"51 #include "AST/Node.hpp"52 #include "AST/Pass.hpp"53 #include "AST/SymbolTable.hpp"54 #include "AST/Type.hpp"55 #include "AST/TypeSubstitution.hpp"56 49 #include "CodeGen/CodeGenerator.h" // for genName 57 50 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign … … 1326 1319 } 1327 1320 1328 namespace {1329 /// Replaces enum types by int, and function/array types in function parameter and return1330 /// lists by appropriate pointers1331 /*1332 struct EnumAndPointerDecay_new {1333 const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {1334 // set the type of each member of the enumeration to be EnumConstant1335 for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {1336 // build new version of object with EnumConstant1337 ast::ptr< ast::ObjectDecl > obj =1338 enumDecl->members[i].strict_as< ast::ObjectDecl >();1339 obj.get_and_mutate()->type =1340 new ast::EnumInstType{ enumDecl->name, ast::CV::Const };1341 1342 // set into decl1343 ast::EnumDecl * mut = mutate( enumDecl );1344 mut->members[i] = obj.get();1345 enumDecl = mut;1346 }1347 return enumDecl;1348 }1349 1350 static const ast::FunctionType * fixFunctionList(1351 const ast::FunctionType * func,1352 std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field,1353 ast::ArgumentFlag isVarArgs = ast::FixedArgs1354 ) {1355 const auto & dwts = func->* field;1356 unsigned nvals = dwts.size();1357 bool hasVoid = false;1358 for ( unsigned i = 0; i < nvals; ++i ) {1359 func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) );1360 }1361 1362 // the only case in which "void" is valid is where it is the only one in the list1363 if ( hasVoid && ( nvals > 1 || isVarArgs ) ) {1364 SemanticError(1365 dwts.front()->location, func, "invalid type void in function type" );1366 }1367 1368 // one void is the only thing in the list, remove it1369 if ( hasVoid ) {1370 func = ast::mutate_field(1371 func, field, std::vector< ast::ptr< ast::DeclWithType > >{} );1372 }1373 1374 return func;1375 }1376 1377 const ast::FunctionType * previsit( const ast::FunctionType * func ) {1378 func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs );1379 return fixFunctionList( func, &ast::FunctionType::returns );1380 }1381 };1382 1383 /// expand assertions from a trait instance, performing appropriate type variable substitutions1384 void expandAssertions(1385 const ast::TraitInstType * inst, std::vector< ast::ptr< ast::DeclWithType > > & out1386 ) {1387 assertf( inst->base, "Trait instance not linked to base trait: %s", toCString( inst ) );1388 1389 // build list of trait members, substituting trait decl parameters for instance parameters1390 ast::TypeSubstitution sub{1391 inst->base->params.begin(), inst->base->params.end(), inst->params.begin() };1392 // deliberately take ast::ptr by-value to ensure this does not mutate inst->base1393 for ( ast::ptr< ast::Decl > decl : inst->base->members ) {1394 auto member = decl.strict_as< ast::DeclWithType >();1395 sub.apply( member );1396 out.emplace_back( member );1397 }1398 }1399 1400 /// Associates forward declarations of aggregates with their definitions1401 class LinkReferenceToTypes_new final1402 : public ast::WithSymbolTable, public ast::WithGuards, public1403 ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting {1404 1405 // these maps of uses of forward declarations of types need to have the actual type1406 // declaration switched in * after * they have been traversed. To enable this in the1407 // ast::Pass framework, any node that needs to be so mutated has mutate() called on it1408 // before it is placed in the map, properly updating its parents in the usual traversal,1409 // then can have the actual mutation applied later1410 using ForwardEnumsType = std::unordered_multimap< std::string, ast::EnumInstType * >;1411 using ForwardStructsType = std::unordered_multimap< std::string, ast::StructInstType * >;1412 using ForwardUnionsType = std::unordered_multimap< std::string, ast::UnionInstType * >;1413 1414 const CodeLocation & location;1415 const ast::SymbolTable * localSymtab;1416 1417 ForwardEnumsType forwardEnums;1418 ForwardStructsType forwardStructs;1419 ForwardUnionsType forwardUnions;1420 1421 /// true if currently in a generic type body, so that type parameter instances can be1422 /// renamed appropriately1423 bool inGeneric = false;1424 1425 public:1426 /// contstruct using running symbol table1427 LinkReferenceToTypes_new( const CodeLocation & loc )1428 : location( loc ), localSymtab( &symtab ) {}1429 1430 /// construct using provided symbol table1431 LinkReferenceToTypes_new( const CodeLocation & loc, const ast::SymbolTable & syms )1432 : location( loc ), localSymtab( &syms ) {}1433 1434 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {1435 // ensure generic parameter instances are renamed like the base type1436 if ( inGeneric && typeInst->base ) {1437 typeInst = ast::mutate_field(1438 typeInst, &ast::TypeInstType::name, typeInst->base->name );1439 }1440 1441 if (1442 auto typeDecl = dynamic_cast< const ast::TypeDecl * >(1443 localSymtab->lookupType( typeInst->name ) )1444 ) {1445 typeInst = ast::mutate_field( typeInst, &ast::TypeInstType::kind, typeDecl->kind );1446 }1447 1448 return typeInst;1449 }1450 1451 const ast::Type * postvisit( const ast::EnumInstType * inst ) {1452 const ast::EnumDecl * decl = localSymtab->lookupEnum( inst->name );1453 // not a semantic error if the enum is not found, just an implicit forward declaration1454 if ( decl ) {1455 inst = ast::mutate_field( inst, &ast::EnumInstType::base, decl );1456 }1457 if ( ! decl || ! decl->body ) {1458 // forward declaration1459 auto mut = mutate( inst );1460 forwardEnums.emplace( inst->name, mut );1461 inst = mut;1462 }1463 return inst;1464 }1465 1466 void checkGenericParameters( const ast::BaseInstType * inst ) {1467 for ( const ast::Expr * param : inst->params ) {1468 if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {1469 SemanticError(1470 location, inst, "Expression parameters for generic types are currently "1471 "unsupported: " );1472 }1473 }1474 }1475 1476 const ast::StructInstType * postvisit( const ast::StructInstType * inst ) {1477 const ast::StructDecl * decl = localSymtab->lookupStruct( inst->name );1478 // not a semantic error if the struct is not found, just an implicit forward declaration1479 if ( decl ) {1480 inst = ast::mutate_field( inst, &ast::StructInstType::base, decl );1481 }1482 if ( ! decl || ! decl->body ) {1483 // forward declaration1484 auto mut = mutate( inst );1485 forwardStructs.emplace( inst->name, mut );1486 inst = mut;1487 }1488 checkGenericParameters( inst );1489 return inst;1490 }1491 1492 const ast::UnionInstType * postvisit( const ast::UnionInstType * inst ) {1493 const ast::UnionDecl * decl = localSymtab->lookupUnion( inst->name );1494 // not a semantic error if the struct is not found, just an implicit forward declaration1495 if ( decl ) {1496 inst = ast::mutate_field( inst, &ast::UnionInstType::base, decl );1497 }1498 if ( ! decl || ! decl->body ) {1499 // forward declaration1500 auto mut = mutate( inst );1501 forwardUnions.emplace( inst->name, mut );1502 inst = mut;1503 }1504 checkGenericParameters( inst );1505 return inst;1506 }1507 1508 const ast::Type * postvisit( const ast::TraitInstType * traitInst ) {1509 // handle other traits1510 const ast::TraitDecl * traitDecl = localSymtab->lookupTrait( traitInst->name );1511 if ( ! traitDecl ) {1512 SemanticError( location, "use of undeclared trait " + traitInst->name );1513 }1514 if ( traitDecl->params.size() != traitInst->params.size() ) {1515 SemanticError( location, traitInst, "incorrect number of trait parameters: " );1516 }1517 traitInst = ast::mutate_field( traitInst, &ast::TraitInstType::base, traitDecl );1518 1519 // need to carry over the "sized" status of each decl in the instance1520 for ( unsigned i = 0; i < traitDecl->params.size(); ++i ) {1521 auto expr = traitInst->params[i].as< ast::TypeExpr >();1522 if ( ! expr ) {1523 SemanticError(1524 traitInst->params[i].get(), "Expression parameters for trait instances "1525 "are currently unsupported: " );1526 }1527 1528 if ( auto inst = expr->type.as< ast::TypeInstType >() ) {1529 if ( traitDecl->params[i]->sized && ! inst->base->sized ) {1530 // traitInst = ast::mutate_field_index(1531 // traitInst, &ast::TraitInstType::params, i,1532 // ...1533 // );1534 ast::TraitInstType * mut = ast::mutate( traitInst );1535 ast::chain_mutate( mut->params[i] )1536 ( &ast::TypeExpr::type )1537 ( &ast::TypeInstType::base )->sized = true;1538 traitInst = mut;1539 }1540 }1541 }1542 1543 return traitInst;1544 }1545 1546 void previsit( const ast::QualifiedType * ) { visit_children = false; }1547 1548 const ast::Type * postvisit( const ast::QualifiedType * qualType ) {1549 // linking only makes sense for the "oldest ancestor" of the qualified type1550 return ast::mutate_field(1551 qualType, &ast::QualifiedType::parent, qualType->parent->accept( * visitor ) );1552 }1553 1554 const ast::Decl * postvisit( const ast::EnumDecl * enumDecl ) {1555 // visit enum members first so that the types of self-referencing members are updated1556 // properly1557 if ( ! enumDecl->body ) return enumDecl;1558 1559 // update forward declarations to point here1560 auto fwds = forwardEnums.equal_range( enumDecl->name );1561 if ( fwds.first != fwds.second ) {1562 auto inst = fwds.first;1563 do {1564 // forward decl is stored * mutably * in map, can thus be updated1565 inst->second->base = enumDecl;1566 } while ( ++inst != fwds.second );1567 forwardEnums.erase( fwds.first, fwds.second );1568 }1569 1570 // ensure that enumerator initializers are properly set1571 for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {1572 auto field = enumDecl->members[i].strict_as< ast::ObjectDecl >();1573 if ( field->init ) {1574 // need to resolve enumerator initializers early so that other passes that1575 // determine if an expression is constexpr have appropriate information1576 auto init = field->init.strict_as< ast::SingleInit >();1577 1578 enumDecl = ast::mutate_field_index(1579 enumDecl, &ast::EnumDecl::members, i,1580 ast::mutate_field( field, &ast::ObjectDecl::init,1581 ast::mutate_field( init, &ast::SingleInit::value,1582 ResolvExpr::findSingleExpression(1583 init->value, new ast::BasicType{ ast::BasicType::SignedInt },1584 symtab ) ) ) );1585 }1586 }1587 1588 return enumDecl;1589 }1590 1591 /// rename generic type parameters uniquely so that they do not conflict with user defined1592 /// function forall parameters, e.g. the T in Box and the T in f, below1593 /// forall(otype T)1594 /// struct Box {1595 /// T x;1596 /// };1597 /// forall(otype T)1598 /// void f(Box(T) b) {1599 /// ...1600 /// }1601 template< typename AggrDecl >1602 const AggrDecl * renameGenericParams( const AggrDecl * aggr ) {1603 GuardValue( inGeneric );1604 inGeneric = ! aggr->params.empty();1605 1606 for ( unsigned i = 0; i < aggr->params.size(); ++i ) {1607 const ast::TypeDecl * td = aggr->params[i];1608 1609 aggr = ast::mutate_field_index(1610 aggr, &AggrDecl::params, i,1611 ast::mutate_field( td, &ast::TypeDecl::name, "__" + td->name + "_generic_" ) );1612 }1613 return aggr;1614 }1615 1616 const ast::StructDecl * previsit( const ast::StructDecl * structDecl ) {1617 return renameGenericParams( structDecl );1618 }1619 1620 void postvisit( const ast::StructDecl * structDecl ) {1621 // visit struct members first so that the types of self-referencing members are1622 // updated properly1623 if ( ! structDecl->body ) return;1624 1625 // update forward declarations to point here1626 auto fwds = forwardStructs.equal_range( structDecl->name );1627 if ( fwds.first != fwds.second ) {1628 auto inst = fwds.first;1629 do {1630 // forward decl is stored * mutably * in map, can thus be updated1631 inst->second->base = structDecl;1632 } while ( ++inst != fwds.second );1633 forwardStructs.erase( fwds.first, fwds.second );1634 }1635 }1636 1637 const ast::UnionDecl * previsit( const ast::UnionDecl * unionDecl ) {1638 return renameGenericParams( unionDecl );1639 }1640 1641 void postvisit( const ast::UnionDecl * unionDecl ) {1642 // visit union members first so that the types of self-referencing members are updated1643 // properly1644 if ( ! unionDecl->body ) return;1645 1646 // update forward declarations to point here1647 auto fwds = forwardUnions.equal_range( unionDecl->name );1648 if ( fwds.first != fwds.second ) {1649 auto inst = fwds.first;1650 do {1651 // forward decl is stored * mutably * in map, can thus be updated1652 inst->second->base = unionDecl;1653 } while ( ++inst != fwds.second );1654 forwardUnions.erase( fwds.first, fwds.second );1655 }1656 }1657 1658 const ast::Decl * postvisit( const ast::TraitDecl * traitDecl ) {1659 // set the "sized" status for the special "sized" trait1660 if ( traitDecl->name == "sized" ) {1661 assertf( traitDecl->params.size() == 1, "Built-in trait 'sized' has incorrect "1662 "number of parameters: %zd", traitDecl->params.size() );1663 1664 traitDecl = ast::mutate_field_index(1665 traitDecl, &ast::TraitDecl::params, 0,1666 ast::mutate_field(1667 traitDecl->params.front().get(), &ast::TypeDecl::sized, true ) );1668 }1669 1670 // move assertions from type parameters into the body of the trait1671 std::vector< ast::ptr< ast::DeclWithType > > added;1672 for ( const ast::TypeDecl * td : traitDecl->params ) {1673 for ( const ast::DeclWithType * assn : td->assertions ) {1674 auto inst = dynamic_cast< const ast::TraitInstType * >( assn->get_type() );1675 if ( inst ) {1676 expandAssertions( inst, added );1677 } else {1678 added.emplace_back( assn );1679 }1680 }1681 }1682 if ( ! added.empty() ) {1683 auto mut = mutate( traitDecl );1684 for ( const ast::DeclWithType * decl : added ) {1685 mut->members.emplace_back( decl );1686 }1687 traitDecl = mut;1688 }1689 1690 return traitDecl;1691 }1692 };1693 1694 /// Replaces array and function types in forall lists by appropriate pointer type and assigns1695 /// each object and function declaration a unique ID1696 class ForallPointerDecay_new {1697 const CodeLocation & location;1698 public:1699 ForallPointerDecay_new( const CodeLocation & loc ) : location( loc ) {}1700 1701 const ast::ObjectDecl * previsit( const ast::ObjectDecl * obj ) {1702 // ensure that operator names only apply to functions or function pointers1703 if (1704 CodeGen::isOperator( obj->name )1705 && ! dynamic_cast< const ast::FunctionType * >( obj->type->stripDeclarator() )1706 ) {1707 SemanticError( obj->location, toCString( "operator ", obj->name.c_str(), " is not "1708 "a function or function pointer." ) );1709 }1710 1711 // ensure object has unique ID1712 if ( obj->uniqueId ) return obj;1713 auto mut = mutate( obj );1714 mut->fixUniqueId();1715 return mut;1716 }1717 1718 const ast::FunctionDecl * previsit( const ast::FunctionDecl * func ) {1719 // ensure function has unique ID1720 if ( func->uniqueId ) return func;1721 auto mut = mutate( func );1722 mut->fixUniqueId();1723 return mut;1724 }1725 1726 /// Fix up assertions -- flattens assertion lists, removing all trait instances1727 template< typename node_t, typename parent_t >1728 static const node_t * forallFixer(1729 const CodeLocation & loc, const node_t * node,1730 ast::FunctionType::ForallList parent_t::* forallField1731 ) {1732 for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {1733 const ast::TypeDecl * type = (node->* forallField)[i];1734 if ( type->assertions.empty() ) continue;1735 1736 std::vector< ast::ptr< ast::DeclWithType > > asserts;1737 asserts.reserve( type->assertions.size() );1738 1739 // expand trait instances into their members1740 for ( const ast::DeclWithType * assn : type->assertions ) {1741 auto traitInst =1742 dynamic_cast< const ast::TraitInstType * >( assn->get_type() );1743 if ( traitInst ) {1744 // expand trait instance to all its members1745 expandAssertions( traitInst, asserts );1746 } else {1747 // pass other assertions through1748 asserts.emplace_back( assn );1749 }1750 }1751 1752 // apply FixFunction to every assertion to check for invalid void type1753 for ( ast::ptr< ast::DeclWithType > & assn : asserts ) {1754 bool isVoid = false;1755 assn = fixFunction( assn, isVoid );1756 if ( isVoid ) {1757 SemanticError( loc, node, "invalid type void in assertion of function " );1758 }1759 }1760 1761 // place mutated assertion list in node1762 auto mut = mutate( type );1763 mut->assertions = move( asserts );1764 node = ast::mutate_field_index( node, forallField, i, mut );1765 }1766 return node;1767 }1768 1769 const ast::FunctionType * previsit( const ast::FunctionType * ftype ) {1770 return forallFixer( location, ftype, &ast::FunctionType::forall );1771 }1772 1773 const ast::StructDecl * previsit( const ast::StructDecl * aggrDecl ) {1774 return forallFixer( aggrDecl->location, aggrDecl, &ast::StructDecl::params );1775 }1776 1777 const ast::UnionDecl * previsit( const ast::UnionDecl * aggrDecl ) {1778 return forallFixer( aggrDecl->location, aggrDecl, &ast::UnionDecl::params );1779 }1780 };1781 */1782 } // anonymous namespace1783 1784 /*1785 const ast::Type * validateType(1786 const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {1787 // ast::Pass< EnumAndPointerDecay_new > epc;1788 ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab };1789 ast::Pass< ForallPointerDecay_new > fpd{ loc };1790 1791 return type->accept( lrt )->accept( fpd );1792 }1793 */1794 1795 1321 } // namespace SymTab 1796 1322 -
src/SynTree/Declaration.h
rb77f0e1 r63be3387 449 449 }; 450 450 451 452 class InlineMemberDecl : public DeclarationWithType { 453 typedef DeclarationWithType Parent; 454 public: 455 Type * type; 456 457 InlineMemberDecl( const std::string & name, Type::StorageClasses scs, LinkageSpec::Spec linkage, Type * type, 458 const std::list< Attribute * > attributes = std::list< Attribute * >(), Type::FuncSpecifiers fs = Type::FuncSpecifiers() ); 459 InlineMemberDecl( const InlineMemberDecl & other ); 460 virtual ~InlineMemberDecl(); 461 462 virtual Type * get_type() const override { return type; } 463 virtual void set_type(Type * newType) override { type = newType; } 464 465 static InlineMemberDecl * newInlineMemberDecl( const std::string & name, Type * type ); 466 467 virtual InlineMemberDecl * clone() const override { return new InlineMemberDecl( *this ); } 468 virtual void accept( Visitor & v ) override { v.visit( this ); } 469 virtual void accept( Visitor & v ) const override { v.visit( this ); } 470 virtual DeclarationWithType * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 471 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 472 virtual void printShort( std::ostream & os, Indenter indent = {} ) const override; 473 474 }; 475 451 476 std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data ); 452 477 -
src/SynTree/Mutator.h
rb77f0e1 r63be3387 36 36 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0; 37 37 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0; 38 virtual DeclarationWithType * mutate( InlineMemberDecl * InlineMemberDecl ) = 0; 38 39 39 40 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) = 0; -
src/SynTree/SynTree.h
rb77f0e1 r63be3387 38 38 class DirectiveDecl; 39 39 class StaticAssertDecl; 40 class InlineMemberDecl; 40 41 41 42 class Statement; -
src/SynTree/Visitor.h
rb77f0e1 r63be3387 49 49 virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); } 50 50 virtual void visit( const StaticAssertDecl * assertDecl ) = 0; 51 virtual void visit( InlineMemberDecl * node ) { visit( const_cast<const InlineMemberDecl *>(node) ); } 52 virtual void visit( const InlineMemberDecl * valueDecl ) = 0; 51 53 52 54 virtual void visit( CompoundStmt * node ) { visit( const_cast<const CompoundStmt *>(node) ); } -
src/SynTree/module.mk
rb77f0e1 r63be3387 42 42 SynTree/Initializer.cc \ 43 43 SynTree/Initializer.h \ 44 SynTree/InlineMemberDecl.cc \ 44 45 SynTree/Label.h \ 45 46 SynTree/LinkageSpec.cc \ -
src/Validate/EnumAndPointerDecay.cpp
rb77f0e1 r63be3387 21 21 #include "AST/Type.hpp" 22 22 #include "SymTab/FixFunction.h" 23 #include "Validate/NoIdSymbolTable.hpp" 23 24 24 25 namespace Validate { … … 26 27 namespace { 27 28 28 struct EnumAndPointerDecayCore final : public ast::WithCodeLocation {29 struct EnumAndPointerDecayCore final : public WithNoIdSymbolTable, public ast::WithCodeLocation { 29 30 ast::EnumDecl const * previsit( ast::EnumDecl const * decl ); 30 31 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ); … … 39 40 // Set the type of each member of the enumeration to be EnumContant. 40 41 auto mut = ast::mutate( decl ); 41 for ( ast::ptr<ast::Decl> & member : mut->members ) { 42 ast::ObjectDecl const * object = member.strict_as<ast::ObjectDecl>(); 43 member = ast::mutate_field( object, &ast::ObjectDecl::type, 44 new ast::EnumInstType( decl, ast::CV::Const ) ); 42 std::vector<ast::ptr<ast::Decl>> buffer; 43 for ( auto member : decl->members ) { 44 if ( ast::ObjectDecl const * object = member.as<ast::ObjectDecl>() ) { 45 buffer.push_back( ast::mutate_field( object, 46 &ast::ObjectDecl::type, 47 new ast::EnumInstType( decl, ast::CV::Const ) ) ); 48 } else if ( auto value = member.as<ast::InlineMemberDecl>() ) { 49 if ( auto targetEnum = symtab.lookupEnum( value->name ) ) { 50 for ( auto enumMember : targetEnum->members ) { 51 auto enumObject = enumMember.strict_as<ast::ObjectDecl>(); 52 buffer.push_back( new ast::ObjectDecl( 53 // Get the location from the "inline" declaration. 54 value->location, 55 enumObject->name, 56 // Construct a new EnumInstType as the type. 57 new ast::EnumInstType( decl, ast::CV::Const ), 58 enumObject->init, 59 enumObject->storage, 60 enumObject->linkage, 61 enumObject->bitfieldWidth, 62 {}, 63 enumObject->funcSpec 64 ) ); 65 } 66 } 67 } 45 68 } 69 mut->members = buffer; 46 70 return mut; 47 71 } -
src/Validate/LinkReferenceToTypes.cpp
rb77f0e1 r63be3387 185 185 decl = mut; 186 186 } 187 // visit the base 187 188 } else if ( auto ptr = decl->base.as<ast::PointerType>() ) { 188 189 if ( auto base = ptr->base.as<ast::TypeInstType>() ) { … … 203 204 204 205 // The following section 205 auto mut = ast::mutate( decl );206 std::vector<ast::ptr<ast::Decl>> buffer;207 for ( auto it = decl->members.begin(); it != decl->members.end(); ++it) {208 auto member = (*it).as<ast::ObjectDecl>();209 if ( member->enumInLine ) {210 auto targetEnum = symtab.lookupEnum( member->name );211 if ( targetEnum ) {212 for ( auto singleMamber : targetEnum->members ) {213 auto tm = singleMamber.as<ast::ObjectDecl>();214 auto t = new ast::ObjectDecl(215 member->location, // use the "inline" location216 tm->name,217 new ast::EnumInstType( decl, ast::CV::Const ),218 // Construct a new EnumInstType as the type219 tm->init,220 tm->storage,221 tm->linkage,222 tm->bitfieldWidth,223 {}, // enum member doesn't have attribute224 tm->funcSpec225 );226 t->importValue = true;227 buffer.push_back(t);228 }229 }230 } else {231 auto search_it = std::find_if( buffer.begin(), buffer.end(), [member](ast::ptr<ast::Decl> cur) {232 auto curAsObjDecl = cur.as<ast::ObjectDecl>();233 return (curAsObjDecl->importValue) && (curAsObjDecl->name == member->name);234 });235 if ( search_it != buffer.end() ) {236 buffer.erase( search_it ); // Found an import enum value that has the same name237 // override the imported value238 }239 buffer.push_back( *it );240 }241 }242 mut->members = buffer;243 decl = mut;244 206 245 207 ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name ); -
src/Virtual/ExpandCasts.cc
rb77f0e1 r63be3387 295 295 // returns the previous declaration for error messages. 296 296 ast::ObjectDecl const * insert( ast::ObjectDecl const * typeIdDecl ) { 297 std::string const & mangledName = 298 Mangle::mangle( typeIdDecl->type, Mangle::typeMode() ); 297 std::string mangledName = Mangle::mangleType( typeIdDecl->type ); 299 298 ast::ObjectDecl const *& value = instances[ mangledName ]; 300 299 if ( value ) { … … 310 309 311 310 ast::ObjectDecl const * lookup( ast::Type const * typeIdType ) { 312 std::string const & mangledName = 313 Mangle::mangle( typeIdType, Mangle::typeMode() ); 311 std::string mangledName = Mangle::mangleType( typeIdType ); 314 312 auto const it = instances.find( mangledName ); 315 313 return ( instances.end() == it ) ? nullptr : it->second; -
tests/array-container/array-basic.cfa
rb77f0e1 r63be3387 78 78 } 79 79 80 forall( A & | ar(A, float) )80 forall( [N], A & | ar(A, float, N) ) 81 81 float total1d_hi( A & a ) { 82 82 float total = 0.0f; 83 for (i; a`len)83 for (i; N) 84 84 total += a[i]; 85 85 return total; -
tests/collections/atomic_mpsc.cfa
rb77f0e1 r63be3387 1 1 #include <fstream.hfa> 2 #include < queueLockFree.hfa>2 #include <containers/lockfree.hfa> 3 3 #include <thread.hfa> 4 4 -
tests/configs/parsebools.cfa
rb77f0e1 r63be3387 16 16 17 17 #include <fstream.hfa> 18 #include <parseargs.hfa>19 18 20 19 #include "../meta/fork+exec.hfa" 20 21 // last as a work around to a parse bug 22 #include <parseargs.hfa> 21 23 22 24 int main(int argc, char * argv[]) { -
tests/configs/parsenums.cfa
rb77f0e1 r63be3387 16 16 17 17 #include <fstream.hfa> 18 19 #include "../meta/fork+exec.hfa" 20 21 // last as workaround to parser bug 18 22 #include <parseargs.hfa> 19 20 #include "../meta/fork+exec.hfa"21 23 22 24 #if __SIZEOF_LONG__ == 4 -
tests/configs/usage.cfa
rb77f0e1 r63be3387 16 16 17 17 #include <fstream.hfa> 18 #include "../meta/fork+exec.hfa" 18 19 #include <parseargs.hfa> 19 20 20 #include "../meta/fork+exec.hfa"21 21 22 22 int main() { -
tests/enum_tests/.expect/enumInlineValue.txt
rb77f0e1 r63be3387 1 1 enumB.A is 5 2 enumB.B is 102 enumB.B is 6 3 3 enumB.D is 11 4 4 enumB.E is 12 -
tests/enum_tests/.expect/qualifiedEnum.cfa
rb77f0e1 r63be3387 1 l : 01 l :1 -
tests/enum_tests/enumInlineValue.cfa
rb77f0e1 r63be3387 6 6 enum enumB { 7 7 inline enumA, 8 E , B=108 E 9 9 }; 10 10 -
tests/enum_tests/qualifiedEnum.cfa
rb77f0e1 r63be3387 8 8 9 9 int main() { 10 enum Level l = Level. LOW;10 enum Level l = Level.MEDIUM; 11 11 sout | "l :" | l; 12 12 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.