1 /* Jitter: runtime VM-independent header for generated executors. 2 3 Copyright (C) 2016, 2017, 2019, 2020 Luca Saiu 4 Written by Luca Saiu 5 6 This file is part of Jitter. 7 8 Jitter is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 Jitter is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */ 20 21 22 /* This header is used internally by machine-generated executors. It 23 is not for the user to see. 24 25 For example, some functionality defined here may depend on 26 JITTER_VM_PREFIX_LOWER_CASE and JITTER_VM_PREFIX_UPPER_CASE, which are 27 defined by machine-generated code in a .c file, without polluting the user 28 name space. */ 29 30 #ifndef JITTER_EXECUTOR_H_ 31 #define JITTER_EXECUTOR_H_ 32 33 /* Fail if this is not included from generated code. 34 * ************************************************************************** */ 35 36 /* This header relies on internal machinery and defines macros that the user 37 should never see out of VM instruction code; using such macros from some 38 other context, even by mistake, is unsupported and might lead to subtle 39 bugs. */ 40 #ifndef JITTER_THIS_CAN_INCLUDE_JITTER_EXECUTOR_H 41 # error "The header <jitter/jitter-executor.h> must only be included from C" 42 # error "files machine-generated by Jitter, and is not for the user to see." 43 # error "You are probably including the header directly." 44 # error "Don't." 45 #endif // #ifndef JITTER_THIS_CAN_INCLUDE_JITTER_EXECUTOR_H 46 47 48 49 50 /* Include headers. 51 * ************************************************************************** */ 52 53 #include <jitter/jitter.h> 54 #include <jitter/jitter-fast-branch.h> 55 #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) 56 # include <jitter/jitter-sections.h> 57 #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) 58 #if defined (JITTER_ENABLE_ASSEMBLY) 59 # include <jitter/machine/jitter-machine.h> 60 #endif //#if defined (JITTER_ENABLE_ASSEMBLY) 61 62 63 /* Consistency check. 64 * ************************************************************************** */ 65 66 // FIXME: this check is probably wrong. Instead I should make sure that fast 67 // branch-and-links are rewritten into a default version using unconditional 68 // fast branches. 69 70 /* /\* Defining patch-in support without procedures leads to subtle annoying */ 71 /* crashes: in practice it's not possible to check if a fast label argument of */ 72 /* some instruction is used only as a simple branch target, or for */ 73 /* branch-and-link as well; when the fast version of a branching macro is */ 74 /* rewritten into the slow version by the fallback definitions below, the */ 75 /* rewritten definition must work: either both branch and branch-and-link are */ 76 /* supported for fast label, or neither. */ 77 78 /* Notice that it is not necessary to explicitly support every conditional */ 79 /* branch variant: if some conditional is not expliticitly defined it is */ 80 /* rewritten into an ordinary C conditional containing an unconditional fast */ 81 /* branch. Having the unconditional version suffices. *\/ */ 82 /* #if defined(JITTER_DISPATCH_NO_THREADING) \ */ 83 /* && defined(JITTER_MACHINE_SUPPORTS_PATCH_IN) \ */ 84 /* && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE) */ 85 /* # error "you can't define machine-specific procedure support without having patch-ins." */ 86 /* #endif */ 87 88 89 90 91 /* Unique string generation in (GNU) CPP. 92 * ************************************************************************** */ 93 94 /* Expand to a string literal, different at every expansion. This is convenient for 95 inline assembly comments, to prevent GCC from factoring code which is meant 96 to be duplicated -- typically to avoid tail-merging in replicated VM 97 instruction code. 98 Notice that the unique identifier generated in inline asm code by "%=" is not 99 enough to prevent tail-merging: GCC sees two identical string literals containing 100 "%=" as, indeed, equal. 101 This relies on __COUNTER__ , a GNU C preprocessor extension, but the advanced 102 dispatching models requiring this rely on GCC anyway. */ 103 #define JITTER_STRING_LITERAL_UNIQUE \ 104 " [" JITTER_STRINGIFY(__COUNTER__) "] " 105 106 /* Expand to an integer literal, different at any expansion. This has similar 107 applications to JITTER_STRING_LITERAL_UNIQUE , but is meant for C 108 identifiers. Again, this relies on the GNU C preprocessor. */ 109 #define JITTER_INTEGER_LITERAL_UNIQUE \ 110 __COUNTER__ 111 112 113 114 115 /* Architecture-specific initialisation and finalisation. 116 * ************************************************************************** */ 117 118 /* Some ports may add their own custom code to be executed at initialisation and 119 finalisation of the executor. 120 121 This feature is meant for tasks such as reading and then restoring the state 122 of some register not visible from C. Since in such a context it is useful to 123 introduce automatic variables visible from VM instruction bodies these macros 124 have a trailing underscore in their names, and are expanded in a context 125 where it is safe not to protect the definition with a do { ... } while 126 (false) loop. */ 127 128 /* This feature is only meant for minimal-threading and no-threading. Disable 129 any architecture-specific execution begin and end code when using simple 130 dispatches. */ 131 #if (! defined(JITTER_DISPATCH_MINIMAL_THREADING)) \ 132 && (! defined(JITTER_DISPATCH_NO_THREADING)) 133 # undef JITTER_EXECUTION_BEGINNING_ 134 # undef JITTER_EXECUTION_END_ 135 #endif 136 137 /* Define a fallback JITTER_EXECUTION_BEGINNING_ if none is defined. */ 138 #if ! defined (JITTER_EXECUTION_BEGINNING_) 139 # define JITTER_EXECUTION_BEGINNING_ {} 140 #endif // #if ! defined (JITTER_EXECUTION_BEGINNING_) 141 142 /* Define a fallback JITTER_EXECUTION_END_ if none is defined. */ 143 #if ! defined (JITTER_EXECUTION_END_) 144 # define JITTER_EXECUTION_END_ {} 145 #endif // #if ! defined (JITTER_EXECUTION_END_) 146 147 148 149 150 /* Miscellaneous machinery for the executor, possibly to move. 151 * ************************************************************************** */ 152 153 /* Expand to a line-comment prefix for assembly as a string. "\n# " is a sensible 154 default working on most architectures, but this can be overridden in the 155 architecture-specific header 156 machine/ARCHICTECTURE/jitter/machine/jitter-machine.h . 157 Rationale for the newline: on SH, at least with the GNU assembler, comments 158 are introduced by "#" at the beginning of a line or by "!" anywhere else; but 159 "!" is not supported on other architectures. */ 160 #ifndef JITTER_ASM_COMMENT_PREFIX 161 # define JITTER_ASM_COMMENT_PREFIX \ 162 "\n# " 163 #endif // #ifndef JITTER_ASM_COMMENT_PREFIX 164 165 /* Expand to a string literal suitable to be part inline asm, containing a 166 comment-opening text and a terminating "\n\t" sequence. */ 167 #define JITTER_ASM_COMMENT(_jitter_string_literal) \ 168 JITTER_ASM_COMMENT_PREFIX _jitter_string_literal "\n\t" 169 170 /* Expand to a string literal suitable to be part inline asm, containing a 171 comment-opening text, a unique identifier making the generated literal 172 different from all others, and a terminating "\n\t" sequence. */ 173 #define JITTER_ASM_COMMENT_UNIQUE(_jitter_string_literal) \ 174 JITTER_ASM_COMMENT_PREFIX _jitter_string_literal " " \ 175 JITTER_STRING_LITERAL_UNIQUE "\n\t" 176 177 /* Expand to an inline asm C statement containing the given comment, and a 178 terminating "\n\t" sequence. */ 179 #define JITTER_COMMENT_IN_ASM_(_jitter_string_literal) \ 180 asm volatile (JITTER_ASM_COMMENT(_jitter_string_literal)) 181 182 /* Expand to a string literal containing an asm comment, including containing 183 the given text and a unique identifier which will prevent GCC from merging 184 different expansions with the same argument. */ 185 #define JITTER_COMMENT_IN_ASM_UNIQUE_(_jitter_string_literal) \ 186 asm volatile (JITTER_ASM_COMMENT_UNIQUE(_jitter_string_literal)) 187 188 189 190 191 /* Debugging features to be used with disassembly. 192 * ************************************************************************** */ 193 194 // FIXME: I should move this section to a different header. 195 196 /* "Debugging nops" serve to generate nop instructions containing recognizable 197 integer arguments, to be read back by humans disassembling compiled code. 198 If there is no architecture-specific code for generating debugging nops, just 199 generate nothing in their place. */ 200 #ifndef _JITTER_ASM_DEBUGGING_NOP 201 # define _JITTER_ASM_DEBUGGING_NOP(integer_literal_as_string) \ 202 "" 203 #endif // #ifndef _JITTER_ASM_DEBUGGING_NOP 204 205 /* Debugging nops: user macro, generating a readable asm comment followed (where 206 possible) by the nop. 207 The argument must be an integer literal in Gas syntax, with no surrounding 208 quotes. The machine-specific macro will emit the appropriate prefix to 209 interpret the digit sequence as a hexadecimal constant. 210 The expansion of this macro should be used in an *extended* asm statement, 211 since '%' characters appearing, for example, as register prefixes, will 212 appear escaped as "%%". 213 For portability with respect to architectures only supporting small operands, 214 the arguments should be non-negative and representable in 7 bits (Rationale: 215 one way to implement a "nop" is by adding a short immediate to a register, 216 followed by adding it back with the opposite sign; another alternative is 217 xoring and a literal constant into the register itself, twice). */ 218 #define JITTER_ASM_DEBUGGING_NOP(integer_literal) \ 219 JITTER_ASM_COMMENT_UNIQUE ("Debugging nop: " \ 220 JITTER_STRINGIFY (integer_literal)) \ 221 _JITTER_ASM_DEBUGGING_NOP(JITTER_STRINGIFY (integer_literal)) \ 222 "\n\t" 223 224 /* A machine code snipped causing a trap, written in text form in a syntax 225 suitable for extended inline asm. If no machine-specific definition exists, 226 define a stub here. */ 227 #ifndef _JITTER_ASM_CRASH 228 # define _JITTER_ASM_CRASH \ 229 JITTER_ASM_COMMENT_PREFIX "unimplemented for this machine" 230 #endif // #ifndef _JITTER_ASM_DEBUGGING_NOP 231 232 /* Expand to a C statement causing a trap. 233 This is meant to catch bugs, by delimiting code past the end of VM 234 specialized instruction which is not supposed to be replicated. If such 235 code is ever executed it is useful to make the failure well visible. 236 It is important that this does not use __builtin_unreachable . The 237 code this is used in is in fact unreachable, but GCC must not be 238 informed about the fact, as the code serves to keep the register 239 assignment compatible across different program points: the compiler 240 must see some impossible control transfers as possible. */ 241 #define JITTER_CRASH_ \ 242 asm volatile (JITTER_ASM_COMMENT_UNIQUE ("Cause a crash") \ 243 _JITTER_ASM_CRASH "\n\t" \ 244 : /* outputs */) 245 246 247 248 249 /* Macros to let GCC see variables as changed. 250 * ************************************************************************** */ 251 252 // FIXME: use in the definitions below. 253 #define JITTER_MARK_AS_ASM_OUTPUT_(_jitter_constraint, _jitter_lvalue) \ 254 asm (JITTER_ASM_COMMENT_UNIQUE("Pretend to set " \ 255 JITTER_STRINGIFY(_jitter_lvalue) \ 256 " with a " \ 257 _jitter_constraint \ 258 " constraint in " \ 259 "%[the_jitter_lvalue]") \ 260 : [the_jitter_lvalue] _jitter_constraint (_jitter_lvalue)) 261 262 // FIXME: comment 263 #define JITTER_MARK_RVALUE_AS_READ_BY_ASSEMBLY(variable) \ 264 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 265 "Pretend to read the register or memory variable " \ 266 JITTER_STRINGIFY(variable) " in " \ 267 "%[_variable]") \ 268 : \ 269 : [_variable] "X" (variable)) 270 #define JITTER_MARK_LVALUE_AS_DEFINED_BY_ASSEMBLY(variable) \ 271 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 272 "Pretend to write the register or memory variable " \ 273 JITTER_STRINGIFY(variable) " in " \ 274 "%[_variable]") \ 275 : [_variable] "=X" (variable)) 276 #define JITTER_MARK_LVALUE_AS_SET_BY_ASSEMBLY(variable) \ 277 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 278 "Pretend to read and write the register or memory " \ 279 "variable " JITTER_STRINGIFY(variable) " in " \ 280 "%[_variable]") \ 281 : [_variable] "+g" (variable)) 282 283 #define JITTER_MARK_REGISTER_AS_DEFINED_BY_ASSEMBLY(variable) \ 284 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 285 "Pretend to write the register variable " \ 286 JITTER_STRINGIFY(variable) " in " \ 287 "%[register_variable]") \ 288 : [register_variable] "=r" (variable)) 289 #define JITTER_MARK_REGISTER_AS_SET_BY_ASSEMBLY(variable) \ 290 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 291 "Pretend to read and write the register variable " \ 292 JITTER_STRINGIFY(variable) " in " \ 293 "%[register_variable]") \ 294 : [register_variable] "+r" (variable)) 295 296 #define JITTER_MARK_MEMORY_AS_DEFINED_BY_ASSEMBLY(variable) \ 297 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 298 "Pretend to write the memory variable " \ 299 JITTER_STRINGIFY(variable)) \ 300 : "=m" (variable)) 301 #define JITTER_MARK_MEMORY_AS_SET_BY_ASSEMBLY(variable) \ 302 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 303 "Pretend to read and write the memory variable " \ 304 JITTER_STRINGIFY(variable)) \ 305 : "+m" (variable)) 306 #define JITTER_MARK_ARRAY_ELEMENT_AS_SET_BY_ASSEMBLY(variable, offset) \ 307 asm volatile (JITTER_ASM_COMMENT_UNIQUE( \ 308 "Pretend to read and write a memory word from " \ 309 JITTER_STRINGIFY(variable) \ 310 " at offset " JITTER_STRINGIFY(offset)) \ 311 : "+m" (* (jitter_int*) ((char*) (variable) + (offset)))) 312 313 314 315 316 /* Fallback defect descriptors. 317 * ************************************************************************** */ 318 319 /* If defect descriptors are not supported, provide a dummy compatibility macro 320 expanding to an empty string. 321 FIXME: use defect descriptors, when possible, with minimal threading. */ 322 #ifndef JITTER_ASM_DEFECT_DESCRIPTOR 323 # define JITTER_ASM_DEFECT_DESCRIPTOR "" 324 #endif // #ifndef JITTER_ASM_DEFECT_DESCRIPTOR 325 326 327 328 /* Macros to let GCC see jumps to indeterminate locations. 329 * ************************************************************************** */ 330 331 // FIXME: comment. 332 #define JITTER_IP_INPUT_CONSTRAINT "r" 333 334 // FIXME: comment. 335 // FIXME: remove. Fake-jumping to an arbitrary label different from 336 // jitter_dispatch_label doesn't work well with defect descriptors. 337 #define JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(_jitter_label) \ 338 asm goto (JITTER_ASM_COMMENT_UNIQUE("Pretend to possibly jump to " \ 339 JITTER_STRINGIFY(_jitter_label) \ 340 " at %l[" \ 341 JITTER_STRINGIFY(_jitter_label) \ 342 "] based on " \ 343 " jitter_ip" \ 344 " at %[the_jitter_ip]") \ 345 : /* outputs */ \ 346 : [the_jitter_ip] JITTER_IP_INPUT_CONSTRAINT (jitter_ip) \ 347 /* inputs */ \ 348 : /* clobbers */ \ 349 : /* jump destinations */ _jitter_label) 350 351 #define JITTER_PRETEND_TO_UPDATE_IP_ \ 352 JITTER_MARK_AS_ASM_OUTPUT_("+" JITTER_IP_INPUT_CONSTRAINT, \ 353 jitter_ip) 354 355 #define JITTER_PRETEND_TO_JUMP_TO_(_jitter_label) \ 356 JITTER_PRETEND_TO_POSSIBLY_JUMP_TO_(_jitter_label); \ 357 __builtin_unreachable () 358 359 /* Expand to zero assembly instructions, but with inline asm constraints 360 affecting GCC's program representation as if the generated code could either 361 jump to the content of jitter_anywhere_variable or fall thru. 362 363 Rationale: see the comment about JITTER_PRETEND_TO_JUMP_ANYWHERE below. */ 364 #define JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE() \ 365 do \ 366 { \ 367 asm goto (JITTER_ASM_DEFECT_DESCRIPTOR \ 368 JITTER_ASM_COMMENT_UNIQUE( \ 369 "# Pretending to possibly jump to " \ 370 "%l[jitter_dispatch_label] thru %[_jitter_ip]") \ 371 : \ 372 : [_jitter_ip] JITTER_IP_INPUT_CONSTRAINT (jitter_ip) \ 373 : \ 374 : jitter_dispatch_label); \ 375 } \ 376 while (false) 377 378 /* Expand to zero assembly instructions, but with inline asm constraints and 379 intrinsics affecting GCC's program representation as if the generated code 380 unconditionally jumped to the content of jitter_anywhere_variable . 381 382 Rationale: this code is actually unreachable, but for this program point I 383 want GCC to use a register assignment which is coherent with the beginning of 384 any other VM instruction, which may actually follow this point during 385 replicated code execution. I would like to simply insert a "goto 386 jump_anywhere;" here, but GCC might move the jump before the instruction end 387 label [FIXME: can it really happen? I'm pretty sure I saw that more than 388 once, but I should ask some GCC expert for confirmation], which must not 389 happen. So, in order to generate something GCC optimizations can't meddle 390 with, I will insert a pretend-jump in inline assembly, with the constraint 391 that the control may only flow to the jump_anywhere label; from there control 392 could actually jump to any label in this function. This way I ensure 393 compatibility among VM instructions without generating too much junk code, if 394 any. The input operand is required to be in memory and *not* in a register, 395 so that GCC doesn't waste a register on this useless thing. */ 396 #define JITTER_PRETEND_TO_JUMP_ANYWHERE \ 397 do \ 398 { \ 399 JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE(); \ 400 __builtin_unreachable (); \ 401 } \ 402 while (false) 403 404 405 406 407 /* Macros expanding to per-instruction labels and variable names. 408 * ************************************************************************** */ 409 410 /* Expand to the label at the beginning of the user code for the specialized 411 instruction with the given name, in case of relocatable instructions; 412 otherwise expand to the label at the beginning of the relocatable stub 413 for non-relocatable instructions. */ 414 #define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(name) \ 415 JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _beginning_label) 416 417 /* Expand to the label at the end of the user code for the specialized 418 instruction with the given name. */ 419 #define JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(name) \ 420 JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _end_label) 421 422 /* Expand to the label at the beginning of the user code for the specialized 423 instruction with the given name, in case of non-relocatable instructions. */ 424 #define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(name) \ 425 JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _non_relocatable_code_label) 426 427 /* Expand to the name of the variable defined as 428 JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(name) . The 429 variable is always stack-allocated and can be safely read from relocated 430 code. */ 431 #define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(name) \ 432 JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _non_relocatable_code_variable) 433 434 435 436 437 /* User macros to access VM state data structures. 438 * ************************************************************************** */ 439 440 /* Expand to the current VM state runtime, as a struct. */ 441 #define JITTER_STATE_RUNTIME \ 442 jitter_state_runtime 443 444 /* The macro JITTER_STATE_BACKING expands to the current VM state backing, as a 445 struct. It is defined in machine-generated code. */ 446 447 /* Expand to an l-value referrign the named field in the current VM state 448 runtime. */ 449 #define JITTER_STATE_RUNTIME_FIELD(field_name) \ 450 (JITTER_STATE_RUNTIME.field_name) 451 452 /* Expand to an l-value referrign the named field in the current VM state 453 backing. */ 454 #define JITTER_STATE_BACKING_FIELD(field_name) \ 455 (JITTER_STATE_BACKING.field_name) 456 457 458 459 460 /* Nullary macros expanding to per-instruction labels and variable names. 461 * ************************************************************************** */ 462 463 /* These rely on JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME , whose definitions 464 is machine-generated to be visible from user instruction code. Using these 465 zero-argument macros is more convenient. 466 467 CPP expansion semantics allows these macros to be used even in the expansion 468 of other macros. */ 469 470 /* Expand to the specialized instruction begin label for the current instruction. */ 471 #define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL \ 472 JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF( \ 473 JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME) 474 475 /* Expand to the stringification of 476 JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL . */ 477 #define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_AS_STRING \ 478 JITTER_STRINGIFY(JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL) 479 480 /* Expand to the specialized instruction end label for the current instruction. */ 481 #define JITTER_SPECIALIZED_INSTRUCTION_END_LABEL \ 482 JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF( \ 483 JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME) 484 485 /* Expand to the label at the beginning of the user code for the current 486 instruction, in case of non-relocatable instructions; expand to some 487 probably unbound identifier otherwise. */ 488 #define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL \ 489 JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF( \ 490 JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME) 491 492 /* Expand to the name of the variable defined as 493 JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL . The variable is 494 always stack-allocated and can be safely read from relocated code. Expand to 495 some probably unbound identifier for relocatable instructions. */ 496 #define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE \ 497 JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF( \ 498 JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME) 499 500 501 502 503 /* VM routine termination. 504 * ************************************************************************** */ 505 506 /* Exit the executor function and return to C. */ 507 #ifdef JITTER_REPLICATE 508 /* With replication enabled it's important to avoid tail-merging, which is why 509 this is a wrapped computed goto rather than a simple goto... */ 510 # define JITTER_EXIT() \ 511 do \ 512 { \ 513 JITTER_COMPUTED_GOTO (jitter_saved_exit_non_replicated_code_pointer); \ 514 } \ 515 while (false) 516 #else 517 /* ...But in the case of switch dispatching computed gotos may not be usable 518 at all, and with direct-threading there is no correctness problem. */ 519 # define JITTER_EXIT() \ 520 do \ 521 { \ 522 goto jitter_exit_vm_label; \ 523 } \ 524 while (false) 525 #endif // #ifdef JITTER_REPLICATE 526 527 528 529 530 /* VM instruction prolog and epilog. 531 * ************************************************************************** */ 532 533 /* VM instruction prolog. */ 534 #if defined(JITTER_DISPATCH_SWITCH) 535 /* VM instruction prolog: switch dispatching. */ 536 # define JITTER_INSTRUCTION_PROLOG_(name, mangled_name, residual_arity) \ 537 case JITTER_CONCATENATE_THREE(JITTER_VM_PREFIX_LOWER_CASE, \ 538 _specialized_instruction_opcode_, \ 539 mangled_name): 540 #else 541 /* VM instruction prolog: every non-switch dispatches. */ 542 # define JITTER_INSTRUCTION_PROLOG_(name, mangled_name, hotness_attribute) \ 543 { \ 544 JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(mangled_name): \ 545 __attribute__ ((hotness_attribute)); \ 546 /*JITTER_COMMENT_IN_ASM_UNIQUE_("here comes " JITTER_STRINGIFY (name));*/ 547 #endif // defined(JITTER_DISPATCH_SWITCH) 548 549 /* How many words are used to encode the current specialized instruction, given 550 its residual arity. According to the dispatching model there may be a word 551 for the opcode or the thread, or not. 552 This relies on JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY being defined, 553 which is the case when this macro is used as intended, from specialized 554 instruction code within the executor. */ 555 #if defined(JITTER_DISPATCH_SWITCH) \ 556 || defined(JITTER_DISPATCH_DIRECT_THREADING) 557 # define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO \ 558 (1 + JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY) 559 #elif defined(JITTER_DISPATCH_MINIMAL_THREADING) 560 # define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO \ 561 JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY 562 #elif defined(JITTER_DISPATCH_NO_THREADING) 563 # define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO \ 564 JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY 565 #else 566 # error "unknown dispatching model" 567 #endif 568 569 /* Modify the instruction pointer, if any, to skip the appropriate number of 570 residuals for the current instruction plus the opcode or thread, if any. 571 This relies on JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY being defined, 572 which is the case when this macro is used as intended, from specialized 573 instruction code within the executor. 574 FIXME: shall I use the do..while (false) trick here? This macro is expanded 575 a lot of times, and never from user code. */ 576 // FIXME: add a _ suffix to the name. 577 // FIXME: do not define for no-threading. 578 #if defined(JITTER_DISPATCH_SWITCH) \ 579 || defined(JITTER_DISPATCH_DIRECT_THREADING) 580 # define JITTER_SKIP_RESIDUALS_ \ 581 JITTER_SET_IP(jitter_ip + JITTER_SPECIALIZED_INSTRUCTION_WORD_NO); 582 #elif defined(JITTER_DISPATCH_MINIMAL_THREADING) 583 # define JITTER_SKIP_RESIDUALS_ \ 584 JITTER_SET_IP(jitter_ip + JITTER_SPECIALIZED_INSTRUCTION_WORD_NO); 585 #elif defined(JITTER_DISPATCH_NO_THREADING) 586 # define JITTER_SKIP_RESIDUALS_ \ 587 /* do nothing. */ 588 #else 589 # error "unknown dispatching model" 590 #endif // #if defined([dispatching model]... 591 592 /* A VM instruction epilog. */ 593 #if defined(JITTER_DISPATCH_SWITCH) 594 # define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity) \ 595 JITTER_SKIP_RESIDUALS_; \ 596 JITTER_BRANCH_TO_IP(); 597 #elif defined(JITTER_DISPATCH_DIRECT_THREADING) 598 # define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity) \ 599 JITTER_SKIP_RESIDUALS_; \ 600 JITTER_BRANCH_TO_IP(); \ 601 } \ 602 JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name): \ 603 __builtin_unreachable (); 604 #elif defined(JITTER_DISPATCH_MINIMAL_THREADING) || defined(JITTER_DISPATCH_NO_THREADING) 605 # define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity) \ 606 JITTER_SKIP_RESIDUALS_; \ 607 } \ 608 /*JITTER_PRETEND_TO_UPDATE_IP_; */ \ 609 /*JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE();*/ \ 610 /*asm goto ("\n\taddiu $0, $0, 2\n\n" : : "r" (jitter_ip) : : JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name)); */\ 611 /* JITTER_PRETEND_TO_UPDATE_IP_;*/ \ 612 /*asm volatile ("\n\taddiu $0, $0, 4\n\t" JITTER_ASM_COMMENT_UNIQUE("foo1"):);*/ \ 613 /*JITTER_PRETEND_TO_UPDATE_IP_;*/ \ 614 JITTER_PRETEND_TO_UPDATE_IP_;\ 615 /* Mark the end of the specialized instruction with a label. */ \ 616 JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name): \ 617 if (jitter_ip != NULL) goto * jitter_ip; \ 618 /*JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE();*/ \ 619 /*__builtin_unreachable ();*/ \ 620 /*JITTER_PRETEND_TO_UPDATE_IP_;*/ \ 621 /*asm volatile ("\n\taddiu $0, $0, 5\n\t" JITTER_ASM_COMMENT_UNIQUE("foo2"));*/ \ 622 /* What follows is unreachable, but serves to prevent GCC from \ 623 reordering code across labels. The final indirect branch, \ 624 which of course would not branch anywhere correct if it were \ 625 actually executed, serves to force the compiler to keep the \ 626 register assignment compatible between this program point, \ 627 at the end of VM instructions, with the register assignment \ 628 at the beginning of every VM instruction, or even at their end. \ 629 From GCC's point of view, this goto * statement may reach any \ 630 label in the function whose address I have taken. */ \ 631 JITTER_CRASH_; \ 632 JITTER_PRETEND_TO_UPDATE_IP_; \ 633 goto * jitter_ip; 634 #else 635 # error "unknown dispatching model" 636 #endif // #if defined(JITTER_DISPATCH_SWITCH) 637 638 639 640 641 /* VM branching utility. 642 * ************************************************************************** */ 643 644 // FIXME: shall I move this page and everything below to some other header? 645 646 /* After a VM branch-and-link operation is performed the rest of the specialized 647 instruction code is unreachable; in other words the return program point is 648 the beginning of the VM instruction following the calling VM instruction, and 649 not the machine instruction following the *machine* calling instruction. 650 This restriction is artificial on machines where VM calls are implemented by 651 native branch-and-link or call instructions, but is needed for compatibility 652 with simpler dispatching models where the intuitive semantics is not 653 implementable. 654 It's important that GCC does not assume that the code past the 655 branch-and-link is *automatically* unreachable, as would be the case if we 656 simply used __builtin_unreachable. 657 This is needed, for example, in the case of a branch-and-link at the end of 658 the first branch of a two-way conditional within a VM specialized instruction. 659 Without this jump the control after returning would fall back into the second 660 branch, which would be incorrect. 661 The solution is this macro: instead of marking the code as unreachable let's 662 simply jump to the end of the specialized instruction after the call. In the 663 common case where there is no code to skip over GCC will optimize the jump 664 away. 665 This macro relies on JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME having the 666 correct definition at the time of the macro call, which is true if the macro 667 is used as intended within user code for VM instructions. */ 668 #define JITTER_JUMP_TO_SPECIALIZED_INSTRUCTION_END \ 669 do \ 670 { \ 671 goto JITTER_SPECIALIZED_INSTRUCTION_END_LABEL; \ 672 } \ 673 while (false) 674 675 676 677 678 /* Avoiding GCC tail-merging optimizations with replicated code. 679 * ************************************************************************** */ 680 681 /* The problem is performing the equivalent of goto * while avoiding 682 tail-merging, which would be disastrous in replicated code when the shared 683 jumping instruction happened to be out of the current VM instruction 684 block. */ 685 686 /* Define a trivial wrapper around GNU C's computed goto. This will be used for 687 direct threading, where tail-merging is not a problem. */ 688 #define JITTER_COMPUTED_GOTO_TRIVIAL(target) \ 689 do \ 690 { \ 691 goto * (target); \ 692 } \ 693 while (false) 694 695 /* Perform the equivalent of a goto * in assembly, using unique inline asm code, 696 different from any other. This is useful to avoid tail-merging, which would 697 be disastrous in replicated code when the shared jumping instruction happened 698 to be out of the current VM instruction block. 699 700 The gotolabel declared in the inline asm statement is the "jump anywhere" 701 label, actually unreachable at run time, but branching to an undetermined 702 label; this is enough for GCC to assume the following to be any VM 703 instruction. 704 The actual jump target, which is always the beginning of the VM instruction, 705 is given as the first inline asm input. The second input, not really used in 706 practice but needed to satisfy GCC, is again the "jump anywhere" label as an 707 expression -- without it, I've seen GCC 8 snapshots ICE at the following 708 __builtin_unreachable () with "error: flow control insn inside a basic 709 block". Omitting __builtin_unreachable () is a no-no, as it enormously 710 simplifies the control-flow graph, and provides more opportunities for 711 optimization. 712 713 This relies, of course, on the architecture-specific assembly syntax for 714 jumping thru a register or memory, along with the appropriate input operand 715 constaraint, to be defined in jitter-machine.h . 716 717 JITTER_ASM_COMPUTED_GOTO_TEMPLATE holds the asm template as a string literal, 718 using an input argument named _jitter_the_target . 719 JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT is the input constraint for the 720 target expression as a string literal, typically "r" but occasionally "rm" 721 on CISC architectrues. */ 722 #if (! defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE)) \ 723 || (! defined(JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT)) 724 /* Fail if only one of the two architecture-specific macros for computed 725 gotos in assembly is defined. That should never happen. */ 726 # if defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE) \ 727 || defined(JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT) 728 # error "only one of JITTER_ASM_COMPUTED_GOTO_TEMPLATE" 729 # error "and JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT is defined" 730 # endif 731 #else 732 /* A few architectures (notably PowerPC) may also need clobbers to jump via 733 register, but that is optional. If no clobbers were defined, define them 734 as empty. */ 735 # if ! defined(JITTER_ASM_COMPUTED_GOTO_CLOBBERS) 736 # define JITTER_ASM_COMPUTED_GOTO_CLOBBERS /* nothing */ 737 # endif // ! defined(JITTER_ASM_COMPUTED_GOTO_CLOBBERS) 738 /* If we arrived here we have all the information to define 739 JITTER_COMPUTED_GOTO_IN_ASM . */ 740 # define JITTER_COMPUTED_GOTO_IN_ASM(target) \ 741 do \ 742 { \ 743 const void *_jitter_the_target = (const void*) (target); \ 744 asm goto (JITTER_ASM_DEFECT_DESCRIPTOR \ 745 JITTER_ASM_COMMENT_UNIQUE("goto* in assembly to " \ 746 JITTER_STRINGIFY(target) " " \ 747 "at %[_jitter_the_target], " \ 748 "not actually going to " \ 749 "jitter_dispatch_label at " \ 750 "%l[jitter_dispatch_label]") \ 751 JITTER_ASM_COMPUTED_GOTO_TEMPLATE \ 752 : /* outputs */ \ 753 : [_jitter_the_target] \ 754 JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT \ 755 (_jitter_the_target) \ 756 /* inputs */ \ 757 : JITTER_ASM_COMPUTED_GOTO_CLOBBERS /* clobbers */ \ 758 : jitter_dispatch_label /* gotolabels */); \ 759 /* This is an unconditional branch: the following statement in the \ 760 same block is unreachable. */ \ 761 __builtin_unreachable(); \ 762 } \ 763 while (false) 764 #endif // #if (! defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE)) || (! defined ... 765 766 /* Define JITTER_COMPUTED_GOTO using one of the macros above. */ 767 #ifdef JITTER_REPLICATE 768 /* Replication is enabled: use the assembly version of goto * , or the trivial 769 version if there is no assembly version available. */ 770 # ifdef JITTER_COMPUTED_GOTO_IN_ASM 771 # define JITTER_COMPUTED_GOTO(target) \ 772 JITTER_COMPUTED_GOTO_IN_ASM(target) 773 # else 774 # define JITTER_COMPUTED_GOTO(target) \ 775 JITTER_COMPUTED_GOTO_TRIVIAL(target) 776 # endif // ifdef JITTER_COMPUTED_GOTO_IN_ASM 777 #else /* replication is disabled */ 778 /* Replication is disabled: we don't need the hacks above, so in this case we 779 can always use the fallback definition, using a native GCC computed goto; 780 this might be more efficient with conditionals. */ 781 # define JITTER_COMPUTED_GOTO(target) \ 782 JITTER_COMPUTED_GOTO_TRIVIAL(target) 783 #endif // #ifdef JITTER_REPLICATE 784 785 786 787 788 /* VM branching. 789 * ************************************************************************** */ 790 791 /* Set the VM instruction pointer. This is only defined for dispatching 792 models where an instruction pointer exists. */ 793 #if defined(JITTER_DISPATCH_SWITCH) \ 794 || defined(JITTER_DISPATCH_DIRECT_THREADING) \ 795 || defined(JITTER_DISPATCH_MINIMAL_THREADING) 796 # define JITTER_SET_IP(target_pointer) \ 797 do \ 798 { \ 799 jitter_ip = (const union jitter_word*)(target_pointer); \ 800 } \ 801 while (false) 802 #endif // #if defined(JITTER_DISPATCH_SWITCH) || ... 803 804 /* Jump to the current VM instruction pointer. This is only defined for 805 dispatching models where an instruction pointer is actually used.*/ 806 #if defined(JITTER_DISPATCH_SWITCH) 807 # define JITTER_BRANCH_TO_IP() \ 808 do \ 809 { \ 810 goto jitter_dispatching_switch_label; \ 811 } \ 812 while (false) 813 #elif defined(JITTER_DISPATCH_DIRECT_THREADING) \ 814 || defined(JITTER_DISPATCH_MINIMAL_THREADING) 815 # define JITTER_BRANCH_TO_IP() \ 816 do \ 817 { \ 818 JITTER_COMPUTED_GOTO(jitter_ip->thread); \ 819 } \ 820 while (false) 821 #endif // #if defined(... 822 823 /* Branch to a given VM label, represented as appropriate for the dispatching 824 model. */ 825 #ifdef JITTER_DISPATCH_NO_THREADING 826 #define JITTER_BRANCH(target) \ 827 do \ 828 { \ 829 JITTER_COMPUTED_GOTO(target); \ 830 } \ 831 while (false) 832 #else 833 #define JITTER_BRANCH(target_pointer) \ 834 do \ 835 { \ 836 JITTER_SET_IP(target_pointer); \ 837 JITTER_BRANCH_TO_IP(); \ 838 __builtin_unreachable (); /* FIXME: this seems beneficial here, differently from the no-threading case; anyway, the problem could be catched with a defect handler, and this is not a guarantee of correctness. */ \ 839 } \ 840 while (false) 841 #endif // #ifdef JITTER_DISPATCH_NO_THREADING 842 843 /* _JITTER_PROCEDURE_PROLOG is only used by generated code in callee 844 instructions, and is not intended for the user. The user is only supposed to 845 read JITTER_LINK , which holds the value set by _JITTER_PROCEDURE_PROLOG -- 846 either as defined here or in a machine-specific definition. */ 847 # define __JITTER_PROCEDURE_PROLOG_COMMON(link_union) \ 848 do \ 849 { \ 850 (link_union).pointer \ 851 = (void *) (jitter_state_runtime._jitter_link); \ 852 } \ 853 while (false) 854 #if defined(JITTER_DISPATCH_SWITCH) \ 855 || defined(JITTER_DISPATCH_DIRECT_THREADING) \ 856 || defined(JITTER_DISPATCH_MINIMAL_THREADING) 857 # define _JITTER_PROCEDURE_PROLOG(link_union) \ 858 __JITTER_PROCEDURE_PROLOG_COMMON(link_union) 859 #elif defined(JITTER_DISPATCH_NO_THREADING) 860 # ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 861 # define _JITTER_PROCEDURE_PROLOG(link_union) \ 862 __JITTER_PROCEDURE_PROLOG_COMMON(link_union) 863 # endif // ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 864 #else 865 # error "unknown dispatching model" 866 #endif 867 868 /* Branch-and-link to a given VM label, represented in a way appropriate for the 869 dispatching model. 870 A branch-and-link operation unconditionally branches to a VM target, and also 871 saves the return address (the beginning of the following VM instruction, 872 ignoring any code in the caller instruction past the branch-and-link) in some 873 implementation-specific resource, only up to the end of the callee 874 instruction. 875 The saved return access is accessible in reading from the target VM 876 instruction, which *must* be a callee instruction, and only reachable thru 877 branch-and-link , as JITTER_LINK . 878 879 This is a generic definition which works everywhere but does not exploit the 880 hardware branch target predictor like a machine-specific implementation 881 could. Return operations will easily mispredict. 882 883 This macro is reserved for internal use. The macro intended for the user 884 is named JITTER_BRANCH_AND_LINK , and is only visible from caller 885 instructions; this forces the user to correctly declare callers so that 886 return labels can be handled in every case. */ 887 #if defined(JITTER_DISPATCH_SWITCH) \ 888 || defined(JITTER_DISPATCH_DIRECT_THREADING) \ 889 || defined(JITTER_DISPATCH_MINIMAL_THREADING) 890 # define JITTER_BRANCH_AND_LINK_INTERNAL(target_rvalue) \ 891 do \ 892 { \ 893 jitter_state_runtime._jitter_link \ 894 = ((const union jitter_word *) \ 895 (jitter_ip + JITTER_SPECIALIZED_INSTRUCTION_WORD_NO)); \ 896 JITTER_BRANCH(target_rvalue); \ 897 } \ 898 while (false) 899 #elif defined(JITTER_DISPATCH_NO_THREADING) 900 # ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 901 # define JITTER_BRANCH_AND_LINK_INTERNAL(target_rvalue) \ 902 do \ 903 { \ 904 /* Use the return address from the implicit specialized argument */ \ 905 jitter_state_runtime._jitter_link = JITTER_RETURN_ADDRESS; \ 906 JITTER_BRANCH(target_rvalue); \ 907 } \ 908 while (false) 909 # endif // ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 910 #else 911 # error "unknown dispatching model" 912 #endif 913 914 /* Define the branch-and-link-with operation, in a way similar to 915 JITTER_BRANCH_AND_LINK_INTERNAL just above. In this case, however, the 916 macro is not conditionally defined: a branch-and-link-with doesn't count as a 917 call (since it can't return), and therefore the operation is available in any 918 VM instruction, even non-callers. This is why the macro name doesn't begin 919 with an underscore. */ 920 #if defined(JITTER_DISPATCH_SWITCH) \ 921 || defined(JITTER_DISPATCH_DIRECT_THREADING) \ 922 || defined(JITTER_DISPATCH_MINIMAL_THREADING) \ 923 || (defined(JITTER_DISPATCH_NO_THREADING) \ 924 && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE)) 925 # define JITTER_BRANCH_AND_LINK_WITH(_jitter_target_rvalue, \ 926 _jitter_new_link) \ 927 do \ 928 { \ 929 jitter_state_runtime._jitter_link = (_jitter_new_link); \ 930 JITTER_BRANCH(_jitter_target_rvalue); \ 931 } \ 932 while (false) 933 #endif 934 935 /* Sanity check, useful for writing new ports. */ 936 #if (defined(JITTER_DISPATCH_NO_THREADING) \ 937 && defined(JITTER_MACHINE_SUPPORTS_PROCEDURE) \ 938 && ! defined(JITTER_BRANCH_AND_LINK_WITH)) 939 # error "The machine claims to support procedures but lacks a definition" 940 # error "for JITTER_BRANCH_AND_LINK_WITH . Can't use no-threading." 941 #endif // #if ... sanity check. 942 943 /* An internal definition used for JITTER_RETURN . */ 944 # define _JITTER_RETURN_COMMON(link_rvalue) \ 945 do \ 946 { \ 947 JITTER_BRANCH(link_rvalue); \ 948 } \ 949 while (false) 950 951 /* Return to the caller, using the label provided as the rvalue parameter as the 952 destination. In its generic implementation this is a simple unconditional 953 branch, but of course machine-specific implementation will use native return 954 or branch-to-link-register instruction, with better branch target prediction 955 performance. */ 956 #if defined(JITTER_DISPATCH_SWITCH) \ 957 || defined(JITTER_DISPATCH_DIRECT_THREADING) \ 958 || defined(JITTER_DISPATCH_MINIMAL_THREADING) 959 # define JITTER_RETURN(link_rvalue) \ 960 _JITTER_RETURN_COMMON(link_rvalue) 961 #elif defined(JITTER_DISPATCH_NO_THREADING) 962 # ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 963 # define JITTER_RETURN(link_rvalue) \ 964 _JITTER_RETURN_COMMON(link_rvalue) 965 # endif // ifndef JITTER_MACHINE_SUPPORTS_PROCEDURE 966 #else 967 # error "unknown dispatching model" 968 #endif 969 970 971 /* VM conditional non-fast branching. 972 * ************************************************************************** */ 973 974 /* These macros are used internally in replacement instructions, as alternatives 975 to fast conditional branches. They are not very useful for human users, as 976 they expand to the same code generated by unconditional branches within 977 conditionals; however their direct use is not forbidden. */ 978 979 /* This macro is only used internally in the following macro definitions in this 980 section. */ 981 #define _JITTER_BRANCH_IF(outer_operator, type, operand0, \ 982 infix_operator, operand1, target) \ 983 do \ 984 { \ 985 if (outer_operator ((type) (operand0) \ 986 infix_operator \ 987 (type) (operand1))) \ 988 JITTER_BRANCH (target); \ 989 } \ 990 while (false) 991 992 /* These are the non-fast counterparts of the similarly named macros in 993 jitter-fast-branch.h and the machine-specific headers. */ 994 #define JITTER_BRANCH_IF_ZERO(operand, target) \ 995 _JITTER_BRANCH_IF(, jitter_uint, operand, ==, 0, target) 996 #define JITTER_BRANCH_IF_NONZERO(operand, target) \ 997 _JITTER_BRANCH_IF(, jitter_uint, operand, !=, 0, target) 998 #define JITTER_BRANCH_IF_POSITIVE(operand, target) \ 999 _JITTER_BRANCH_IF(, jitter_int, operand, >, 0, target) 1000 #define JITTER_BRANCH_IF_NONPOSITIVE(operand, target) \ 1001 _JITTER_BRANCH_IF(, jitter_int, operand, <=, 0, target) 1002 #define JITTER_BRANCH_IF_NEGATIVE(operand, target) \ 1003 _JITTER_BRANCH_IF(, jitter_int, operand, <, 0, target) 1004 #define JITTER_BRANCH_IF_NONNEGATIVE(operand, target) \ 1005 _JITTER_BRANCH_IF(, jitter_int, operand, >=, 0, target) 1006 #define JITTER_BRANCH_IF_EQUAL(operand0, operand1, target) \ 1007 _JITTER_BRANCH_IF(, jitter_int, operand0, ==, operand1, target) 1008 #define JITTER_BRANCH_IF_NOTEQUAL(operand0, operand1, target) \ 1009 _JITTER_BRANCH_IF(, jitter_int, operand0, !=, operand1, target) 1010 #define JITTER_BRANCH_IF_LESS_SIGNED(operand0, operand1, target) \ 1011 _JITTER_BRANCH_IF(, jitter_int, operand0, <, operand1, target) 1012 #define JITTER_BRANCH_IF_LESS_UNSIGNED(operand0, operand1, target) \ 1013 _JITTER_BRANCH_IF(, jitter_uint, operand0, <, operand1, target) 1014 #define JITTER_BRANCH_IF_NOTLESS_SIGNED(operand0, operand1, target) \ 1015 _JITTER_BRANCH_IF(, jitter_int, operand0, >=, operand1, target) 1016 #define JITTER_BRANCH_IF_NOTLESS_UNSIGNED(operand0, operand1, target) \ 1017 _JITTER_BRANCH_IF(, jitter_uint, operand0, >=, operand1, target) 1018 #define JITTER_BRANCH_IF_GREATER_SIGNED(operand0, operand1, target) \ 1019 _JITTER_BRANCH_IF(, jitter_int, operand0, >, operand1, target) 1020 #define JITTER_BRANCH_IF_GREATER_UNSIGNED(operand0, operand1, target) \ 1021 _JITTER_BRANCH_IF(, jitter_uint, operand0, >, operand1, target) 1022 #define JITTER_BRANCH_IF_NOTGREATER_SIGNED(operand0, operand1, target) \ 1023 _JITTER_BRANCH_IF(, jitter_int, operand0, <=, operand1, target) 1024 #define JITTER_BRANCH_IF_NOTGREATER_UNSIGNED(operand0, operand1, target) \ 1025 _JITTER_BRANCH_IF(, jitter_uint, operand0, <=, operand1, target) 1026 #define JITTER_BRANCH_IF_AND(operand0, operand1, target) \ 1027 _JITTER_BRANCH_IF(, jitter_uint, operand0, &, operand1, target) 1028 #define JITTER_BRANCH_IF_NOTAND(operand0, operand1, target) \ 1029 _JITTER_BRANCH_IF(!, jitter_uint, operand0, &, operand1, target) 1030 1031 /* This factors the common code for branch-on-overflow primitives. */ 1032 #define JITTER_BRANCH_IF_OPERATION_OVERFLOWS(operation_name, \ 1033 operand0, operand1, \ 1034 target) \ 1035 do \ 1036 { \ 1037 if (JITTER_CONCATENATE_THREE (JITTER_WOULD_, \ 1038 operation_name, \ 1039 _OVERFLOW) \ 1040 (jitter_uint, jitter_int, \ 1041 (operand0), (operand1), \ 1042 JITTER_BITS_PER_WORD)) \ 1043 JITTER_BRANCH (target); \ 1044 } \ 1045 while (false) 1046 1047 #define JITTER_BRANCH_IF_PLUS_OVERFLOWS(opd0, opd1, tgt) \ 1048 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (PLUS, (opd0), (opd1), (tgt)) 1049 #define JITTER_BRANCH_IF_MINUS_OVERFLOWS(opd0, opd1, tgt) \ 1050 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (MINUS, (opd0), (opd1), (tgt)) 1051 #define JITTER_BRANCH_IF_TIMES_OVERFLOWS(opd0, opd1, tgt) \ 1052 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (TIMES, (opd0), (opd1), (tgt)) 1053 #define JITTER_BRANCH_IF_DIVIDED_OVERFLOWS(opd0, opd1, tgt) \ 1054 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (DIVIDED, (opd0), (opd1), (tgt)) 1055 #define JITTER_BRANCH_IF_REMAINDER_OVERFLOWS(opd0, opd1, tgt) \ 1056 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (REMAINDER, (opd0), (opd1), (tgt)) 1057 #define JITTER_BRANCH_IF_NEGATE_OVERFLOWS(opd0, tgt) \ 1058 JITTER_BRANCH_IF_OPERATION_OVERFLOWS (MINUS, 0, (opd0), (tgt)) 1059 1060 /* This factors the common code for operate-and-branch-on-overflow primitives. */ 1061 #define JITTER_OPERATION_BRANCH_IF_OVERFLOW(res, operation_name, \ 1062 operand0, infix, operand1, \ 1063 target) \ 1064 do \ 1065 { \ 1066 const jitter_int _jitter_opd0_value = (jitter_int) (operand0); \ 1067 const jitter_int _jitter_opd1_value = (jitter_int) (operand1); \ 1068 if (JITTER_CONCATENATE_THREE (JITTER_WOULD_, operation_name, \ 1069 _OVERFLOW) \ 1070 (jitter_uint, jitter_int, \ 1071 _jitter_opd0_value, _jitter_opd1_value, \ 1072 JITTER_BITS_PER_WORD)) \ 1073 JITTER_BRANCH (target); \ 1074 else \ 1075 (res) = _jitter_opd0_value infix _jitter_opd1_value; \ 1076 } \ 1077 while (false) 1078 1079 #define JITTER_PLUS_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt) \ 1080 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), PLUS, (opd0), +, (opd1), (tgt)) 1081 #define JITTER_MINUS_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt) \ 1082 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), MINUS, (opd0), -, (opd1), (tgt)) 1083 #define JITTER_TIMES_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt) \ 1084 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), TIMES, (opd0), *, (opd1), (tgt)) 1085 #define JITTER_DIVIDED_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt) \ 1086 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), DIVIDED, (opd0), /, (opd1), (tgt)) 1087 #define JITTER_REMAINDER_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt) \ 1088 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), REMAINDER, (opd0), %, (opd1), (tgt)) 1089 #define JITTER_NEGATE_BRANCH_IF_OVERFLOW(res, opd0, tgt) \ 1090 JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), MINUS, 0, -, (opd0), (tgt)) 1091 1092 #endif // #ifndef JITTER_EXECUTOR_H_ 1093