Changes in / [63be3387:b77f0e1]
- Files:
-
- 2 added
- 27 deleted
- 72 edited
-
benchmark/io/http/worker.hfa (modified) (1 diff)
-
doc/theses/mike_brooks_MMath/programs/hello-md.cfa (modified) (8 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/text/front.tex (modified) (1 diff)
-
libcfa/src/Makefile.am (modified) (4 diffs)
-
libcfa/src/bits/containers.hfa (modified) (1 diff)
-
libcfa/src/bits/defs.hfa (modified) (1 diff)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (1 diff)
-
libcfa/src/concurrency/invoke.h (modified) (5 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/io/setup.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (11 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (6 diffs)
-
libcfa/src/concurrency/kernel/cluster.cfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/private.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (17 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (7 diffs)
-
libcfa/src/concurrency/once.hfa (deleted)
-
libcfa/src/concurrency/preemption.cfa (modified) (9 diffs)
-
libcfa/src/concurrency/pthread.cfa (deleted)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/thread.hfa (modified) (1 diff)
-
libcfa/src/containers/array.hfa (modified) (6 diffs)
-
libcfa/src/containers/lockfree.hfa (deleted)
-
libcfa/src/containers/queueLockFree.hfa (added)
-
libcfa/src/containers/stackLockFree.hfa (added)
-
libcfa/src/heap.cfa (modified) (22 diffs)
-
libcfa/src/interpose.cfa (modified) (4 diffs)
-
libcfa/src/interpose_thread.cfa (deleted)
-
src/AST/Convert.cpp (modified) (3 diffs)
-
src/AST/Decl.hpp (modified) (3 diffs)
-
src/AST/Fwd.hpp (modified) (1 diff)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (3 diffs)
-
src/AST/Print.cpp (modified) (1 diff)
-
src/AST/Type.cpp (modified) (2 diffs)
-
src/AST/Type.hpp (modified) (1 diff)
-
src/AST/Visitor.hpp (modified) (1 diff)
-
src/Common/CodeLocationTools.cpp (modified) (1 diff)
-
src/Common/PassVisitor.h (modified) (2 diffs)
-
src/Common/PassVisitor.impl.h (modified) (3 diffs)
-
src/Common/utility.h (modified) (1 diff)
-
src/GenPoly/Box.cc (modified) (62 diffs)
-
src/GenPoly/FindFunction.cc (modified) (3 diffs)
-
src/GenPoly/FindFunction.h (modified) (1 diff)
-
src/GenPoly/GenPoly.cc (modified) (6 diffs)
-
src/GenPoly/GenPoly.h (modified) (6 diffs)
-
src/GenPoly/InstantiateGenericNew.cpp (modified) (3 diffs)
-
src/GenPoly/ScrubTyVars.cc (modified) (4 diffs)
-
src/Parser/DeclarationNode.cc (modified) (2 diffs)
-
src/Parser/ExpressionNode.cc (modified) (1 diff)
-
src/Parser/ParseNode.h (modified) (2 diffs)
-
src/Parser/TypeData.cc (modified) (1 diff)
-
src/Parser/parser.yy (modified) (8 diffs)
-
src/ResolvExpr/CommonType.cc (modified) (2 diffs)
-
src/ResolvExpr/ConversionCost.cc (modified) (1 diff)
-
src/ResolvExpr/SatisfyAssertions.cpp (modified) (1 diff)
-
src/SymTab/Mangler.cc (modified) (4 diffs)
-
src/SymTab/Mangler.h (modified) (4 diffs)
-
src/SymTab/Validate.cc (modified) (2 diffs)
-
src/SynTree/Declaration.h (modified) (1 diff)
-
src/SynTree/InlineMemberDecl.cc (deleted)
-
src/SynTree/Mutator.h (modified) (1 diff)
-
src/SynTree/SynTree.h (modified) (1 diff)
-
src/SynTree/Visitor.h (modified) (1 diff)
-
src/SynTree/module.mk (modified) (1 diff)
-
src/Validate/EnumAndPointerDecay.cpp (modified) (3 diffs)
-
src/Validate/LinkReferenceToTypes.cpp (modified) (2 diffs)
-
src/Virtual/ExpandCasts.cc (modified) (2 diffs)
-
tests/.expect/loop-inc.txt (deleted)
-
tests/array-container/.expect/array-sbscr-types.txt (deleted)
-
tests/array-container/array-basic.cfa (modified) (1 diff)
-
tests/array-container/array-sbscr-types.cfa (deleted)
-
tests/collections/atomic_mpsc.cfa (modified) (1 diff)
-
tests/concurrent/.expect/migrate.txt (deleted)
-
tests/concurrent/.expect/once.txt (deleted)
-
tests/concurrent/migrate.cfa (deleted)
-
tests/concurrent/once.cfa (deleted)
-
tests/concurrent/pthread/.expect/bounded_buffer.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_attr_test.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_cond_test.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_demo_create_join.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_demo_lock.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_key_test.txt (deleted)
-
tests/concurrent/pthread/.expect/pthread_once_test.txt (deleted)
-
tests/concurrent/pthread/bounded_buffer.cfa (deleted)
-
tests/concurrent/pthread/pthread_attr_test.cfa (deleted)
-
tests/concurrent/pthread/pthread_cond_test.cfa (deleted)
-
tests/concurrent/pthread/pthread_demo_create_join.cfa (deleted)
-
tests/concurrent/pthread/pthread_demo_lock.cfa (deleted)
-
tests/concurrent/pthread/pthread_key_test.cfa (deleted)
-
tests/concurrent/pthread/pthread_once_test.cfa (deleted)
-
tests/configs/parsebools.cfa (modified) (1 diff)
-
tests/configs/parsenums.cfa (modified) (1 diff)
-
tests/configs/usage.cfa (modified) (1 diff)
-
tests/enum_tests/.expect/enumInlineValue.txt (modified) (1 diff)
-
tests/enum_tests/.expect/qualifiedEnum.cfa (modified) (1 diff)
-
tests/enum_tests/enumInlineValue.cfa (modified) (1 diff)
-
tests/enum_tests/qualifiedEnum.cfa (modified) (1 diff)
-
tests/loop-inc.cfa (deleted)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/io/http/worker.hfa
r63be3387 rb77f0e1 2 2 3 3 #include <iofwd.hfa> 4 #include < containers/lockfree.hfa>4 #include <queueLockFree.hfa> 5 5 #include <thread.hfa> 6 6 -
doc/theses/mike_brooks_MMath/programs/hello-md.cfa
r63be3387 rb77f0e1 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) ) {} 2 11 3 12 … … 29 38 30 39 31 32 33 34 35 36 37 38 39 40 forall( [N] ) 40 forall( ztype( N ) ) 41 41 void print1d_cstyle( array(float, N) & c ); 42 42 43 forall( [N], C & | ar( C, float, N ) )43 forall( C &, ztype( N ) | ix( C, float, N ) ) 44 44 void print1d( C & c ); 45 45 … … 58 58 59 59 60 forall( [N])60 forall( ztype( N ) ) 61 61 void print1d_cstyle( array(float, N) & c ) { 62 for( i; N) {62 for( i; z(N) ) { 63 63 printf("%.1f ", c[i]); 64 64 } … … 78 78 79 79 80 forall( [N], C & | ar( C, float, N ) )80 forall( C &, ztype( N ) | ix( C, float, N ) ) 81 81 void print1d( C & c ) { 82 for( i; N) {82 for( i; z(N) ) { 83 83 printf("%.1f ", c[i]); 84 84 } … … 99 99 100 100 101 void fill( array(float, 5, 7) & a ) {101 void fill( array(float, Z(5), Z(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, 5, 7) a;120 array( float, Z(5), Z(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 _ERROR_1163 #ifdef SHOWERR1 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
r63be3387 rb77f0e1 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 , the corporate partnership with Huawei Ltd. and the Natural Sciences and Engineering Research Council.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. 164 164 \cleardoublepage 165 165 -
libcfa/src/Makefile.am
r63be3387 rb77f0e1 62 62 containers/array.hfa \ 63 63 containers/list.hfa \ 64 containers/lockfree.hfa \ 64 containers/queueLockFree.hfa \ 65 containers/stackLockFree.hfa \ 65 66 containers/string_sharectx.hfa \ 66 67 containers/vector2.hfa \ … … 111 112 concurrency/invoke.h \ 112 113 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 \130 129 bits/signal.hfa \ 131 130 concurrency/clib/cfathread.cfa \ … … 146 145 concurrency/stats.cfa \ 147 146 concurrency/stats.hfa \ 148 concurrency/stats.hfa \ 149 concurrency/pthread.cfa 147 concurrency/stats.hfa 150 148 151 149 else -
libcfa/src/bits/containers.hfa
r63be3387 rb77f0e1 152 152 153 153 void append( __queue(T) & this, T * val ) with(this) { 154 verify(get_next( *val ) == 0p);155 154 verify(this.tail != 0p); 156 155 verify(*this.tail == 1p); -
libcfa/src/bits/defs.hfa
r63be3387 rb77f0e1 30 30 #ifdef __cforall 31 31 #define __cfa_anonymous_object(x) inline struct x 32 #define __cfa_dlink(x) inline dlink(x) 32 33 #else 33 34 #define __cfa_anonymous_object(x) struct x __cfa_anonymous_object 35 #define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute 34 36 #endif 35 37 -
libcfa/src/concurrency/clib/cfathread.cfa
r63be3387 rb77f0e1 172 172 173 173 pthread_attr_t attr; 174 if (int ret = __cfaabi_pthread_attr_init(&attr); 0 != ret) {174 if (int ret = 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 = __cfaabi_pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {178 if (int ret = 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
r63be3387 rb77f0e1 146 146 147 147 // Link lists fields 148 // instrusive link field for threads in the ready-queue148 // instrusive link field for threads 149 149 struct __thread_desc_link { 150 150 struct thread$ * next; 151 151 volatile unsigned long long ts; 152 152 }; 153 154 // Link lists fields155 // instrusive link field for threads in the user_link/cltr_link156 struct __thread_user_link {157 #ifdef __cforall158 inline dlink(thread$);159 #else160 struct thread$ * next; struct thread$ * back;161 #endif162 };163 _Static_assert(sizeof(struct __thread_user_link) == 2 * sizeof(struct thread$ *), "__thread_user_link should be consistent in C and Cforall");164 153 165 154 struct thread$ { … … 170 159 // Link lists fields 171 160 // instrusive link field for threads 172 struct __thread_desc_link rdy_link;161 struct __thread_desc_link link; 173 162 174 163 // current execution status for coroutine … … 206 195 struct __monitor_group_t monitors; 207 196 208 // intrusive link fields, used for locks, monitors and any user defineddata structure209 // default link fields for dlist210 struct __thread_user_link user_link; 211 212 // secondary intrusive link fields, used for global cluster list213 // default link fields for dlist214 struct __thread_user_link cltr_link;197 // used to put threads on dlist data structure 198 __cfa_dlink(thread$); 199 200 struct { 201 struct thread$ * next; 202 struct thread$ * prev; 203 } node; 215 204 216 205 // used to store state between clh lock/unlock … … 225 214 226 215 #if defined( __CFA_WITH_VERIFY__ ) 227 struct processor * volatile executing;228 216 void * canary; 229 217 #endif 230 218 }; 231 219 #ifdef __cforall 220 P9_EMBEDDED( thread$, dlink(thread$) ) 221 #endif 232 222 // Wrapper for gdb 233 223 struct cfathread_thread_t { struct thread$ debug; }; … … 241 231 #ifdef __cforall 242 232 extern "Cforall" { 243 static inline thread$ * volatile & ?`next ( thread$ * this ) {244 return this->user_link.next;245 }246 233 247 234 static inline thread$ *& get_next( thread$ & this ) __attribute__((const)) { 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$)) 235 return this.link.next; 236 } 237 238 static inline [thread$ *&, thread$ *& ] __get( thread$ & this ) __attribute__((const)) { 239 return this.node.[next, prev]; 240 } 265 241 266 242 static inline void ?{}(__monitor_group_t & this) { -
libcfa/src/concurrency/io.cfa
r63be3387 rb77f0e1 610 610 if( we ) { 611 611 sigval_t value = { PREEMPT_IO }; 612 __cfaabi_pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);612 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 path 653 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 successful 659 __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 #else 680 #error CFA_WITH_IO_URING_IDLE but none of CFA_HAVE_READV, CFA_HAVE_IORING_OP_READV or CFA_HAVE_IORING_OP_READ defined 681 #endif 682 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 read 703 if(available(*ftr)) { 704 // There is no pending read, we need to add one 705 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 #endif 641 729 #endif -
libcfa/src/concurrency/io/setup.cfa
r63be3387 rb77f0e1 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))) {} 36 37 void __cfa_io_stop ( processor * proc ) {} 37 38 … … 316 317 } 317 318 319 //============================================================================================= 320 // I/O Context Sleep 321 //============================================================================================= 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 stop 338 // size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST); 339 340 // // Remove the fd from the iopoller 341 // __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE"); 342 343 // // Notify the io poller thread of the shutdown 344 // iopoll.run = false; 345 // sigval val = { 1 }; 346 // pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 347 348 // // Make sure all this is done 349 // __atomic_thread_fence(__ATOMIC_SEQ_CST); 350 351 // // Wait for the next epoch 352 // 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 318 360 319 361 //============================================================================================= -
libcfa/src/concurrency/kernel.cfa
r63be3387 rb77f0e1 138 138 extern bool __cfa_io_drain( processor * proc ) __attribute__((nonnull (1))); 139 139 extern bool __cfa_io_flush( processor * ) __attribute__((nonnull (1))); 140 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 141 145 142 146 extern void __disable_interrupts_hard(); … … 158 162 verify(this); 159 163 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 present 168 // mark it as already fulfilled so we know if there is a pending request or not 169 this->idle_wctx.ftr->self.ptr = 1p; 170 160 171 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 161 172 #if !defined(__CFA_NO_STATISTICS__) … … 280 291 /* paranoid */ verify( ! __preemption_enabled() ); 281 292 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); 282 /* paranoid */ verifyf( thrd_dst-> rdy_link.next == 0p, "Expected null got %p", thrd_dst->rdy_link.next );293 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 283 294 __builtin_prefetch( thrd_dst->context.SP ); 284 295 … … 310 321 /* 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 311 322 /* 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 );313 323 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 314 324 … … 322 332 323 333 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 324 /* paranoid */ verify( __atomic_exchange_n( &thrd_dst->executing, 0p, __ATOMIC_SEQ_CST) == this );325 334 /* 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 ); 326 335 /* 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 );328 336 /* paranoid */ verify( thrd_dst->context.SP ); 337 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr ); 329 338 /* paranoid */ verify( kernelTLS().this_thread == thrd_dst ); 330 339 /* paranoid */ verify( ! __preemption_enabled() ); … … 443 452 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted ); 444 453 /* paranoid */ #endif 445 /* paranoid */ verifyf( thrd-> rdy_link.next == 0p, "Expected null got %p", thrd->rdy_link.next );454 /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next ); 446 455 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary ); 447 456 … … 591 600 /* 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 ); 592 601 602 thrd->state = Halting; 593 603 if( TICKET_RUNNING != thrd->ticket ) { abort( "Thread terminated with pending unpark" ); } 594 604 if( thrd != this->owner ) { abort( "Thread internal monitor has incorrect owner" ); } 595 605 if( this->recursion != 1) { abort( "Thread internal monitor has unbalanced recursion" ); } 596 597 thrd->state = Halting;598 thrd->ticket = TICKET_DEAD;599 606 600 607 // Leave the thread … … 617 624 // If that is the case, abandon the preemption. 618 625 bool preempted = false; 619 if(thrd-> rdy_link.next == 0p) {626 if(thrd->link.next == 0p) { 620 627 preempted = true; 621 628 thrd->preempted = reason; … … 719 726 720 727 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 ) ); 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()); 743 732 } 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 } 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 ); 751 762 #endif 752 763 } … … 764 775 insert_first(this.idles, proc); 765 776 766 // update the pointer to the head wait context, which should now point to this proc.767 777 __atomic_store_n(&this.fdw, &proc.idle_wctx, __ATOMIC_SEQ_CST); 768 778 unlock( this ); … … 781 791 782 792 { 783 // update the pointer to the head wait context784 793 struct __fd_waitctx * wctx = 0; 785 794 if(!this.idles`isEmpty) wctx = &this.idles`first.idle_wctx; -
libcfa/src/concurrency/kernel.hfa
r63be3387 rb77f0e1 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.67 66 volatile int sem; 68 67 … … 70 69 int evfd; 71 70 72 // Used for debugging, should be removed eventually. 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 73 79 volatile unsigned long long wake__time; 74 80 volatile unsigned long long sleep_time; … … 154 160 // P9_EMBEDDED( processor, dlink(processor) ) 155 161 static inline tytagref( dlink(processor), dlink(processor) ) ?`inner( processor & this ) { 156 dlink(processor) & b = this.link;157 tytagref( dlink(processor), dlink(processor) ) result = { b };158 return result;162 dlink(processor) & b = this.link; 163 tytagref( dlink(processor), dlink(processor) ) result = { b }; 164 return result; 159 165 } 160 166 … … 250 256 // List of threads 251 257 __spinlock_t thread_list_lock; 252 dlist(struct thread$, struct __thread_user_link) threads;258 __dllist_t(struct thread$) threads; 253 259 unsigned int nthreads; 254 260 … … 263 269 io_context_params params; 264 270 } io; 265 266 struct {267 struct processor ** procs;268 unsigned cnt;269 } managed;270 271 271 272 #if !defined(__CFA_NO_STATISTICS__) … … 297 298 static inline struct cluster * active_cluster () { return publicTLS_get( this_processor )->cltr; } 298 299 299 // set the number of internal processors300 // these processors are in addition to any explicitly declared processors301 unsigned set_concurrency( cluster & this, unsigned new_count );302 303 300 #if !defined(__CFA_NO_STATISTICS__) 304 301 void print_stats_now( cluster & this, int flags ); -
libcfa/src/concurrency/kernel/cluster.cfa
r63be3387 rb77f0e1 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$, 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 );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 ); 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
r63be3387 rb77f0e1 20 20 #endif 21 21 22 #include <signal.h>23 24 22 #include "kernel.hfa" 25 23 #include "thread.hfa" … … 41 39 } 42 40 41 // Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call 42 // #define CFA_WANT_IO_URING_IDLE 43 44 // Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call 45 #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_IDLE 48 #endif 49 #endif 50 43 51 // #define READYQ_USE_LINEAR_AVG 44 52 #define READYQ_USE_LOGDBL_AVG … … 55 63 #endif 56 64 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 69 65 //----------------------------------------------------------------------------- 70 66 // Scheduler … … 157 153 #define TICKET_RUNNING ( 0) // thread is running 158 154 #define TICKET_UNBLOCK ( 1) // thread should ignore next block 159 #define TICKET_DEAD (0xDEAD) // thread should never be unparked160 155 161 156 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/kernel/startup.cfa
r63be3387 rb77f0e1 16 16 #define __cforall_thread__ 17 17 #define _GNU_SOURCE 18 19 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__20 18 21 19 // C Includes … … 115 113 KERNEL_STORAGE(thread$, mainThread); 116 114 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); 117 118 #if !defined(__CFA_NO_STATISTICS__) 118 119 KERNEL_STORAGE(__stats_t, mainProcStats); … … 221 222 ( this.runner ){}; 222 223 init( this, "Main Processor", *mainCluster, 0p ); 223 kernel_thread = __cfaabi_pthread_self();224 kernel_thread = pthread_self(); 224 225 225 226 runner{ &this }; … … 231 232 mainProcessor = (processor *)&storage_mainProcessor; 232 233 (*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) ); 233 238 234 239 __cfa_io_start( mainProcessor ); … … 278 283 } 279 284 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_concurrency289 pthread_delete_kernel_threads_();290 291 287 /* paranoid */ verify( __preemption_enabled() ); 292 288 disable_interrupts(); … … 331 327 332 328 /* paranoid */ verify( this.do_terminate == true ); 333 __cfa dbg_print_safe(runtime_core,"Kernel : destroyed main processor context %p\n", &runner);329 __cfaabi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner); 334 330 } 335 331 … … 377 373 register_tls( proc ); 378 374 375 // used for idle sleep when io_uring is present 376 io_future_t future; 377 eventfd_t idle_buf; 378 proc->idle_wctx.ftr = &future; 379 proc->idle_wctx.rdbuf = &idle_buf; 380 381 379 382 // SKULLDUGGERY: We want to create a context for the processor coroutine 380 383 // which is needed for the 2-step context switch. However, there is no reason … … 385 388 (proc->runner){ proc, &info }; 386 389 387 __cfa dbg_print_safe(runtime_core,"Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);390 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 388 391 389 392 //Set global state … … 511 514 self_mon.recursion = 1; 512 515 self_mon_p = &self_mon; 513 rdy_link.next = 0p;514 rdy_link.ts = MAX;516 link.next = 0p; 517 link.ts = MAX; 515 518 preferred = ready_queue_new_preferred(); 516 519 last_proc = 0p; 517 520 random_state = __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl(); 518 521 #if defined( __CFA_WITH_VERIFY__ ) 519 executing = 0p;520 522 canary = 0x0D15EA5E0D15EA5Ep; 521 523 #endif 522 524 525 node.next = 0p; 526 node.prev = 0p; 523 527 doregister(curr_cluster, this); 524 528 … … 643 647 #endif 644 648 645 threads{ };649 threads{ __get }; 646 650 647 651 io.arbiter = create(); 648 652 io.params = io_params; 649 650 managed.procs = 0p;651 managed.cnt = 0;652 653 653 654 doregister(this); … … 666 667 667 668 void ^?{}(cluster & this) libcfa_public { 668 set_concurrency( this, 0 );669 670 669 destroy(this.io.arbiter); 671 670 … … 723 722 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 724 723 cltr->nthreads += 1; 725 insert_first(cltr->threads, thrd);724 push_front(cltr->threads, thrd); 726 725 unlock (cltr->thread_list_lock); 727 726 } … … 729 728 void unregister( cluster * cltr, thread$ & thrd ) { 730 729 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 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 } 730 remove(cltr->threads, thrd ); 731 cltr->nthreads -= 1; 737 732 unlock(cltr->thread_list_lock); 738 733 } … … 782 777 pthread_attr_t attr; 783 778 784 check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute779 check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute 785 780 786 781 size_t stacksize = max( PTHREAD_STACK_MIN, DEFAULT_STACK_SIZE ); … … 809 804 #endif 810 805 811 check( __cfaabi_pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );812 check( __cfaabi_pthread_create( pthread, &attr, start, arg ), "pthread_create" );806 check( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" ); 807 check( pthread_create( pthread, &attr, start, arg ), "pthread_create" ); 813 808 return stack; 814 809 } 815 810 816 811 void __destroy_pthread( pthread_t pthread, void * stack, void ** retval ) { 817 int err = __cfaabi_pthread_join( pthread, retval );812 int err = pthread_join( pthread, retval ); 818 813 if( err != 0 ) abort("KERNEL ERROR: joining pthread %p caused error %s\n", (void*)pthread, strerror(err)); 819 814 … … 821 816 pthread_attr_t attr; 822 817 823 check( __cfaabi_pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute818 check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute 824 819 825 820 size_t stacksize; 826 821 // default stack size, normally defined by shell limit 827 check( __cfaabi_pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );822 check( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" ); 828 823 assert( stacksize >= PTHREAD_STACK_MIN ); 829 824 stacksize += __page_size; … … 843 838 } 844 839 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 procs851 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 procs861 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 count867 return old;868 }869 870 840 #if defined(__CFA_WITH_VERIFY__) 871 841 static bool verify_fwd_bck_rng(void) { -
libcfa/src/concurrency/locks.hfa
r63be3387 rb77f0e1 21 21 22 22 #include "bits/weakso_locks.hfa" 23 #include "containers/ lockfree.hfa"23 #include "containers/queueLockFree.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
r63be3387 rb77f0e1 122 122 123 123 // Some one else has the monitor, wait in line for it 124 /* paranoid */ verify( thrd-> user_link.next == 0p );124 /* paranoid */ verify( thrd->link.next == 0p ); 125 125 append( this->entry_queue, thrd ); 126 /* paranoid */ verify( thrd-> user_link.next == 1p );126 /* paranoid */ verify( thrd->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-> user_link.next == 0p );235 /* paranoid */ verify( thrd->link.next == 0p ); 236 236 append( this->entry_queue, thrd ); 237 /* paranoid */ verify( thrd-> user_link.next == 1p );237 /* paranoid */ verify( thrd->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-> user_link.next == 0p );793 /* paranoid */ verify( !new_owner || new_owner->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 #endif940 937 // For each thread in the entry-queue 941 938 for( thread$ ** thrd_it = &entry_queue.head; 942 939 (*thrd_it) != 1p; 943 thrd_it = & get_next(**thrd_it)940 thrd_it = &(*thrd_it)->link.next 944 941 ) { 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 950 942 // For each acceptable check if it matches 951 943 int i = 0; … … 954 946 for( __acceptable_t * it = begin; it != end; it++, i++ ) { 955 947 // Check if we have a match 956 if( *it == curr->monitors ) {948 if( *it == (*thrd_it)->monitors ) { 957 949 958 950 // If we have a match return it … … 961 953 } 962 954 } 963 964 #if defined( __CFA_WITH_VERIFY__ )965 last = curr;966 #endif967 955 } 968 956 … … 1037 1025 1038 1026 // Some one else has the monitor, wait in line for it 1039 /* paranoid */ verify( thrd-> user_link.next == 0p );1027 /* paranoid */ verify( thrd->link.next == 0p ); 1040 1028 append( this->entry_queue, thrd ); 1041 /* paranoid */ verify( thrd-> user_link.next == 1p );1029 /* paranoid */ verify( thrd->link.next == 1p ); 1042 1030 1043 1031 unlock( this->lock ); -
libcfa/src/concurrency/preemption.cfa
r63be3387 rb77f0e1 352 352 sigset_t oldset; 353 353 int ret; 354 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary354 ret = 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 ( __cfaabi_pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) {387 if ( 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 ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {398 if ( 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 __cfaabi_pthread_sigqueue( this->kernel_thread, SIGUSR1, value );406 pthread_sigqueue( this->kernel_thread, SIGUSR1, value ); 407 407 } 408 408 … … 415 415 sigset_t oldset; 416 416 int ret; 417 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary417 ret = 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 = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary436 ret = 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 __cfaabi_pthread_sigqueue( alarm_thread, SIGALRM, val );507 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 ( __cfaabi_pthread_sigmask( SIG_SETMASK, (sigset_t *)&(cxt->uc_sigmask), 0p ) == -1 ) {581 if ( 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 ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {609 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 610 610 abort( "internal error, pthread_sigmask" ); 611 611 } -
libcfa/src/concurrency/ready_subqueue.hfa
r63be3387 rb77f0e1 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$, rdy_link )27 (uintptr_t)( &this.l.anchor ) - __builtin_offsetof( thread$, 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-> 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 );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 ); 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-> rdy_link.next = node;54 __atomic_store_n(&this.l.prev-> rdy_link.ts, rdtscl(), __ATOMIC_RELAXED);53 this.l.prev->link.next = node; 54 __atomic_store_n(&this.l.prev->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-> rdy_link.next;73 __atomic_store_n(&this.l.anchor.ts, __atomic_load_n(&node-> rdy_link.ts, __ATOMIC_RELAXED), __ATOMIC_RELAXED);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); 74 74 bool is_empty = this.l.anchor.next == 0p; 75 node-> rdy_link.next = 0p;76 __atomic_store_n(&node-> rdy_link.ts, ULLONG_MAX, __ATOMIC_RELAXED);75 node->link.next = 0p; 76 __atomic_store_n(&node->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-> 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 );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 ); 88 88 /* paranoid */ verify( ats != 0 ); 89 89 /* paranoid */ verify( (ats == MAX) == is_empty ); -
libcfa/src/concurrency/thread.cfa
r63be3387 rb77f0e1 44 44 self_mon_p = &self_mon; 45 45 curr_cluster = &cl; 46 rdy_link.next = 0p;47 rdy_link.ts = MAX;46 link.next = 0p; 47 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;53 52 canary = 0x0D15EA5E0D15EA5Ep; 54 53 #endif 54 55 node.next = 0p; 56 node.prev = 0p; 55 57 56 58 clh_node = malloc( ); … … 175 177 176 178 //----------------------------------------------------------------------------- 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 false186 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 this198 // not as important if we aren't local199 disable_interrupts();200 201 // actually move the thread202 unregister( thrd->curr_cluster, *thrd );203 thrd->curr_cluster = &cl;204 doregister( thrd->curr_cluster, *thrd );205 206 // restore interrupts207 enable_interrupts();208 209 // if this is the local thread, we are still running on the old cluster210 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 //-----------------------------------------------------------------------------223 179 #define GENERATOR LCG 224 180 -
libcfa/src/concurrency/thread.hfa
r63be3387 rb77f0e1 132 132 133 133 //---------- 134 // misc135 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 //----------142 134 // prng 143 135 static inline { -
libcfa/src/containers/array.hfa
r63be3387 rb77f0e1 1 #pragma once2 3 1 #include <assert.h> 4 2 … … 20 18 // About the choice of integral types offered as subscript overloads: 21 19 // Intent is to cover these use cases: 22 // a[0] // i : zero_t23 // a[1] // i : one_t24 // a[2] // i : int25 20 // float foo( ptrdiff_t i ) { return a[i]; } // i : ptrdiff_t 26 // float foo( size_t i ) { return a[i]; } // i : size_t27 21 // forall( [N] ) ... for( i; N ) { total += a[i]; } // i : typeof( sizeof(42) ) 28 22 // for( i; 5 ) { total += a[i]; } // i : int 29 //30 23 // It gets complicated by: 31 24 // - CFA does overloading on concrete types, like int and unsigned int, not on typedefed … … 35 28 // should give them type size_t. 36 29 // 37 // gcc -m32 cfa -m32 given bug gcc -m64 (and cfa)30 // gcc -m32 cfa -m32 given bug gcc -m64 38 31 // ptrdiff_t int int long int 39 32 // size_t unsigned int unsigned int unsigned long int 40 33 // typeof( sizeof(42) ) unsigned int unsigned long int unsigned long int 41 34 // 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-dimensional47 // subscripting and operations on slices use asserted subscript operators. The test case48 // array-container/array-sbscr-cases covers the combinations. Mike beleives that commenting out49 // 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 }61 35 62 36 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) { … … 103 77 return N; 104 78 } 105 106 static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}107 79 108 80 // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa) … … 184 156 #endif 185 157 186 // Available for users to work around Trac #265187 // If `a[...0...]` isn't working, try `a[...ix0...]` instead.188 189 #define ix0 ((ptrdiff_t)0)190 191 192 193 158 // 194 159 // Rotation … … 220 185 // 221 186 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 } 187 trait ar(A &, Tv &) { 188 Tv& ?[?]( A&, ptrdiff_t ); 189 size_t ?`len( A& ); 190 }; -
libcfa/src/heap.cfa
r63be3387 rb77f0e1 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 30 20:56:20202213 // Update Count : 15 8412 // Last Modified On : Thu Oct 13 22:21:52 2022 13 // Update Count : 1557 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 stack 45 46 #define OWNERSHIP // return freed memory to owner thread 46 #define RETURNSPIN // toggle spinlock / lockfree queue47 #if ! defined( OWNERSHIP ) && defined( RETURNSPIN )48 #warning "RETURNSPIN is ignored without OWNERSHIP; suggest commenting out RETURNSPIN"49 #endif // ! OWNERSHIP && RETURNSPIN50 47 51 48 #define CACHE_ALIGN 64 … … 112 109 113 110 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 111 //######################### Spin Lock ######################### 131 112 132 113 … … 225 206 226 207 208 #define SPINLOCK 0 209 #define LOCKFREE 1 210 #define BUCKETLOCK SPINLOCK 211 #if BUCKETLOCK == SPINLOCK 212 #elif BUCKETLOCK == LOCKFREE 213 #include <stackLockFree.hfa> 214 #else 215 #error undefined lock type for bucket lock 216 #endif // LOCKFREE 217 227 218 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage. 228 219 // Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined. … … 241 232 void * home; // allocated block points back to home locations (must overlay alignment) 242 233 size_t blockSize; // size for munmap (must overlay alignment) 234 #if BUCKETLOCK == SPINLOCK 243 235 Storage * next; // freed block points to next freed block of same size 236 #endif // SPINLOCK 244 237 }; 245 238 size_t size; // allocation size in bytes 246 239 }; 240 #if BUCKETLOCK == LOCKFREE 241 Link(Storage) next; // freed block points next freed block of same size (double-wide) 242 #endif // LOCKFREE 247 243 }; 248 244 } real; // RealHeader … … 263 259 struct __attribute__(( aligned (8) )) FreeHeader { 264 260 size_t blockSize __attribute__(( aligned(8) )); // size of allocations on this list 261 #if BUCKETLOCK == SPINLOCK 265 262 #ifdef OWNERSHIP 266 263 #ifdef RETURNSPIN … … 269 266 Storage * returnList; // other thread return list 270 267 #endif // OWNERSHIP 271 272 268 Storage * freeList; // thread free list 269 #else 270 StackLF(Storage) freeList; 271 #endif // BUCKETLOCK 273 272 Heap * homeManager; // heap owner (free storage to bucket, from bucket to heap) 274 273 }; // FreeHeader … … 291 290 #endif // __STATISTICS__ 292 291 }; // Heap 292 293 #if BUCKETLOCK == LOCKFREE 294 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 } // distribution 300 #endif // LOCKFREE 293 301 294 302 … … 377 385 378 386 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 const 394 l = m + 1; 395 } else { 396 h = m; 397 } // if 398 } // while 399 return l; 400 } // Bsearchl 401 402 379 403 void heapMasterCtor() with( heapMaster ) { 380 404 // Singleton pattern to initialize heap master … … 385 409 __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC; 386 410 387 extLock = 0;388 mgrLock = 0;411 ?{}( extLock ); 412 ?{}( mgrLock ); 389 413 390 414 char * end = (char *)sbrk( 0 ); … … 473 497 #ifdef OWNERSHIP 474 498 #ifdef RETURNSPIN 475 freeLists[j].returnLock = 0; 499 ?{}( freeLists[j].returnLock ); 500 #endif // RETURNSPIN 476 501 freeLists[j].returnList = 0p; 477 #endif // RETURNSPIN478 502 #endif // OWNERSHIP 479 480 503 freeLists[j].freeList = 0p; 481 504 freeLists[j].homeManager = heap; 482 505 freeLists[j].blockSize = bucketSizes[j]; 483 506 } // for 484 507 485 508 heapBuffer = 0p; 486 509 heapReserve = 0; … … 499 522 if ( unlikely( ! heapMasterBootFlag ) ) heapMasterCtor(); 500 523 501 lock( heapMaster.mgrLock ); // protect heapMaster counters524 lock( heapMaster.mgrLock ); // protect heapMaster counters 502 525 503 526 // get storage for heap manager … … 687 710 // find the closest bucket size less than or equal to the mmapStart size 688 711 maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search 689 690 712 verify( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 691 713 verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? … … 810 832 811 833 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() ); 834 // Do not call abort or strerror( errno ) as they may call malloc. 812 835 if ( unlikely( sbrk( increase ) == (void *)-1 ) ) { // failed, no memory ? 813 836 unlock( extLock ); 814 abort( NO_MEMORY_MSG, size ); // give up837 abort( NO_MEMORY_MSG, size ); // no memory 815 838 } // if 816 839 … … 948 971 #endif // __STATISTICS__ 949 972 973 // Spin until the lock is acquired for this particular size of block. 974 975 #if BUCKETLOCK == SPINLOCK 950 976 block = freeHead->freeList; // remove node from stack 977 #else 978 block = pop( freeHead->freeList ); 979 #endif // BUCKETLOCK 951 980 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 there953 // is enough left, or get some more heap storage and carve it off.954 981 #ifdef OWNERSHIP 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 { 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? 974 995 #endif // OWNERSHIP 975 996 // Do not leave kernel thread as manager_extend accesses heapManager. … … 981 1002 982 1003 #ifdef __CFA_DEBUG__ 983 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZEbytes.1004 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes. 984 1005 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) ); 985 1006 #endif // __CFA_DEBUG__ 1007 #endif // BUCKETLOCK 986 1008 #ifdef OWNERSHIP 1009 } else { // merge returnList into freeHead 1010 #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; 987 1017 } // if 988 1018 #endif // OWNERSHIP … … 996 1026 if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p; 997 1027 tsize = ceiling2( tsize, __page_size ); // must be multiple of page size 998 999 1028 #ifdef __STATISTICS__ 1000 1029 stats.counters[STAT_NAME].alloc += tsize; … … 1013 1042 if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory 1014 1043 // Do not call strerror( errno ) as it may call malloc. 1015 abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", 1016 size, heapMaster.mmapStart, errno ); 1044 abort( "**** Error **** attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno ); 1017 1045 } // if 1018 1046 block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap 1019 1047 1020 1048 #ifdef __CFA_DEBUG__ 1021 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first SCRUB_SIZE bytes. The1022 // rest ofthe storage set to 0 by mmap.1049 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes. The rest of 1050 // the storage set to 0 by mmap. 1023 1051 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) ); 1024 1052 #endif // __CFA_DEBUG__ … … 1098 1126 #endif // __CFA_DEBUG__ 1099 1127 1100 #ifdef OWNERSHIP1101 1128 if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread 1102 1129 header->kind.real.next = freeHead->freeList; // push on stack … … 1105 1132 verify( heapManager ); 1106 1133 1134 #ifdef OWNERSHIP 1107 1135 #ifdef RETURNSPIN 1108 1136 lock( freeHead->returnLock ); … … 1113 1141 header->kind.real.next = freeHead->returnList; // link new node to top node 1114 1142 // CAS resets header->kind.real.next = freeHead->returnList on failure 1115 while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, (Heap.Storage *)header,1143 while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header, 1116 1144 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ); 1117 1145 #endif // RETURNSPIN 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. 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 1135 1162 } // if 1136 1163 … … 1159 1186 #endif // __STATISTICS__ 1160 1187 1188 #if BUCKETLOCK == SPINLOCK 1161 1189 for ( Heap.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 1190 #else 1191 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 // BUCKETLOCK 1162 1198 total += size; 1163 1199 #ifdef __STATISTICS__ -
libcfa/src/interpose.cfa
r63be3387 rb77f0e1 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 #else56 originalFunc.ptr = dlsym( library, symbol );57 #endif // _GNU_SOURCE58 59 error = dlerror();60 if ( error ) abort( "interpose_symbol : internal error, %s\n", error );61 62 return originalFunc.fptr;63 }64 65 44 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 66 45 const char * error; 67 46 68 47 static void * library; 69 static void * pthread_library;70 48 if ( ! library ) { 71 49 #if defined( RTLD_NEXT ) … … 80 58 #endif 81 59 } // if 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); 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; 96 77 } 97 78 … … 116 97 117 98 extern "C" { 118 void __cfathreadabi_interpose_startup( generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ) ) __attribute__((weak));119 99 void __cfaabi_interpose_startup( void ) { 120 100 const char *version = 0p; … … 128 108 INTERPOSE_LIBC( exit , version ); 129 109 #pragma GCC diagnostic pop 130 131 if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol );132 110 133 111 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because -
src/AST/Convert.cpp
r63be3387 rb77f0e1 234 234 } 235 235 return declWithTypePostamble( decl, node ); 236 }237 238 // InlineMemberDecl vanish after EnumAndPointerDecay pass so no necessary to implement NewToOld239 const ast::DeclWithType * visit( const ast::InlineMemberDecl * node ) override final {240 assert( false );241 (void) node;242 return nullptr;243 236 } 244 237 … … 1621 1614 { old->get_funcSpec().val } 1622 1615 ); 1616 decl->enumInLine = old->enumInLine; 1623 1617 cache.emplace(old, decl); 1624 1618 assert(cache.find( old ) != cache.end()); … … 1865 1859 decl->uniqueId = old->uniqueId; 1866 1860 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;1895 1861 1896 1862 this->node = decl; -
src/AST/Decl.hpp
r63be3387 rb77f0e1 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 else 107 110 108 111 ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type, … … 397 400 }; 398 401 399 /// Static Assertion `_Static_assert( ... , ... );`400 402 class StaticAssertDecl : public Decl { 401 403 public: … … 409 411 private: 410 412 StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); } 411 MUTATE_FRIEND412 };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 }; }430 413 MUTATE_FRIEND 431 414 }; -
src/AST/Fwd.hpp
r63be3387 rb77f0e1 37 37 class DirectiveDecl; 38 38 class StaticAssertDecl; 39 class InlineMemberDecl;40 39 41 40 class Stmt; -
src/AST/Pass.hpp
r63be3387 rb77f0e1 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;144 143 const ast::CompoundStmt * visit( const ast::CompoundStmt * ) override final; 145 144 const ast::Stmt * visit( const ast::ExprStmt * ) override final; -
src/AST/Pass.impl.hpp
r63be3387 rb77f0e1 617 617 maybe_accept( node, &FunctionDecl::returns ); 618 618 maybe_accept( node, &FunctionDecl::type ); 619 maybe_accept( node, &FunctionDecl::attributes );620 619 // First remember that we are now within a function. 621 620 ValueGuard< bool > oldInFunction( inFunction ); … … 626 625 atFunctionTop = true; 627 626 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 // InlineMemberDecl806 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 );818 802 } 819 803 -
src/AST/Print.cpp
r63be3387 rb77f0e1 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 407 400 return node; 408 401 } -
src/AST/Type.cpp
r63be3387 rb77f0e1 147 147 // --- TypeInstType 148 148 149 bool TypeInstType::operator==( const TypeInstType & other ) const {150 return base == other.base151 && formal_usage == other.formal_usage152 && expr_id == other.expr_id;153 }154 155 149 TypeInstType::TypeInstType( const TypeDecl * b, 156 150 CV::Qualifiers q, std::vector<ptr<Attribute>> && as ) … … 163 157 164 158 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.base174 && formal_usage == other.formal_usage175 && 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 }194 159 195 160 // --- TupleType -
src/AST/Type.hpp
r63be3387 rb77f0e1 408 408 409 409 TypeEnvKey() = default; 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; 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; } 417 414 }; 418 415 419 bool operator==(const TypeInstType & other) const ;416 bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; } 420 417 421 418 TypeInstType( -
src/AST/Visitor.hpp
r63be3387 rb77f0e1 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;36 35 virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * ) = 0; 37 36 virtual const ast::Stmt * visit( const ast::ExprStmt * ) = 0; -
src/Common/CodeLocationTools.cpp
r63be3387 rb77f0e1 111 111 macro(DirectiveDecl, DirectiveDecl) \ 112 112 macro(StaticAssertDecl, StaticAssertDecl) \ 113 macro(InlineMemberDecl, DeclWithType) \114 113 macro(CompoundStmt, CompoundStmt) \ 115 114 macro(ExprStmt, Stmt) \ -
src/Common/PassVisitor.h
r63be3387 rb77f0e1 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;85 83 86 84 virtual void visit( CompoundStmt * compoundStmt ) override final; … … 275 273 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final; 276 274 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final; 277 virtual DeclarationWithType * mutate( InlineMemberDecl * valueDecl ) override final;278 275 279 276 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) override final; -
src/Common/PassVisitor.impl.h
r63be3387 rb77f0e1 607 607 indexerAddId( &func ); 608 608 maybeMutate_impl( node->type, *this ); 609 maybeMutate_impl( node->attributes, *this );610 609 // First remember that we are now within a function. 611 610 ValueGuard< bool > oldInFunction( inFunction ); … … 616 615 atFunctionTop = true; 617 616 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 // InlineMemberDecl1050 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 );1075 1046 } 1076 1047 -
src/Common/utility.h
r63be3387 rb77f0e1 452 452 453 453 // ----------------------------------------------------------------------------- 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 )... ); 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; 463 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) ); 481 478 } 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 } 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) ); } 495 481 }; 496 482 497 public: 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. 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. 521 488 template< typename... Args > 522 489 group_iterate_t<Args...> group_iterate( Args &&... args ) { 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. 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. 528 494 template< typename... Args > 529 495 group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) { 530 return group_iterate_t<Args...>( std::forward<Args>( args )...);496 return group_iterate_t<Args...>(true, std::forward<Args>( args )...); 531 497 } 532 498 -
src/GenPoly/Box.cc
r63be3387 rb77f0e1 58 58 namespace GenPoly { 59 59 namespace { 60 FunctionType *makeAdapterType( FunctionType const*adaptee, const TyVarMap &tyVars );60 FunctionType *makeAdapterType( FunctionType *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; 70 72 public: 73 void previsit( FunctionDecl *functionDecl ); 71 74 void previsit( StructDecl *structDecl ); 72 75 void previsit( UnionDecl *unionDecl ); … … 97 100 void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ); 98 101 /// passes extra type parameters into a polymorphic function application 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 ); 102 void passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ); 102 103 /// wraps a function application with a new temporary for the out-parameter return value 103 /// The new out-parameter is the new first parameter. 104 Expression *addRetParam( ApplicationExpr *appExpr, Type *retType ); 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 ); 105 110 /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value 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 ); 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 ); 121 116 /// Stores assignment operators from assertion list in local map of assignment operations 122 117 void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars ); 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 ); 118 FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ); 127 119 /// Replaces intrinsic operator functions with their arithmetic desugaring 128 120 Expression *handleIntrinsics( ApplicationExpr *appExpr ); … … 190 182 ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 ); 191 183 /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns 192 bool findGeneric( Type const*ty );184 bool findGeneric( Type *ty ); 193 185 /// adds type parameters to the layout call; will generate the appropriate parameters if needed 194 186 void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ); … … 229 221 } // anonymous namespace 230 222 223 /// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging 224 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 prelude 235 } 236 237 *i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) ); 238 assert( *i ); 239 } // if 240 } catch( SemanticErrorException &e ) { 241 errors.append( e ); 242 } // try 243 } // for 244 if ( ! errors.isEmpty() ) { 245 throw errors; 246 } // if 247 } 248 231 249 void box( std::list< Declaration *>& translationUnit ) { 232 250 PassVisitor<LayoutFunctionBuilder> layoutBuilder; … … 245 263 ////////////////////////////////// LayoutFunctionBuilder //////////////////////////////////////////// 246 264 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 247 273 /// Get a list of type declarations that will affect a layout function 248 274 std::list< TypeDecl* > takeOtypeOnly( std::list< TypeDecl* > &decls ) { 249 275 std::list< TypeDecl * > otypeDecls; 250 276 251 for ( TypeDecl * const decl : decls) {252 if ( decl->isComplete() ) {253 otypeDecls.push_back( decl );277 for ( std::list< TypeDecl* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl ) { 278 if ( (*decl)->isComplete() ) { 279 otypeDecls.push_back( *decl ); 254 280 } 255 281 } … … 262 288 BasicType sizeAlignType( Type::Qualifiers(), BasicType::LongUnsignedInt ); 263 289 264 for ( TypeDecl * const param : otypeParams) {265 TypeInstType paramType( Type::Qualifiers(), param->get_name(),param );290 for ( std::list< TypeDecl* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) { 291 TypeInstType paramType( Type::Qualifiers(), (*param)->get_name(), *param ); 266 292 std::string paramName = mangleType( ¶mType ); 267 293 layoutFnType->get_parameters().push_back( new ObjectDecl( sizeofName( paramName ), Type::StorageClasses(), LinkageSpec::Cforall, 0, sizeAlignType.clone(), 0 ) ); … … 271 297 272 298 /// Builds a layout function declaration 273 FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, bool isInFunction, FunctionType *layoutFnType ) {299 FunctionDecl *buildLayoutFunctionDecl( AggregateDecl *typeDecl, unsigned int functionNesting, FunctionType *layoutFnType ) { 274 300 // Routines at global scope marked "static" to prevent multiple definitions is separate translation units 275 301 // because each unit generates copies of the default routines for each aggregate. 276 302 FunctionDecl *layoutDecl = new FunctionDecl( layoutofName( typeDecl ), 277 isInFunction? Type::StorageClasses() : Type::StorageClasses( Type::Static ),303 functionNesting > 0 ? Type::StorageClasses() : Type::StorageClasses( Type::Static ), 278 304 LinkageSpec::AutoGen, layoutFnType, new CompoundStmt(), 279 305 std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ); 280 306 layoutDecl->fixUniqueId(); 281 307 return layoutDecl; 308 } 309 310 /// Makes a unary operation 311 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; 282 315 } 283 316 … … 347 380 348 381 // build function decl 349 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, isInFunction(), layoutFnType );382 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( structDecl, functionNesting, layoutFnType ); 350 383 351 384 // calculate struct layout in function body … … 354 387 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 0 ) ) ) ); 355 388 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 356 for ( auto index_member : enumerate( structDecl->members ) ) { 357 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( index_member.val ); 389 unsigned long n_members = 0; 390 bool firstMember = true; 391 for ( Declaration* member : structDecl->get_members() ) { 392 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member ); 358 393 assert( dwt ); 359 394 Type *memberType = dwt->get_type(); 360 395 361 if ( 0 < index_member.idx ) { 396 if ( firstMember ) { 397 firstMember = false; 398 } else { 362 399 // make sure all members after the first (automatically aligned at 0) are properly padded for alignment 363 400 addStmt( layoutDecl->get_statements(), makeAlignTo( derefVar( sizeParam ), new AlignofExpr( memberType->clone() ) ) ); … … 365 402 366 403 // place current size in the current offset index 367 addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( index_member.idx) ) ),404 addExpr( layoutDecl->get_statements(), makeOp( "?=?", makeOp( "?[?]", new VariableExpr( offsetParam ), new ConstantExpr( Constant::from_ulong( n_members ) ) ), 368 405 derefVar( sizeParam ) ) ); 406 ++n_members; 369 407 370 408 // add member size to current size … … 401 439 402 440 // build function decl 403 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, isInFunction(), layoutFnType );441 FunctionDecl *layoutDecl = buildLayoutFunctionDecl( unionDecl, functionNesting, layoutFnType ); 404 442 405 443 // calculate union layout in function body 406 444 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( sizeParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 407 445 addExpr( layoutDecl->get_statements(), makeOp( "?=?", derefVar( alignParam ), new ConstantExpr( Constant::from_ulong( 1 ) ) ) ); 408 for ( Declaration * const member : unionDecl->members) {409 DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( member );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 ); 410 448 assert( dwt ); 411 449 Type *memberType = dwt->get_type(); … … 426 464 427 465 namespace { 428 std::string makePolyMonoSuffix( FunctionType const* function, const TyVarMap &tyVars ) {466 std::string makePolyMonoSuffix( FunctionType * function, const TyVarMap &tyVars ) { 429 467 std::stringstream name; 430 468 … … 435 473 // to take those polymorphic types as pointers. Therefore, there can be two different functions 436 474 // with the same mangled name, so we need to further mangle the names. 437 for ( DeclarationWithType const * const ret : function->returnVals) {438 if ( isPolyType( ret->get_type(), tyVars ) ) {475 for ( std::list< DeclarationWithType *>::iterator retval = function->get_returnVals().begin(); retval != function->get_returnVals().end(); ++retval ) { 476 if ( isPolyType( (*retval)->get_type(), tyVars ) ) { 439 477 name << "P"; 440 478 } else { … … 443 481 } 444 482 name << "_"; 445 for ( DeclarationWithType const * const arg : function->parameters ) { 446 if ( isPolyType( arg->get_type(), tyVars ) ) { 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 ) ) { 447 486 name << "P"; 448 487 } else { … … 453 492 } 454 493 455 std::string mangleAdapterName( FunctionType const* function, const TyVarMap &tyVars ) {494 std::string mangleAdapterName( FunctionType * function, const TyVarMap &tyVars ) { 456 495 return SymTab::Mangler::mangle( function ) + makePolyMonoSuffix( function, tyVars ); 457 496 } … … 460 499 return "_adapter" + mangleName; 461 500 } 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 types465 Type *replaceWithConcrete( Type *type, TypeSubstitution const * env, bool doClone = true );466 501 467 502 Pass1::Pass1() : tempNamer( "_temp" ) {} … … 489 524 490 525 std::list< DeclarationWithType *> ¶mList = functionType->parameters; 491 std::list< FunctionType const*> functions;492 for ( Type Decl * const tyVar : functionType->forall) {493 for ( DeclarationWithType * const assert : tyVar->assertions) {494 findFunction( assert->get_type(), functions, scopeTyVars, needsAdapter );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 ); 495 530 } // for 496 531 } // for 497 for ( DeclarationWithType * const arg : paramList) {498 findFunction( arg->get_type(), functions, scopeTyVars, needsAdapter );532 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { 533 findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter ); 499 534 } // for 500 535 501 for ( FunctionType const * const funType : functions) {502 std::string mangleName = mangleAdapterName( funType, scopeTyVars );536 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) { 537 std::string mangleName = mangleAdapterName( *funType, scopeTyVars ); 503 538 if ( adapters.find( mangleName ) == adapters.end() ) { 504 539 std::string adapterName = makeAdapterName( mangleName ); 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 ) ) );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 ) ) ); 506 541 } // if 507 542 } // for … … 558 593 } 559 594 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(); 595 void Pass1::passTypeVars( ApplicationExpr *appExpr, Type *polyRetType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) { 563 596 // pass size/align for type variables 564 for ( std::pair<std::string, TypeDecl::Data> const & tyParam : exprTyVars) {597 for ( TyVarMap::const_iterator tyParm = exprTyVars.begin(); tyParm != exprTyVars.end(); ++tyParm ) { 565 598 ResolvExpr::EqvClass eqvClass; 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++; 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 576 611 } // if 577 612 } // for 578 613 579 614 // add size/align for generic types to parameter list 580 if ( ! appExpr->get_function()->result ) return arg;615 if ( ! appExpr->get_function()->result ) return; 581 616 FunctionType *funcType = getFunctionType( appExpr->get_function()->get_result() ); 582 617 assert( funcType ); 583 618 584 // These iterators don't advance in unison.585 619 std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); 586 620 std::list< Expression* >::const_iterator fnArg = arg; … … 589 623 // a polymorphic return type may need to be added to the argument list 590 624 if ( polyRetType ) { 591 Type *concRetType = replaceWithConcrete( polyRetType, env);625 Type *concRetType = replaceWithConcrete( appExpr, polyRetType ); 592 626 passArgTypeVars( appExpr, polyRetType, concRetType, arg, exprTyVars, seenTypes ); 593 627 ++fnArg; // skip the return parameter in the argument list … … 600 634 passArgTypeVars( appExpr, (*fnParm)->get_type(), argType, arg, exprTyVars, seenTypes ); 601 635 } 602 return arg;603 636 } 604 637 … … 609 642 } 610 643 611 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType ) {644 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, Type *retType, std::list< Expression *>::iterator &arg ) { 612 645 // Create temporary to hold return value of polymorphic function and produce that temporary as a result 613 646 // using a comma expression. … … 629 662 paramExpr = new AddressExpr( paramExpr ); 630 663 } // if 631 // Add argument to function call.632 a ppExpr->args.push_front( paramExpr );664 arg = appExpr->args.insert( arg, paramExpr ); // add argument to function call 665 arg++; 633 666 // Build a comma expression to call the function and emulate a normal return. 634 667 CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr ); … … 638 671 } 639 672 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 ); 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 ); 644 676 assertf(paramType, "Aggregate parameters should be type expressions"); 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 ); 677 paramType->set_type( replaceWithConcrete( appExpr, paramType->get_type(), false ) ); 678 } 679 } 680 681 Type *Pass1::replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone ) { 652 682 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) { 653 683 Type *concrete = env->lookup( typeInst->get_name() ); … … 660 690 structType = structType->clone(); 661 691 } 662 replaceParametersWithConcrete( structType->get_parameters(), env);692 replaceParametersWithConcrete( appExpr, structType->get_parameters() ); 663 693 return structType; 664 694 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) { … … 666 696 unionType = unionType->clone(); 667 697 } 668 replaceParametersWithConcrete( unionType->get_parameters(), env);698 replaceParametersWithConcrete( appExpr, unionType->get_parameters() ); 669 699 return unionType; 670 700 } … … 672 702 } 673 703 674 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType ) { 675 Type *concrete = replaceWithConcrete( dynType, env ); 704 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) { 705 assert( env ); 706 Type *concrete = replaceWithConcrete( appExpr, dynType ); 676 707 // add out-parameter for return value 677 return addRetParam( appExpr, concrete );678 } 679 680 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function ) {708 return addRetParam( appExpr, concrete, arg ); 709 } 710 711 Expression *Pass1::applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) { 681 712 Expression *ret = appExpr; 682 713 // if ( ! function->get_returnVals().empty() && isPolyType( function->get_returnVals().front()->get_type(), tyVars ) ) { 683 if ( isDynRet( function, scopeTyVars ) ) {684 ret = addRetParam( appExpr, function->returnVals.front()->get_type() );714 if ( isDynRet( function, tyVars ) ) { 715 ret = addRetParam( appExpr, function->returnVals.front()->get_type(), arg ); 685 716 } // if 686 std::string mangleName = mangleAdapterName( function, scopeTyVars );717 std::string mangleName = mangleAdapterName( function, tyVars ); 687 718 std::string adapterName = makeAdapterName( mangleName ); 688 719 … … 693 724 694 725 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 variables 747 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 } // if 695 758 } 696 759 … … 728 791 } 729 792 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; 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 ); 770 798 } // for 771 799 } 772 800 773 void Pass1::addInferredParams( ApplicationExpr *appExpr, std::list< Expression *>::iterator arg, FunctionType *functionType, const TyVarMap &tyVars ) {801 void Pass1::addInferredParams( ApplicationExpr *appExpr, FunctionType *functionType, std::list< Expression *>::iterator &arg, const TyVarMap &tyVars ) { 774 802 std::list< Expression *>::iterator cur = arg; 775 for ( Type Decl * 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() );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() ); 779 807 Expression *newExpr = inferParam->second.expr->clone(); 780 boxParam( newExpr, assert->get_type(), tyVars ); 808 addCast( newExpr, (*assert)->get_type(), tyVars ); 809 boxParam( (*assert)->get_type(), newExpr, tyVars ); 781 810 appExpr->get_args().insert( cur, newExpr ); 782 811 } // for … … 795 824 } 796 825 797 FunctionType *makeAdapterType( FunctionType const*adaptee, const TyVarMap &tyVars ) {826 FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars ) { 798 827 // actually make the adapter type 799 828 FunctionType *adapter = adaptee->clone(); … … 805 834 } 806 835 807 Expression *makeAdapterArg( 808 DeclarationWithType *param, 809 DeclarationWithType const *arg, 810 DeclarationWithType const *realParam, 811 const TyVarMap &tyVars ) { 836 Expression *makeAdapterArg( DeclarationWithType *param, DeclarationWithType *arg, DeclarationWithType *realParam, const TyVarMap &tyVars ) { 812 837 assert( param ); 813 838 assert( arg ); 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; 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 820 846 } // if 821 847 return new VariableExpr( param ); 822 848 } 823 849 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 ) { 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 ) { 831 851 UniqueName paramNamer( "_p" ); 832 852 for ( ; param != paramEnd; ++param, ++arg, ++realParam ) { … … 839 859 } 840 860 841 FunctionDecl *Pass1::makeAdapter( FunctionType const*adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {861 FunctionDecl *Pass1::makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) { 842 862 FunctionType *adapterType = makeAdapterType( adaptee, tyVars ); 843 863 adapterType = ScrubTyVars::scrub( adapterType, tyVars ); … … 856 876 Statement *bodyStmt; 857 877 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 ) ); 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 ) ); 867 889 } // for 868 890 } // for 869 891 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();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(); 873 895 param++; // skip adaptee parameter in the adapter type 874 896 if ( realType->get_returnVals().empty() ) { … … 876 898 addAdapterParams( adapteeApp, arg, param, adapterType->get_parameters().end(), realParam, tyVars ); 877 899 bodyStmt = new ExprStmt( adapteeApp ); 878 } else if ( isDynType( adaptee-> returnVals.front()->get_type(), tyVars ) ) {900 } else if ( isDynType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) { 879 901 // return type T 880 902 if ( (*param)->get_name() == "" ) { … … 901 923 void Pass1::passAdapters( ApplicationExpr * appExpr, FunctionType * functionType, const TyVarMap & exprTyVars ) { 902 924 // collect a list of function types passed as parameters or implicit parameters (assertions) 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 ); 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 ); 907 930 } // for 908 931 } // for 909 for ( DeclarationWithType * const arg : functionType->get_parameters()) {910 findFunction( arg->get_type(), functions, exprTyVars, needsAdapter );932 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { 933 findFunction( (*arg)->get_type(), functions, exprTyVars, needsAdapter ); 911 934 } // for 912 935 … … 915 938 std::set< std::string > adaptersDone; 916 939 917 for ( FunctionType const * const funType : functions) {918 FunctionType *originalFunction = funType->clone();919 FunctionType *realFunction = funType->clone();940 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) { 941 FunctionType *originalFunction = (*funType)->clone(); 942 FunctionType *realFunction = (*funType)->clone(); 920 943 std::string mangleName = SymTab::Mangler::mangle( realFunction ); 921 944 … … 935 958 if ( adapter == adapters.end() ) { 936 959 // adapter has not been created yet in the current scope, so define it 937 FunctionDecl *newAdapter = makeAdapter( funType, realFunction, mangleName, exprTyVars );960 FunctionDecl *newAdapter = makeAdapter( *funType, realFunction, mangleName, exprTyVars ); 938 961 std::pair< AdapterIter, bool > answer = adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, newAdapter ) ); 939 962 adapter = answer.first; … … 949 972 950 973 Expression *makeIncrDecrExpr( ApplicationExpr *appExpr, Type *polyType, bool isIncr ) { 951 NameExpr *opExpr = new NameExpr( ( isIncr ) ? "?+=?" : "?-=?" ); 974 NameExpr *opExpr; 975 if ( isIncr ) { 976 opExpr = new NameExpr( "?+=?" ); 977 } else { 978 opExpr = new NameExpr( "?-=?" ); 979 } // if 952 980 UntypedExpr *addAssign = new UntypedExpr( opExpr ); 953 981 if ( AddressExpr *address = dynamic_cast< AddressExpr *>( appExpr->get_args().front() ) ) { … … 1092 1120 Expression *Pass1::postmutate( ApplicationExpr *appExpr ) { 1093 1121 // std::cerr << "mutate appExpr: " << InitTweak::getFunctionName( appExpr ) << std::endl; 1094 // for ( auto tyVar : scopeTyVars) {1095 // std::cerr << tyVar.first << " ";1122 // for ( TyVarMap::iterator i = scopeTyVars.begin(); i != scopeTyVars.end(); ++i ) { 1123 // std::cerr << i->first << " "; 1096 1124 // } 1097 1125 // std::cerr << "\n"; … … 1106 1134 1107 1135 Expression *ret = appExpr; 1136 1137 std::list< Expression *>::iterator arg = appExpr->get_args().begin(); 1108 1138 std::list< Expression *>::iterator paramBegin = appExpr->get_args().begin(); 1109 1139 … … 1126 1156 // std::cerr << "dynRetType: " << dynRetType << std::endl; 1127 1157 Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result(); 1128 ret = addDynRetParam( appExpr, concRetType ); // xxx - used to use dynRetType instead of concRetType1158 ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType 1129 1159 } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...? 1130 1160 // 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. … … 1134 1164 // std::cerr << *env << std::endl; 1135 1165 // change the application so it calls the adapter rather than the passed function 1136 ret = applyAdapter( appExpr, function );1166 ret = applyAdapter( appExpr, function, arg, scopeTyVars ); 1137 1167 } // if 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 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 ); 1147 1177 passAdapters( appExpr, function, exprTyVars ); 1148 1178 … … 1150 1180 } 1151 1181 1152 bool isPolyDeref( UntypedExpr const * expr, TyVarMap const & scopeTyVars, TypeSubstitution const * env) {1182 Expression * Pass1::postmutate( UntypedExpr *expr ) { 1153 1183 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) { 1154 if ( auto name = dynamic_cast<NameExpr const*>( expr->function ) ) {1184 if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) { 1155 1185 if ( name->name == "*?" ) { 1156 return true; 1186 Expression *ret = expr->args.front(); 1187 expr->args.clear(); 1188 delete expr; 1189 return ret; 1157 1190 } // if 1158 1191 } // if 1159 1192 } // 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 }1170 1193 return expr; 1171 1194 } … … 1177 1200 bool needs = false; 1178 1201 if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) { 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 ); 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 1185 1212 } // if 1186 1213 } // if … … 1233 1260 void Pass2::addAdapters( FunctionType *functionType ) { 1234 1261 std::list< DeclarationWithType *> ¶mList = functionType->parameters; 1235 std::list< FunctionType const*> functions;1236 for ( DeclarationWithType * const arg : functionType->parameters) {1237 Type *orig = arg->get_type();1262 std::list< FunctionType *> functions; 1263 for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) { 1264 Type *orig = (*arg)->get_type(); 1238 1265 findAndReplaceFunction( orig, functions, scopeTyVars, needsAdapter ); 1239 arg->set_type( orig );1266 (*arg)->set_type( orig ); 1240 1267 } 1241 1268 std::set< std::string > adaptersDone; 1242 for ( FunctionType const * const funType : functions) {1243 std::string mangleName = mangleAdapterName( funType, scopeTyVars );1269 for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) { 1270 std::string mangleName = mangleAdapterName( *funType, scopeTyVars ); 1244 1271 if ( adaptersDone.find( mangleName ) == adaptersDone.end() ) { 1245 1272 std::string adapterName = makeAdapterName( mangleName ); 1246 1273 // adapter may not be used in body, pass along with unused attribute. 1247 paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) );1274 paramList.push_front( new ObjectDecl( adapterName, Type::StorageClasses(), LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0, { new Attribute( "unused" ) } ) ); 1248 1275 adaptersDone.insert( adaptersDone.begin(), mangleName ); 1249 1276 } … … 1322 1349 ObjectDecl newPtr( "", Type::StorageClasses(), LinkageSpec::C, 0, 1323 1350 new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 ); 1324 for ( Type Decl * const tyParam : funcType->get_forall()) {1351 for ( Type::ForallList::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) { 1325 1352 ObjectDecl *sizeParm, *alignParm; 1326 1353 // add all size and alignment parameters to parameter list 1327 if ( tyParam->isComplete() ) {1328 TypeInstType parmType( Type::Qualifiers(), tyParam->get_name(), tyParam );1354 if ( (*tyParm)->isComplete() ) { 1355 TypeInstType parmType( Type::Qualifiers(), (*tyParm)->get_name(), *tyParm ); 1329 1356 std::string parmName = mangleType( &parmType ); 1330 1357 … … 1340 1367 } 1341 1368 // move all assertions into parameter list 1342 for ( DeclarationWithType * const assert : tyParam->get_assertions()) {1369 for ( std::list< DeclarationWithType *>::iterator assert = (*tyParm)->get_assertions().begin(); assert != (*tyParm)->get_assertions().end(); ++assert ) { 1343 1370 // assertion parameters may not be used in body, pass along with unused attribute. 1344 assert->get_attributes().push_back( new Attribute( "unused" ) );1345 inferredParams.push_back( assert );1346 } 1347 tyParam->get_assertions().clear();1371 (*assert)->get_attributes().push_back( new Attribute( "unused" ) ); 1372 inferredParams.push_back( *assert ); 1373 } 1374 (*tyParm)->get_assertions().clear(); 1348 1375 } 1349 1376 1350 1377 // add size/align for generic parameter types to parameter list 1351 1378 std::set< std::string > seenTypes; // sizeofName for generic types we've seen 1352 for ( DeclarationWithType * const fnParam : funcType->get_parameters()) {1353 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );1379 for ( std::list< DeclarationWithType* >::const_iterator fnParm = last; fnParm != funcType->get_parameters().end(); ++fnParm ) { 1380 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars ); 1354 1381 if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) { 1355 1382 std::string typeName = mangleType( polyType ); … … 1455 1482 1456 1483 if(!expect_func_type) { 1484 GuardAction( [this]() { 1485 knownLayouts.endScope(); 1486 knownOffsets.endScope(); 1487 }); 1457 1488 // If this is the first function type we see 1458 1489 // Then it's the type of the declaration and we care about it 1459 GuardScope( *this ); 1490 knownLayouts.beginScope(); 1491 knownOffsets.beginScope(); 1460 1492 } 1461 1493 … … 1465 1497 1466 1498 // make sure that any type information passed into the function is accounted for 1467 for ( DeclarationWithType * const fnParam : funcType->get_parameters()) {1499 for ( std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); fnParm != funcType->get_parameters().end(); ++fnParm ) { 1468 1500 // condition here duplicates that in Pass2::mutate( FunctionType* ) 1469 Type *polyType = isPolyType( fnParam->get_type(), scopeTyVars );1501 Type *polyType = isPolyType( (*fnParm)->get_type(), scopeTyVars ); 1470 1502 if ( polyType && ! dynamic_cast< TypeInstType* >( polyType ) ) { 1471 1503 knownLayouts.insert( mangleType( polyType ) ); … … 1475 1507 1476 1508 /// converts polymorphic type T into a suitable monomorphic representation, currently: __attribute__((aligned(8)) char[size_T] 1477 Type * polyToMonoType( Type const* declType ) {1509 Type * polyToMonoType( Type * declType ) { 1478 1510 Type * charType = new BasicType( Type::Qualifiers(), BasicType::Kind::Char); 1479 1511 Expression * size = new NameExpr( sizeofName( mangleType(declType) ) ); … … 1540 1572 /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present 1541 1573 long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) { 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() ) 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() ) 1546 1577 continue; 1547 1578 1548 1579 if ( memberDecl->get_name().empty() ) { 1549 1580 // plan-9 field: match on unique_id 1550 if ( memberDecl->get_uniqueId() == decl->get_uniqueId() )1581 if ( memberDecl->get_uniqueId() == (*decl)->get_uniqueId() ) 1551 1582 return i; 1552 1583 else … … 1554 1585 } 1555 1586 1556 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );1587 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( *decl ); 1557 1588 1558 1589 if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) { … … 1572 1603 1573 1604 /// Returns an index expression into the offset array for a type 1574 Expression *makeOffsetIndex( Type const*objectType, long i ) {1605 Expression *makeOffsetIndex( Type *objectType, long i ) { 1575 1606 ConstantExpr *fieldIndex = new ConstantExpr( Constant::from_ulong( i ) ); 1576 1607 UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) ); … … 1665 1696 1666 1697 void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) { 1667 for ( Type * const param : otypeParams) {1668 if ( findGeneric( param ) ) {1698 for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) { 1699 if ( findGeneric( *param ) ) { 1669 1700 // push size/align vars for a generic parameter back 1670 std::string paramName = mangleType( param );1701 std::string paramName = mangleType( *param ); 1671 1702 layoutCall->get_args().push_back( new NameExpr( sizeofName( paramName ) ) ); 1672 1703 layoutCall->get_args().push_back( new NameExpr( alignofName( paramName ) ) ); 1673 1704 } else { 1674 layoutCall->get_args().push_back( new SizeofExpr( param->clone() ) );1675 layoutCall->get_args().push_back( new AlignofExpr( param->clone() ) );1705 layoutCall->get_args().push_back( new SizeofExpr( (*param)->clone() ) ); 1706 layoutCall->get_args().push_back( new AlignofExpr( (*param)->clone() ) ); 1676 1707 } 1677 1708 } … … 1679 1710 1680 1711 /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list 1681 bool findGenericParams( std::list< TypeDecl* > const &baseParams, std::list< Expression* > const&typeParams, std::list< Type* > &out ) {1712 bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* > &typeParams, std::list< Type* > &out ) { 1682 1713 bool hasDynamicLayout = false; 1683 1714 1684 for ( auto paramPair : group_iterate( baseParams, typeParams ) ) {1685 TypeDecl * baseParam = std::get<0>( paramPair);1686 Expression * typeParam = std::get<1>( paramPair );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 ) { 1687 1718 // skip non-otype parameters 1688 if ( ! baseParam->isComplete() ) continue;1689 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( typeParam );1719 if ( ! (*baseParam)->isComplete() ) continue; 1720 TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam ); 1690 1721 assert( typeExpr && "all otype parameters should be type expressions" ); 1691 1722 … … 1694 1725 if ( isPolyType( type ) ) hasDynamicLayout = true; 1695 1726 } 1727 assert( baseParam == baseParams.end() && typeParam == typeParams.end() ); 1696 1728 1697 1729 return hasDynamicLayout; 1698 1730 } 1699 1731 1700 bool PolyGenericCalculator::findGeneric( Type const*ty ) {1732 bool PolyGenericCalculator::findGeneric( Type *ty ) { 1701 1733 ty = replaceTypeInst( ty, env ); 1702 1734 1703 if ( auto typeInst = dynamic_cast< TypeInstType const* >( ty ) ) {1735 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) { 1704 1736 if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) { 1705 1737 // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set … … 1707 1739 } 1708 1740 return false; 1709 } else if ( auto structTy = dynamic_cast< StructInstType const* >( ty ) ) {1741 } else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) { 1710 1742 // check if this type already has a layout generated for it 1711 1743 std::string typeName = mangleType( ty ); … … 1714 1746 // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized 1715 1747 std::list< Type* > otypeParams; 1716 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy-> parameters, otypeParams ) ) return false;1748 if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->get_parameters(), otypeParams ) ) return false; 1717 1749 1718 1750 // insert local variables for layout and generate call to layout function … … 1744 1776 1745 1777 return true; 1746 } else if ( auto unionTy = dynamic_cast< UnionInstType const* >( ty ) ) {1778 } else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) { 1747 1779 // check if this type already has a layout generated for it 1748 1780 std::string typeName = mangleType( ty ); … … 1751 1783 // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized 1752 1784 std::list< Type* > otypeParams; 1753 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy-> parameters, otypeParams ) ) return false;1785 if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->get_parameters(), otypeParams ) ) return false; 1754 1786 1755 1787 // insert local variables for layout and generate call to layout function … … 1849 1881 // build initializer list for offset array 1850 1882 std::list< Initializer* > inits; 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 ) ) ); 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 } 1855 1889 } 1856 1890 … … 1931 1965 // compile-command: "make install" // 1932 1966 // End: // 1933 -
src/GenPoly/FindFunction.cc
r63be3387 rb77f0e1 29 29 class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting { 30 30 public: 31 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );31 FindFunction( std::list< FunctionType* > &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 const * > &functions;39 std::list< FunctionType* > &functions; 40 40 TyVarMap tyVars; 41 41 bool replaceMode; … … 43 43 }; 44 44 45 void findFunction( Type *type, std::list< FunctionType const* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {45 void findFunction( Type *type, std::list< FunctionType* > &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 const* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {50 void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &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 const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )55 FindFunction::FindFunction( std::list< FunctionType* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate ) 56 56 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) { 57 57 } -
src/GenPoly/FindFunction.h
r63be3387 rb77f0e1 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 const* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );29 void findFunction( Type *type, std::list< FunctionType* > &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 const* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );31 void findAndReplaceFunction( Type *&type, std::list< FunctionType* > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ); 32 32 } // namespace GenPoly 33 33 -
src/GenPoly/GenPoly.cc
r63be3387 rb77f0e1 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 24 15:19:00 202213 // Update Count : 1 712 // Last Modified On : Fri Oct 7 15:25:00 2022 13 // Update Count : 16 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 129 120 const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { 130 121 if (!env) return type; 131 if ( auto typeInst = dynamic_cast<const ast::TypeInstType*>(type)) {122 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) { 132 123 auto newType = env->lookup(typeInst); 133 124 if (newType) return newType; … … 203 194 204 195 if ( auto inst = dynamic_cast< const ast::TypeInstType * >( type ) ) { 205 if ( typeVars.find( *inst) != typeVars.end() ) return type;196 if ( typeVars.find( inst->typeString() ) != typeVars.end() ) return type; 206 197 } else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) { 207 198 return isPolyType( array->base, subst ); … … 236 227 237 228 if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) { 238 auto var = typeVars.find( *inst);229 auto var = typeVars.find( inst->name ); 239 230 if ( var != typeVars.end() && var->second.isComplete ) { 240 return inst; 231 241 232 } 242 233 } else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) { … … 793 784 794 785 void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars ) { 795 typeVars.insert( *type, ast::TypeDecl::Data( type->base ) );786 typeVars.insert( type->typeString(), ast::TypeDecl::Data( type->base ) ); 796 787 } 797 788 … … 825 816 } 826 817 818 void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ) { 819 for ( auto const & pair : typeVars ) { 820 os << pair.first << " (" << pair.second << ") "; 821 } // for 822 os << std::endl; 823 } 824 827 825 } // namespace GenPoly 828 826 -
src/GenPoly/GenPoly.h
r63be3387 rb77f0e1 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 24 15:18:00 202213 // Update Count : 1112 // Last Modified On : Fri Oct 7 15:06:00 2022 13 // Update Count : 9 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::TypeEnvKey25 24 #include "SymTab/Mangler.h" // for Mangler 26 25 #include "SynTree/Declaration.h" // for TypeDecl::Data, AggregateDecl, Type... … … 29 28 namespace GenPoly { 30 29 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< ast::TypeInstType::TypeEnvKey, ast::TypeDecl::Data >;32 using TypeVarMap = ErasableScopedMap< std::string, 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 * );38 36 39 37 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided … … 55 53 /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters 56 54 ReferenceToType *isDynRet( FunctionType *function ); 57 const ast::BaseInstType *isDynRet( const ast::FunctionType * func );58 55 59 56 /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type … … 115 112 /// Prints type variable map 116 113 void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ); 114 void printTypeVarMap( std::ostream &os, const TypeVarMap & typeVars ); 117 115 118 116 /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType(). 119 inline std::string mangleType( constType *ty ) { return SymTab::Mangler::mangleType( ty ); }117 inline std::string mangleType( Type *ty ) { return SymTab::Mangler::mangleType( ty ); } 120 118 121 119 /// Gets the name of the sizeof parameter for the type, given its mangled name … … 130 128 /// Gets the name of the layout function for a given aggregate type, given its declaration 131 129 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 }135 130 136 131 } // namespace GenPoly -
src/GenPoly/InstantiateGenericNew.cpp
r63be3387 rb77f0e1 10 10 // Created On : Tue Aug 16 10:51:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 31 16:48:00 202213 // Update Count : 112 // Last Modified On : Tue Sep 13 16:03:00 2022 13 // Update Count : 0 14 14 // 15 15 … … 378 378 // Ptr(int) p; 379 379 // int i; 380 // The original expression:381 380 // p.x = &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: 381 // becomes 382 // int *& _dtype_static_member_0 = (int **)&p.x; 383 // _dtype_static_member_0 = &i; 388 384 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::ExplicitCast 389 ); 389 390 ast::ObjectDecl * tmp = new ast::ObjectDecl( location, 390 391 tmpNamer.newName(), 391 392 new ast::ReferenceType( concType ), 392 n ullptr,393 new ast::SingleInit( location, init ), 393 394 ast::Storage::Classes(), 394 395 ast::Linkage::C 395 396 ); 396 397 stmtsToAddBefore.push_back( new ast::DeclStmt( 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 ); 398 return new ast::VariableExpr( location, tmp ); 411 399 } else { 412 400 // Here, it can simply add a cast to actual types. … … 488 476 }; 489 477 478 // I think this and the UnionInstType can be made into a template function. 490 479 ast::Type const * GenericInstantiator::postvisit( 491 480 ast::StructInstType const * inst ) { -
src/GenPoly/ScrubTyVars.cc
r63be3387 rb77f0e1 20 20 #include "GenPoly/ErasableScopedMap.h" // for ErasableScopedMap<>::const_it... 21 21 #include "ScrubTyVars.h" 22 #include "SymTab/Mangler.h" // for mangle Type22 #include "SymTab/Mangler.h" // for mangle, typeMode 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 );197 auto typeVar = typeVars->find( type->name ); 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 Type( dynType) ) );229 sizeofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) ); 230 230 } else { 231 231 return expr; … … 237 237 if ( dynType ) { 238 238 return new ast::NameExpr( expr->location, 239 alignofName( Mangle::mangle Type( dynType) ) );239 alignofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) ); 240 240 } else { 241 241 return expr; -
src/Parser/DeclarationNode.cc
r63be3387 rb77f0e1 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, InlineMemberDecl,Declaration29 #include "SynTree/Declaration.h" // for TypeDecl, ObjectDecl, 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 } // if1170 1167 assertf( name, "ObjectDecl must a have name\n" ); 1171 1168 return (new ObjectDecl( *name, storageClasses, linkage, maybeBuild< Expression >( bitfieldWidth ), nullptr, maybeBuild< Initializer >( initializer ) ))->set_asmName( asmName )->set_extension( extension ); -
src/Parser/ExpressionNode.cc
r63be3387 rb77f0e1 519 519 } 520 520 } 521 return new QualifiedNameExpr( newDecl, name->name ); 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; 522 527 } 523 528 -
src/Parser/ParseNode.h
r63be3387 rb77f0e1 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 2 21:27:07202213 // Update Count : 93 912 // Last Modified On : Tue Oct 18 16:22:15 2022 13 // Update Count : 937 14 14 // 15 15 … … 168 168 Ctor, Dtor, 169 169 }; // OperKinds 170 171 enum class EnumHiding { Visible, Hide };172 170 173 171 struct LabelNode { -
src/Parser/TypeData.cc
r63be3387 rb77f0e1 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 // Do Nothing 928 } else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) { 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() ) { 929 932 SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." ); 930 933 } else if ( cur->has_enumeratorValue() ) { -
src/Parser/parser.yy
r63be3387 rb77f0e1 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 2 21:31:21202213 // Update Count : 5 81012 // Last Modified On : Fri Oct 14 14:04:43 2022 13 // Update Count : 5751 14 14 // 15 15 … … 278 278 279 279 // Types declaration for productions 280 281 280 %union { 282 281 Token tok; … … 291 290 CondCtl * ifctl; 292 291 ForCtrl * fctl; 293 OperKinds compop;292 enum OperKinds compop; 294 293 LabelNode * label; 295 294 InitializerNode * in; … … 297 296 std::string * str; 298 297 bool flag; 299 EnumHiding hide;300 298 CatchStmt::Kind catch_kind; 301 299 GenericExpr * genexpr; … … 366 364 %type<constant> string_literal 367 365 %type<str> string_literal_list 368 369 %type<hide> hide_opt visible_hide_opt370 366 371 367 // expressions … … 2557 2553 | ENUM attribute_list_opt identifier 2558 2554 { typedefTable.makeTypedef( *$3 ); } 2559 hide_opt'{' enumerator_list comma_opt '}'2560 { $$ = DeclarationNode::newEnum( $3, $7, true, false )->addQualifiers( $2 ); }2555 '{' enumerator_list comma_opt '}' 2556 { $$ = DeclarationNode::newEnum( $3, $6, true, false )->addQualifiers( $2 ); } 2561 2557 | ENUM attribute_list_opt typedef_name // unqualified type name 2562 hide_opt'{' enumerator_list comma_opt '}'2563 { $$ = DeclarationNode::newEnum( $3->name, $ 6, true, false )->addQualifiers( $2 ); }2558 '{' enumerator_list comma_opt '}' 2559 { $$ = DeclarationNode::newEnum( $3->name, $5, true, false )->addQualifiers( $2 ); } 2564 2560 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2565 2561 { … … 2578 2574 typedefTable.makeTypedef( *$6 ); 2579 2575 } 2580 hide_opt'{' enumerator_list comma_opt '}'2581 { 2582 $$ = DeclarationNode::newEnum( $6, $1 1, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 );2576 '{' enumerator_list comma_opt '}' 2577 { 2578 $$ = DeclarationNode::newEnum( $6, $10, true, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2583 2579 } 2584 2580 | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt 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 ); 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 ); 2598 2592 } 2599 2593 | enum_type_nobody 2600 ;2601 2602 hide_opt:2603 // empty2604 { $$ = EnumHiding::Visible; }2605 | '!'2606 { $$ = EnumHiding::Hide; }2607 2594 ; 2608 2595 … … 2615 2602 2616 2603 enumerator_list: 2617 visible_hide_optidentifier_or_type_name enumerator_value_opt2618 { $$ = DeclarationNode::newEnumValueGeneric( $ 2, $3); }2604 identifier_or_type_name enumerator_value_opt 2605 { $$ = DeclarationNode::newEnumValueGeneric( $1, $2 ); } 2619 2606 | INLINE type_name 2620 2607 { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); } 2621 | enumerator_list ',' visible_hide_optidentifier_or_type_name enumerator_value_opt2622 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $ 4, $5) ); }2608 | enumerator_list ',' identifier_or_type_name enumerator_value_opt 2609 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $3, $4 ) ); } 2623 2610 | enumerator_list ',' INLINE type_name enumerator_value_opt 2624 2611 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); } 2625 ;2626 2627 visible_hide_opt:2628 hide_opt2629 | '^'2630 { $$ = EnumHiding::Visible; }2631 2612 ; 2632 2613 -
src/ResolvExpr/CommonType.cc
r63be3387 rb77f0e1 991 991 add_qualifiers( result, type2->qualifiers ); 992 992 } else { 993 // xxx - does unifying a ref with typed enumInst makes sense? 993 994 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 994 995 result = commonType( type2, ref, tenv, need, have, open, widen, symtab ); … … 1009 1010 1010 1011 void postvisit( const ast::EnumInstType * enumInst ) { 1012 // reuse BasicType/EnumInstType common type by swapping 1013 // xxx - is this already handled by unify? 1011 1014 if (!dynamic_cast<const ast::EnumInstType *>(type2)) 1012 1015 result = commonType( type2, enumInst, tenv, need, have, open, widen, symtab); -
src/ResolvExpr/ConversionCost.cc
r63be3387 rb77f0e1 720 720 costCalc( baseType, dst, srcIsLvalue, symtab, env ); 721 721 } else { 722 (void)enumInstType; 722 723 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 723 724 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); -
src/ResolvExpr/SatisfyAssertions.cpp
r63be3387 rb77f0e1 268 268 ast::ptr< ast::Type > resType = cand.expr->result; 269 269 cand.env.apply( resType ); 270 return Mangle::mangle Type( resType);270 return Mangle::mangle( resType, Mangle::typeMode() ); 271 271 } 272 272 -
src/SymTab/Mangler.cc
r63be3387 rb77f0e1 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:40:29 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Oct 21 16:18:00 202213 // Update Count : 7 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 11 21:56:06 2021 13 // Update Count : 74 14 14 // 15 15 #include "Mangler.h" … … 418 418 void postvisit( const ast::QualifiedType * qualType ); 419 419 420 /// The result is the current constructed mangled name. 421 std::string result() const { return mangleName; } 420 std::string get_mangleName() { return mangleName; } 422 421 private: 423 422 std::string mangleName; ///< Mangled name being constructed … … 445 444 } // namespace 446 445 446 447 447 std::string mangle( const ast::Node * decl, Mangle::Mode mode ) { 448 return ast::Pass<Mangler_new>::read( decl, mode ); 448 ast::Pass<Mangler_new> mangler( mode ); 449 maybeAccept( decl, mangler ); 450 return mangler.core.get_mangleName(); 449 451 } 450 452 … … 687 689 } // for 688 690 for ( auto & assert : ptype->assertions ) { 689 assertionNames.push_back( ast::Pass<Mangler_new>::read( 690 assert->var.get(), 691 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) ); 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() ); 692 695 acount++; 693 696 } // for -
src/SymTab/Mangler.h
r63be3387 rb77f0e1 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:44:03 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thu Oct 27 11:58:00 202213 // Update Count : 1 611 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:45:30 2017 13 // Update Count : 15 14 14 // 15 15 … … 22 22 23 23 #include "AST/Bitfield.hpp" 24 #include "AST/Fwd.hpp" 24 25 #include "SynTree/SynTree.h" // for Types 25 26 #include "SynTree/Visitor.h" // for Visitor, maybeAccept … … 32 33 // * Currently name compression is not implemented. 33 34 34 namespace ast {35 class Node;36 }37 35 namespace ResolvExpr { 38 36 class TypeEnvironment; … … 103 101 using Mode = bitfield<mangle_flags>; 104 102 105 /// Mangle declaration name. 103 static inline Mode typeMode() { return NoOverrideable | Type; } 104 105 /// Mangle declaration name 106 106 std::string mangle( const ast::Node * decl, Mode mode = {} ); 107 108 /// Most common mangle configuration for types.109 static inline std::string mangleType( const ast::Node * type ) {110 return mangle( type, { NoOverrideable | Type } );111 }112 107 113 108 namespace Encoding { -
src/SymTab/Validate.cc
r63be3387 rb77f0e1 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" 49 56 #include "CodeGen/CodeGenerator.h" // for genName 50 57 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign … … 1319 1326 } 1320 1327 1328 namespace { 1329 /// Replaces enum types by int, and function/array types in function parameter and return 1330 /// lists by appropriate pointers 1331 /* 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 EnumConstant 1335 for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) { 1336 // build new version of object with EnumConstant 1337 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 decl 1343 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::FixedArgs 1354 ) { 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 list 1363 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 it 1369 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 substitutions 1384 void expandAssertions( 1385 const ast::TraitInstType * inst, std::vector< ast::ptr< ast::DeclWithType > > & out 1386 ) { 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 parameters 1390 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->base 1393 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 definitions 1401 class LinkReferenceToTypes_new final 1402 : public ast::WithSymbolTable, public ast::WithGuards, public 1403 ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting { 1404 1405 // these maps of uses of forward declarations of types need to have the actual type 1406 // declaration switched in * after * they have been traversed. To enable this in the 1407 // ast::Pass framework, any node that needs to be so mutated has mutate() called on it 1408 // before it is placed in the map, properly updating its parents in the usual traversal, 1409 // then can have the actual mutation applied later 1410 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 be 1422 /// renamed appropriately 1423 bool inGeneric = false; 1424 1425 public: 1426 /// contstruct using running symbol table 1427 LinkReferenceToTypes_new( const CodeLocation & loc ) 1428 : location( loc ), localSymtab( &symtab ) {} 1429 1430 /// construct using provided symbol table 1431 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 type 1436 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 declaration 1454 if ( decl ) { 1455 inst = ast::mutate_field( inst, &ast::EnumInstType::base, decl ); 1456 } 1457 if ( ! decl || ! decl->body ) { 1458 // forward declaration 1459 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 declaration 1479 if ( decl ) { 1480 inst = ast::mutate_field( inst, &ast::StructInstType::base, decl ); 1481 } 1482 if ( ! decl || ! decl->body ) { 1483 // forward declaration 1484 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 declaration 1495 if ( decl ) { 1496 inst = ast::mutate_field( inst, &ast::UnionInstType::base, decl ); 1497 } 1498 if ( ! decl || ! decl->body ) { 1499 // forward declaration 1500 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 traits 1510 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 instance 1520 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 type 1550 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 updated 1556 // properly 1557 if ( ! enumDecl->body ) return enumDecl; 1558 1559 // update forward declarations to point here 1560 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 updated 1565 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 set 1571 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 that 1575 // determine if an expression is constexpr have appropriate information 1576 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 defined 1592 /// function forall parameters, e.g. the T in Box and the T in f, below 1593 /// 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 are 1622 // updated properly 1623 if ( ! structDecl->body ) return; 1624 1625 // update forward declarations to point here 1626 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 updated 1631 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 updated 1643 // properly 1644 if ( ! unionDecl->body ) return; 1645 1646 // update forward declarations to point here 1647 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 updated 1652 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" trait 1660 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 trait 1671 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 assigns 1695 /// each object and function declaration a unique ID 1696 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 pointers 1703 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 ID 1712 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 ID 1720 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 instances 1727 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::* forallField 1731 ) { 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 members 1740 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 members 1745 expandAssertions( traitInst, asserts ); 1746 } else { 1747 // pass other assertions through 1748 asserts.emplace_back( assn ); 1749 } 1750 } 1751 1752 // apply FixFunction to every assertion to check for invalid void type 1753 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 node 1762 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 namespace 1783 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 1321 1795 } // namespace SymTab 1322 1796 -
src/SynTree/Declaration.h
r63be3387 rb77f0e1 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 476 451 std::ostream & operator<<( std::ostream & os, const TypeDecl::Data & data ); 477 452 -
src/SynTree/Mutator.h
r63be3387 rb77f0e1 36 36 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0; 37 37 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0; 38 virtual DeclarationWithType * mutate( InlineMemberDecl * InlineMemberDecl ) = 0;39 38 40 39 virtual CompoundStmt * mutate( CompoundStmt * compoundStmt ) = 0; -
src/SynTree/SynTree.h
r63be3387 rb77f0e1 38 38 class DirectiveDecl; 39 39 class StaticAssertDecl; 40 class InlineMemberDecl;41 40 42 41 class Statement; -
src/SynTree/Visitor.h
r63be3387 rb77f0e1 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;53 51 54 52 virtual void visit( CompoundStmt * node ) { visit( const_cast<const CompoundStmt *>(node) ); } -
src/SynTree/module.mk
r63be3387 rb77f0e1 42 42 SynTree/Initializer.cc \ 43 43 SynTree/Initializer.h \ 44 SynTree/InlineMemberDecl.cc \45 44 SynTree/Label.h \ 46 45 SynTree/LinkageSpec.cc \ -
src/Validate/EnumAndPointerDecay.cpp
r63be3387 rb77f0e1 21 21 #include "AST/Type.hpp" 22 22 #include "SymTab/FixFunction.h" 23 #include "Validate/NoIdSymbolTable.hpp"24 23 25 24 namespace Validate { … … 27 26 namespace { 28 27 29 struct EnumAndPointerDecayCore final : public WithNoIdSymbolTable, publicast::WithCodeLocation {28 struct EnumAndPointerDecayCore final : public ast::WithCodeLocation { 30 29 ast::EnumDecl const * previsit( ast::EnumDecl const * decl ); 31 30 ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ); … … 40 39 // Set the type of each member of the enumeration to be EnumContant. 41 40 auto mut = ast::mutate( decl ); 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 } 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 ) ); 68 45 } 69 mut->members = buffer;70 46 return mut; 71 47 } -
src/Validate/LinkReferenceToTypes.cpp
r63be3387 rb77f0e1 185 185 decl = mut; 186 186 } 187 // visit the base188 187 } else if ( auto ptr = decl->base.as<ast::PointerType>() ) { 189 188 if ( auto base = ptr->base.as<ast::TypeInstType>() ) { … … 204 203 205 204 // 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" location 216 tm->name, 217 new ast::EnumInstType( decl, ast::CV::Const ), 218 // Construct a new EnumInstType as the type 219 tm->init, 220 tm->storage, 221 tm->linkage, 222 tm->bitfieldWidth, 223 {}, // enum member doesn't have attribute 224 tm->funcSpec 225 ); 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 name 237 // override the imported value 238 } 239 buffer.push_back( *it ); 240 } 241 } 242 mut->members = buffer; 243 decl = mut; 206 244 207 245 ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name ); -
src/Virtual/ExpandCasts.cc
r63be3387 rb77f0e1 295 295 // returns the previous declaration for error messages. 296 296 ast::ObjectDecl const * insert( ast::ObjectDecl const * typeIdDecl ) { 297 std::string mangledName = Mangle::mangleType( typeIdDecl->type ); 297 std::string const & mangledName = 298 Mangle::mangle( typeIdDecl->type, Mangle::typeMode() ); 298 299 ast::ObjectDecl const *& value = instances[ mangledName ]; 299 300 if ( value ) { … … 309 310 310 311 ast::ObjectDecl const * lookup( ast::Type const * typeIdType ) { 311 std::string mangledName = Mangle::mangleType( typeIdType ); 312 std::string const & mangledName = 313 Mangle::mangle( typeIdType, Mangle::typeMode() ); 312 314 auto const it = instances.find( mangledName ); 313 315 return ( instances.end() == it ) ? nullptr : it->second; -
tests/array-container/array-basic.cfa
r63be3387 rb77f0e1 78 78 } 79 79 80 forall( [N], A & | ar(A, float, N) )80 forall( A & | ar(A, float) ) 81 81 float total1d_hi( A & a ) { 82 82 float total = 0.0f; 83 for (i; N)83 for (i; a`len) 84 84 total += a[i]; 85 85 return total; -
tests/collections/atomic_mpsc.cfa
r63be3387 rb77f0e1 1 1 #include <fstream.hfa> 2 #include < containers/lockfree.hfa>2 #include <queueLockFree.hfa> 3 3 #include <thread.hfa> 4 4 -
tests/configs/parsebools.cfa
r63be3387 rb77f0e1 16 16 17 17 #include <fstream.hfa> 18 #include <parseargs.hfa> 18 19 19 20 #include "../meta/fork+exec.hfa" 20 21 // last as a work around to a parse bug22 #include <parseargs.hfa>23 21 24 22 int main(int argc, char * argv[]) { -
tests/configs/parsenums.cfa
r63be3387 rb77f0e1 16 16 17 17 #include <fstream.hfa> 18 #include <parseargs.hfa> 18 19 19 20 #include "../meta/fork+exec.hfa" 20 21 // last as workaround to parser bug22 #include <parseargs.hfa>23 21 24 22 #if __SIZEOF_LONG__ == 4 -
tests/configs/usage.cfa
r63be3387 rb77f0e1 16 16 17 17 #include <fstream.hfa> 18 #include "../meta/fork+exec.hfa"19 18 #include <parseargs.hfa> 20 19 20 #include "../meta/fork+exec.hfa" 21 21 22 22 int main() { -
tests/enum_tests/.expect/enumInlineValue.txt
r63be3387 rb77f0e1 1 1 enumB.A is 5 2 enumB.B is 62 enumB.B is 10 3 3 enumB.D is 11 4 4 enumB.E is 12 -
tests/enum_tests/.expect/qualifiedEnum.cfa
r63be3387 rb77f0e1 1 l : 11 l :0 -
tests/enum_tests/enumInlineValue.cfa
r63be3387 rb77f0e1 6 6 enum enumB { 7 7 inline enumA, 8 E 8 E, B=10 9 9 }; 10 10 -
tests/enum_tests/qualifiedEnum.cfa
r63be3387 rb77f0e1 8 8 9 9 int main() { 10 enum Level l = Level. MEDIUM;10 enum Level l = Level.LOW; 11 11 sout | "l :" | l; 12 12 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.