1 /* This file is part of the dynarmic project. 2 * Copyright (c) 2016 MerryMage 3 * SPDX-License-Identifier: 0BSD 4 */ 5 6 #pragma once 7 8 #include <boost/variant.hpp> 9 10 #include "common/common_types.h" 11 #include "frontend/ir/cond.h" 12 #include "frontend/ir/location_descriptor.h" 13 14 namespace Dynarmic::IR { 15 namespace Term { 16 17 struct Invalid {}; 18 19 /** 20 * This terminal instruction calls the interpreter, starting at `next`. 21 * The interpreter must interpret exactly `num_instructions` instructions. 22 */ 23 struct Interpret { InterpretInterpret24 explicit Interpret(const LocationDescriptor& next_) : next(next_) {} 25 LocationDescriptor next; ///< Location at which interpretation starts. 26 size_t num_instructions = 1; 27 }; 28 29 /** 30 * This terminal instruction returns control to the dispatcher. 31 * The dispatcher will use the current cpu state to determine what comes next. 32 */ 33 struct ReturnToDispatch {}; 34 35 /** 36 * This terminal instruction jumps to the basic block described by `next` if we have enough 37 * cycles remaining. If we do not have enough cycles remaining, we return to the 38 * dispatcher, which will return control to the host. 39 */ 40 struct LinkBlock { LinkBlockLinkBlock41 explicit LinkBlock(const LocationDescriptor& next_) : next(next_) {} 42 LocationDescriptor next; ///< Location descriptor for next block. 43 }; 44 45 /** 46 * This terminal instruction jumps to the basic block described by `next` unconditionally. 47 * This is an optimization and MUST only be emitted when this is guaranteed not to result 48 * in hanging, even in the face of other optimizations. (In practice, this means that only 49 * forward jumps to short-ish blocks would use this instruction.) 50 * A backend that doesn't support this optimization may choose to implement this exactly 51 * as LinkBlock. 52 */ 53 struct LinkBlockFast { LinkBlockFastLinkBlockFast54 explicit LinkBlockFast(const LocationDescriptor& next_) : next(next_) {} 55 LocationDescriptor next; ///< Location descriptor for next block. 56 }; 57 58 /** 59 * This terminal instruction checks the top of the Return Stack Buffer against the current 60 * location descriptor. If RSB lookup fails, control is returned to the dispatcher. 61 * This is an optimization for faster function calls. A backend that doesn't support 62 * this optimization or doesn't have a RSB may choose to implement this exactly as 63 * ReturnToDispatch. 64 */ 65 struct PopRSBHint {}; 66 67 /** 68 * This terminal instruction performs a lookup of the current location descriptor in the 69 * fast dispatch lookup table. A backend that doesn't support this optimization may choose 70 * to implement this exactly as ReturnToDispatch. 71 */ 72 struct FastDispatchHint {}; 73 74 struct If; 75 struct CheckBit; 76 struct CheckHalt; 77 /// A Terminal is the terminal instruction in a MicroBlock. 78 using Terminal = boost::variant< 79 Invalid, 80 Interpret, 81 ReturnToDispatch, 82 LinkBlock, 83 LinkBlockFast, 84 PopRSBHint, 85 FastDispatchHint, 86 boost::recursive_wrapper<If>, 87 boost::recursive_wrapper<CheckBit>, 88 boost::recursive_wrapper<CheckHalt> 89 >; 90 91 /** 92 * This terminal instruction conditionally executes one terminal or another depending 93 * on the run-time state of the ARM flags. 94 */ 95 struct If { IfIf96 If(Cond if_, Terminal then_, Terminal else_) : if_(if_), then_(std::move(then_)), else_(std::move(else_)) {} 97 Cond if_; 98 Terminal then_; 99 Terminal else_; 100 }; 101 102 /** 103 * This terminal instruction conditionally executes one terminal or another depending 104 * on the run-time state of the check bit. 105 * then_ is executed if the check bit is non-zero, otherwise else_ is executed. 106 */ 107 struct CheckBit { CheckBitCheckBit108 CheckBit(Terminal then_, Terminal else_) : then_(std::move(then_)), else_(std::move(else_)) {} 109 Terminal then_; 110 Terminal else_; 111 }; 112 113 /** 114 * This terminal instruction checks if a halt was requested. If it wasn't, else_ is 115 * executed. 116 */ 117 struct CheckHalt { CheckHaltCheckHalt118 explicit CheckHalt(Terminal else_) : else_(std::move(else_)) {} 119 Terminal else_; 120 }; 121 122 } // namespace Term 123 124 using Term::Terminal; 125 126 } // namespace Dynarmic::IR 127