30#define REX_DETAIL_MIDASM_COUNT(...) \
31 REX_DETAIL_MIDASM_PICK(__VA_ARGS__ __VA_OPT__(, ) 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, \
32 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, \
45#define REX_DETAIL_MIDASM_PICK(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \
46 _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, \
47 _29, _30, _31, _32, count, ...) \
57#define REX_DETAIL_MIDASM_UNPAREN(...) __VA_ARGS__
66#define REX_DETAIL_MIDASM_EXPAND_PASTE(a, b) REX_DETAIL_MIDASM_PASTE(a, b)
75#define REX_DETAIL_MIDASM_PASTE(a, b) a##b
84#define REX_DETAIL_MIDASM_PARAM(body, index) \
85 rex::ppc::detail::MidAsmErasedT<rex::ppc::detail::MidAsmArg<decltype(&(body)), (index)>> \
95#define REX_DETAIL_MIDASM_ARG(body, index) \
96 rex::ppc::detail::RestoreMidAsmArg<rex::ppc::detail::MidAsmArg<decltype(&(body)), (index)>>( \
108#define REX_DETAIL_MIDASM_LIST_0(body, each)
119#define REX_DETAIL_MIDASM_LIST_1(body, each) each(body, 0)
130#define REX_DETAIL_MIDASM_LIST_2(body, each) REX_DETAIL_MIDASM_LIST_1(body, each), each(body, 1)
141#define REX_DETAIL_MIDASM_LIST_3(body, each) REX_DETAIL_MIDASM_LIST_2(body, each), each(body, 2)
152#define REX_DETAIL_MIDASM_LIST_4(body, each) REX_DETAIL_MIDASM_LIST_3(body, each), each(body, 3)
163#define REX_DETAIL_MIDASM_LIST_5(body, each) REX_DETAIL_MIDASM_LIST_4(body, each), each(body, 4)
174#define REX_DETAIL_MIDASM_LIST_6(body, each) REX_DETAIL_MIDASM_LIST_5(body, each), each(body, 5)
185#define REX_DETAIL_MIDASM_LIST_7(body, each) REX_DETAIL_MIDASM_LIST_6(body, each), each(body, 6)
196#define REX_DETAIL_MIDASM_LIST_8(body, each) REX_DETAIL_MIDASM_LIST_7(body, each), each(body, 7)
207#define REX_DETAIL_MIDASM_LIST_9(body, each) REX_DETAIL_MIDASM_LIST_8(body, each), each(body, 8)
218#define REX_DETAIL_MIDASM_LIST_10(body, each) REX_DETAIL_MIDASM_LIST_9(body, each), each(body, 9)
229#define REX_DETAIL_MIDASM_LIST_11(body, each) REX_DETAIL_MIDASM_LIST_10(body, each), each(body, 10)
240#define REX_DETAIL_MIDASM_LIST_12(body, each) REX_DETAIL_MIDASM_LIST_11(body, each), each(body, 11)
251#define REX_DETAIL_MIDASM_LIST_13(body, each) REX_DETAIL_MIDASM_LIST_12(body, each), each(body, 12)
262#define REX_DETAIL_MIDASM_LIST_14(body, each) REX_DETAIL_MIDASM_LIST_13(body, each), each(body, 13)
273#define REX_DETAIL_MIDASM_LIST_15(body, each) REX_DETAIL_MIDASM_LIST_14(body, each), each(body, 14)
284#define REX_DETAIL_MIDASM_LIST_16(body, each) REX_DETAIL_MIDASM_LIST_15(body, each), each(body, 15)
295#define REX_DETAIL_MIDASM_LIST_17(body, each) REX_DETAIL_MIDASM_LIST_16(body, each), each(body, 16)
306#define REX_DETAIL_MIDASM_LIST_18(body, each) REX_DETAIL_MIDASM_LIST_17(body, each), each(body, 17)
317#define REX_DETAIL_MIDASM_LIST_19(body, each) REX_DETAIL_MIDASM_LIST_18(body, each), each(body, 18)
328#define REX_DETAIL_MIDASM_LIST_20(body, each) REX_DETAIL_MIDASM_LIST_19(body, each), each(body, 19)
339#define REX_DETAIL_MIDASM_LIST_21(body, each) REX_DETAIL_MIDASM_LIST_20(body, each), each(body, 20)
350#define REX_DETAIL_MIDASM_LIST_22(body, each) REX_DETAIL_MIDASM_LIST_21(body, each), each(body, 21)
361#define REX_DETAIL_MIDASM_LIST_23(body, each) REX_DETAIL_MIDASM_LIST_22(body, each), each(body, 22)
372#define REX_DETAIL_MIDASM_LIST_24(body, each) REX_DETAIL_MIDASM_LIST_23(body, each), each(body, 23)
383#define REX_DETAIL_MIDASM_LIST_25(body, each) REX_DETAIL_MIDASM_LIST_24(body, each), each(body, 24)
394#define REX_DETAIL_MIDASM_LIST_26(body, each) REX_DETAIL_MIDASM_LIST_25(body, each), each(body, 25)
405#define REX_DETAIL_MIDASM_LIST_27(body, each) REX_DETAIL_MIDASM_LIST_26(body, each), each(body, 26)
416#define REX_DETAIL_MIDASM_LIST_28(body, each) REX_DETAIL_MIDASM_LIST_27(body, each), each(body, 27)
427#define REX_DETAIL_MIDASM_LIST_29(body, each) REX_DETAIL_MIDASM_LIST_28(body, each), each(body, 28)
438#define REX_DETAIL_MIDASM_LIST_30(body, each) REX_DETAIL_MIDASM_LIST_29(body, each), each(body, 29)
449#define REX_DETAIL_MIDASM_LIST_31(body, each) REX_DETAIL_MIDASM_LIST_30(body, each), each(body, 30)
460#define REX_DETAIL_MIDASM_LIST_32(body, each) REX_DETAIL_MIDASM_LIST_31(body, each), each(body, 31)
474#define REX_DETAIL_MIDASM_ENTRY(ret, name, params) \
475 extern "C" ret name(REX_DETAIL_MIDASM_EXPAND_PASTE( \
476 REX_DETAIL_MIDASM_LIST_, REX_DETAIL_MIDASM_COUNT(REX_DETAIL_MIDASM_UNPAREN params))( \
477 name##_rex_body, REX_DETAIL_MIDASM_PARAM)) { \
478 return name##_rex_body(REX_DETAIL_MIDASM_EXPAND_PASTE( \
479 REX_DETAIL_MIDASM_LIST_, REX_DETAIL_MIDASM_COUNT(REX_DETAIL_MIDASM_UNPAREN params))( \
480 name##_rex_body, REX_DETAIL_MIDASM_ARG)); \
484namespace rex::ppc::detail {
486enum class MidAsmType : u8 {
492enum class MidAsmParam : u8 {
508enum class MidAsmRegisterType : u8 {
521enum class MidAsmAtResult : u8 {
532inline constexpr size_t kMaxMidAsmParams = 32;
537 std::array<MidAsmParam, kMaxMidAsmParams> params;
542constexpr MidAsmParam ClassifyMidAsmParam() {
543 if constexpr (!std::is_reference_v<T>) {
544 if constexpr (std::is_same_v<T, u32>) {
545 return MidAsmParam::kU32;
546 }
else if constexpr (std::is_same_v<T, u64>) {
547 return MidAsmParam::kU64;
548 }
else if constexpr (std::is_same_v<T, f64>) {
549 return MidAsmParam::kF64;
550 }
else if constexpr (std::is_same_v<T, PPCVRegister>) {
551 return MidAsmParam::kVector;
552 }
else if constexpr (std::is_pointer_v<T> && !std::is_function_v<std::remove_pointer_t<T>>) {
553 return MidAsmParam::kPointer;
554 }
else if constexpr (memory::is_mapped_ptr_v<T>) {
555 return MidAsmParam::kMappedPointer;
557 return MidAsmParam::kInvalid;
559 }
else if constexpr (std::is_lvalue_reference_v<T> &&
560 !std::is_const_v<std::remove_reference_t<T>>) {
561 using Bare = std::remove_reference_t<T>;
562 if constexpr (std::is_same_v<Bare, PPCRegister>) {
563 return MidAsmParam::kRegister;
564 }
else if constexpr (std::is_same_v<Bare, PPCVRegister>) {
565 return MidAsmParam::kVectorRef;
566 }
else if constexpr (std::is_same_v<Bare, PPCCRRegister>) {
567 return MidAsmParam::kCR;
568 }
else if constexpr (std::is_same_v<Bare, PPCXERRegister>) {
569 return MidAsmParam::kXER;
570 }
else if constexpr (std::is_same_v<Bare, PPCFPSCRRegister>) {
571 return MidAsmParam::kFPSCR;
572 }
else if constexpr (std::is_same_v<Bare, PPCContext>) {
573 return MidAsmParam::kContext;
575 return MidAsmParam::kInvalid;
578 return MidAsmParam::kInvalid;
586template <
typename R,
typename... A>
587struct MidAsmParams<R (*)(A...)> {
588 static constexpr size_t kCount =
sizeof...(A);
589 using Types = std::tuple<A...>;
590 static constexpr std::array<MidAsmParam,
sizeof...(A)> kTypes = {ClassifyMidAsmParam<A>()...};
593template <
typename F,
size_t I>
594using MidAsmArg = std::tuple_element_t<I, typename MidAsmParams<F>::Types>;
607struct MidAsmErased<T*> {
613struct MidAsmErased<memory::MappedPtr<T>> {
614 using Type = memory::MappedPtr<u8>;
619using MidAsmErasedT = MidAsmErased<T>::Type;
623constexpr T RestoreMidAsmArg(MidAsmErasedT<T> value) {
624 if constexpr (std::is_pointer_v<T>) {
625 return static_cast<T
>(value);
626 }
else if constexpr (memory::is_mapped_ptr_v<T>) {
627 return T(
reinterpret_cast<memory::MappedPtrInnerType<T>::type*
>(value.GetHostPtr()),
628 value.GetGuestAddress());
640constexpr MidAsmBody MakeMidAsmBody(MidAsmType type) {
641 using Traits = MidAsmParams<F>;
642 static_assert(Traits::kCount <= kMaxMidAsmParams,
"A mid asm body takes at most 32 parameters");
643 MidAsmBody body{type, Traits::kCount, {}};
644 for (
size_t index = 0; index < Traits::kCount; ++index) {
645 body.params[index] = Traits::kTypes[index];
655constexpr bool IsMidAsmBodyValid(
const MidAsmBody& body) {
656 for (
size_t index = 0; index < body.count; ++index) {
657 if (body.params[index] == MidAsmParam::kInvalid) {
671constexpr bool ParseMidAsmIndex(std::string_view text, u32 limit, u32& value) {
672 if (text.empty() || text.size() > 3 || (text.size() > 1 && text[0] ==
'0')) {
676 for (
const char digit : text) {
677 if (digit <
'0' || digit >
'9') {
680 result = result * 10 +
static_cast<u32
>(digit -
'0');
682 if (result > limit) {
695constexpr bool ParseMidAsmAddress(std::string_view text, u32& value) {
696 while (!text.empty() &&
697 (text.back() ==
'u' || text.back() ==
'U' || text.back() ==
'l' || text.back() ==
'L')) {
698 text.remove_suffix(1);
706 if (text.size() > 2 && text[0] ==
'0' && (text[1] ==
'x' || text[1] ==
'X')) {
709 }
else if (text.size() > 2 && text[0] ==
'0' && (text[1] ==
'b' || text[1] ==
'B')) {
712 }
else if (text.size() > 1 && text[0] ==
'0') {
717 for (; index < text.size(); ++index) {
718 const char digit = text[index];
720 if (digit ==
'\'' && digits && index + 1 < text.size()) {
723 if (digit >=
'0' && digit <=
'9') {
724 digit_value =
static_cast<u32
>(digit -
'0');
725 }
else if (radix == 16 && digit >=
'a' && digit <=
'f') {
726 digit_value =
static_cast<u32
>(digit -
'a') + 10;
727 }
else if (radix == 16 && digit >=
'A' && digit <=
'F') {
728 digit_value =
static_cast<u32
>(digit -
'A') + 10;
732 if (digit_value >= radix) {
736 result = result * radix + digit_value;
737 if (result > 0xFFFFFFFFull) {
744 value =
static_cast<u32
>(result);
753constexpr bool IsMidAsmAddress(u64 address) {
754 return address != 0 && address % 4 == 0 && address <= 0xFFFFFFFFull;
757constexpr std::string_view TrimMidAsmToken(std::string_view text) {
758 while (!text.empty() && (text.front() ==
' ' || text.front() ==
'\t' || text.front() ==
'\n' ||
759 text.front() ==
'\r')) {
760 text.remove_prefix(1);
762 while (!text.empty() && (text.back() ==
' ' || text.back() ==
'\t' || text.back() ==
'\n' ||
763 text.back() ==
'\r')) {
764 text.remove_suffix(1);
775constexpr MidAsmRegisterType ParseMidAsmRegister(std::string_view token) {
777 if (token ==
"ctx") {
778 return MidAsmRegisterType::kContext;
780 if (token ==
"ctr") {
781 return MidAsmRegisterType::kCTR;
783 if (token ==
"xer") {
784 return MidAsmRegisterType::kXER;
786 if (token ==
"fpscr") {
787 return MidAsmRegisterType::kFPSCR;
789 if (token ==
"reserved") {
790 return MidAsmRegisterType::kReserved;
792 if (token.starts_with(
"cr")) {
793 return ParseMidAsmIndex(token.substr(2), 7, index) ? MidAsmRegisterType::kCR
794 : MidAsmRegisterType::kInvalid;
796 if (token.starts_with(
"r")) {
797 return ParseMidAsmIndex(token.substr(1), 31, index) && index != 1
798 ? MidAsmRegisterType::kGPR
799 : MidAsmRegisterType::kInvalid;
801 if (token.starts_with(
"f")) {
802 return ParseMidAsmIndex(token.substr(1), 31, index) ? MidAsmRegisterType::kFPR
803 : MidAsmRegisterType::kInvalid;
805 if (token.starts_with(
"v")) {
806 return ParseMidAsmIndex(token.substr(1), 127, index) ? MidAsmRegisterType::kVR
807 : MidAsmRegisterType::kInvalid;
809 return MidAsmRegisterType::kInvalid;
818constexpr bool IsMidAsmRegisterFit(MidAsmRegisterType reg, MidAsmParam param) {
820 case MidAsmRegisterType::kGPR:
821 return param == MidAsmParam::kU32 || param == MidAsmParam::kU64 ||
822 param == MidAsmParam::kRegister || param == MidAsmParam::kPointer ||
823 param == MidAsmParam::kMappedPointer;
824 case MidAsmRegisterType::kFPR:
825 return param == MidAsmParam::kF64 || param == MidAsmParam::kRegister;
826 case MidAsmRegisterType::kVR:
827 return param == MidAsmParam::kVector || param == MidAsmParam::kVectorRef;
828 case MidAsmRegisterType::kCR:
829 return param == MidAsmParam::kCR;
830 case MidAsmRegisterType::kCTR:
831 case MidAsmRegisterType::kReserved:
832 return param == MidAsmParam::kRegister;
833 case MidAsmRegisterType::kXER:
834 return param == MidAsmParam::kXER;
835 case MidAsmRegisterType::kFPSCR:
836 return param == MidAsmParam::kFPSCR;
837 case MidAsmRegisterType::kContext:
838 return param == MidAsmParam::kContext;
839 case MidAsmRegisterType::kInvalid:
852constexpr MidAsmAtResult CheckMidAsmAt(
const MidAsmBody& body, std::string_view placement,
853 std::string_view arguments) {
854 if (TrimMidAsmToken(placement) !=
"before" && TrimMidAsmToken(placement) !=
"after") {
855 return MidAsmAtResult::kBadPlacement;
857 std::string_view rest = TrimMidAsmToken(arguments);
858 const bool has_arguments = !rest.empty();
859 size_t registers = 0;
861 while (has_arguments) {
862 const size_t comma = rest.find(
',');
863 const std::string_view token = TrimMidAsmToken(rest.substr(0, comma));
864 const bool is_number = !token.empty() && token[0] >=
'0' && token[0] <=
'9';
865 if (first && body.type == MidAsmType::kBranch) {
867 return MidAsmAtResult::kMissingTarget;
870 if (!ParseMidAsmAddress(token, target) || !IsMidAsmAddress(target)) {
871 return MidAsmAtResult::kBadTarget;
873 }
else if (first && is_number) {
874 return MidAsmAtResult::kUnexpectedTarget;
876 const MidAsmRegisterType type = ParseMidAsmRegister(token);
877 if (type == MidAsmRegisterType::kInvalid) {
878 return MidAsmAtResult::kBadRegister;
880 if (registers < body.count && !IsMidAsmRegisterFit(type, body.params[registers])) {
881 return MidAsmAtResult::kTypeMismatch;
886 if (comma == std::string_view::npos) {
889 rest.remove_prefix(comma + 1);
891 if (body.type == MidAsmType::kBranch && first) {
892 return MidAsmAtResult::kMissingTarget;
894 if (registers != body.count) {
895 return MidAsmAtResult::kCountMismatch;
897 return MidAsmAtResult::kOk;
918#define REX_DETAIL_MIDASM_BODY(type, ret, name, params) \
919 static ret name##_rex_body params; \
920 inline constexpr rex::ppc::detail::MidAsmBody name##_rex_midasm = \
921 rex::ppc::detail::MakeMidAsmBody<decltype(&name##_rex_body)>( \
922 rex::ppc::detail::MidAsmType::type); \
923 static_assert(rex::ppc::detail::IsMidAsmBodyValid(name##_rex_midasm), \
924 "A mid asm body takes u32, u64, f64, PPCVRegister, a pointer, a MappedPtr, " \
925 "or a non const reference to a register type or PPCContext"); \
926 REX_DETAIL_MIDASM_ENTRY(ret, name, params) \
927 static ret name##_rex_body params
944#define REX_MIDASM_HOOK(name, params) REX_DETAIL_MIDASM_BODY(kHook, void, name, params)
960#define REX_MIDASM_BRANCH(name, params) REX_DETAIL_MIDASM_BODY(kBranch, bool, name, params)
976#define REX_MIDASM_RETURN_IF(name, params) REX_DETAIL_MIDASM_BODY(kReturnIf, bool, name, params)
990#define REX_DETAIL_MIDASM_AT_CHECK(name, placement, arguments, code, text) \
991 static_assert(rex::ppc::detail::CheckMidAsmAt(name##_rex_midasm, placement, arguments) != \
992 rex::ppc::detail::MidAsmAtResult::code, \
1009#define REX_MIDASM_AT(name, address, placement, ...) \
1010 static_assert(rex::ppc::detail::IsMidAsmAddress(address), \
1011 "REX_MIDASM_AT address must be a nonzero multiple of 4"); \
1012 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kBadPlacement, \
1013 "REX_MIDASM_AT placement must be before or after"); \
1014 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kUnexpectedTarget, \
1015 "REX_MIDASM_AT takes a target only for a branch body"); \
1016 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kMissingTarget, \
1017 "REX_MIDASM_AT needs the target of a branch body first"); \
1018 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kBadTarget, \
1019 "REX_MIDASM_AT target must be a nonzero multiple of 4"); \
1020 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kBadRegister, \
1021 "REX_MIDASM_AT register must be r0 to r31 except r1, f0 to f31, " \
1022 "v0 to v127, cr0 to cr7, ctr, xer, fpscr, reserved or ctx"); \
1023 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kCountMismatch, \
1024 "REX_MIDASM_AT register count must equal the body parameters"); \
1025 REX_DETAIL_MIDASM_AT_CHECK(name, #placement, #__VA_ARGS__, kTypeMismatch, \
1026 "REX_MIDASM_AT register type does not fit its parameter")
@ kCount
Definition guest_allocator.h:42
Integer types, byte order wrappers and size literals.