Changes in / [34c32f0:3e5db5b4]
- Files:
-
- 2 deleted
- 21 edited
-
libcfa/src/concurrency/kernel.cfa (modified) (13 diffs)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (1 diff)
-
src/AST/Stmt.hpp (modified) (12 diffs)
-
src/ControlStruct/ExceptTranslateNew.cpp (modified) (3 diffs)
-
src/ControlStruct/FixLabels.cpp (modified) (8 diffs)
-
src/ControlStruct/FixLabels.hpp (modified) (2 diffs)
-
src/ControlStruct/ForExprMutator.h (modified) (2 diffs)
-
src/ControlStruct/HoistControlDecls.cpp (modified) (2 diffs)
-
src/ControlStruct/HoistControlDecls.hpp (modified) (2 diffs)
-
src/ControlStruct/LabelFixer.cc (modified) (2 diffs)
-
src/ControlStruct/LabelFixer.h (modified) (2 diffs)
-
src/ControlStruct/LabelGenerator.cc (modified) (3 diffs)
-
src/ControlStruct/LabelGenerator.h (modified) (2 diffs)
-
src/ControlStruct/LabelGeneratorNew.cpp (deleted)
-
src/ControlStruct/LabelGeneratorNew.hpp (deleted)
-
src/ControlStruct/MultiLevelExit.cpp (modified) (28 diffs)
-
src/ControlStruct/MultiLevelExit.hpp (modified) (2 diffs)
-
src/ControlStruct/module.mk (modified) (2 diffs)
-
src/Parser/ParseNode.h (modified) (3 diffs)
-
src/Parser/StatementNode.cc (modified) (4 diffs)
-
src/Parser/parser.yy (modified) (5 diffs)
-
tests/concurrent/preempt.cfa (modified) (4 diffs)
-
tools/auto-complete.md (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r34c32f0 r3e5db5b4 42 42 43 43 #if !defined(__CFA_NO_STATISTICS__) 44 #define __STATS _DEF( ...) __VA_ARGS__44 #define __STATS( ...) __VA_ARGS__ 45 45 #else 46 #define __STATS _DEF( ...)46 #define __STATS( ...) 47 47 #endif 48 48 … … 122 122 static thread$ * __next_thread(cluster * this); 123 123 static thread$ * __next_thread_slow(cluster * this); 124 static thread$ * __next_thread_search(cluster * this);125 124 static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1))); 126 125 static void __run_thread(processor * this, thread$ * dst); … … 188 187 MAIN_LOOP: 189 188 for() { 189 #define OLD_MAIN 1 190 #if OLD_MAIN 190 191 // Check if there is pending io 191 192 __maybe_io_drain( this ); … … 195 196 196 197 if( !readyThread ) { 197 __ IO_STATS__(true, io.flush.idle++; )198 __tls_stats()->io.flush.idle++; 198 199 __cfa_io_flush( this, 0 ); 199 200 200 readyThread = __next_thread( this->cltr );201 }202 203 if( !readyThread ) for(5) {204 __IO_STATS__(true, io.flush.idle++; )205 206 201 readyThread = __next_thread_slow( this->cltr ); 207 208 if( readyThread ) break;209 210 __cfa_io_flush( this, 0 );211 202 } 212 203 … … 220 211 221 212 // Confirm the ready-queue is empty 222 readyThread = __next_thread_s earch( this->cltr );213 readyThread = __next_thread_slow( this->cltr ); 223 214 if( readyThread ) { 224 215 // A thread was found, cancel the halt 225 216 mark_awake(this->cltr->procs, * this); 226 217 227 __STATS__(true, ready.sleep.cancels++; ) 218 #if !defined(__CFA_NO_STATISTICS__) 219 __tls_stats()->ready.sleep.cancels++; 220 #endif 228 221 229 222 // continue the mai loop … … 252 245 253 246 if(this->io.pending && !this->io.dirty) { 254 __ IO_STATS__(true, io.flush.dirty++; )247 __tls_stats()->io.flush.dirty++; 255 248 __cfa_io_flush( this, 0 ); 256 249 } 250 251 #else 252 #warning new kernel loop 253 SEARCH: { 254 /* paranoid */ verify( ! __preemption_enabled() ); 255 256 // First, lock the scheduler since we are searching for a thread 257 ready_schedule_lock(); 258 259 // Try to get the next thread 260 readyThread = pop_fast( this->cltr ); 261 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 262 263 // If we can't find a thread, might as well flush any outstanding I/O 264 if(this->io.pending) { __cfa_io_flush( this, 0 ); } 265 266 // Spin a little on I/O, just in case 267 for(5) { 268 __maybe_io_drain( this ); 269 readyThread = pop_fast( this->cltr ); 270 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 271 } 272 273 // no luck, try stealing a few times 274 for(5) { 275 if( __maybe_io_drain( this ) ) { 276 readyThread = pop_fast( this->cltr ); 277 } else { 278 readyThread = pop_slow( this->cltr ); 279 } 280 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 281 } 282 283 // still no luck, search for a thread 284 readyThread = pop_search( this->cltr ); 285 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 286 287 // Don't block if we are done 288 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) { 289 ready_schedule_unlock(); 290 break MAIN_LOOP; 291 } 292 293 __STATS( __tls_stats()->ready.sleep.halts++; ) 294 295 // Push self to idle stack 296 ready_schedule_unlock(); 297 if(!mark_idle(this->cltr->procs, * this)) goto SEARCH; 298 ready_schedule_lock(); 299 300 // Confirm the ready-queue is empty 301 __maybe_io_drain( this ); 302 readyThread = pop_search( this->cltr ); 303 ready_schedule_unlock(); 304 305 if( readyThread ) { 306 // A thread was found, cancel the halt 307 mark_awake(this->cltr->procs, * this); 308 309 __STATS( __tls_stats()->ready.sleep.cancels++; ) 310 311 // continue the main loop 312 break SEARCH; 313 } 314 315 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 316 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 317 318 { 319 eventfd_t val; 320 ssize_t ret = read( this->idle_fd, &val, sizeof(val) ); 321 if(ret < 0) { 322 switch((int)errno) { 323 case EAGAIN: 324 #if EAGAIN != EWOULDBLOCK 325 case EWOULDBLOCK: 326 #endif 327 case EINTR: 328 // No need to do anything special here, just assume it's a legitimate wake-up 329 break; 330 default: 331 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 332 } 333 } 334 } 335 336 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) 337 338 // We were woken up, remove self from idle 339 mark_awake(this->cltr->procs, * this); 340 341 // DON'T just proceed, start looking again 342 continue MAIN_LOOP; 343 } 344 345 RUN_THREAD: 346 /* paranoid */ verify( ! __preemption_enabled() ); 347 /* paranoid */ verify( readyThread ); 348 349 // Reset io dirty bit 350 this->io.dirty = false; 351 352 // We found a thread run it 353 __run_thread(this, readyThread); 354 355 // Are we done? 356 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 357 358 if(this->io.pending && !this->io.dirty) { 359 __cfa_io_flush( this, 0 ); 360 } 361 362 ready_schedule_lock(); 363 __maybe_io_drain( this ); 364 ready_schedule_unlock(); 365 #endif 257 366 } 258 367 … … 365 474 break RUNNING; 366 475 case TICKET_UNBLOCK: 367 __STATS__(true, ready.threads.threads++; ) 476 #if !defined(__CFA_NO_STATISTICS__) 477 __tls_stats()->ready.threads.threads++; 478 #endif 368 479 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 369 480 // In this case, just run it again. … … 380 491 __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst); 381 492 382 __STATS__(true, ready.threads.threads--; ) 493 #if !defined(__CFA_NO_STATISTICS__) 494 __tls_stats()->ready.threads.threads--; 495 #endif 383 496 384 497 /* paranoid */ verify( ! __preemption_enabled() ); … … 391 504 thread$ * thrd_src = kernelTLS().this_thread; 392 505 393 __STATS _DEF( thrd_src->last_proc = kernelTLS().this_processor; )506 __STATS( thrd_src->last_proc = kernelTLS().this_processor; ) 394 507 395 508 // Run the thread on this processor … … 443 556 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 444 557 struct cluster * cl = thrd->curr_cluster; 445 __STATS _DEF(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )558 __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 446 559 447 560 // push the thread to the cluster ready-queue … … 494 607 495 608 ready_schedule_lock(); 496 thread$ * thrd = pop_slow( this ); 497 ready_schedule_unlock(); 498 499 /* paranoid */ verify( ! __preemption_enabled() ); 500 return thrd; 501 } 502 503 // KERNEL ONLY 504 static inline thread$ * __next_thread_search(cluster * this) with( *this ) { 505 /* paranoid */ verify( ! __preemption_enabled() ); 506 507 ready_schedule_lock(); 508 thread$ * thrd = pop_search( this ); 609 thread$ * thrd; 610 for(25) { 611 thrd = pop_slow( this ); 612 if(thrd) goto RET; 613 } 614 thrd = pop_search( this ); 615 616 RET: 509 617 ready_schedule_unlock(); 510 618 … … 748 856 749 857 static bool mark_idle(__cluster_proc_list & this, processor & proc) { 750 __STATS__(true, ready.sleep.halts++; ) 858 #if !defined(__CFA_NO_STATISTICS__) 859 __tls_stats()->ready.sleep.halts++; 860 #endif 751 861 752 862 proc.idle_wctx.fd = 0; … … 841 951 unsigned tail = *ctx->cq.tail; 842 952 if(head == tail) return false; 843 ready_schedule_lock(); 844 ret = __cfa_io_drain( proc ); 845 ready_schedule_unlock(); 953 #if OLD_MAIN 954 ready_schedule_lock(); 955 ret = __cfa_io_drain( proc ); 956 ready_schedule_unlock(); 957 #else 958 ret = __cfa_io_drain( proc ); 959 #endif 846 960 #endif 847 961 return ret; -
libcfa/src/concurrency/kernel/fwd.hfa
r34c32f0 r3e5db5b4 396 396 if( !(in_kernel) ) enable_interrupts(); \ 397 397 } 398 #if defined(CFA_HAVE_LINUX_IO_URING_H)399 #define __IO_STATS__(in_kernel, ...) { \400 if( !(in_kernel) ) disable_interrupts(); \401 with( *__tls_stats() ) { \402 __VA_ARGS__ \403 } \404 if( !(in_kernel) ) enable_interrupts(); \405 }406 #else407 #define __IO_STATS__(in_kernel, ...)408 #endif409 398 #else 410 399 #define __STATS__(in_kernel, ...) 411 #define __IO_STATS__(in_kernel, ...)412 400 #endif 413 401 } -
src/AST/Stmt.hpp
r34c32f0 r3e5db5b4 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed May 8 13:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:38:53 202213 // Update Count : 1211 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri May 17 12:45:00 2019 13 // Update Count : 5 14 14 // 15 15 … … 17 17 18 18 #include <list> 19 #include <utility> // for move19 #include <utility> // for move 20 20 #include <vector> 21 21 22 22 #include "Label.hpp" 23 #include "Node.hpp" // for node, ptr23 #include "Node.hpp" // for node, ptr 24 24 #include "ParseNode.hpp" 25 25 #include "Visitor.hpp" … … 27 27 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 #define MUTATE_FRIEND \29 #define MUTATE_FRIEND \ 30 30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 32 32 33 33 namespace ast { 34 34 35 class Expr; 35 36 36 // Base statement node37 /// Base statement node 37 38 class Stmt : public ParseNode { 38 public:39 public: 39 40 std::vector<Label> labels; 40 41 41 42 Stmt( const CodeLocation & loc, std::vector<Label> && labels = {} ) 42 : ParseNode(loc), labels(std::move(labels)) {}43 : ParseNode(loc), labels(std::move(labels)) {} 43 44 44 45 Stmt(const Stmt& o) : ParseNode(o), labels(o.labels) {} 45 46 46 47 const Stmt * accept( Visitor & v ) const override = 0; 47 private:48 private: 48 49 Stmt * clone() const override = 0; 49 50 MUTATE_FRIEND 50 51 }; 51 52 52 // Compound statement: { ... }53 /// Compound statement `{ ... }` 53 54 class CompoundStmt final : public Stmt { 54 public:55 public: 55 56 std::list<ptr<Stmt>> kids; 56 57 57 58 CompoundStmt(const CodeLocation & loc, std::list<ptr<Stmt>> && ks = {}, 58 std::vector<Label>&& labels = {} )59 : Stmt(loc, std::move(labels)), kids(std::move(ks)) {}59 std::vector<Label>&& labels = {} ) 60 : Stmt(loc, std::move(labels)), kids(std::move(ks)) {} 60 61 61 62 CompoundStmt( const CompoundStmt& o ); … … 66 67 67 68 const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); } 68 private:69 private: 69 70 CompoundStmt * clone() const override { return new CompoundStmt{ *this }; } 70 71 MUTATE_FRIEND 71 72 }; 72 73 73 // Empty statment: ;74 /// Empty statment `;` 74 75 class NullStmt final : public Stmt { 75 public:76 public: 76 77 NullStmt( const CodeLocation & loc, std::vector<Label> && labels = {} ) 77 : Stmt(loc, std::move(labels)) {}78 : Stmt(loc, std::move(labels)) {} 78 79 79 80 const NullStmt * accept( Visitor & v ) const override { return v.visit( this ); } 80 private:81 private: 81 82 NullStmt * clone() const override { return new NullStmt{ *this }; } 82 83 MUTATE_FRIEND 83 84 }; 84 85 85 // Expression wrapped by statement86 /// Expression wrapped by statement 86 87 class ExprStmt final : public Stmt { 87 public:88 public: 88 89 ptr<Expr> expr; 89 90 90 91 ExprStmt( const CodeLocation& loc, const Expr* e, std::vector<Label>&& labels = {} ) 91 : Stmt(loc, std::move(labels)), expr(e) {}92 93 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 94 private:92 : Stmt(loc, std::move(labels)), expr(e) {} 93 94 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 95 private: 95 96 ExprStmt * clone() const override { return new ExprStmt{ *this }; } 96 97 MUTATE_FRIEND 97 98 }; 98 99 99 // Assembly statement: asm ... ( "..." : ... )100 /// Assembly statement `asm ... ( "..." : ... )` 100 101 class AsmStmt final : public Stmt { 101 public:102 public: 102 103 bool isVolatile; 103 104 ptr<Expr> instruction; … … 107 108 108 109 AsmStmt( const CodeLocation & loc, bool isVolatile, const Expr * instruction, 109 std::vector<ptr<Expr>> && output, std::vector<ptr<Expr>> && input,110 std::vector<ptr<ConstantExpr>> && clobber, std::vector<Label> && gotoLabels,111 std::vector<Label> && labels = {})112 : Stmt(loc, std::move(labels)), isVolatile(isVolatile), instruction(instruction),113 output(std::move(output)), input(std::move(input)), clobber(std::move(clobber)),114 gotoLabels(std::move(gotoLabels)) {}115 116 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 117 private:110 std::vector<ptr<Expr>> && output, std::vector<ptr<Expr>> && input, 111 std::vector<ptr<ConstantExpr>> && clobber, std::vector<Label> && gotoLabels, 112 std::vector<Label> && labels = {}) 113 : Stmt(loc, std::move(labels)), isVolatile(isVolatile), instruction(instruction), 114 output(std::move(output)), input(std::move(input)), clobber(std::move(clobber)), 115 gotoLabels(std::move(gotoLabels)) {} 116 117 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 118 private: 118 119 AsmStmt * clone() const override { return new AsmStmt{ *this }; } 119 120 MUTATE_FRIEND 120 121 }; 121 122 122 // C-preprocessor directive: #...123 /// C-preprocessor directive `#...` 123 124 class DirectiveStmt final : public Stmt { 124 public:125 public: 125 126 std::string directive; 126 127 127 128 DirectiveStmt( const CodeLocation & loc, const std::string & directive, 128 std::vector<Label> && labels = {} )129 : Stmt(loc, std::move(labels)), directive(directive) {}130 131 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 132 private:129 std::vector<Label> && labels = {} ) 130 : Stmt(loc, std::move(labels)), directive(directive) {} 131 132 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 133 private: 133 134 DirectiveStmt * clone() const override { return new DirectiveStmt{ *this }; } 134 135 MUTATE_FRIEND 135 136 }; 136 137 137 // If statement: if (...) ... else ...138 /// If conditional statement `if (...) ... else ...` 138 139 class IfStmt final : public Stmt { 139 public:140 public: 140 141 ptr<Expr> cond; 141 142 ptr<Stmt> thenPart; … … 144 145 145 146 IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * thenPart, 146 const Stmt * elsePart = nullptr, std::vector<ptr<Stmt>> && inits = {},147 std::vector<Label> && labels = {} )148 : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart),149 inits(std::move(inits)) {}150 151 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 152 private:147 const Stmt * elsePart = nullptr, std::vector<ptr<Stmt>> && inits = {}, 148 std::vector<Label> && labels = {} ) 149 : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart), 150 inits(std::move(inits)) {} 151 152 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 153 private: 153 154 IfStmt * clone() const override { return new IfStmt{ *this }; } 154 155 MUTATE_FRIEND 155 156 }; 156 157 157 // Switch or choose statement: switch (...) { ... }158 /// Switch or choose conditional statement `switch (...) { ... }` 158 159 class SwitchStmt final : public Stmt { 159 public:160 public: 160 161 ptr<Expr> cond; 161 162 std::vector<ptr<Stmt>> stmts; 162 163 163 164 SwitchStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts, 164 std::vector<Label> && labels = {} )165 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}166 167 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 168 private:165 std::vector<Label> && labels = {} ) 166 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {} 167 168 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 169 private: 169 170 SwitchStmt * clone() const override { return new SwitchStmt{ *this }; } 170 171 MUTATE_FRIEND 171 172 }; 172 173 173 // Case label: case ...: or default:174 /// Case label `case ...:` `default:` 174 175 class CaseStmt final : public Stmt { 175 public:176 // Null for the default label.176 public: 177 /// Null for the default label. 177 178 ptr<Expr> cond; 178 179 std::vector<ptr<Stmt>> stmts; 179 180 180 181 CaseStmt( const CodeLocation & loc, const Expr * cond, std::vector<ptr<Stmt>> && stmts, 181 std::vector<Label> && labels = {} )182 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {}182 std::vector<Label> && labels = {} ) 183 : Stmt(loc, std::move(labels)), cond(cond), stmts(std::move(stmts)) {} 183 184 184 185 bool isDefault() const { return !cond; } 185 186 186 187 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 187 private:188 private: 188 189 CaseStmt * clone() const override { return new CaseStmt{ *this }; } 189 190 MUTATE_FRIEND 190 191 }; 191 192 192 // While loop: while (...) ... else ... or do ... while (...) else ...;193 /// While loop `while (...) ...` `do ... while (...); 193 194 class WhileStmt final : public Stmt { 194 public:195 public: 195 196 ptr<Expr> cond; 196 197 ptr<Stmt> body; 197 ptr<Stmt> elsePart;198 198 std::vector<ptr<Stmt>> inits; 199 199 bool isDoWhile; 200 200 201 201 WhileStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, 202 std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, std::vector<Label> && labels = {} ) 203 : Stmt(loc, std::move(labels)), cond(cond), body(body), inits(std::move(inits)), isDoWhile(isDoWhile) {} 204 205 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 206 private: 202 std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, std::vector<Label> && labels = {} ) 203 : Stmt(loc, std::move(labels)), cond(cond), body(body), inits(std::move(inits)), 204 isDoWhile(isDoWhile) {} 205 206 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 207 private: 207 208 WhileStmt * clone() const override { return new WhileStmt{ *this }; } 208 209 MUTATE_FRIEND 209 210 }; 210 211 211 // For loop: for (... ; ... ; ...) ... else ...212 /// For loop `for (... ; ... ; ...) ...` 212 213 class ForStmt final : public Stmt { 213 public:214 public: 214 215 std::vector<ptr<Stmt>> inits; 215 216 ptr<Expr> cond; 216 217 ptr<Expr> inc; 217 218 ptr<Stmt> body; 218 ptr<Stmt> elsePart;219 219 220 220 ForStmt( const CodeLocation & loc, std::vector<ptr<Stmt>> && inits, const Expr * cond, 221 const Expr * inc, const Stmt * body, std::vector<Label> && labels = {} ) 222 : Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {} 223 224 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 225 private: 221 const Expr * inc, const Stmt * body, std::vector<Label> && labels = {} ) 222 : Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc), 223 body(body) {} 224 225 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 226 private: 226 227 ForStmt * clone() const override { return new ForStmt{ *this }; } 227 228 MUTATE_FRIEND 228 229 }; 229 230 230 // Branch control flow statement: goto ... or break or continue or fallthru231 /// Branch control flow statement `goto ...` `break` `continue` `fallthru` 231 232 class BranchStmt final : public Stmt { 232 public:233 public: 233 234 enum Kind { Goto, Break, Continue, FallThrough, FallThroughDefault }; 234 235 static constexpr size_t kindEnd = 1 + (size_t)FallThroughDefault; … … 240 241 241 242 BranchStmt( const CodeLocation & loc, Kind kind, Label target, 242 std::vector<Label> && labels = {} );243 std::vector<Label> && labels = {} ); 243 244 BranchStmt( const CodeLocation & loc, const Expr * computedTarget, 244 std::vector<Label> && labels = {} )245 : Stmt(loc, std::move(labels)), originalTarget(loc), target(loc),246 computedTarget(computedTarget), kind(Goto) {}245 std::vector<Label> && labels = {} ) 246 : Stmt(loc, std::move(labels)), originalTarget(loc), target(loc), 247 computedTarget(computedTarget), kind(Goto) {} 247 248 248 249 const char * kindName() const { return kindNames[kind]; } 249 250 250 251 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 251 private:252 private: 252 253 BranchStmt * clone() const override { return new BranchStmt{ *this }; } 253 254 MUTATE_FRIEND … … 256 257 }; 257 258 258 // Return statement: return ...259 /// Return statement `return ...` 259 260 class ReturnStmt final : public Stmt { 260 public:261 public: 261 262 ptr<Expr> expr; 262 263 263 264 ReturnStmt( const CodeLocation & loc, const Expr * expr, std::vector<Label> && labels = {} ) 264 : Stmt(loc, std::move(labels)), expr(expr) {}265 266 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 267 private:265 : Stmt(loc, std::move(labels)), expr(expr) {} 266 267 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 268 private: 268 269 ReturnStmt * clone() const override { return new ReturnStmt{ *this }; } 269 270 MUTATE_FRIEND 270 271 }; 271 272 272 // Kind of exception273 /// Kind of exception 273 274 enum ExceptionKind { Terminate, Resume }; 274 275 275 // Throw statement: throw ...276 /// Throw statement `throw ...` 276 277 class ThrowStmt final : public Stmt { 277 public:278 public: 278 279 ptr<Expr> expr; 279 280 ptr<Expr> target; … … 283 284 const CodeLocation & loc, ExceptionKind kind, const Expr * expr, const Expr * target, 284 285 std::vector<Label> && labels = {} ) 285 : Stmt(loc, std::move(labels)), expr(expr), target(target), kind(kind) {}286 287 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 288 private:286 : Stmt(loc, std::move(labels)), expr(expr), target(target), kind(kind) {} 287 288 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 289 private: 289 290 ThrowStmt * clone() const override { return new ThrowStmt{ *this }; } 290 291 MUTATE_FRIEND 291 292 }; 292 293 293 // Try statement: try { ... } ...294 /// Try statement `try { ... } ...` 294 295 class TryStmt final : public Stmt { 295 public:296 public: 296 297 ptr<CompoundStmt> body; 297 298 std::vector<ptr<CatchStmt>> handlers; … … 302 303 std::vector<ptr<CatchStmt>> && handlers, const FinallyStmt * finally, 303 304 std::vector<Label> && labels = {} ) 304 : Stmt(loc, std::move(labels)), body(body), handlers(std::move(handlers)), finally(finally) {}305 306 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 307 private:305 : Stmt(loc, std::move(labels)), body(body), handlers(std::move(handlers)), finally(finally) {} 306 307 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 308 private: 308 309 TryStmt * clone() const override { return new TryStmt{ *this }; } 309 310 MUTATE_FRIEND 310 311 }; 311 312 312 // Catch clause of try statement313 /// Catch clause of try statement 313 314 class CatchStmt final : public Stmt { 314 public:315 public: 315 316 ptr<Decl> decl; 316 317 ptr<Expr> cond; … … 321 322 const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond, 322 323 const Stmt * body, std::vector<Label> && labels = {} ) 323 : Stmt(loc, std::move(labels)), decl(decl), cond(cond), body(body), kind(kind) {}324 325 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 326 private:324 : Stmt(loc, std::move(labels)), decl(decl), cond(cond), body(body), kind(kind) {} 325 326 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 327 private: 327 328 CatchStmt * clone() const override { return new CatchStmt{ *this }; } 328 329 MUTATE_FRIEND 329 330 }; 330 331 331 // Finally clause of try statement332 /// Finally clause of try statement 332 333 class FinallyStmt final : public Stmt { 333 public:334 public: 334 335 ptr<CompoundStmt> body; 335 336 336 337 FinallyStmt( const CodeLocation & loc, const CompoundStmt * body, 337 std::vector<Label> && labels = {} )338 : Stmt(loc, std::move(labels)), body(body) {}339 340 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 341 private:338 std::vector<Label> && labels = {} ) 339 : Stmt(loc, std::move(labels)), body(body) {} 340 341 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 342 private: 342 343 FinallyStmt * clone() const override { return new FinallyStmt{ *this }; } 343 344 MUTATE_FRIEND 344 345 }; 345 346 346 // Suspend statement347 /// Suspend statement 347 348 class SuspendStmt final : public Stmt { 348 public:349 public: 349 350 ptr<CompoundStmt> then; 350 351 enum Type { None, Coroutine, Generator } type = None; 351 352 352 353 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} ) 353 : Stmt(loc, std::move(labels)), then(then), type(type) {}354 355 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 356 private:354 : Stmt(loc, std::move(labels)), then(then), type(type) {} 355 356 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 357 private: 357 358 SuspendStmt * clone() const override { return new SuspendStmt{ *this }; } 358 359 MUTATE_FRIEND 359 360 }; 360 361 361 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...362 /// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...` 362 363 class WaitForStmt final : public Stmt { 363 public:364 public: 364 365 struct Target { 365 366 ptr<Expr> func; … … 389 390 390 391 WaitForStmt( const CodeLocation & loc, std::vector<Label> && labels = {} ) 391 : Stmt(loc, std::move(labels)) {}392 393 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 394 private:392 : Stmt(loc, std::move(labels)) {} 393 394 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 395 private: 395 396 WaitForStmt * clone() const override { return new WaitForStmt{ *this }; } 396 397 MUTATE_FRIEND 397 398 }; 398 399 399 // Any declaration in a (compound) statement.400 /// Any declaration in a (compound) statement. 400 401 class DeclStmt final : public Stmt { 401 public:402 public: 402 403 ptr<Decl> decl; 403 404 404 405 DeclStmt( const CodeLocation & loc, const Decl * decl, std::vector<Label> && labels = {} ) 405 : Stmt(loc, std::move(labels)), decl(decl) {}406 407 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 408 private:406 : Stmt(loc, std::move(labels)), decl(decl) {} 407 408 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 409 private: 409 410 DeclStmt * clone() const override { return new DeclStmt{ *this }; } 410 411 MUTATE_FRIEND 411 412 }; 412 413 413 // Represents an implicit application of a constructor or destructor.414 /// Represents an implicit application of a constructor or destructor. 414 415 class ImplicitCtorDtorStmt final : public Stmt { 415 public:416 public: 416 417 ptr<Stmt> callStmt; 417 418 418 419 ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt, 419 std::vector<Label> && labels = {} )420 : Stmt(loc, std::move(labels)), callStmt(callStmt) {}421 422 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 423 private:420 std::vector<Label> && labels = {} ) 421 : Stmt(loc, std::move(labels)), callStmt(callStmt) {} 422 423 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 424 private: 424 425 ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt{ *this }; } 425 426 MUTATE_FRIEND 426 427 }; 427 428 428 // Mutex Statement429 /// Mutex Statement 429 430 class MutexStmt final : public Stmt { 430 public:431 public: 431 432 ptr<Stmt> stmt; 432 433 std::vector<ptr<Expr>> mutexObjs; 433 434 434 435 MutexStmt( const CodeLocation & loc, const Stmt * stmt, 435 std::vector<ptr<Expr>> && mutexes, std::vector<Label> && labels = {} )436 : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {}437 438 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 439 private:436 std::vector<ptr<Expr>> && mutexes, std::vector<Label> && labels = {} ) 437 : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {} 438 439 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 440 private: 440 441 MutexStmt * clone() const override { return new MutexStmt{ *this }; } 441 442 MUTATE_FRIEND 442 443 }; 443 } // namespace ast 444 445 } 444 446 445 447 #undef MUTATE_FRIEND 446 448 447 449 // Local Variables: // 450 // tab-width: 4 // 448 451 // mode: c++ // 452 // compile-command: "make install" // 449 453 // End: // -
src/ControlStruct/ExceptTranslateNew.cpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 8 11:53:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 18:49:58 202213 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 16:50:00 2021 13 // Update Count : 0 14 14 // 15 15 … … 22 22 23 23 namespace ControlStruct { 24 25 namespace { 24 26 25 27 class TranslateThrowsCore : public ast::WithGuards { … … 126 128 } 127 129 130 } // namespace 131 128 132 void translateThrows( ast::TranslationUnit & transUnit ) { 129 133 ast::Pass<TranslateThrowsCore>::run( transUnit ); -
src/ControlStruct/FixLabels.cpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 1 09:39:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:19:17 202213 // Update Count : 911 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:53:00 2021 13 // Update Count : 3 14 14 // 15 15 … … 20 20 #include "AST/Stmt.hpp" 21 21 #include "ControlStruct/MultiLevelExit.hpp" 22 using namespace ast;23 22 24 23 namespace ControlStruct { 25 class FixLabelsCore final : public WithGuards { 24 25 namespace { 26 27 class FixLabelsCore final : public ast::WithGuards { 26 28 LabelToStmt labelTable; 27 public:29 public: 28 30 FixLabelsCore() : labelTable() {} 29 31 30 void previsit( const FunctionDecl * );31 const FunctionDecl * postvisit( constFunctionDecl * );32 void previsit( const Stmt * );33 void previsit( const BranchStmt * );34 void previsit( const LabelAddressExpr * );32 void previsit( const ast::FunctionDecl * ); 33 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * ); 34 void previsit( const ast::Stmt * ); 35 void previsit( const ast::BranchStmt * ); 36 void previsit( const ast::LabelAddressExpr * ); 35 37 36 void setLabelsDef( const std::vector< Label> &, constStmt * );37 void setLabelsUsage( const Label & );38 void setLabelsDef( const std::vector<ast::Label> &, const ast::Stmt * ); 39 void setLabelsUsage( const ast::Label & ); 38 40 }; 39 41 40 void FixLabelsCore::previsit( const FunctionDecl * ) {42 void FixLabelsCore::previsit( const ast::FunctionDecl * ) { 41 43 GuardValue( labelTable ).clear(); 42 44 } 43 45 44 const FunctionDecl * FixLabelsCore::postvisit(45 constFunctionDecl * decl ) {46 const ast::FunctionDecl * FixLabelsCore::postvisit( 47 const ast::FunctionDecl * decl ) { 46 48 if ( nullptr == decl->stmts ) return decl; 47 49 for ( auto kvp : labelTable ) { 48 50 if ( nullptr == kvp.second ) { 49 51 SemanticError( kvp.first.location, 50 "Use of undefined label: " + kvp.first.name );52 "Use of undefined label: " + kvp.first.name ); 51 53 } 52 54 } 53 return mutate_field( decl, &FunctionDecl::stmts,54 multiLevelExitUpdate( decl->stmts.get(), labelTable ) );55 return ast::mutate_field( decl, &ast::FunctionDecl::stmts, 56 multiLevelExitUpdate( decl->stmts.get(), labelTable ) ); 55 57 } 56 58 57 void FixLabelsCore::previsit( const Stmt * stmt ) {59 void FixLabelsCore::previsit( const ast::Stmt * stmt ) { 58 60 if ( !stmt->labels.empty() ) { 59 61 setLabelsDef( stmt->labels, stmt ); … … 61 63 } 62 64 63 void FixLabelsCore::previsit( const BranchStmt * stmt ) {65 void FixLabelsCore::previsit( const ast::BranchStmt * stmt ) { 64 66 if ( !stmt->labels.empty() ) { 65 67 setLabelsDef( stmt->labels, stmt ); … … 70 72 } 71 73 72 void FixLabelsCore::previsit( const LabelAddressExpr * expr ) {74 void FixLabelsCore::previsit( const ast::LabelAddressExpr * expr ) { 73 75 assert( !expr->arg.empty() ); 74 76 setLabelsUsage( expr->arg ); … … 76 78 77 79 void FixLabelsCore::setLabelsDef( 78 const std::vector<Label> & labels, constStmt * stmt ) {80 const std::vector<ast::Label> & labels, const ast::Stmt * stmt ) { 79 81 assert( !labels.empty() ); 80 82 assert( stmt ); … … 87 89 // Duplicate definition, this is an error. 88 90 SemanticError( label.location, 89 "Duplicate definition of label: " + label.name );91 "Duplicate definition of label: " + label.name ); 90 92 } else { 91 93 // Perviously used, but not defined until now. … … 96 98 97 99 // Label was used, if it is new add it to the table. 98 void FixLabelsCore::setLabelsUsage( const Label & label ) {100 void FixLabelsCore::setLabelsUsage( const ast::Label & label ) { 99 101 if ( labelTable.find( label ) == labelTable.end() ) { 100 102 labelTable[ label ] = nullptr; … … 102 104 } 103 105 104 void fixLabels( TranslationUnit & translationUnit ) { 105 Pass<FixLabelsCore>::run( translationUnit ); 106 } // namespace 107 108 void fixLabels( ast::TranslationUnit & translationUnit ) { 109 ast::Pass<FixLabelsCore>::run( translationUnit ); 106 110 } 111 107 112 } // namespace ControlStruct 108 113 -
src/ControlStruct/FixLabels.hpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 1 09:36:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:18:43 202213 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 1 09:40:00 2021 13 // Update Count : 0 14 14 // 15 15 … … 17 17 18 18 namespace ast { 19 class TranslationUnit;19 class TranslationUnit; 20 20 } 21 21 22 22 namespace ControlStruct { 23 // normalizes label definitions and generates multi-level exit labels 23 24 /// normalizes label definitions and generates multi-level exit labels 24 25 void fixLabels( ast::TranslationUnit & translationUnit ); 26 25 27 } 26 28 -
src/ControlStruct/ForExprMutator.h
r34c32f0 r3e5db5b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 30 09:14:46 202213 // Update Count : 612 // Last Modified On : Thu Aug 17 15:32:48 2017 13 // Update Count : 5 14 14 // 15 15 … … 24 24 class ForExprMutator { 25 25 public: 26 Statement * postmutate( IfStmt * );27 Statement * postmutate( ForStmt * );28 Statement * postmutate( WhileStmt * );26 Statement *postmutate( IfStmt * ); 27 Statement *postmutate( ForStmt * ); 28 Statement *postmutate( WhileStmt * ); 29 29 }; 30 30 } // namespace ControlStruct -
src/ControlStruct/HoistControlDecls.cpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Fri Dec 3 15:34:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 18:52:35 202213 // Update Count : 2311 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Dec 3 15:34:00 2021 13 // Update Count : 0 14 14 // 15 15 … … 19 19 #include "AST/Pass.hpp" 20 20 #include "AST/TranslationUnit.hpp" 21 using namespace ast;22 21 23 22 namespace ControlStruct { 24 23 24 namespace { 25 25 26 template<typename StmtT> 26 const Stmt * hoist( const StmtT * stmt ) {27 const ast::Stmt * hoist( const StmtT * stmt ) { 27 28 // If no hoisting is needed, then make no changes. 29 if ( 0 == stmt->inits.size() ) { 30 return stmt; 31 } 28 32 29 if ( stmt->inits.size() == 0 ) { // no declarations ? 30 // if ( /* no conditional declarations */ ... ) ... 31 return stmt; 32 } // if 33 34 // Put hoist declarations and modified statement in a compound statement. 35 36 CompoundStmt * block = new CompoundStmt( stmt->location ); // create empty compound statement 37 // { 38 // } 39 40 for ( const Stmt * next : stmt->inits ) { // link conditional declarations into compound 33 // Put initializers and the old statement in the compound statement. 34 ast::CompoundStmt * block = new ast::CompoundStmt( stmt->location ); 35 StmtT * mutStmt = ast::mutate( stmt ); 36 for ( const ast::Stmt * next : mutStmt->inits ) { 41 37 block->kids.push_back( next ); 42 38 } 43 // if ( int x = f(), y = g(); ... ) ... 44 // link declarations into compound statement 45 // { 46 // int x = f(); 47 // int y = g(); 48 // } 49 50 StmtT * mutStmt = mutate( stmt ); // create mutate handle to change statement 51 mutStmt->inits.clear(); // remove declarations 52 // if ( ... ) ... 53 54 block->kids.push_back( mutStmt ); // link modified statement into compound 55 // { 56 // int x = f(); 57 // int y = g(); 58 // if ( ... ) ... 59 // } 39 mutStmt->inits.clear(); 40 block->kids.push_back( mutStmt ); 60 41 return block; 61 42 } 62 43 63 struct hoistControlDeclsCore { 64 // Statements with declarations in conditional. 65 const Stmt * postvisit( const IfStmt * stmt ) { 66 return hoist<IfStmt>( stmt ); 44 struct HoistControlCore { 45 const ast::Stmt * postvisit( const ast::IfStmt * stmt ) { 46 return hoist<ast::IfStmt>( stmt ); 67 47 } 68 const Stmt * postvisit( constForStmt * stmt ) {69 return hoist< ForStmt>( stmt );48 const ast::Stmt * postvisit( const ast::ForStmt * stmt ) { 49 return hoist<ast::ForStmt>( stmt ); 70 50 } 71 const Stmt * postvisit( constWhileStmt * stmt ) {72 return hoist< WhileStmt>( stmt );51 const ast::Stmt * postvisit( const ast::WhileStmt * stmt ) { 52 return hoist<ast::WhileStmt>( stmt ); 73 53 } 74 54 }; 75 55 76 // Hoist initialization out of for statements. 77 void hoistControlDecls( TranslationUnit & translationUnit ) { 78 Pass<hoistControlDeclsCore>::run( translationUnit ); 56 } // namespace 57 58 /// Hoist initialization out of for statements. 59 void hoistControlDecls( ast::TranslationUnit & translationUnit ) { 60 ast::Pass<HoistControlCore>::run( translationUnit ); 79 61 } 80 62 -
src/ControlStruct/HoistControlDecls.hpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Fri Dec 3 15:31:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:25:07 202213 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Dec 3 15:31:00 2021 13 // Update Count : 0 14 14 // 15 15 … … 17 17 18 18 namespace ast { 19 class TranslationUnit;19 class TranslationUnit; 20 20 } 21 21 22 22 namespace ControlStruct { 23 // Hoist declarations out of control flow statements into compound statement. 23 24 /// Hoist initialization out of control flow statements. 24 25 void hoistControlDecls( ast::TranslationUnit & translationUnit ); 26 25 27 } // namespace ControlStruct 26 28 -
src/ControlStruct/LabelFixer.cc
r34c32f0 r3e5db5b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:28:31 202213 // Update Count : 16 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Jan 21 10:32:00 2020 13 // Update Count : 160 14 14 // 15 15 … … 27 27 28 28 namespace ControlStruct { 29 bool LabelFixer::Entry::insideLoop() {30 return ( dynamic_cast< ForStmt * > ( definition ) ||31 dynamic_cast< WhileStmt * > ( definition ) );32 }29 bool LabelFixer::Entry::insideLoop() { 30 return ( dynamic_cast< ForStmt * > ( definition ) || 31 dynamic_cast< WhileStmt * > ( definition ) ); 32 } 33 33 34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {35 if ( generator == 0 )36 generator = LabelGenerator::getGenerator();37 }34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) { 35 if ( generator == 0 ) 36 generator = LabelGenerator::getGenerator(); 37 } 38 38 39 void LabelFixer::previsit( FunctionDecl * ) {40 // need to go into a nested function in a fresh state41 GuardValue( labelTable );42 labelTable.clear();43 }39 void LabelFixer::previsit( FunctionDecl * ) { 40 // need to go into a nested function in a fresh state 41 GuardValue( labelTable ); 42 labelTable.clear(); 43 } 44 44 45 void LabelFixer::postvisit( FunctionDecl * functionDecl ) {46 PassVisitor<MultiLevelExitMutator> mlem( resolveJumps(), generator );47 // We start in the body so we can stop when we hit another FunctionDecl.48 maybeMutate( functionDecl->statements, mlem );49 }45 void LabelFixer::postvisit( FunctionDecl * functionDecl ) { 46 PassVisitor<MultiLevelExitMutator> mlem( resolveJumps(), generator ); 47 // We start in the body so we can stop when we hit another FunctionDecl. 48 maybeMutate( functionDecl->statements, mlem ); 49 } 50 50 51 // prune to at most one label definition for each statement52 void LabelFixer::previsit( Statement * stmt ) {53 std::list< Label > &labels = stmt->get_labels();51 // prune to at most one label definition for each statement 52 void LabelFixer::previsit( Statement * stmt ) { 53 std::list< Label > &labels = stmt->get_labels(); 54 54 55 if ( ! labels.empty() ) {56 // only remember one label for each statement57 Label current = setLabelsDef( labels, stmt );58 } // if59 }55 if ( ! labels.empty() ) { 56 // only remember one label for each statement 57 Label current = setLabelsDef( labels, stmt ); 58 } // if 59 } 60 60 61 void LabelFixer::previsit( BranchStmt * branchStmt ) {62 previsit( ( Statement *)branchStmt );61 void LabelFixer::previsit( BranchStmt * branchStmt ) { 62 previsit( ( Statement *)branchStmt ); 63 63 64 // for labeled branches, add an entry to the label table 65 Label target = branchStmt->get_target(); 66 if ( target != "" ) { 67 setLabelsUsg( target, branchStmt ); 64 // for labeled branches, add an entry to the label table 65 Label target = branchStmt->get_target(); 66 if ( target != "" ) { 67 setLabelsUsg( target, branchStmt ); 68 } 68 69 } 69 }70 70 71 void LabelFixer::previsit( LabelAddressExpr * addrExpr ) {72 Label & target = addrExpr->arg;73 assert( target != "" );74 setLabelsUsg( target, addrExpr );75 }71 void LabelFixer::previsit( LabelAddressExpr * addrExpr ) { 72 Label & target = addrExpr->arg; 73 assert( target != "" ); 74 setLabelsUsg( target, addrExpr ); 75 } 76 76 77 77 78 // Sets the definition of the labelTable entry to be the provided statement for every label in79 // the list parameter. Happens for every kind of statement.80 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {81 assert( definition != 0 );82 assert( llabel.size() > 0 );78 // Sets the definition of the labelTable entry to be the provided statement for every label in 79 // the list parameter. Happens for every kind of statement. 80 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) { 81 assert( definition != 0 ); 82 assert( llabel.size() > 0 ); 83 83 84 for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) {85 Label & l = *i;86 l.set_statement( definition ); // attach statement to the label to be used later87 if ( labelTable.find( l ) == labelTable.end() ) {88 // All labels on this statement need to use the same entry,89 // so this should only be created once.90 // undefined and unused until now, add an entry91 labelTable[ l ] = new Entry( definition );92 } else if ( labelTable[ l ]->defined() ) {93 // defined twice, error94 SemanticError( l.get_statement()->location,95 "Duplicate definition of label: " + l.get_name() );96 } else {97 // used previously, but undefined until now -> link with this entry98 // Question: Is changing objects important?99 delete labelTable[ l ];100 labelTable[ l ] = new Entry( definition );101 } // if102 } // for84 for ( std::list< Label >::iterator i = llabel.begin(); i != llabel.end(); i++ ) { 85 Label & l = *i; 86 l.set_statement( definition ); // attach statement to the label to be used later 87 if ( labelTable.find( l ) == labelTable.end() ) { 88 // All labels on this statement need to use the same entry, 89 // so this should only be created once. 90 // undefined and unused until now, add an entry 91 labelTable[ l ] = new Entry( definition ); 92 } else if ( labelTable[ l ]->defined() ) { 93 // defined twice, error 94 SemanticError( l.get_statement()->location, 95 "Duplicate definition of label: " + l.get_name() ); 96 } else { 97 // used previously, but undefined until now -> link with this entry 98 // Question: Is changing objects important? 99 delete labelTable[ l ]; 100 labelTable[ l ] = new Entry( definition ); 101 } // if 102 } // for 103 103 104 // Produce one of the labels attached to this statement to be temporarily used as the 105 // canonical label. 106 return labelTable[ llabel.front() ]->get_label(); 107 } 108 109 // A label was used, add it to the table if it isn't already there 110 template< typename UsageNode > 111 void LabelFixer::setLabelsUsg( Label orgValue, UsageNode *use ) { 112 assert( use != 0 ); 113 114 // add label with an unknown origin 115 if ( labelTable.find( orgValue ) == labelTable.end() ) { 116 labelTable[ orgValue ] = new Entry( 0 ); 117 } 118 } 119 120 // Builds a table that maps a label to its defining statement. 121 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) { 122 std::map< Label, Statement * > *ret = new std::map< Label, Statement * >(); 123 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { 124 if ( ! i->second->defined() ) { 125 SemanticError( i->first.get_statement()->location, "Use of undefined label: " + i->first.get_name() ); 126 } 127 (*ret)[ i->first ] = i->second->get_definition(); 104 // Produce one of the labels attached to this statement to be temporarily used as the 105 // canonical label. 106 return labelTable[ llabel.front() ]->get_label(); 128 107 } 129 108 130 return ret; 131 } 109 // A label was used, add it to the table if it isn't already there 110 template< typename UsageNode > 111 void LabelFixer::setLabelsUsg( Label orgValue, UsageNode *use ) { 112 assert( use != 0 ); 113 114 // add label with an unknown origin 115 if ( labelTable.find( orgValue ) == labelTable.end() ) { 116 labelTable[ orgValue ] = new Entry( 0 ); 117 } 118 } 119 120 // Builds a table that maps a label to its defining statement. 121 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) { 122 std::map< Label, Statement * > *ret = new std::map< Label, Statement * >(); 123 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { 124 if ( ! i->second->defined() ) { 125 SemanticError( i->first.get_statement()->location, "Use of undefined label: " + i->first.get_name() ); 126 } 127 (*ret)[ i->first ] = i->second->get_definition(); 128 } 129 130 return ret; 131 } 132 132 } // namespace ControlStruct 133 133 -
src/ControlStruct/LabelFixer.h
r34c32f0 r3e5db5b4 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 31 22:28:04 202213 // Update Count : 3 512 // Last Modified On : Sat Jul 22 09:17:24 2017 13 // Update Count : 34 14 14 // 15 15 … … 26 26 27 27 namespace ControlStruct { 28 // normalizes label definitions and generates multi-level exit labels29 class LabelGenerator;28 /// normalizes label definitions and generates multi-level exit labels 29 class LabelGenerator; 30 30 31 class LabelFixer final : public WithGuards {32 public:33 LabelFixer( LabelGenerator *gen = 0 );31 class LabelFixer final : public WithGuards { 32 public: 33 LabelFixer( LabelGenerator *gen = 0 ); 34 34 35 std::map < Label, Statement * > *resolveJumps() throw ( SemanticErrorException );35 std::map < Label, Statement * > *resolveJumps() throw ( SemanticErrorException ); 36 36 37 // Declarations38 void previsit( FunctionDecl *functionDecl );39 void postvisit( FunctionDecl *functionDecl );37 // Declarations 38 void previsit( FunctionDecl *functionDecl ); 39 void postvisit( FunctionDecl *functionDecl ); 40 40 41 // Statements42 void previsit( Statement *stmt );43 void previsit( BranchStmt *branchStmt );41 // Statements 42 void previsit( Statement *stmt ); 43 void previsit( BranchStmt *branchStmt ); 44 44 45 // Expressions46 void previsit( LabelAddressExpr *addrExpr );45 // Expressions 46 void previsit( LabelAddressExpr *addrExpr ); 47 47 48 Label setLabelsDef( std::list< Label > &, Statement *definition ); 49 template< typename UsageNode > 50 void setLabelsUsg( Label, UsageNode *usage = 0 ); 51 52 private: 53 class Entry { 54 public: 55 Entry( Statement *to ) : definition( to ) {} 56 bool defined() { return ( definition != 0 ); } 57 bool insideLoop(); 58 59 Label get_label() const { return label; } 60 void set_label( Label lab ) { label = lab; } 61 62 Statement *get_definition() const { return definition; } 63 void set_definition( Statement *def ) { definition = def; } 48 Label setLabelsDef( std::list< Label > &, Statement *definition ); 49 template< typename UsageNode > 50 void setLabelsUsg( Label, UsageNode *usage = 0 ); 64 51 65 52 private: 66 Label label; 67 Statement *definition; 53 class Entry { 54 public: 55 Entry( Statement *to ) : definition( to ) {} 56 bool defined() { return ( definition != 0 ); } 57 bool insideLoop(); 58 59 Label get_label() const { return label; } 60 void set_label( Label lab ) { label = lab; } 61 62 Statement *get_definition() const { return definition; } 63 void set_definition( Statement *def ) { definition = def; } 64 65 private: 66 Label label; 67 Statement *definition; 68 }; 69 70 std::map < Label, Entry *> labelTable; 71 LabelGenerator *generator; 68 72 }; 69 70 std::map < Label, Entry *> labelTable;71 LabelGenerator *generator;72 };73 73 } // namespace ControlStruct 74 74 -
src/ControlStruct/LabelGenerator.cc
r34c32f0 r3e5db5b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:30:26 202213 // Update Count : 2811 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:18:00 2021 13 // Update Count : 17 14 14 // 15 15 … … 17 17 #include <sstream> // for ostringstream 18 18 #include <list> // for list 19 using namespace std;20 19 21 20 #include "LabelGenerator.h" 22 21 22 #include "AST/Attribute.hpp" 23 #include "AST/Label.hpp" 24 #include "AST/Stmt.hpp" 23 25 #include "SynTree/Attribute.h" // for Attribute 24 26 #include "SynTree/Label.h" // for Label, operator<< … … 26 28 27 29 namespace ControlStruct { 30 28 31 int LabelGenerator::current = 0; 29 32 LabelGenerator * LabelGenerator::labelGenerator = nullptr; 30 33 31 LabelGenerator * LabelGenerator::getGenerator() { 32 if ( LabelGenerator::labelGenerator == 0 ) 33 LabelGenerator::labelGenerator = new LabelGenerator(); 34 return labelGenerator; 34 LabelGenerator * LabelGenerator::getGenerator() { 35 if ( LabelGenerator::labelGenerator == 0 ) 36 LabelGenerator::labelGenerator = new LabelGenerator(); 37 return labelGenerator; 38 } 39 40 Label LabelGenerator::newLabel( std::string suffix, Statement * stmt ) { 41 std::ostringstream os; 42 os << "__L" << current++ << "__" << suffix; 43 if ( stmt && ! stmt->get_labels().empty() ) { 44 os << "_" << stmt->get_labels().front() << "__"; 45 } // if 46 std::string ret = os.str(); 47 Label l( ret ); 48 l.get_attributes().push_back( new Attribute("unused") ); 49 return l; 50 } 51 52 ast::Label LabelGenerator::newLabel( 53 const std::string & suffix, const ast::Stmt * stmt ) { 54 assert( stmt ); 55 56 std::ostringstream os; 57 os << "__L" << current++ << "__" << suffix; 58 if ( stmt && !stmt->labels.empty() ) { 59 os << "_" << stmt->labels.front() << "__"; 60 } 61 ast::Label ret_label( stmt->location, os.str() ); 62 ret_label.attributes.push_back( new ast::Attribute( "unused" ) ); 63 return ret_label; 35 64 } 36 65 37 Label LabelGenerator::newLabel( string suffix, Statement * stmt ) {38 ostringstream os;39 os << "__L_OLD" << current++ << "__" << suffix;40 if ( stmt && ! stmt->get_labels().empty() ) {41 os << "_" << stmt->get_labels().front() << "__";42 } // if43 string ret = os.str();44 Label l( ret );45 l.get_attributes().push_back( new Attribute( "unused" ) );46 return l;47 }48 66 } // namespace ControlStruct 49 67 50 68 // Local Variables: // 69 // tab-width: 4 // 51 70 // mode: c++ // 71 // compile-command: "make install" // 52 72 // End: // -
src/ControlStruct/LabelGenerator.h
r34c32f0 r3e5db5b4 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:30:10 202213 // Update Count : 1611 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:16:00 2021 13 // Update Count : 8 14 14 // 15 15 … … 21 21 22 22 class Statement; 23 24 23 namespace ast { 25 class Stmt;26 class Label;24 class Stmt; 25 class Label; 27 26 } 28 27 29 28 namespace ControlStruct { 29 30 30 class LabelGenerator { 31 31 static int current; 32 32 static LabelGenerator *labelGenerator; 33 protected:33 protected: 34 34 LabelGenerator() {} 35 public:35 public: 36 36 static LabelGenerator *getGenerator(); 37 37 static Label newLabel(std::string suffix, Statement * stmt = nullptr); 38 static ast::Label newLabel( const std::string&, const ast::Stmt * ); 39 static void reset() { current = 0; } 40 static void rewind() { current--; } 38 41 }; 42 39 43 } // namespace ControlStruct 40 44 -
src/ControlStruct/MultiLevelExit.cpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 1 13:48:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:35:08 202213 // Update Count : 2 811 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:56:00 2021 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include "AST/Pass.hpp" 19 19 #include "AST/Stmt.hpp" 20 #include " LabelGeneratorNew.hpp"20 #include "ControlStruct/LabelGenerator.h" 21 21 22 22 #include <set> 23 using namespace std;24 using namespace ast;25 23 26 24 namespace ControlStruct { 25 26 namespace { 27 27 28 class Entry { 28 public:29 const Stmt * stmt;30 private:29 public: 30 const ast::Stmt * stmt; 31 private: 31 32 // Organized like a manual ADT. Avoids creating a bunch of dead data. 32 33 struct Target { 33 Label label;34 ast::Label label; 34 35 bool used = false; 35 Target( const Label & label ) : label( label ) {}36 Target( const ast::Label & label ) : label( label ) {} 36 37 Target() : label( CodeLocation() ) {} 37 38 }; … … 40 41 41 42 enum Kind { 42 ForStmt K, WhileStmtK, CompoundStmtK, IfStmtK, CaseStmtK, SwitchStmtK, TryStmtK43 ForStmt, WhileStmt, CompoundStmt, IfStmt, CaseStmt, SwitchStmt, TryStmt 43 44 } kind; 44 45 45 46 bool fallDefaultValid = true; 46 47 47 static Label & useTarget( Target & target ) {48 static ast::Label & useTarget( Target & target ) { 48 49 target.used = true; 49 50 return target.label; 50 51 } 51 52 52 public:53 Entry( const ForStmt * stmt, Label breakExit,Label contExit ) :54 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( ForStmt K) {}55 Entry( const WhileStmt * stmt, Label breakExit,Label contExit ) :56 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( WhileStmt K) {}57 Entry( const CompoundStmt *stmt,Label breakExit ) :58 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( CompoundStmt K) {}59 Entry( const IfStmt *stmt,Label breakExit ) :60 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( IfStmt K) {}61 Entry( const CaseStmt *stmt,Label fallExit ) :62 stmt( stmt ), firstTarget( fallExit ), secondTarget(), kind( CaseStmt K) {}63 Entry( const SwitchStmt *stmt, Label breakExit,Label fallDefaultExit ) :64 stmt( stmt ), firstTarget( breakExit ), secondTarget( fallDefaultExit ), kind( SwitchStmt K) {}65 Entry( const TryStmt *stmt,Label breakExit ) :66 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmt K) {}67 68 bool isContTarget() const { return kind <= WhileStmt K; }69 bool isBreakTarget() const { return kind != CaseStmtK; }70 bool isFallTarget() const { return kind == CaseStmtK; }71 bool isFallDefaultTarget() const { return kind == SwitchStmtK; }53 public: 54 Entry( const ast::ForStmt * stmt, ast::Label breakExit, ast::Label contExit ) : 55 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( ForStmt ) {} 56 Entry( const ast::WhileStmt * stmt, ast::Label breakExit, ast::Label contExit ) : 57 stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( WhileStmt ) {} 58 Entry( const ast::CompoundStmt *stmt, ast::Label breakExit ) : 59 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( CompoundStmt ) {} 60 Entry( const ast::IfStmt *stmt, ast::Label breakExit ) : 61 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( IfStmt ) {} 62 Entry( const ast::CaseStmt *stmt, ast::Label fallExit ) : 63 stmt( stmt ), firstTarget( fallExit ), secondTarget(), kind( CaseStmt ) {} 64 Entry( const ast::SwitchStmt *stmt, ast::Label breakExit, ast::Label fallDefaultExit ) : 65 stmt( stmt ), firstTarget( breakExit ), secondTarget( fallDefaultExit ), kind( SwitchStmt ) {} 66 Entry( const ast::TryStmt *stmt, ast::Label breakExit ) : 67 stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmt ) {} 68 69 bool isContTarget() const { return kind <= WhileStmt; } 70 bool isBreakTarget() const { return CaseStmt != kind; } 71 bool isFallTarget() const { return CaseStmt == kind; } 72 bool isFallDefaultTarget() const { return SwitchStmt == kind; } 72 73 73 74 // These routines set a target as being "used" by a BranchStmt 74 Label useContExit() { assert( kind <= WhileStmtK); return useTarget(secondTarget); }75 Label useBreakExit() { assert( kind != CaseStmtK); return useTarget(firstTarget); }76 Label useFallExit() { assert( kind == CaseStmtK); return useTarget(firstTarget); }77 Label useFallDefaultExit() { assert( kind == SwitchStmtK); return useTarget(secondTarget); }75 ast::Label useContExit() { assert( kind <= WhileStmt ); return useTarget(secondTarget); } 76 ast::Label useBreakExit() { assert( CaseStmt != kind ); return useTarget(firstTarget); } 77 ast::Label useFallExit() { assert( CaseStmt == kind ); return useTarget(firstTarget); } 78 ast::Label useFallDefaultExit() { assert( SwitchStmt == kind ); return useTarget(secondTarget); } 78 79 79 80 // These routines check if a specific label for a statement is used by a BranchStmt 80 bool isContUsed() const { assert( kind <= WhileStmt K); return secondTarget.used; }81 bool isBreakUsed() const { assert( kind != CaseStmtK); return firstTarget.used; }82 bool isFallUsed() const { assert( kind == CaseStmtK); return firstTarget.used; }83 bool isFallDefaultUsed() const { assert( kind == SwitchStmtK); return secondTarget.used; }81 bool isContUsed() const { assert( kind <= WhileStmt ); return secondTarget.used; } 82 bool isBreakUsed() const { assert( CaseStmt != kind ); return firstTarget.used; } 83 bool isFallUsed() const { assert( CaseStmt == kind ); return firstTarget.used; } 84 bool isFallDefaultUsed() const { assert( SwitchStmt == kind ); return secondTarget.used; } 84 85 void seenDefault() { fallDefaultValid = false; } 85 86 bool isFallDefaultValid() const { return fallDefaultValid; } 86 87 }; 87 88 88 // Helper predicates used in find_if calls (it doesn't take methods):89 // Helper predicates used in std::find_if calls (it doesn't take methods): 89 90 bool isBreakTarget( const Entry & entry ) { 90 91 return entry.isBreakTarget(); … … 104 105 105 106 struct MultiLevelExitCore final : 106 publicWithVisitorRef<MultiLevelExitCore>,107 public WithShortCircuiting, publicWithGuards {107 public ast::WithVisitorRef<MultiLevelExitCore>, 108 public ast::WithShortCircuiting, public ast::WithGuards { 108 109 MultiLevelExitCore( const LabelToStmt & lt ); 109 110 110 void previsit( const FunctionDecl * );111 112 const CompoundStmt * previsit( constCompoundStmt * );113 const BranchStmt * postvisit( constBranchStmt * );114 void previsit( const WhileStmt * );115 const WhileStmt * postvisit( constWhileStmt * );116 void previsit( const ForStmt * );117 const ForStmt * postvisit( constForStmt * );118 const CaseStmt * previsit( constCaseStmt * );119 void previsit( const IfStmt * );120 const IfStmt * postvisit( constIfStmt * );121 void previsit( const SwitchStmt * );122 const SwitchStmt * postvisit( constSwitchStmt * );123 void previsit( const ReturnStmt * );124 void previsit( const TryStmt * );125 void postvisit( const TryStmt * );126 void previsit( const FinallyStmt * );127 128 const Stmt * mutateLoop( constStmt * body, Entry& );111 void previsit( const ast::FunctionDecl * ); 112 113 const ast::CompoundStmt * previsit( const ast::CompoundStmt * ); 114 const ast::BranchStmt * postvisit( const ast::BranchStmt * ); 115 void previsit( const ast::WhileStmt * ); 116 const ast::WhileStmt * postvisit( const ast::WhileStmt * ); 117 void previsit( const ast::ForStmt * ); 118 const ast::ForStmt * postvisit( const ast::ForStmt * ); 119 const ast::CaseStmt * previsit( const ast::CaseStmt * ); 120 void previsit( const ast::IfStmt * ); 121 const ast::IfStmt * postvisit( const ast::IfStmt * ); 122 void previsit( const ast::SwitchStmt * ); 123 const ast::SwitchStmt * postvisit( const ast::SwitchStmt * ); 124 void previsit( const ast::ReturnStmt * ); 125 void previsit( const ast::TryStmt * ); 126 void postvisit( const ast::TryStmt * ); 127 void previsit( const ast::FinallyStmt * ); 128 129 const ast::Stmt * mutateLoop( const ast::Stmt * body, Entry& ); 129 130 130 131 const LabelToStmt & target_table; 131 s et<Label> fallthrough_labels;132 vector<Entry> enclosing_control_structures;133 Label break_label;132 std::set<ast::Label> fallthrough_labels; 133 std::vector<Entry> enclosing_control_structures; 134 ast::Label break_label; 134 135 bool inFinally; 135 136 … … 139 140 const LoopNode * posthandleLoopStmt( const LoopNode * loopStmt ); 140 141 141 list<ptr<Stmt>> fixBlock(142 const list<ptr<Stmt>> & kids, bool caseClause );142 std::list<ast::ptr<ast::Stmt>> fixBlock( 143 const std::list<ast::ptr<ast::Stmt>> & kids, bool caseClause ); 143 144 144 145 template<typename UnaryPredicate> 145 146 auto findEnclosingControlStructure( UnaryPredicate pred ) { 146 return find_if( enclosing_control_structures.rbegin(),147 enclosing_control_structures.rend(), pred );147 return std::find_if( enclosing_control_structures.rbegin(), 148 enclosing_control_structures.rend(), pred ); 148 149 } 149 150 }; 150 151 151 NullStmt * labelledNullStmt(152 const CodeLocation & cl, constLabel & label ) {153 return new NullStmt( cl, vector<Label>{ label } );152 ast::NullStmt * labelledNullStmt( 153 const CodeLocation & cl, const ast::Label & label ) { 154 return new ast::NullStmt( cl, std::vector<ast::Label>{ label } ); 154 155 } 155 156 … … 159 160 {} 160 161 161 void MultiLevelExitCore::previsit( const FunctionDecl * ) {162 void MultiLevelExitCore::previsit( const ast::FunctionDecl * ) { 162 163 visit_children = false; 163 164 } 164 165 165 const CompoundStmt * MultiLevelExitCore::previsit(166 constCompoundStmt * stmt ) {166 const ast::CompoundStmt * MultiLevelExitCore::previsit( 167 const ast::CompoundStmt * stmt ) { 167 168 visit_children = false; 168 169 … … 170 171 bool isLabeled = !stmt->labels.empty(); 171 172 if ( isLabeled ) { 172 Label breakLabel =newLabel( "blockBreak", stmt );173 ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt ); 173 174 enclosing_control_structures.emplace_back( stmt, breakLabel ); 174 175 GuardAction( [this]() { enclosing_control_structures.pop_back(); } ); 175 176 } 176 177 177 auto mutStmt = mutate( stmt );178 auto mutStmt = ast::mutate( stmt ); 178 179 // A child statement may set the break label. 179 mutStmt->kids = move( fixBlock( stmt->kids, false ) );180 mutStmt->kids = std::move( fixBlock( stmt->kids, false ) ); 180 181 181 182 if ( isLabeled ) { … … 190 191 191 192 size_t getUnusedIndex( 192 const Stmt * stmt, constLabel & originalTarget ) {193 const ast::Stmt * stmt, const ast::Label & originalTarget ) { 193 194 const size_t size = stmt->labels.size(); 194 195 195 // If the label is empty, do not add unused attribute.196 if ( originalTarget.empty() ) return size;196 // If the label is empty, we can skip adding the unused attribute: 197 if ( originalTarget.empty() ) return size; 197 198 198 199 // Search for a label that matches the originalTarget. 199 200 for ( size_t i = 0 ; i < size ; ++i ) { 200 const Label & label = stmt->labels[i];201 const ast::Label & label = stmt->labels[i]; 201 202 if ( label == originalTarget ) { 202 for ( const Attribute * attr : label.attributes ) {203 for ( const ast::Attribute * attr : label.attributes ) { 203 204 if ( attr->name == "unused" ) return size; 204 205 } … … 207 208 } 208 209 assertf( false, "Could not find label '%s' on statement %s", 209 originalTarget.name.c_str(), toString( stmt ).c_str() );210 } 211 212 const Stmt * addUnused(213 const Stmt * stmt, constLabel & originalTarget ) {210 originalTarget.name.c_str(), toString( stmt ).c_str() ); 211 } 212 213 const ast::Stmt * addUnused( 214 const ast::Stmt * stmt, const ast::Label & originalTarget ) { 214 215 size_t i = getUnusedIndex( stmt, originalTarget ); 215 216 if ( i == stmt->labels.size() ) { 216 217 return stmt; 217 218 } 218 Stmt * mutStmt =mutate( stmt );219 mutStmt->labels[i].attributes.push_back( new Attribute( "unused" ) );219 ast::Stmt * mutStmt = ast::mutate( stmt ); 220 mutStmt->labels[i].attributes.push_back( new ast::Attribute( "unused" ) ); 220 221 return mutStmt; 221 222 } … … 223 224 // This routine updates targets on enclosing control structures to indicate which 224 225 // label is used by the BranchStmt that is passed 225 const BranchStmt * MultiLevelExitCore::postvisit( constBranchStmt * stmt ) {226 vector<Entry>::reverse_iterator targetEntry =226 const ast::BranchStmt * MultiLevelExitCore::postvisit( const ast::BranchStmt * stmt ) { 227 std::vector<Entry>::reverse_iterator targetEntry = 227 228 enclosing_control_structures.rend(); 228 229 229 230 // Labels on different stmts require different approaches to access 230 231 switch ( stmt->kind ) { 231 caseBranchStmt::Goto:232 case ast::BranchStmt::Goto: 232 233 return stmt; 233 case BranchStmt::Continue: 234 case BranchStmt::Break: { 235 bool isContinue = stmt->kind == BranchStmt::Continue; 236 // Handle unlabeled break and continue. 237 if ( stmt->target.empty() ) { 238 if ( isContinue ) { 239 targetEntry = findEnclosingControlStructure( isContinueTarget ); 240 } else { 241 if ( enclosing_control_structures.empty() ) { 242 SemanticError( stmt->location, 243 "'break' outside a loop, 'switch', or labelled block" ); 244 } 245 targetEntry = findEnclosingControlStructure( isBreakTarget ); 246 } 247 // Handle labeled break and continue. 248 } else { 249 // Lookup label in table to find attached control structure. 250 targetEntry = findEnclosingControlStructure( 251 [ targetStmt = target_table.at(stmt->target) ](auto entry){ 252 return entry.stmt == targetStmt; 253 } ); 254 } 255 // Ensure that selected target is valid. 256 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && !isContinueTarget( *targetEntry ) ) ) { 257 SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"), 258 " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "), 259 stmt->originalTarget ) ); 260 } 261 break; 262 } 263 // handle fallthrough in case/switch stmts 264 case BranchStmt::FallThrough: { 265 targetEntry = findEnclosingControlStructure( isFallthroughTarget ); 266 // Check that target is valid. 267 if ( targetEntry == enclosing_control_structures.rend() ) { 268 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 269 } 270 if ( !stmt->target.empty() ) { 271 // Labelled fallthrough: target must be a valid fallthough label. 272 if ( !fallthrough_labels.count( stmt->target ) ) { 273 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ", 274 stmt->originalTarget ) ); 275 } 276 return new BranchStmt( 277 stmt->location, BranchStmt::Goto, stmt->originalTarget ); 278 } 279 break; 280 } 281 case BranchStmt::FallThroughDefault: { 282 targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget ); 283 284 // Check if in switch or choose statement. 285 if ( targetEntry == enclosing_control_structures.rend() ) { 286 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 287 } 288 289 // Check if switch or choose has default clause. 290 auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt ); 291 bool foundDefault = false; 292 for ( auto subStmt : switchStmt->stmts ) { 293 const CaseStmt * caseStmt = subStmt.strict_as<CaseStmt>(); 294 if ( caseStmt->isDefault() ) { 295 foundDefault = true; 296 break; 297 } 298 } 299 if ( ! foundDefault ) { 300 SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'" 301 "control structure with a 'default' clause" ); 302 } 303 break; 304 } 305 default: 234 case ast::BranchStmt::Continue: 235 case ast::BranchStmt::Break: { 236 bool isContinue = stmt->kind == ast::BranchStmt::Continue; 237 // Handle unlabeled break and continue. 238 if ( stmt->target.empty() ) { 239 if ( isContinue ) { 240 targetEntry = findEnclosingControlStructure( isContinueTarget ); 241 } else { 242 if ( enclosing_control_structures.empty() ) { 243 SemanticError( stmt->location, 244 "'break' outside a loop, 'switch', or labelled block" ); 245 } 246 targetEntry = findEnclosingControlStructure( isBreakTarget ); 247 } 248 // Handle labeled break and continue. 249 } else { 250 // Lookup label in table to find attached control structure. 251 targetEntry = findEnclosingControlStructure( 252 [ targetStmt = target_table.at(stmt->target) ](auto entry){ 253 return entry.stmt == targetStmt; 254 } ); 255 } 256 // Ensure that selected target is valid. 257 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && !isContinueTarget( *targetEntry ) ) ) { 258 SemanticError( 259 stmt->location, 260 toString( (isContinue ? "'continue'" : "'break'"), 261 " target must be an enclosing ", 262 (isContinue ? "loop: " : "control structure: "), 263 stmt->originalTarget ) ); 264 } 265 break; 266 } 267 // handle fallthrough in case/switch stmts 268 case ast::BranchStmt::FallThrough: { 269 targetEntry = findEnclosingControlStructure( isFallthroughTarget ); 270 // Check that target is valid. 271 if ( targetEntry == enclosing_control_structures.rend() ) { 272 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 273 } 274 if ( !stmt->target.empty() ) { 275 // Labelled fallthrough: target must be a valid fallthough label. 276 if ( !fallthrough_labels.count( stmt->target ) ) { 277 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ", stmt->originalTarget ) ); 278 } 279 return new ast::BranchStmt( 280 stmt->location, ast::BranchStmt::Goto, stmt->originalTarget ); 281 } 282 break; 283 } 284 case ast::BranchStmt::FallThroughDefault: { 285 targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget ); 286 287 // Check that this is in a switch or choose statement. 288 if ( targetEntry == enclosing_control_structures.rend() ) { 289 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 290 } 291 292 // Check that the switch or choose has a default clause. 293 auto switchStmt = strict_dynamic_cast< const ast::SwitchStmt * >( 294 targetEntry->stmt ); 295 bool foundDefault = false; 296 for ( auto subStmt : switchStmt->stmts ) { 297 const ast::CaseStmt * caseStmt = subStmt.strict_as<ast::CaseStmt>(); 298 if ( caseStmt->isDefault() ) { 299 foundDefault = true; 300 break; 301 } 302 } 303 if ( !foundDefault ) { 304 SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose' control structure with a 'default' clause" ); 305 } 306 break; 307 } 308 default: 306 309 assert( false ); 307 310 } 308 311 309 312 // Branch error checks: get the appropriate label name: 310 // (This label is alwaysreplaced.)311 Label exitLabel( CodeLocation(), "" );313 // (This label will always be replaced.) 314 ast::Label exitLabel( CodeLocation(), "" ); 312 315 switch ( stmt->kind ) { 313 caseBranchStmt::Break:316 case ast::BranchStmt::Break: 314 317 assert( !targetEntry->useBreakExit().empty() ); 315 318 exitLabel = targetEntry->useBreakExit(); 316 319 break; 317 caseBranchStmt::Continue:320 case ast::BranchStmt::Continue: 318 321 assert( !targetEntry->useContExit().empty() ); 319 322 exitLabel = targetEntry->useContExit(); 320 323 break; 321 caseBranchStmt::FallThrough:324 case ast::BranchStmt::FallThrough: 322 325 assert( !targetEntry->useFallExit().empty() ); 323 326 exitLabel = targetEntry->useFallExit(); 324 327 break; 325 caseBranchStmt::FallThroughDefault:328 case ast::BranchStmt::FallThroughDefault: 326 329 assert( !targetEntry->useFallDefaultExit().empty() ); 327 330 exitLabel = targetEntry->useFallDefaultExit(); 328 331 // Check that fallthrough default comes before the default clause. 329 332 if ( !targetEntry->isFallDefaultValid() ) { 330 SemanticError( stmt->location, "'fallthrough default' must precede the 'default' clause" ); 333 SemanticError( stmt->location, 334 "'fallthrough default' must precede the 'default' clause" ); 331 335 } 332 336 break; 333 default:337 default: 334 338 assert(0); 335 339 } … … 338 342 targetEntry->stmt = addUnused( targetEntry->stmt, stmt->originalTarget ); 339 343 340 // Replace withgoto to make later passes more uniform.341 return new BranchStmt( stmt->location,BranchStmt::Goto, exitLabel );342 } 343 344 void MultiLevelExitCore::previsit( const WhileStmt * stmt ) {344 // Replace this with a goto to make later passes more uniform. 345 return new ast::BranchStmt( stmt->location, ast::BranchStmt::Goto, exitLabel ); 346 } 347 348 void MultiLevelExitCore::previsit( const ast::WhileStmt * stmt ) { 345 349 return prehandleLoopStmt( stmt ); 346 350 } 347 351 348 const WhileStmt * MultiLevelExitCore::postvisit( constWhileStmt * stmt ) {352 const ast::WhileStmt * MultiLevelExitCore::postvisit( const ast::WhileStmt * stmt ) { 349 353 return posthandleLoopStmt( stmt ); 350 354 } 351 355 352 void MultiLevelExitCore::previsit( const ForStmt * stmt ) {356 void MultiLevelExitCore::previsit( const ast::ForStmt * stmt ) { 353 357 return prehandleLoopStmt( stmt ); 354 358 } 355 359 356 const ForStmt * MultiLevelExitCore::postvisit( constForStmt * stmt ) {360 const ast::ForStmt * MultiLevelExitCore::postvisit( const ast::ForStmt * stmt ) { 357 361 return posthandleLoopStmt( stmt ); 358 362 } … … 360 364 // Mimic what the built-in push_front would do anyways. It is O(n). 361 365 void push_front( 362 vector<ptr<Stmt>> & vec, constStmt * element ) {366 std::vector<ast::ptr<ast::Stmt>> & vec, const ast::Stmt * element ) { 363 367 vec.emplace_back( nullptr ); 364 368 for ( size_t i = vec.size() - 1 ; 0 < i ; --i ) { 365 vec[ i ] = move( vec[ i - 1 ] );369 vec[ i ] = std::move( vec[ i - 1 ] ); 366 370 } 367 371 vec[ 0 ] = element; 368 372 } 369 373 370 const CaseStmt * MultiLevelExitCore::previsit( constCaseStmt * stmt ) {374 const ast::CaseStmt * MultiLevelExitCore::previsit( const ast::CaseStmt * stmt ) { 371 375 visit_children = false; 372 376 373 // If default, markseen.377 // If it is the default, mark the default as seen. 374 378 if ( stmt->isDefault() ) { 375 379 assert( !enclosing_control_structures.empty() ); … … 378 382 379 383 // The cond may not exist, but if it does update it now. 380 visitor->maybe_accept( stmt, & CaseStmt::cond );384 visitor->maybe_accept( stmt, &ast::CaseStmt::cond ); 381 385 382 386 // Just save the mutated node for simplicity. 383 CaseStmt * mutStmt =mutate( stmt );384 385 Label fallLabel =newLabel( "fallThrough", stmt );386 if ( ! mutStmt->stmts.empty() ) {387 ast::CaseStmt * mutStmt = ast::mutate( stmt ); 388 389 ast::Label fallLabel = LabelGenerator::newLabel( "fallThrough", stmt ); 390 if ( !mutStmt->stmts.empty() ) { 387 391 // Ensure that the stack isn't corrupted by exceptions in fixBlock. 388 392 auto guard = makeFuncGuard( 389 393 [&](){ enclosing_control_structures.emplace_back( mutStmt, fallLabel ); }, 390 394 [this](){ enclosing_control_structures.pop_back(); } 391 );395 ); 392 396 393 397 // These should already be in a block. 394 auto block = mutate( mutStmt->stmts.front().strict_as<CompoundStmt>() );398 auto block = ast::mutate( mutStmt->stmts.front().strict_as<ast::CompoundStmt>() ); 395 399 block->kids = fixBlock( block->kids, true ); 396 400 397 401 // Add fallthrough label if necessary. 398 assert( ! enclosing_control_structures.empty() );402 assert( !enclosing_control_structures.empty() ); 399 403 Entry & entry = enclosing_control_structures.back(); 400 404 if ( entry.isFallUsed() ) { … … 403 407 } 404 408 } 405 assert( ! enclosing_control_structures.empty() );409 assert( !enclosing_control_structures.empty() ); 406 410 Entry & entry = enclosing_control_structures.back(); 407 assertf( dynamic_cast< const SwitchStmt * >( entry.stmt ),408 "Control structure enclosing a case clause must be a switch, but is: %s",409 toString( entry.stmt ).c_str() );411 assertf( dynamic_cast< const ast::SwitchStmt * >( entry.stmt ), 412 "Control structure enclosing a case clause must be a switch, but is: %s", 413 toString( entry.stmt ).c_str() ); 410 414 if ( mutStmt->isDefault() ) { 411 415 if ( entry.isFallDefaultUsed() ) { 412 416 // Add fallthrough default label if necessary. 413 417 push_front( mutStmt->stmts, labelledNullStmt( 414 stmt->location, entry.useFallDefaultExit()415 ) );418 stmt->location, entry.useFallDefaultExit() 419 ) ); 416 420 } 417 421 } … … 419 423 } 420 424 421 void MultiLevelExitCore::previsit( const IfStmt * stmt ) {425 void MultiLevelExitCore::previsit( const ast::IfStmt * stmt ) { 422 426 bool labeledBlock = !stmt->labels.empty(); 423 427 if ( labeledBlock ) { 424 Label breakLabel =newLabel( "blockBreak", stmt );428 ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt ); 425 429 enclosing_control_structures.emplace_back( stmt, breakLabel ); 426 430 GuardAction( [this](){ enclosing_control_structures.pop_back(); } ); … … 428 432 } 429 433 430 const IfStmt * MultiLevelExitCore::postvisit( constIfStmt * stmt ) {434 const ast::IfStmt * MultiLevelExitCore::postvisit( const ast::IfStmt * stmt ) { 431 435 bool labeledBlock = !stmt->labels.empty(); 432 436 if ( labeledBlock ) { … … 439 443 } 440 444 441 bool isDefaultCase( const ptr<Stmt> & stmt ) {442 const CaseStmt * caseStmt = stmt.strict_as<CaseStmt>();445 bool isDefaultCase( const ast::ptr<ast::Stmt> & stmt ) { 446 const ast::CaseStmt * caseStmt = stmt.strict_as<ast::CaseStmt>(); 443 447 return caseStmt->isDefault(); 444 448 } 445 449 446 void MultiLevelExitCore::previsit( const SwitchStmt * stmt ) {447 Label label =newLabel( "switchBreak", stmt );448 auto it = find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase );449 450 const CaseStmt * defaultCase = it != stmt->stmts.rend()451 ? (it)->strict_as< CaseStmt>() : nullptr;452 Label defaultLabel = defaultCase453 ? newLabel( "fallThroughDefault", defaultCase )454 : Label( stmt->location, "" );450 void MultiLevelExitCore::previsit( const ast::SwitchStmt * stmt ) { 451 ast::Label label = LabelGenerator::newLabel( "switchBreak", stmt ); 452 auto it = std::find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase ); 453 454 const ast::CaseStmt * defaultCase = it != stmt->stmts.rend() 455 ? (it)->strict_as<ast::CaseStmt>() : nullptr; 456 ast::Label defaultLabel = defaultCase 457 ? LabelGenerator::newLabel( "fallThroughDefault", defaultCase ) 458 : ast::Label( stmt->location, "" ); 455 459 enclosing_control_structures.emplace_back( stmt, label, defaultLabel ); 456 460 GuardAction( [this]() { enclosing_control_structures.pop_back(); } ); 457 461 458 462 // Collect valid labels for fallthrough. It starts with all labels at 459 // this level, then remove as each is seen duringtraversal.460 for ( const Stmt * stmt : stmt->stmts ) {461 auto * caseStmt = strict_dynamic_cast< const CaseStmt * >( stmt );463 // this level, then removed as we see them in traversal. 464 for ( const ast::Stmt * stmt : stmt->stmts ) { 465 auto * caseStmt = strict_dynamic_cast< const ast::CaseStmt * >( stmt ); 462 466 if ( caseStmt->stmts.empty() ) continue; 463 auto block = caseStmt->stmts.front().strict_as< CompoundStmt>();464 for ( const Stmt * stmt : block->kids ) {465 for ( const Label & l : stmt->labels ) {467 auto block = caseStmt->stmts.front().strict_as<ast::CompoundStmt>(); 468 for ( const ast::Stmt * stmt : block->kids ) { 469 for ( const ast::Label & l : stmt->labels ) { 466 470 fallthrough_labels.insert( l ); 467 471 } … … 470 474 } 471 475 472 const SwitchStmt * MultiLevelExitCore::postvisit( constSwitchStmt * stmt ) {476 const ast::SwitchStmt * MultiLevelExitCore::postvisit( const ast::SwitchStmt * stmt ) { 473 477 assert( !enclosing_control_structures.empty() ); 474 478 Entry & entry = enclosing_control_structures.back(); 475 479 assert( entry.stmt == stmt ); 476 480 477 // Only run to generate the break label.481 // Only run if we need to generate the break label. 478 482 if ( entry.isBreakUsed() ) { 479 483 // To keep the switch statements uniform (all direct children of a 480 484 // SwitchStmt should be CastStmts), append the exit label and break 481 485 // to the last case, create a default case is there are no cases. 482 SwitchStmt * mutStmt =mutate( stmt );486 ast::SwitchStmt * mutStmt = ast::mutate( stmt ); 483 487 if ( mutStmt->stmts.empty() ) { 484 mutStmt->stmts.push_back( new CaseStmt(485 mutStmt->location, nullptr, {} ));486 } 487 488 auto caseStmt = mutStmt->stmts.back().strict_as< CaseStmt>();489 auto mutCase = mutate( caseStmt );488 mutStmt->stmts.push_back( new ast::CaseStmt( 489 mutStmt->location, nullptr, {} )); 490 } 491 492 auto caseStmt = mutStmt->stmts.back().strict_as<ast::CaseStmt>(); 493 auto mutCase = ast::mutate( caseStmt ); 490 494 mutStmt->stmts.back() = mutCase; 491 495 492 Label label( mutCase->location, "breakLabel" );493 auto branch = new BranchStmt( mutCase->location,BranchStmt::Break, label );496 ast::Label label( mutCase->location, "breakLabel" ); 497 auto branch = new ast::BranchStmt( mutCase->location, ast::BranchStmt::Break, label ); 494 498 branch->labels.push_back( entry.useBreakExit() ); 495 499 mutCase->stmts.push_back( branch ); … … 500 504 } 501 505 502 void MultiLevelExitCore::previsit( const ReturnStmt * stmt ) {506 void MultiLevelExitCore::previsit( const ast::ReturnStmt * stmt ) { 503 507 if ( inFinally ) { 504 508 SemanticError( stmt->location, "'return' may not appear in a finally clause" ); … … 506 510 } 507 511 508 void MultiLevelExitCore::previsit( const TryStmt * stmt ) {512 void MultiLevelExitCore::previsit( const ast::TryStmt * stmt ) { 509 513 bool isLabeled = !stmt->labels.empty(); 510 514 if ( isLabeled ) { 511 Label breakLabel =newLabel( "blockBreak", stmt );515 ast::Label breakLabel = LabelGenerator::newLabel( "blockBreak", stmt ); 512 516 enclosing_control_structures.emplace_back( stmt, breakLabel ); 513 517 GuardAction([this](){ enclosing_control_structures.pop_back(); } ); … … 515 519 } 516 520 517 void MultiLevelExitCore::postvisit( const TryStmt * stmt ) {521 void MultiLevelExitCore::postvisit( const ast::TryStmt * stmt ) { 518 522 bool isLabeled = !stmt->labels.empty(); 519 523 if ( isLabeled ) { … … 525 529 } 526 530 527 void MultiLevelExitCore::previsit( const FinallyStmt * ) {528 GuardAction([this, old = move(enclosing_control_structures)](){529 enclosing_control_structures =move(old);530 });531 enclosing_control_structures = vector<Entry>();531 void MultiLevelExitCore::previsit( const ast::FinallyStmt * ) { 532 GuardAction([this, old = std::move(enclosing_control_structures)](){ 533 enclosing_control_structures = std::move(old); 534 }); 535 enclosing_control_structures = std::vector<Entry>(); 532 536 GuardValue( inFinally ) = true; 533 537 } 534 538 535 const Stmt * MultiLevelExitCore::mutateLoop(536 constStmt * body, Entry & entry ) {539 const ast::Stmt * MultiLevelExitCore::mutateLoop( 540 const ast::Stmt * body, Entry & entry ) { 537 541 if ( entry.isBreakUsed() ) { 538 542 break_label = entry.useBreakExit(); … … 541 545 // if continue is used insert a continue label into the back of the body of the loop 542 546 if ( entry.isContUsed() ) { 543 CompoundStmt * new_body = newCompoundStmt( body->location );547 ast::CompoundStmt * new_body = new ast::CompoundStmt( body->location ); 544 548 // {} 545 549 new_body->kids.push_back( body ); … … 563 567 // Remember is loop before going onto mutate the body. 564 568 // The labels will be folded in if they are used. 565 Label breakLabel =newLabel( "loopBreak", loopStmt );566 Label contLabel =newLabel( "loopContinue", loopStmt );569 ast::Label breakLabel = LabelGenerator::newLabel( "loopBreak", loopStmt ); 570 ast::Label contLabel = LabelGenerator::newLabel( "loopContinue", loopStmt ); 567 571 enclosing_control_structures.emplace_back( loopStmt, breakLabel, contLabel ); 568 572 // labels are added temporarily to see if they are used and then added permanently in postvisit if ther are used … … 579 583 assert( entry.stmt == loopStmt ); 580 584 581 // Now check if the labels are used and add them if so.582 return mutate_field(585 // Now we check if the labels are used and add them if so. 586 return ast::mutate_field( 583 587 loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) ); 584 588 // this call to mutate_field compares loopStmt->body and the result of mutateLoop … … 587 591 } 588 592 589 list<ptr<Stmt>> MultiLevelExitCore::fixBlock(590 const list<ptr<Stmt>> & kids, bool is_case_clause ) {591 // Unfortunately cannot use automatic error collection.593 std::list<ast::ptr<ast::Stmt>> MultiLevelExitCore::fixBlock( 594 const std::list<ast::ptr<ast::Stmt>> & kids, bool is_case_clause ) { 595 // Unfortunately we can't use the automatic error collection. 592 596 SemanticErrorException errors; 593 597 594 list<ptr<Stmt>> ret;598 std::list<ast::ptr<ast::Stmt>> ret; 595 599 596 600 // Manually visit each child. 597 for ( const ptr<Stmt> & kid : kids ) {601 for ( const ast::ptr<ast::Stmt> & kid : kids ) { 598 602 if ( is_case_clause ) { 599 603 // Once a label is seen, it's no longer a valid for fallthrough. 600 for ( const Label & l : kid->labels ) {604 for ( const ast::Label & l : kid->labels ) { 601 605 fallthrough_labels.erase( l ); 602 606 } … … 612 616 ret.push_back( 613 617 labelledNullStmt( ret.back()->location, break_label ) ); 614 break_label = Label( CodeLocation(), "" );618 break_label = ast::Label( CodeLocation(), "" ); 615 619 } 616 620 } … … 622 626 } 623 627 624 const CompoundStmt * multiLevelExitUpdate( 625 const CompoundStmt * stmt, 626 const LabelToStmt & labelTable ) { 628 } // namespace 629 630 const ast::CompoundStmt * multiLevelExitUpdate( 631 const ast::CompoundStmt * stmt, 632 const LabelToStmt & labelTable ) { 627 633 // Must start in the body, so FunctionDecls can be a stopping point. 628 Pass<MultiLevelExitCore> visitor( labelTable );629 const CompoundStmt * ret = stmt->accept( visitor );634 ast::Pass<MultiLevelExitCore> visitor( labelTable ); 635 const ast::CompoundStmt * ret = stmt->accept( visitor ); 630 636 return ret; 631 637 } 638 632 639 } // namespace ControlStruct 633 640 -
src/ControlStruct/MultiLevelExit.hpp
r34c32f0 r3e5db5b4 9 9 // Author : Andrew Beach 10 10 // Created On : Mon Nov 1 13:49:00 2021 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Jan 31 22:34:06 202213 // Update Count : 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:53:00 2021 13 // Update Count : 3 14 14 // 15 15 … … 19 19 20 20 namespace ast { 21 class CompoundStmt;22 class Label;23 class Stmt;21 class CompoundStmt; 22 class Label; 23 class Stmt; 24 24 } 25 25 26 26 namespace ControlStruct { 27 27 28 using LabelToStmt = std::map<ast::Label, const ast::Stmt *>; 28 29 29 // Mutate a function body to handle multi-level exits. 30 const ast::CompoundStmt * multiLevelExitUpdate( const ast::CompoundStmt *, const LabelToStmt & ); 30 /// Mutate a function body to handle multi-level exits. 31 const ast::CompoundStmt * multiLevelExitUpdate( 32 const ast::CompoundStmt *, const LabelToStmt & ); 33 31 34 } 32 35 -
src/ControlStruct/module.mk
r34c32f0 r3e5db5b4 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Sat Jan 29 12:04:19 202214 ## Update Count : 712 ## Last Modified By : Henry Xue 13 ## Last Modified On : Tue Jul 20 04:10:50 2021 14 ## Update Count : 5 15 15 ############################################################################### 16 16 … … 28 28 ControlStruct/LabelGenerator.cc \ 29 29 ControlStruct/LabelGenerator.h \ 30 ControlStruct/LabelGeneratorNew.cpp \31 ControlStruct/LabelGeneratorNew.hpp \32 30 ControlStruct/MLEMutator.cc \ 33 31 ControlStruct/MLEMutator.h \ -
src/Parser/ParseNode.h
r34c32f0 r3e5db5b4 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jan 29 09:45:56 202213 // Update Count : 90 112 // Last Modified On : Wed Jul 14 17:28:53 2021 13 // Update Count : 900 14 14 // 15 15 … … 390 390 Statement * build_expr( ExpressionNode * ctl ); 391 391 392 struct CondCtl {393 CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :392 struct IfCtrl { 393 IfCtrl( DeclarationNode * decl, ExpressionNode * condition ) : 394 394 init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {} 395 395 … … 409 409 }; 410 410 411 Expression * build_if_control( CondCtl * ctl, std::list< Statement * > & init );412 Statement * build_if( CondCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt );411 Expression * build_if_control( IfCtrl * ctl, std::list< Statement * > & init ); 412 Statement * build_if( IfCtrl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ); 413 413 Statement * build_switch( bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ); 414 414 Statement * build_case( ExpressionNode * ctl ); 415 415 Statement * build_default(); 416 Statement * build_while( CondCtl * ctl, StatementNode * stmt );416 Statement * build_while( IfCtrl * ctl, StatementNode * stmt ); 417 417 Statement * build_do_while( ExpressionNode * ctl, StatementNode * stmt ); 418 418 Statement * build_for( ForCtrl * forctl, StatementNode * stmt ); -
src/Parser/StatementNode.cc
r34c32f0 r3e5db5b4 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jan 29 09:45:51 202213 // Update Count : 38 412 // Last Modified On : Sat Oct 24 04:20:55 2020 13 // Update Count : 383 14 14 // 15 15 … … 78 78 } // build_expr 79 79 80 Expression * build_if_control( CondCtl * ctl, std::list< Statement * > & init ) {80 Expression * build_if_control( IfCtrl * ctl, std::list< Statement * > & init ) { 81 81 if ( ctl->init != 0 ) { 82 82 buildMoveList( ctl->init, init ); … … 100 100 } // build_if_control 101 101 102 Statement * build_if( CondCtl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ) {102 Statement * build_if( IfCtrl * ctl, StatementNode * then_stmt, StatementNode * else_stmt ) { 103 103 Statement * thenb, * elseb = nullptr; 104 104 std::list< Statement * > branches; … … 145 145 } // build_default 146 146 147 Statement * build_while( CondCtl * ctl, StatementNode * stmt ) {147 Statement * build_while( IfCtrl * ctl, StatementNode * stmt ) { 148 148 std::list< Statement * > branches; 149 149 buildMoveList< Statement, StatementNode >( stmt, branches ); -
src/Parser/parser.yy
r34c32f0 r3e5db5b4 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 30 09:41:13 202213 // Update Count : 516 512 // Last Modified On : Fri Oct 15 09:20:17 2021 13 // Update Count : 5163 14 14 // 15 15 … … 238 238 WaitForStmt * wfs; 239 239 Expression * constant; 240 CondCtl * ifctl;240 IfCtrl * ifctl; 241 241 ForCtrl * fctl; 242 242 enum OperKinds compop; … … 327 327 %type<en> comma_expression comma_expression_opt 328 328 %type<en> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt 329 %type<ifctl> conditional_declaration329 %type<ifctl> if_control_expression 330 330 %type<fctl> for_control_expression for_control_expression_list 331 331 %type<compop> inclexcl … … 1123 1123 1124 1124 if_statement: 1125 IF '(' conditional_declaration ')' statement%prec THEN1125 IF '(' if_control_expression ')' statement %prec THEN 1126 1126 // explicitly deal with the shift/reduce conflict on if/else 1127 1127 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); } 1128 | IF '(' conditional_declaration ')' statement ELSE statement1128 | IF '(' if_control_expression ')' statement ELSE statement 1129 1129 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); } 1130 1130 ; 1131 1131 1132 conditional_declaration:1132 if_control_expression: 1133 1133 comma_expression 1134 { $$ = new CondCtl( nullptr, $1 ); }1134 { $$ = new IfCtrl( nullptr, $1 ); } 1135 1135 | c_declaration // no semi-colon 1136 { $$ = new CondCtl( $1, nullptr ); }1136 { $$ = new IfCtrl( $1, nullptr ); } 1137 1137 | cfa_declaration // no semi-colon 1138 { $$ = new CondCtl( $1, nullptr ); }1138 { $$ = new IfCtrl( $1, nullptr ); } 1139 1139 | declaration comma_expression // semi-colon separated 1140 { $$ = new CondCtl( $1, $2 ); }1140 { $$ = new IfCtrl( $1, $2 ); } 1141 1141 ; 1142 1142 … … 1193 1193 iteration_statement: 1194 1194 WHILE '(' ')' statement // CFA => while ( 1 ) 1195 { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }1196 | WHILE '(' conditional_declaration ')' statement%prec THEN1195 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1196 | WHILE '(' if_control_expression ')' statement %prec THEN 1197 1197 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); } 1198 | WHILE '(' conditional_declaration ')' statement ELSE statement // CFA1198 | WHILE '(' if_control_expression ')' statement ELSE statement // CFA 1199 1199 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1200 1200 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) -
tests/concurrent/preempt.cfa
r34c32f0 r3e5db5b4 1 #include <clock.hfa>2 1 #include <fstream.hfa> 3 2 #include <kernel.hfa> … … 23 22 extern void __cfaabi_check_preemption(); 24 23 25 static struct { 26 volatile int counter; 27 volatile Time prev; 28 Duration durations[6]; 29 } globals; 24 static volatile int counter = 0; 30 25 31 26 thread worker_t { 32 27 int value; 33 unsigned long longspin;28 unsigned spin; 34 29 }; 35 30 … … 40 35 41 36 void main(worker_t & this) { 42 while(TEST( globals.counter < N)) {43 if(this.spin > 50_000_000_000) abort | "Worker" | this.value | "has been spinning too long! (" | this.spin | ")";37 while(TEST(counter < N)) { 38 if(this.spin > 100_000_000) abort | "Worker" | this.value | "has been spinning too long! (" | this.spin | ")"; 44 39 __cfaabi_check_preemption(); 45 if( ( globals.counter % 7) == this.value ) {40 if( (counter % 7) == this.value ) { 46 41 __cfaabi_check_preemption(); 47 #if !defined(TEST_LONG) 48 Time now = timeHiRes(); 49 Duration diff = now - globals.prev; 50 globals.prev = now; 51 #endif 52 int next = __atomic_add_fetch( &globals.counter, 1, __ATOMIC_SEQ_CST ); 42 int next = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST ); 53 43 __cfaabi_check_preemption(); 54 if( (next % 100) == 0 ) { 55 #if !defined(TEST_LONG) 56 unsigned idx = next / 100; 57 if (idx >= 6) abort | "Idx from next is invalid: " | idx | "vs" | next; 58 globals.durations[idx] = diff; 59 if(diff > 12`s) serr | "Duration suspiciously large:" | diff; 60 #endif 61 printf("%d\n", (int)next); 62 63 } 44 if( (next % 100) == 0 ) printf("%d\n", (int)next); 64 45 __cfaabi_check_preemption(); 65 46 this.spin = 0; … … 73 54 int main(int argc, char* argv[]) { 74 55 processor p; 75 globals.counter = 0;76 globals.durations[0] = 0;77 globals.durations[1] = 0;78 globals.durations[2] = 0;79 globals.durations[3] = 0;80 globals.durations[4] = 0;81 globals.durations[5] = 0;82 56 { 83 globals.prev = timeHiRes();84 57 worker_t w0 = 0; 85 58 worker_t w1 = 1; -
tools/auto-complete.md
r34c32f0 r3e5db5b4 32 32 33 33 ### Zsh 34 35 1 - Add the following somewhere:36 #compdef test.py37 38 _test_py() {39 local -a options40 options=$($words[1] --list-comp)41 _alternative "files:filenames:($options)"42 }43 44 _test_py "$@"45 46 2 - Add the path to that file to the "fpath" environment variable.47 48 3 - In ~/.zshrc add49 autoload -U compinit50 compinit51 52 *How it works:* I don't know ;P53 54
Note:
See TracChangeset
for help on using the changeset viewer.