commit ff3eb7a796b56bda2152651d4db8f61d7d74d6fa Author: Merry Date: Sat Jul 2 20:31:43 2022 +0100 First commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..28884fb --- /dev/null +++ b/.clang-format @@ -0,0 +1,218 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: None +AlignEscapedNewlines: Right +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Custom +BreakBeforeConceptDeclarations: true +BreakBeforeTernaryOperators: true +BreakBeforeInheritanceComma: false +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +# EmptyLineAfterAccessModifier: Leave +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '(^)|(^)|(^)' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<([^\.])*>$' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 4 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +# IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: NoIndent +IndentGotoLabels: false +IndentPPDirectives: AfterHash +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +# InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +NamespaceMacros: +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +# ShortNamespaceLines: 5 +SortIncludes: true +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +# SpacesInLineCommentPrefix: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +TypenameMacros: +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME + - FCODE + - ICODE +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0b234b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +a.out +*work*/ +*build*/ diff --git a/include/oaknut/impl/arm64_mnemonics.inc b/include/oaknut/impl/arm64_mnemonics.inc new file mode 100644 index 0000000..1bfb8cf --- /dev/null +++ b/include/oaknut/impl/arm64_mnemonics.inc @@ -0,0 +1,398 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +void ADC(WReg wd, WReg wn, WReg wm) { emit<"00011010000mmmmm000000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void ADC(XReg xd, XReg xn, XReg xm) { emit<"10011010000mmmmm000000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void ADCS(WReg wd, WReg wn, WReg wm) { emit<"00111010000mmmmm000000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void ADCS(XReg xd, XReg xn, XReg xm) { emit<"10111010000mmmmm000000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void ADD(WRegWsp wd, WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wd); emit<"00001011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(wd, wn, wm, ext, shift_amount); } +void ADD(XRegSp xd, XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xd); emit<"10001011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(xd, xn, rm, ext, shift_amount); } +void ADD(WRegWsp wd, WRegWsp wn, AddSubImm imm) { emit<"000100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(wd, wn, imm); } +void ADD(XRegSp xd, XRegSp xn, AddSubImm imm) { emit<"100100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(xd, xn, imm); } +void ADD(WReg wd, WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"00001011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void ADD(XReg xd, XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"10001011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ADDS(WReg wd, WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wd); emit<"00101011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(wd, wn, wm, ext, shift_amount); } +void ADDS(XReg xd, XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xd); emit<"10101011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(xd, xn, rm, ext, shift_amount); } +void ADDS(WReg wd, WRegWsp wn, AddSubImm imm) { emit<"001100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(wd, wn, imm); } +void ADDS(XReg xd, XRegSp xn, AddSubImm imm) { emit<"101100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(xd, xn, imm); } +void ADDS(WReg wd, WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"00101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void ADDS(XReg xd, XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"10101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ADR(XReg xd, AddrOffset<21, 0> label) { emit<"0ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label); } +void ADRP(XReg xd, PageOffset<21> label) { emit<"1ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label); } +void AND(WRegWsp wd, WReg wn, BitImm32 imm) { emit<"0001001000rrrrrrssssssnnnnnddddd", "d", "n", "rs">(wd, wn, imm); } +void AND(XRegSp xd, XReg xn, BitImm64 imm) { emit<"100100100Nrrrrrrssssssnnnnnddddd", "d", "n", "Nrs">(xd, xn, imm); } +void AND(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"00001010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void AND(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"10001010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ANDS(WReg wd, WReg wn, BitImm32 imm) { emit<"0111001000rrrrrrssssssnnnnnddddd", "d", "n", "rs">(wd, wn, imm); } +void ANDS(XReg xd, XReg xn, BitImm64 imm) { emit<"111100100Nrrrrrrssssssnnnnnddddd", "d", "n", "Nrs">(xd, xn, imm); } +void ANDS(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"01101010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void ANDS(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"11101010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ASR(WReg wd, WReg wn, Imm<5> shift_amount) { emit<"0001001100rrrrrr011111nnnnnddddd", "d", "n", "r">(wd, wn, shift_amount); } +void ASR(XReg xd, XReg xn, Imm<6> shift_amount) { emit<"1001001101rrrrrr111111nnnnnddddd", "d", "n", "r">(xd, xn, shift_amount); } +void ASR(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001010nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void ASR(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001010nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void ASRV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001010nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void ASRV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001010nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void AT(AtOp op, XReg xt) { emit<"1101010100001ooo0111100Mooottttt", "oMo", "t">(op, xt); } +void B(AddrOffset<28, 2> label) { emit<"000101iiiiiiiiiiiiiiiiiiiiiiiiii", "i">(label); } +void B(Cond cond, AddrOffset<21, 2> label) { emit<"01010100iiiiiiiiiiiiiiiiiii0cccc", "c", "i">(cond, label); } +void BFI(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0011001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void BFI(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1011001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void BFM(WReg wd, WReg wn, Imm<5> immr, Imm<5> imms) { emit<"0011001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, immr, imms); } +void BFM(XReg xd, XReg xn, Imm<6> immr, Imm<6> imms) { emit<"1011001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, immr, imms); } +void BFXIL(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0011001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void BFXIL(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1011001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void BIC(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"00001010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void BIC(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"10001010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void BICS(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"01101010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void BICS(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"11101010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void BL(AddrOffset<28, 2> label) { emit<"100101iiiiiiiiiiiiiiiiiiiiiiiiii", "i">(label); } +void BLR(XReg xn) { emit<"1101011000111111000000nnnnn00000", "n">(xn); } +void BR(XReg xn) { emit<"1101011000011111000000nnnnn00000", "n">(xn); } +void BRK(Imm<16> imm) { emit<"11010100001iiiiiiiiiiiiiiii00000", "i">(imm); } +void CBNZ(WReg wt, AddrOffset<21, 2> label) { emit<"00110101iiiiiiiiiiiiiiiiiiittttt", "t", "i">(wt, label); } +void CBNZ(XReg xt, AddrOffset<21, 2> label) { emit<"10110101iiiiiiiiiiiiiiiiiiittttt", "t", "i">(xt, label); } +void CBZ(WReg wt, AddrOffset<21, 2> label) { emit<"00110100iiiiiiiiiiiiiiiiiiittttt", "t", "i">(wt, label); } +void CBZ(XReg xt, AddrOffset<21, 2> label) { emit<"10110100iiiiiiiiiiiiiiiiiiittttt", "t", "i">(xt, label); } +void CCMN(WReg wn, Imm<5> imm, Imm<4> nzcv, Cond cond) { emit<"00111010010iiiiicccc10nnnnn0ffff", "n", "i", "f", "c">(wn, imm, nzcv, cond); } +void CCMN(XReg xn, Imm<5> imm, Imm<4> nzcv, Cond cond) { emit<"10111010010iiiiicccc10nnnnn0ffff", "n", "i", "f", "c">(xn, imm, nzcv, cond); } +void CCMN(WReg wn, WReg wm, Imm<4> nzcv, Cond cond) { emit<"00111010010mmmmmcccc00nnnnn0ffff", "n", "m", "f", "c">(wn, wm, nzcv, cond); } +void CCMN(XReg xn, XReg xm, Imm<4> nzcv, Cond cond) { emit<"10111010010mmmmmcccc00nnnnn0ffff", "n", "m", "f", "c">(xn, xm, nzcv, cond); } +void CCMP(WReg wn, Imm<5> imm, Imm<4> nzcv, Cond cond) { emit<"01111010010iiiiicccc10nnnnn0ffff", "n", "i", "f", "c">(wn, imm, nzcv, cond); } +void CCMP(XReg xn, Imm<5> imm, Imm<4> nzcv, Cond cond) { emit<"11111010010iiiiicccc10nnnnn0ffff", "n", "i", "f", "c">(xn, imm, nzcv, cond); } +void CCMP(WReg wn, WReg wm, Imm<4> nzcv, Cond cond) { emit<"01111010010mmmmmcccc00nnnnn0ffff", "n", "m", "f", "c">(wn, wm, nzcv, cond); } +void CCMP(XReg xn, XReg xm, Imm<4> nzcv, Cond cond) { emit<"11111010010mmmmmcccc00nnnnn0ffff", "n", "m", "f", "c">(xn, xm, nzcv, cond); } +void CINC(WReg wd, WReg wn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"00011010100mmmmmcccc01nnnnnddddd", "d", "n", "c">(wd, wn, invert(cond)); } +void CINC(XReg xd, XReg xn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"10011010100mmmmmcccc01nnnnnddddd", "d", "n", "c">(xd, xn, invert(cond)); } +void CINV(WReg wd, WReg wn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"01011010100mmmmmcccc00nnnnnddddd", "d", "n", "c">(wd, wn, invert(cond)); } +void CINV(XReg xd, XReg xn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"11011010100mmmmmcccc00nnnnnddddd", "d", "n", "c">(xd, xn, invert(cond)); } +void CLREX(Imm<4> imm = 15) { emit<"11010101000000110011MMMM01011111", "M">(imm); } +void CLS(WReg wd, WReg wn) { emit<"0101101011000000000101nnnnnddddd", "d", "n">(wd, wn); } +void CLS(XReg xd, XReg xn) { emit<"1101101011000000000101nnnnnddddd", "d", "n">(xd, xn); } +void CLZ(WReg wd, WReg wn) { emit<"0101101011000000000100nnnnnddddd", "d", "n">(wd, wn); } +void CLZ(XReg xd, XReg xn) { emit<"1101101011000000000100nnnnnddddd", "d", "n">(xd, xn); } +void CMN(WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wn); emit<"00101011001mmmmmxxxiiinnnnn11111", "n", "m", "x", "i">(wn, wm, ext, shift_amount); } +void CMN(XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xn); emit<"10101011001mmmmmxxxiiinnnnn11111", "n", "m", "x", "i">(xn, rm, ext, shift_amount); } +void CMN(WRegWsp wn, AddSubImm imm) { emit<"001100010siiiiiiiiiiiinnnnn11111", "n", "si">(wn, imm); } +void CMN(XRegSp xn, AddSubImm imm) { emit<"101100010siiiiiiiiiiiinnnnn11111", "n", "si">(xn, imm); } +void CMN(WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"00101011ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(wn, wm, shift, shift_amount); } +void CMN(XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"10101011ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(xn, xm, shift, shift_amount); } +void CMP(WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wn); emit<"01101011001mmmmmxxxiiinnnnn11111", "n", "m", "x", "i">(wn, wm, ext, shift_amount); } +void CMP(XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xn); emit<"11101011001mmmmmxxxiiinnnnn11111", "n", "m", "x", "i">(xn, rm, ext, shift_amount); } +void CMP(WRegWsp wn, AddSubImm imm) { emit<"011100010siiiiiiiiiiiinnnnn11111", "n", "si">(wn, imm); } +void CMP(XRegSp xn, AddSubImm imm) { emit<"111100010siiiiiiiiiiiinnnnn11111", "n", "si">(xn, imm); } +void CMP(WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"01101011ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(wn, wm, shift, shift_amount); } +void CMP(XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"11101011ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(xn, xm, shift, shift_amount); } +void CNEG(WReg wd, WReg wn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"01011010100mmmmmcccc01nnnnnddddd", "d", "n", "c">(wd, wn, invert(cond)); } +void CNEG(XReg xd, XReg xn, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"11011010100mmmmmcccc01nnnnnddddd", "d", "n", "c">(xd, xn, invert(cond)); } +void CRC32B(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32H(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010001nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32W(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010010nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32X(WReg wd, WReg wn, XReg xm) { emit<"10011010110mmmmm010011nnnnnddddd", "d", "n", "m">(wd, wn, xm); } +void CRC32CB(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010100nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32CH(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010101nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32CW(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm010110nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void CRC32CX(WReg wd, WReg wn, XReg xm) { emit<"10011010110mmmmm010111nnnnnddddd", "d", "n", "m">(wd, wn, xm); } +void CSDB() { emit<"11010101000000110010001010011111">(); } +void CSEL(WReg wd, WReg wn, WReg wm, Cond cond) { emit<"00011010100mmmmmcccc00nnnnnddddd", "d", "n", "m", "c">(wd, wn, wm, cond); } +void CSEL(XReg xd, XReg xn, XReg xm, Cond cond) { emit<"10011010100mmmmmcccc00nnnnnddddd", "d", "n", "m", "c">(xd, xn, xm, cond); } +void CSET(WReg wd, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"0001101010011111cccc0111111ddddd", "d", "c">(wd, invert(cond)); } +void CSET(XReg xd, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"1001101010011111cccc0111111ddddd", "d", "c">(xd, invert(cond)); } +void CSETM(WReg wd, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"0101101010011111cccc0011111ddddd", "d", "c">(wd, invert(cond)); } +void CSETM(XReg xd, Cond cond) { if (cond != Cond::AL && cond != Cond::NV) throw "invalid Cond"; emit<"1101101010011111cccc0011111ddddd", "d", "c">(xd, invert(cond)); } +void CSINC(WReg wd, WReg wn, WReg wm, Cond cond) { emit<"00011010100mmmmmcccc01nnnnnddddd", "d", "n", "m", "c">(wd, wn, wm, cond); } +void CSINC(XReg xd, XReg xn, XReg xm, Cond cond) { emit<"10011010100mmmmmcccc01nnnnnddddd", "d", "n", "m", "c">(xd, xn, xm, cond); } +void CSINV(WReg wd, WReg wn, WReg wm, Cond cond) { emit<"01011010100mmmmmcccc00nnnnnddddd", "d", "n", "m", "c">(wd, wn, wm, cond); } +void CSINV(XReg xd, XReg xn, XReg xm, Cond cond) { emit<"11011010100mmmmmcccc00nnnnnddddd", "d", "n", "m", "c">(xd, xn, xm, cond); } +void CSNEG(WReg wd, WReg wn, WReg wm, Cond cond) { emit<"01011010100mmmmmcccc01nnnnnddddd", "d", "n", "m", "c">(wd, wn, wm, cond); } +void CSNEG(XReg xd, XReg xn, XReg xm, Cond cond) { emit<"11011010100mmmmmcccc01nnnnnddddd", "d", "n", "m", "c">(xd, xn, xm, cond); } +void DC(DcOp op, XReg xt) { emit<"1101010100001ooo0111MMMMooottttt", "oMo", "t">(op, xt); } +void DCPS1(Imm<16> imm = 0) { emit<"11010100101iiiiiiiiiiiiiiii00001", "i">(imm); } +void DCPS2(Imm<16> imm = 0) { emit<"11010100101iiiiiiiiiiiiiiii00010", "i">(imm); } +void DMB(BarrierOp imm) { emit<"11010101000000110011MMMM10111111", "M">(imm); } +void DRPS() { emit<"11010110101111110000001111100000">(); } +void DSB(BarrierOp imm) { emit<"11010101000000110011MMMM10011111", "M">(imm); } +void EON(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"01001010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void EON(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"11001010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void EOR(WRegWsp wd, WReg wn, BitImm32 imm) { emit<"0101001000rrrrrrssssssnnnnnddddd", "d", "n", "rs">(wd, wn, imm); } +void EOR(XRegSp xd, XReg xn, BitImm64 imm) { emit<"110100100Nrrrrrrssssssnnnnnddddd", "d", "n", "Nrs">(xd, xn, imm); } +void EOR(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"01001010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void EOR(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"11001010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ERET() { emit<"11010110100111110000001111100000">(); } +void EXTR(WReg wd, WReg wn, WReg wm, Imm<5> imms) { emit<"00010011100mmmmm0sssssnnnnnddddd", "d", "n", "m", "s">(wd, wn, wm, imms); } +void EXTR(XReg xd, XReg xn, XReg xm, Imm<6> imms) { emit<"10010011110mmmmmssssssnnnnnddddd", "d", "n", "m", "s">(xd, xn, xm, imms); } +void HINT(Imm<7> imm) { emit<"11010101000000110010MMMMooo11111", "Mo">(imm); } +void HLT(Imm<16> imm) { emit<"11010100010iiiiiiiiiiiiiiii00000", "i">(imm); } +void HVC(Imm<16> imm) { emit<"11010100000iiiiiiiiiiiiiiii00010", "i">(imm); } +void IC(IcOp op, XReg xt) { emit<"1101010100001ooo0111MMMMooottttt", "oMo", "t">(op, xt); } +void ISB(BarrierOp imm = BarrierOp::SY) { emit<"11010101000000110011MMMM11011111", "M">(imm); } +void LDAR(WReg wt, XRegSp xn) { emit<"1000100011011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDAR(XReg xt, XRegSp xn) { emit<"1100100011011111111111nnnnnttttt", "t", "n">(xt, xn); } +void LDARB(WReg wt, XRegSp xn) { emit<"0000100011011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDARH(WReg wt, XRegSp xn) { emit<"0100100011011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDAXP(WReg wt1, WReg wt2, XRegSp xn) { emit<"10001000011111111uuuuunnnnnttttt", "t", "u", "n">(wt1, wt2, xn); } +void LDAXP(XReg xt1, XReg xt2, XRegSp xn) { emit<"11001000011111111uuuuunnnnnttttt", "t", "u", "n">(xt1, xt2, xn); } +void LDAXR(WReg wt, XRegSp xn) { emit<"1000100001011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDAXR(XReg xt, XRegSp xn) { emit<"1100100001011111111111nnnnnttttt", "t", "n">(xt, xn); } +void LDAXRB(WReg wt, XRegSp xn) { emit<"0000100001011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDAXRH(WReg wt, XRegSp xn) { emit<"0100100001011111111111nnnnnttttt", "t", "n">(wt, xn); } +void LDNP(WReg wt1, WReg wt2, XRegSp xn, SOffset<9, 2> imm = 0) { emit<"0010100001iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void LDNP(XReg xt1, XReg xt2, XRegSp xn, SOffset<10, 3> imm = 0) { emit<"1010100001iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDP(WReg wt1, WReg wt2, XRegSp xn, PostIndexed, SOffset<9, 2> imm) { emit<"0010100011iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void LDP(XReg xt1, XReg xt2, XRegSp xn, PostIndexed, SOffset<10, 3> imm) { emit<"1010100011iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDP(WReg wt1, WReg wt2, XRegSp xn, PreIndexed, SOffset<9, 2> imm) { emit<"0010100111iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void LDP(XReg xt1, XReg xt2, XRegSp xn, PreIndexed, SOffset<10, 3> imm) { emit<"1010100111iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDP(WReg wt1, WReg wt2, XRegSp xn, SOffset<9, 2> imm = 0) { emit<"0010100101iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void LDP(XReg xt1, XReg xt2, XRegSp xn, SOffset<10, 3> imm = 0) { emit<"1010100101iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDPSW(XReg xt1, XReg xt2, XRegSp xn, PostIndexed, SOffset<9, 2> imm) { emit<"0110100011iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDPSW(XReg xt1, XReg xt2, XRegSp xn, PreIndexed, SOffset<9, 2> imm) { emit<"0110100111iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDPSW(XReg xt1, XReg xt2, XRegSp xn, SOffset<9, 2> imm = 0) { emit<"0110100101iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void LDR(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"10111000010iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDR(XReg xt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"11111000010iiiiiiiii01nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDR(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"10111000010iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDR(XReg xt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"11111000010iiiiiiiii11nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDR(WReg wt, XRegSp xn, POffset<14, 2> pimm = 0) { emit<"1011100101iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void LDR(XReg xt, XRegSp xn, POffset<15, 3> pimm = 0) { emit<"1111100101iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(xt, xn, pimm); } +void LDR(WReg wt, AddrOffset<21, 2> label) { emit<"00011000iiiiiiiiiiiiiiiiiiittttt", "t", "i">(wt, label); } +void LDR(XReg xt, AddrOffset<21, 2> label) { emit<"01011000iiiiiiiiiiiiiiiiiiittttt", "t", "i">(xt, label); } +void LDR(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 2> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"10111000011mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void LDR(XReg xt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 3> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"11111000011mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(xt, xn, rm, ext, amount); } +void LDRB(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"00111000010iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRB(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"00111000010iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRB(WReg wt, XRegSp xn, POffset<12, 0> pimm = 0) { emit<"0011100101iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void LDRB(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 0> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"00111000011mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void LDRH(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"01111000010iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRH(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"01111000010iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRH(WReg wt, XRegSp xn, POffset<13, 1> pimm = 0) { emit<"0111100101iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void LDRH(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 1> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"01111000011mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void LDRSB(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"00111000110iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRSB(XReg xt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"00111000100iiiiiiiii01nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSB(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"00111000110iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRSB(XReg xt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"00111000100iiiiiiiii11nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSB(WReg wt, XRegSp xn, POffset<12, 0> pimm = 0) { emit<"0011100111iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void LDRSB(XReg xt, XRegSp xn, POffset<12, 0> pimm = 0) { emit<"0011100110iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(xt, xn, pimm); } +void LDRSB(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 0> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"00111000111mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void LDRSB(WReg wt, XRegSp xn, XReg xm, ImmChoice<0, 0> amount = 0) { emit<"00111000111mmmmm011S10nnnnnttttt", "t", "n", "m", "S">(wt, xn, xm, amount); } +void LDRSB(XReg xt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 0> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"00111000101mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(xt, xn, rm, ext, amount); } +void LDRSB(XReg xt, XRegSp xn, XReg xm, ImmChoice<0, 0> amount = 0) { emit<"00111000101mmmmm011S10nnnnnttttt", "t", "n", "m", "S">(xt, xn, xm, amount); } +void LDRSH(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"01111000110iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRSH(XReg xt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"01111000100iiiiiiiii01nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSH(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"01111000110iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDRSH(XReg xt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"01111000100iiiiiiiii11nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSH(WReg wt, XRegSp xn, POffset<13, 1> pimm = 0) { emit<"0111100111iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void LDRSH(XReg xt, XRegSp xn, POffset<13, 1> pimm = 0) { emit<"0111100110iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(xt, xn, pimm); } +void LDRSH(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 1> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"01111000111mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void LDRSH(XReg xt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 1> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"01111000101mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(xt, xn, rm, ext, amount); } +void LDRSW(XReg xt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"10111000100iiiiiiiii01nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSW(XReg xt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"10111000100iiiiiiiii11nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDRSW(XReg xt, XRegSp xn, POffset<14, 2> pimm = 0) { emit<"1011100110iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(xt, xn, pimm); } +void LDRSW(XReg xt, AddrOffset<21, 2> label) { emit<"10011000iiiiiiiiiiiiiiiiiiittttt", "t", "i">(xt, label); } +void LDRSW(XReg xt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 2> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"10111000101mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(xt, xn, rm, ext, amount); } +void LDTR(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000010iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDTR(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"11111000010iiiiiiiii10nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDTRB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000010iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDTRH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000010iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDTRSB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000110iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDTRSB(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000100iiiiiiiii10nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDTRSH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000110iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDTRSH(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000100iiiiiiiii10nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDTRSW(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000100iiiiiiiii10nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDUR(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000010iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDUR(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"11111000010iiiiiiiii00nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDURB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000010iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDURH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000010iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDURSB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000110iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDURSB(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000100iiiiiiiii00nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDURSH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000110iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void LDURSH(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000100iiiiiiiii00nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDURSW(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000100iiiiiiiii00nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void LDXP(WReg wt1, WReg wt2, XRegSp xn) { emit<"10001000011111110uuuuunnnnnttttt", "t", "u", "n">(wt1, wt2, xn); } +void LDXP(XReg xt1, XReg xt2, XRegSp xn) { emit<"11001000011111110uuuuunnnnnttttt", "t", "u", "n">(xt1, xt2, xn); } +void LDXR(WReg wt, XRegSp xn) { emit<"1000100001011111011111nnnnnttttt", "t", "n">(wt, xn); } +void LDXR(XReg xt, XRegSp xn) { emit<"1100100001011111011111nnnnnttttt", "t", "n">(xt, xn); } +void LDXRB(WReg wt, XRegSp xn) { emit<"0000100001011111011111nnnnnttttt", "t", "n">(wt, xn); } +void LDXRH(WReg wt, XRegSp xn) { emit<"0100100001011111011111nnnnnttttt", "t", "n">(wt, xn); } +void LSL(WReg wd, WReg wn, LslShift<32> shift_amount) { emit<"0101001100rrrrrrssssssnnnnnddddd", "d", "n", "rs">(wd, wn, shift_amount); } +void LSL(XReg xd, XReg xn, LslShift<64> shift_amount) { emit<"1101001101rrrrrrssssssnnnnnddddd", "d", "n", "rs">(xd, xn, shift_amount); } +void LSL(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void LSL(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void LSLV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void LSLV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void LSR(WReg wd, WReg wn, Imm<5> shift_amount) { emit<"0101001100rrrrrr011111nnnnnddddd", "d", "n", "r">(wd, wn, shift_amount); } +void LSR(XReg xd, XReg xn, Imm<6> shift_amount) { emit<"1101001101rrrrrr111111nnnnnddddd", "d", "n", "r">(xd, xn, shift_amount); } +void LSR(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001001nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void LSR(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001001nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void LSRV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001001nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void LSRV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001001nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void MADD(WReg wd, WReg wn, WReg wm, WReg wa) { emit<"00011011000mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(wd, wn, wm, wa); } +void MADD(XReg xd, XReg xn, XReg xm, XReg xa) { emit<"10011011000mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(xd, xn, xm, xa); } +void MNEG(WReg wd, WReg wn, WReg wm) { emit<"00011011000mmmmm111111nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void MNEG(XReg xd, XReg xn, XReg xm) { emit<"10011011000mmmmm111111nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void MOV(WReg wd, WReg wm) { emit<"00101010000mmmmm00000011111ddddd", "d", "m">(wd, wm); } +void MOV(XReg xd, XReg xm) { emit<"10101010000mmmmm00000011111ddddd", "d", "m">(xd, xm); } +void MOV(WRegWsp wd, WRegWsp wn) { emit<"0001000100000000000000nnnnnddddd", "d", "n">(wd, wn); } +void MOV(XRegSp xd, XRegSp xn) { emit<"1001000100000000000000nnnnnddddd", "d", "n">(xd, xn); } +void MOVK(WReg wd, MovImm16 imm) { emit<"0111001010hiiiiiiiiiiiiiiiiddddd", "d", "hi">(wd, imm); } +void MOVK(XReg xd, MovImm16 imm) { emit<"111100101hhiiiiiiiiiiiiiiiiddddd", "d", "hi">(xd, imm); } +void MOVN(WReg wd, MovImm16 imm) { emit<"0001001010hiiiiiiiiiiiiiiiiddddd", "d", "hi">(wd, imm); } +void MOVN(XReg xd, MovImm16 imm) { emit<"100100101hhiiiiiiiiiiiiiiiiddddd", "d", "hi">(xd, imm); } +void MOVZ(WReg wd, MovImm16 imm) { emit<"0101001010hiiiiiiiiiiiiiiiiddddd", "d", "hi">(wd, imm); } +void MOVZ(XReg xd, MovImm16 imm) { emit<"110100101hhiiiiiiiiiiiiiiiiddddd", "d", "hi">(xd, imm); } +void MRS(XReg xt, SystemReg systemreg) { emit<"110101010011ooooNNNNMMMMooottttt", "t", "oNMo">(xt, systemreg); } +void MSR(PstateField pstatefield, Imm<4> imm) { emit<"1101010100000ooo0100MMMMooo11111", "o", "M">(pstatefield, imm); } +void MSR(SystemReg systemreg, XReg xt) { emit<"110101010001ooooNNNNMMMMooottttt", "oNMo", "t">(systemreg, xt); } +void MSUB(WReg wd, WReg wn, WReg wm, WReg wa) { emit<"00011011000mmmmm1aaaaannnnnddddd", "d", "n", "m", "a">(wd, wn, wm, wa); } +void MSUB(XReg xd, XReg xn, XReg xm, XReg xa) { emit<"10011011000mmmmm1aaaaannnnnddddd", "d", "n", "m", "a">(xd, xn, xm, xa); } +void MUL(WReg wd, WReg wn, WReg wm) { emit<"00011011000mmmmm011111nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void MUL(XReg xd, XReg xn, XReg xm) { emit<"10011011000mmmmm011111nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void MVN(WReg wd, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"00101010ss1mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(wd, wm, shift, shift_amount); } +void MVN(XReg xd, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"10101010ss1mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(xd, xm, shift, shift_amount); } +void NEG(WReg wd, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"01001011ss0mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(wd, wm, shift, shift_amount); } +void NEG(XReg xd, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"11001011ss0mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(xd, xm, shift, shift_amount); } +void NEGS(WReg wd, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"01101011ss0mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(wd, wm, shift, shift_amount); } +void NEGS(XReg xd, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"11101011ss0mmmmmiiiiii11111ddddd", "d", "m", "s", "i">(xd, xm, shift, shift_amount); } +void NGC(WReg wd, WReg wm) { emit<"01011010000mmmmm00000011111ddddd", "d", "m">(wd, wm); } +void NGC(XReg xd, XReg xm) { emit<"11011010000mmmmm00000011111ddddd", "d", "m">(xd, xm); } +void NGCS(WReg wd, WReg wm) { emit<"01111010000mmmmm00000011111ddddd", "d", "m">(wd, wm); } +void NGCS(XReg xd, XReg xm) { emit<"11111010000mmmmm00000011111ddddd", "d", "m">(xd, xm); } +void NOP() { emit<"11010101000000110010000000011111">(); } +void ORN(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"00101010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void ORN(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"10101010ss1mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void ORR(WRegWsp wd, WReg wn, BitImm32 imm) { emit<"0011001000rrrrrrssssssnnnnnddddd", "d", "n", "rs">(wd, wn, imm); } +void ORR(XRegSp xd, XReg xn, BitImm64 imm) { emit<"101100100Nrrrrrrssssssnnnnnddddd", "d", "n", "Nrs">(xd, xn, imm); } +void ORR(WReg wd, WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"00101010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void ORR(XReg xd, XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"10101010ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void PRFM(PrfOp prfop, XRegSp xn, POffset<15, 3> pimm = 0) { emit<"1111100110iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(prfop, xn, pimm); } +void PRFM(PrfOp prfop, AddrOffset<21, 2> label) { emit<"11011000iiiiiiiiiiiiiiiiiiittttt", "t", "i">(prfop, label); } +void PRFM(PrfOp prfop, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 3> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"11111000101mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(prfop, xn, rm, ext, amount); } +void PRFUM(PrfOp prfop, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"11111000100iiiiiiiii00nnnnnttttt", "t", "n", "i">(prfop, xn, simm); } +void PSSBB() { emit<"11010101000000110011010010011111">(); } +void RBIT(WReg wd, WReg wn) { emit<"0101101011000000000000nnnnnddddd", "d", "n">(wd, wn); } +void RBIT(XReg xd, XReg xn) { emit<"1101101011000000000000nnnnnddddd", "d", "n">(xd, xn); } +void RET(XReg xn) { emit<"1101011001011111000000nnnnn00000", "n">(xn); } +void REV(WReg wd, WReg wn) { emit<"0101101011000000000010nnnnnddddd", "d", "n">(wd, wn); } +void REV(XReg xd, XReg xn) { emit<"1101101011000000000011nnnnnddddd", "d", "n">(xd, xn); } +void REV16(WReg wd, WReg wn) { emit<"0101101011000000000001nnnnnddddd", "d", "n">(wd, wn); } +void REV16(XReg xd, XReg xn) { emit<"1101101011000000000001nnnnnddddd", "d", "n">(xd, xn); } +void REV32(XReg xd, XReg xn) { emit<"1101101011000000000010nnnnnddddd", "d", "n">(xd, xn); } +void REV64(XReg xd, XReg xn) { emit<"1101101011000000000011nnnnnddddd", "d", "n">(xd, xn); } +void ROR(WReg wd, WReg ws, Imm<5> shift_amount) { emit<"00010011100mmmmm0sssssnnnnnddddd", "d", "n", "m", "s">(wd, ws, ws, shift_amount); } +void ROR(XReg xd, XReg xs, Imm<6> shift_amount) { emit<"10010011110mmmmmssssssnnnnnddddd", "d", "n", "m", "s">(xd, xs, xs, shift_amount); } +void ROR(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001011nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void ROR(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001011nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void RORV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm001011nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void RORV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm001011nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void SB() { emit<"11010101000000110011000011111111">(); } +void SBC(WReg wd, WReg wn, WReg wm) { emit<"01011010000mmmmm000000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void SBC(XReg xd, XReg xn, XReg xm) { emit<"11011010000mmmmm000000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void SBCS(WReg wd, WReg wn, WReg wm) { emit<"01111010000mmmmm000000nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void SBCS(XReg xd, XReg xn, XReg xm) { emit<"11111010000mmmmm000000nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void SBFIZ(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0001001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void SBFIZ(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1001001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void SBFM(WReg wd, WReg wn, Imm<5> immr, Imm<5> imms) { emit<"0001001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, immr, imms); } +void SBFM(XReg xd, XReg xn, Imm<6> immr, Imm<6> imms) { emit<"1001001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, immr, imms); } +void SBFX(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0001001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void SBFX(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1001001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void SDIV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm000011nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void SDIV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm000011nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void SEV() { emit<"11010101000000110010000010011111">(); } +void SEVL() { emit<"11010101000000110010000010111111">(); } +void SMADDL(XReg xd, WReg wn, WReg wm, XReg xa) { emit<"10011011001mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(xd, wn, wm, xa); } +void SMNEGL(XReg xd, WReg wn, WReg wm) { emit<"10011011001mmmmm111111nnnnnddddd", "d", "n", "m">(xd, wn, wm); } +void SMSUBL(XReg xd, WReg wn, WReg wm, XReg xa) { emit<"10011011001mmmmm1aaaaannnnnddddd", "d", "n", "m", "a">(xd, wn, wm, xa); } +void SMULH(XReg xd, XReg xn, XReg xm) { emit<"10011011010mmmmm011111nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void SMULL(XReg xd, WReg wn, WReg wm) { emit<"10011011001mmmmm011111nnnnnddddd", "d", "n", "m">(xd, wn, wm); } +void SSBB() { emit<"11010101000000110011000010011111">(); } +void STLR(WReg wt, XRegSp xn) { emit<"1000100010011111111111nnnnnttttt", "t", "n">(wt, xn); } +void STLR(XReg xt, XRegSp xn) { emit<"1100100010011111111111nnnnnttttt", "t", "n">(xt, xn); } +void STLRB(WReg wt, XRegSp xn) { emit<"0000100010011111111111nnnnnttttt", "t", "n">(wt, xn); } +void STLRH(WReg wt, XRegSp xn) { emit<"0100100010011111111111nnnnnttttt", "t", "n">(wt, xn); } +void STLXP(WReg ws, WReg wt1, WReg wt2, XRegSp xn) { emit<"10001000001sssss1uuuuunnnnnttttt", "s", "t", "u", "n">(ws, wt1, wt2, xn); } +void STLXP(WReg ws, XReg xt1, XReg xt2, XRegSp xn) { emit<"11001000001sssss1uuuuunnnnnttttt", "s", "t", "u", "n">(ws, xt1, xt2, xn); } +void STLXR(WReg ws, WReg wt, XRegSp xn) { emit<"10001000000sssss111111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void STLXR(WReg ws, XReg xt, XRegSp xn) { emit<"11001000000sssss111111nnnnnttttt", "s", "t", "n">(ws, xt, xn); } +void STLXRB(WReg ws, WReg wt, XRegSp xn) { emit<"00001000000sssss111111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void STLXRH(WReg ws, WReg wt, XRegSp xn) { emit<"01001000000sssss111111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void STNP(WReg wt1, WReg wt2, XRegSp xn, SOffset<9, 2> imm = 0) { emit<"0010100000iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void STNP(XReg xt1, XReg xt2, XRegSp xn, SOffset<10, 3> imm = 0) { emit<"1010100000iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void STP(WReg wt1, WReg wt2, XRegSp xn, PostIndexed, SOffset<9, 2> imm) { emit<"0010100010iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void STP(XReg xt1, XReg xt2, XRegSp xn, PostIndexed, SOffset<10, 3> imm) { emit<"1010100010iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void STP(WReg wt1, WReg wt2, XRegSp xn, PreIndexed, SOffset<9, 2> imm) { emit<"0010100110iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void STP(XReg xt1, XReg xt2, XRegSp xn, PreIndexed, SOffset<10, 3> imm) { emit<"1010100110iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void STP(WReg wt1, WReg wt2, XRegSp xn, SOffset<9, 2> imm = 0) { emit<"0010100100iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(wt1, wt2, xn, imm); } +void STP(XReg xt1, XReg xt2, XRegSp xn, SOffset<10, 3> imm = 0) { emit<"1010100100iiiiiiiuuuuunnnnnttttt", "t", "u", "n", "i">(xt1, xt2, xn, imm); } +void STR(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"10111000000iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STR(XReg xt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"11111000000iiiiiiiii01nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void STR(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"10111000000iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STR(XReg xt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"11111000000iiiiiiiii11nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void STR(WReg wt, XRegSp xn, POffset<14, 2> pimm = 0) { emit<"1011100100iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void STR(XReg xt, XRegSp xn, POffset<15, 3> pimm = 0) { emit<"1111100100iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(xt, xn, pimm); } +void STR(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 2> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"10111000001mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void STR(XReg xt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 3> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"11111000001mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(xt, xn, rm, ext, amount); } +void STRB(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"00111000000iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STRB(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"00111000000iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STRB(WReg wt, XRegSp xn, POffset<12, 0> pimm = 0) { emit<"0011100100iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void STRB(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 0> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"00111000001mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void STRB(WReg wt, XRegSp xn, XReg xm, ImmChoice<0, 0> amount = 0) { emit<"00111000001mmmmm011S10nnnnnttttt", "t", "n", "m", "S">(wt, xn, xm, amount); } +void STRH(WReg wt, XRegSp xn, PostIndexed, SOffset<9, 0> simm) { emit<"01111000000iiiiiiiii01nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STRH(WReg wt, XRegSp xn, PreIndexed, SOffset<9, 0> simm) { emit<"01111000000iiiiiiiii11nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STRH(WReg wt, XRegSp xn, POffset<13, 1> pimm = 0) { emit<"0111100100iiiiiiiiiiiinnnnnttttt", "t", "n", "i">(wt, xn, pimm); } +void STRH(WReg wt, XRegSp xn, RReg rm, IndexExt ext = IndexExt::LSL, ImmChoice<0, 1> amount = 0) { indexext_verify_reg_size(ext, rm); emit<"01111000001mmmmmxxxS10nnnnnttttt", "t", "n", "m", "x", "S">(wt, xn, rm, ext, amount); } +void STTR(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000000iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STTR(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"11111000000iiiiiiiii10nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void STTRB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000000iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STTRH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000000iiiiiiiii10nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STUR(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"10111000000iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STUR(XReg xt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"11111000000iiiiiiiii00nnnnnttttt", "t", "n", "i">(xt, xn, simm); } +void STURB(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"00111000000iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STURH(WReg wt, XRegSp xn, SOffset<9, 0> simm = 0) { emit<"01111000000iiiiiiiii00nnnnnttttt", "t", "n", "i">(wt, xn, simm); } +void STXP(WReg ws, WReg wt1, WReg wt2, XRegSp xn) { emit<"10001000001sssss0uuuuunnnnnttttt", "s", "t", "u", "n">(ws, wt1, wt2, xn); } +void STXP(WReg ws, XReg xt1, XReg xt2, XRegSp xn) { emit<"11001000001sssss0uuuuunnnnnttttt", "s", "t", "u", "n">(ws, xt1, xt2, xn); } +void STXR(WReg ws, WReg wt, XRegSp xn) { emit<"10001000000sssss011111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void STXR(WReg ws, XReg xt, XRegSp xn) { emit<"11001000000sssss011111nnnnnttttt", "s", "t", "n">(ws, xt, xn); } +void STXRB(WReg ws, WReg wt, XRegSp xn) { emit<"00001000000sssss011111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void STXRH(WReg ws, WReg wt, XRegSp xn) { emit<"01001000000sssss011111nnnnnttttt", "s", "t", "n">(ws, wt, xn); } +void SUB(WRegWsp wd, WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wd); emit<"01001011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(wd, wn, wm, ext, shift_amount); } +void SUB(XRegSp xd, XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xd); emit<"11001011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(xd, xn, rm, ext, shift_amount); } +void SUB(WRegWsp wd, WRegWsp wn, AddSubImm imm) { emit<"010100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(wd, wn, imm); } +void SUB(XRegSp xd, XRegSp xn, AddSubImm imm) { emit<"110100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(xd, xn, imm); } +void SUB(WReg wd, WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"01001011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void SUB(XReg xd, XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"11001011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void SUBS(WReg wd, WRegWsp wn, WReg wm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_lsl_correction(ext, wd); emit<"01101011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(wd, wn, wm, ext, shift_amount); } +void SUBS(XReg xd, XRegSp xn, RReg rm, AddSubExt ext = AddSubExt::LSL, Imm<3> shift_amount = 0) { addsubext_verify_reg_size(ext, rm); addsubext_lsl_correction(ext, xd); emit<"11101011001mmmmmxxxiiinnnnnddddd", "d", "n", "m", "x", "i">(xd, xn, rm, ext, shift_amount); } +void SUBS(WReg wd, WRegWsp wn, AddSubImm imm) { emit<"011100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(wd, wn, imm); } +void SUBS(XReg xd, XRegSp xn, AddSubImm imm) { emit<"111100010siiiiiiiiiiiinnnnnddddd", "d", "n", "si">(xd, xn, imm); } +void SUBS(WReg wd, WReg wn, WReg wm, AddSubShift shift = AddSubShift::LSL, Imm<5> shift_amount = 0) { emit<"01101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(wd, wn, wm, shift, shift_amount); } +void SUBS(XReg xd, XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6> shift_amount = 0) { emit<"11101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount); } +void SVC(Imm<16> imm) { emit<"11010100000iiiiiiiiiiiiiiii00001", "i">(imm); } +void SXTB(WReg wd, WReg wn) { emit<"0001001100000000000111nnnnnddddd", "d", "n">(wd, wn); } +void SXTB(XReg xd, WReg wn) { emit<"1001001101000000000111nnnnnddddd", "d", "n">(xd, wn); } +void SXTH(WReg wd, WReg wn) { emit<"0001001100000000001111nnnnnddddd", "d", "n">(wd, wn); } +void SXTH(XReg xd, WReg wn) { emit<"1001001101000000001111nnnnnddddd", "d", "n">(xd, wn); } +void SXTW(XReg xd, WReg wn) { emit<"1001001101000000011111nnnnnddddd", "d", "n">(xd, wn); } +void TBNZ(RReg rt, Imm<6> imm, AddrOffset<16, 2> label) { tbz_verify_reg_size(rt, imm); emit<"b0110111bbbbbiiiiiiiiiiiiiittttt", "t", "b", "i">(rt, imm, label); } +void TBZ(RReg rt, Imm<6> imm, AddrOffset<16, 2> label) { tbz_verify_reg_size(rt, imm); emit<"b0110110bbbbbiiiiiiiiiiiiiittttt", "t", "b", "i">(rt, imm, label); } +void TLBI(TlbiOp op, XReg xt) { emit<"1101010100001ooo1000MMMMooottttt", "oMo", "t">(op, xt); } +void TST(WReg wn, BitImm32 imm) { emit<"0111001000rrrrrrssssssnnnnn11111", "n", "rs">(wn, imm); } +void TST(XReg xn, BitImm64 imm) { emit<"111100100Nrrrrrrssssssnnnnn11111", "n", "Nrs">(xn, imm); } +void TST(WReg wn, WReg wm, LogShift shift = LogShift::LSL, Imm<5> shift_amount = 0) { emit<"01101010ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(wn, wm, shift, shift_amount); } +void TST(XReg xn, XReg xm, LogShift shift = LogShift::LSL, Imm<6> shift_amount = 0) { emit<"11101010ss0mmmmmiiiiiinnnnn11111", "n", "m", "s", "i">(xn, xm, shift, shift_amount); } +void UBFIZ(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0101001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void UBFIZ(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1101001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void UBFM(WReg wd, WReg wn, Imm<5> immr, Imm<5> imms) { emit<"0101001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, immr, imms); } +void UBFM(XReg xd, XReg xn, Imm<6> immr, Imm<6> imms) { emit<"1101001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, immr, imms); } +void UBFX(WReg wd, WReg wn, Imm<5> lsb, Imm<5> width) { if (width.value() == 0 || width.value() > (32 - lsb.value())) throw "invalid width"; emit<"0101001100rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(wd, wn, (-lsb.value()) & 31, width.value() - 1); } +void UBFX(XReg xd, XReg xn, Imm<6> lsb, Imm<6> width) { if (width.value() == 0 || width.value() > (64 - lsb.value())) throw "invalid width"; emit<"1101001101rrrrrrssssssnnnnnddddd", "d", "n", "r", "s">(xd, xn, (-lsb.value()) & 63, width.value() - 1); } +void UDF(Imm<16> imm) { emit<"0000000000000000iiiiiiiiiiiiiiii", "i">(imm); } +void UDIV(WReg wd, WReg wn, WReg wm) { emit<"00011010110mmmmm000010nnnnnddddd", "d", "n", "m">(wd, wn, wm); } +void UDIV(XReg xd, XReg xn, XReg xm) { emit<"10011010110mmmmm000010nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void UMADDL(XReg xd, WReg wn, WReg wm, XReg xa) { emit<"10011011101mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(xd, wn, wm, xa); } +void UMNEGL(XReg xd, WReg wn, WReg wm) { emit<"10011011101mmmmm111111nnnnnddddd", "d", "n", "m">(xd, wn, wm); } +void UMSUBL(XReg xd, WReg wn, WReg wm, XReg xa) { emit<"10011011101mmmmm1aaaaannnnnddddd", "d", "n", "m", "a">(xd, wn, wm, xa); } +void UMULH(XReg xd, XReg xn, XReg xm) { emit<"10011011110mmmmm011111nnnnnddddd", "d", "n", "m">(xd, xn, xm); } +void UMULL(XReg xd, WReg wn, WReg wm) { emit<"10011011101mmmmm011111nnnnnddddd", "d", "n", "m">(xd, wn, wm); } +void UXTB(WReg wd, WReg wn) { emit<"0101001100000000000111nnnnnddddd", "d", "n">(wd, wn); } +void UXTH(WReg wd, WReg wn) { emit<"0101001100000000001111nnnnnddddd", "d", "n">(wd, wn); } +void WFE() { emit<"11010101000000110010000001011111">(); } +void WFI() { emit<"11010101000000110010000001111111">(); } +void YIELD() { emit<"11010101000000110010000000111111">(); } diff --git a/include/oaknut/impl/enum.hpp b/include/oaknut/impl/enum.hpp new file mode 100644 index 0000000..49abc68 --- /dev/null +++ b/include/oaknut/impl/enum.hpp @@ -0,0 +1,234 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace oaknut { + +struct PostIndexed {}; + +struct PreIndexed {}; + +enum class Cond { + EQ, + NE, + CS, + CC, + MI, + PL, + VS, + VC, + HI, + LS, + GE, + LT, + GT, + LE, + AL, + NV, + HS = CS, + LO = CC, +}; + +Cond invert(Cond c) +{ + return static_cast(static_cast(c) ^ 1); +} + +enum class AddSubExt { + UXTB, + UXTH, + UXTW, + UXTX, + SXTB, + SXTH, + SXTW, + SXTX, + LSL, // UXTW (32-bit) or UXTX (64-bit) +}; + +enum class IndexExt { + UXTW = 0b010, + LSL = 0b011, + SXTW = 0b110, + SXTX = 0b111, +}; + +enum class AddSubShift { + LSL, + LSR, + ASR, +}; + +enum class LogShift { + LSL, + LSR, + ASR, + ROR, +}; + +enum class PstateField { + UAO = 0b000'011, // ARMv8.2-UAO + PAN = 0b000'100, // ARMv8.1-PAN + SPSel = 0b000'101, + DIT = 0b011'010, // ARMv8.4-DIT + DAIFSet = 0b011'110, + DAIFClr = 0b011'111, +}; + +enum class SystemReg { +}; + +enum class AtOp { + S1E1R = 0b000'0'000, + S1E1W = 0b000'0'001, + S1E0R = 0b000'0'010, + S1E0W = 0b000'0'011, + S1E1RP = 0b000'1'000, // ARMv8.2-ATS1E1 + S1E1WP = 0b000'1'001, // ARMv8.2-ATS1E1 + S1E2R = 0b100'0'000, + S1E2W = 0b100'0'001, + S12E1R = 0b100'0'100, + S12E1W = 0b100'0'101, + S12E0R = 0b100'0'110, + S12E0W = 0b100'0'111, + S1E3R = 0b110'0'000, + S1E3W = 0b110'0'001, +}; + +enum class BarrierOp { + SY = 0b1111, + ST = 0b1110, + LD = 0b1101, + ISH = 0b1011, + ISHST = 0b1010, + ISHLD = 0b1001, + NSH = 0b0111, + NSHST = 0b0110, + NSHLD = 0b0101, + OSH = 0b0011, + OSHST = 0b0010, + OSHLD = 0b0001, +}; + +enum class DcOp { + IVAC = 0b000'0110'001, + ISW = 0b000'0110'010, + CSW = 0b000'1010'010, + CISW = 0b000'1110'010, + ZVA = 0b011'0100'001, + CVAC = 0b011'1010'001, + CVAU = 0b011'1011'001, + CVAP = 0b011'1100'001, // ARMv8.2-DCPoP + CIVAC = 0b011'1110'001, +}; + +enum class IcOp { + IALLUIS = 0b000'0001'000, + IALLU = 0b000'0101'000, + IVAU = 0b011'0101'001, +}; + +enum class PrfOp { + PLDL1KEEP = 0b00'00'0, + PLDL1STRM = 0b00'00'1, + PLDL2KEEP = 0b00'01'0, + PLDL2STRM = 0b00'01'1, + PLDL3KEEP = 0b00'10'0, + PLDL3STRM = 0b00'10'1, + PLIL1KEEP = 0b01'00'0, + PLIL1STRM = 0b01'00'1, + PLIL2KEEP = 0b01'01'0, + PLIL2STRM = 0b01'01'1, + PLIL3KEEP = 0b01'10'0, + PLIL3STRM = 0b01'10'1, + PSTL1KEEP = 0b10'00'0, + PSTL1STRM = 0b10'00'1, + PSTL2KEEP = 0b10'01'0, + PSTL2STRM = 0b10'01'1, + PSTL3KEEP = 0b10'10'0, + PSTL3STRM = 0b10'10'1, +}; + +enum class TlbiOp { + VMALLE1OS = 0b000'0001'000, // ARMv8.4-TLBI + VAE1OS = 0b000'0001'001, // ARMv8.4-TLBI + ASIDE1OS = 0b000'0001'010, // ARMv8.4-TLBI + VAAE1OS = 0b000'0001'011, // ARMv8.4-TLBI + VALE1OS = 0b000'0001'101, // ARMv8.4-TLBI + VAALE1OS = 0b000'0001'111, // ARMv8.4-TLBI + RVAE1IS = 0b000'0010'001, // ARMv8.4-TLBI + RVAAE1IS = 0b000'0010'011, // ARMv8.4-TLBI + RVALE1IS = 0b000'0010'101, // ARMv8.4-TLBI + RVAALE1IS = 0b000'0010'111, // ARMv8.4-TLBI + VMALLE1IS = 0b000'0011'000, + VAE1IS = 0b000'0011'001, + ASIDE1IS = 0b000'0011'010, + VAAE1IS = 0b000'0011'011, + VALE1IS = 0b000'0011'101, + VAALE1IS = 0b000'0011'111, + RVAE1OS = 0b000'0101'001, // ARMv8.4-TLBI + RVAAE1OS = 0b000'0101'011, // ARMv8.4-TLBI + RVALE1OS = 0b000'0101'101, // ARMv8.4-TLBI + RVAALE1OS = 0b000'0101'111, // ARMv8.4-TLBI + RVAE1 = 0b000'0110'001, // ARMv8.4-TLBI + RVAAE1 = 0b000'0110'011, // ARMv8.4-TLBI + RVALE1 = 0b000'0110'101, // ARMv8.4-TLBI + RVAALE1 = 0b000'0110'111, // ARMv8.4-TLBI + VMALLE1 = 0b000'0111'000, + VAE1 = 0b000'0111'001, + ASIDE1 = 0b000'0111'010, + VAAE1 = 0b000'0111'011, + VALE1 = 0b000'0111'101, + VAALE1 = 0b000'0111'111, + IPAS2E1IS = 0b100'0000'001, + RIPAS2E1IS = 0b100'0000'010, // ARMv8.4-TLBI + IPAS2LE1IS = 0b100'0000'101, + RIPAS2LE1IS = 0b100'0000'110, // ARMv8.4-TLBI + ALLE2OS = 0b100'0001'000, // ARMv8.4-TLBI + VAE2OS = 0b100'0001'001, // ARMv8.4-TLBI + ALLE1OS = 0b100'0001'100, // ARMv8.4-TLBI + VALE2OS = 0b100'0001'101, // ARMv8.4-TLBI + VMALLS12E1OS = 0b100'0001'110, // ARMv8.4-TLBI + RVAE2IS = 0b100'0010'001, // ARMv8.4-TLBI + RVALE2IS = 0b100'0010'101, // ARMv8.4-TLBI + ALLE2IS = 0b100'0011'000, + VAE2IS = 0b100'0011'001, + ALLE1IS = 0b100'0011'100, + VALE2IS = 0b100'0011'101, + VMALLS12E1IS = 0b100'0011'110, + IPAS2E1OS = 0b100'0100'000, // ARMv8.4-TLBI + IPAS2E1 = 0b100'0100'001, + RIPAS2E1 = 0b100'0100'010, // ARMv8.4-TLBI + RIPAS2E1OS = 0b100'0100'011, // ARMv8.4-TLBI + IPAS2LE1OS = 0b100'0100'100, // ARMv8.4-TLBI + IPAS2LE1 = 0b100'0100'101, + RIPAS2LE1 = 0b100'0100'110, // ARMv8.4-TLBI + RIPAS2LE1OS = 0b100'0100'111, // ARMv8.4-TLBI + RVAE2OS = 0b100'0101'001, // ARMv8.4-TLBI + RVALE2OS = 0b100'0101'101, // ARMv8.4-TLBI + RVAE2 = 0b100'0110'001, // ARMv8.4-TLBI + RVALE2 = 0b100'0110'101, // ARMv8.4-TLBI + ALLE2 = 0b100'0111'000, + VAE2 = 0b100'0111'001, + ALLE1 = 0b100'0111'100, + VALE2 = 0b100'0111'101, + VMALLS12E1 = 0b100'0111'110, + ALLE3OS = 0b110'0001'000, // ARMv8.4-TLBI + VAE3OS = 0b110'0001'001, // ARMv8.4-TLBI + VALE3OS = 0b110'0001'101, // ARMv8.4-TLBI + RVAE3IS = 0b110'0010'001, // ARMv8.4-TLBI + RVALE3IS = 0b110'0010'101, // ARMv8.4-TLBI + ALLE3IS = 0b110'0011'000, + VAE3IS = 0b110'0011'001, + VALE3IS = 0b110'0011'101, + RVAE3OS = 0b110'0101'001, // ARMv8.4-TLBI + RVALE3OS = 0b110'0101'101, // ARMv8.4-TLBI + RVAE3 = 0b110'0110'001, // ARMv8.4-TLBI + RVALE3 = 0b110'0110'101, // ARMv8.4-TLBI + ALLE3 = 0b110'0111'000, + VAE3 = 0b110'0111'001, + VALE3 = 0b110'0111'101, +}; + +} // namespace oaknut diff --git a/include/oaknut/impl/imm.hpp b/include/oaknut/impl/imm.hpp new file mode 100644 index 0000000..758c6e5 --- /dev/null +++ b/include/oaknut/impl/imm.hpp @@ -0,0 +1,245 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include + +namespace oaknut { + +template +struct Imm { +public: + static_assert(bit_size_ != 0 && bit_size_ <= 32, "Invalid bit_size"); + static constexpr std::size_t bit_size = bit_size_; + static constexpr std::uint32_t mask = (1 << bit_size) - 1; + + constexpr /* implicit */ Imm(std::uint32_t value_) + : m_value(value_) + { + if (!is_valid(value_)) + throw "outsized Imm value"; + } + + constexpr auto operator<=>(const Imm& other) const { return m_value <=> other.m_value; } + constexpr auto operator<=>(std::uint32_t other) const { return operator<=>(Imm{other}); } + + constexpr std::uint32_t value() const { return m_value; } + + static bool is_valid(std::uint32_t value_) + { + return ((value_ & mask) != value_); + } + +private: + friend class CodeGenerator; + std::uint32_t m_value; +}; + +enum class AddSubImmShift { + SHL_0, + SHL_12, +}; + +struct AddSubImm { +public: + constexpr AddSubImm(std::uint16_t value_, AddSubImmShift shift_) + : m_encoded(value_ | ((shift_ == AddSubImmShift::SHL_12) ? 1 << 12 : 0)) + { + if ((value_ & 0xFFF) != value_) + throw "invalid AddSubImm"; + } + + constexpr /* implicit */ AddSubImm(std::uint64_t value_) + { + if ((value_ & 0xFFF) == value_) { + m_encoded = value_; + } else if ((value_ & 0xFFF000) == value_) { + m_encoded = (value_ >> 12) | (1 << 12); + } else { + throw "invalid AddSubImm"; + } + } + + static constexpr bool is_valid(std::uint64_t value_) + { + return ((value_ & 0xFFF) == value_) || ((value_ & 0xFFF000) == value_); + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +enum class MovImm16Shift { + SHL_0, + SHL_16, + SHL_32, + SHL_48, +}; + +struct MovImm16 { +public: + MovImm16(std::uint16_t value_, MovImm16Shift shift_) + : m_encoded(static_cast(value_) | (static_cast(shift_) << 16)) + {} + + constexpr /* implict */ MovImm16(std::uint64_t value_) + { + std::uint32_t shift = 0; + while (value_ != 0) { + const std::uint32_t lsw = static_cast(value_ & 0xFFFF); + if (value_ == lsw) { + m_encoded = lsw | (shift << 16); + return; + } else if (lsw != 0) { + throw "invalid MovImm16"; + } + value_ >>= 16; + shift++; + } + } + + static constexpr bool is_valid(std::uint64_t value_) + { + return ((value_ & 0xFFFF) == value_) || ((value_ & 0xFFFF0000) == value_) || ((value_ & 0xFFFF00000000) == value_) || ((value_ & 0xFFFF000000000000) == value_); + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +namespace detail { + +constexpr std::uint64_t mask_from_esize(std::size_t esize) +{ + return (~std::uint64_t{0}) >> (64 - esize); +} + +constexpr std::optional encode_bit_imm(std::uint32_t value) +{ + const std::uint64_t value_u64 = (static_cast(value) << 32) | static_cast(value); + const auto result = encode_bit_imm(value_u64); + if (result && (*result & 0x3FF) != *result) + return std::nullopt; + return result; +} + +constexpr std::uint64_t inverse_mask_from_trailing_ones(std::uint64_t value) +{ + return ~value | (value + 1); +} + +constexpr std::uint64_t is_contiguous_mask_from_lsb(std::uint64_t value) +{ + return value && ((value + 1) & value) == 0; +} + +constexpr std::optional encode_bit_imm(std::uint64_t value) +{ + if (value == 0 || (~value) == 0) + return std::nullopt; + + const std::size_t esize = [value] { + for (std::size_t esize = 64; esize > 1; esize /= 2) { + if (value != std::rotr(value, esize / 2)) { + return esize; + } + } + return std::size_t{0}; + }(); + + if (esize == 0) + return std::nullopt; + + const std::size_t rotation = std::countr_zero(value & inverse_mask_from_trailing_ones(value)); + const std::uint64_t emask = mask_from_esize(esize); + const std::uint64_t rot_element = std::rotr(value, rotation) & emask; + + if (!is_contiguous_mask_from_lsb(rot_element)) + return std::nullopt; + + const std::uint32_t S = std::popcount(rot_element) - 1; + const std::uint32_t R = rotation & (esize - 1); + + return static_cast(((((-esize) << 7) | (S << 6) | R) ^ 0x1000) & 0x1fff); +} + +} // namespace detail + +struct BitImm32 { +public: + constexpr BitImm32(Imm<6> imms, Imm<6> immr) + : m_encoded((imms.value() << 6) | immr.value()) + {} + + constexpr /* implicit */ BitImm32(std::uint32_t value) + { + const auto encoded = detail::encode_bit_imm(value); + if (!encoded || (*encoded & 0x1000) != 0) + throw "invalid BitImm32"; + m_encoded = *encoded; + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +struct BitImm64 { +public: + constexpr BitImm64(bool N, Imm<6> imms, Imm<6> immr) + : m_encoded((N ? 1 << 12 : 0) | (imms.value() << 6) | immr.value()) + {} + + constexpr /* implicit */ BitImm64(std::uint64_t value) + { + const auto encoded = detail::encode_bit_imm(value); + if (!encoded) + throw "invalid BitImm64"; + m_encoded = *encoded; + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +template +struct ImmChoice { + constexpr /* implicit */ ImmChoice(int value) + { + if (value == A) { + m_encoded = 0; + } else if (value == B) { + m_encoded = 1; + } else { + throw "invalid ImmChoice"; + } + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +template +struct LslShift { + constexpr /* implicit */ LslShift(std::size_t amount) + : m_amount(amount) + { + if (amount >= max_value) + throw "LslShift out of range"; + } + +private: + friend class CodeGenerator; + std::size_t m_amount; +}; + +} // namespace oaknut diff --git a/include/oaknut/impl/multi_typed_name.hpp b/include/oaknut/impl/multi_typed_name.hpp new file mode 100644 index 0000000..c2a00f2 --- /dev/null +++ b/include/oaknut/impl/multi_typed_name.hpp @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +namespace oaknut { + +template +struct MultiTypedName; + +template<> +struct MultiTypedName<> {}; + +template +struct MultiTypedName : public MultiTypedName { + constexpr operator decltype(V)() const { return V; } +}; + +} // namespace oaknut diff --git a/include/oaknut/impl/offset.hpp b/include/oaknut/impl/offset.hpp new file mode 100644 index 0000000..198276a --- /dev/null +++ b/include/oaknut/impl/offset.hpp @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace oaknut { + +namespace detail { + +constexpr std::uint64_t inverse_mask_from_size(std::size_t size) +{ + return (~std::uint64_t{0}) << size; +} + +constexpr std::uint64_t mask_from_size(std::size_t size) +{ + return (~std::uint64_t{0}) >> (64 - size); +} + +template +constexpr std::uint64_t sign_extend(std::uint64_t value) +{ + static_assert(bit_count != 0, "cannot sign-extend zero-sized value"); + constexpr size_t shift_amount = 64 - bit_count; + return static_cast(static_cast(value << shift_amount) >> shift_amount); +} + +} // namespace detail + +template +struct AddrOffset { + AddrOffset(std::ptrdiff_t diff) + { + const std::uint64_t diff_u64 = static_cast(diff); + if (detail::sign_extend(diff_u64) != diff_u64) + throw "out of range"; + if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment))) + throw "misalignment"; + + m_encoded = static_cast((diff_u64 & detail::mask_from_size(bitsize)) >> alignment); + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +template +struct PageOffset { + PageOffset(void* ptr) + : m_ptr(ptr) + {} + +private: + friend class CodeGenerator; + void* m_ptr; +}; + +template +struct SOffset { + SOffset(std::int64_t offset) + { + const std::uint64_t diff_u64 = static_cast(offset); + if (detail::sign_extend(diff_u64) != diff_u64) + throw "out of range"; + if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment))) + throw "misalignment"; + + m_encoded = static_cast((diff_u64 & detail::mask_from_size(bitsize)) >> alignment); + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +template +struct POffset { + POffset(std::int64_t offset) + { + const std::uint64_t diff_u64 = static_cast(offset); + if (diff_u64 > detail::mask_from_size(bitsize)) + throw "out of range"; + if (diff_u64 != (diff_u64 & detail::inverse_mask_from_size(alignment))) + throw "misalignment"; + + m_encoded = static_cast((diff_u64 & detail::mask_from_size(bitsize)) >> alignment); + } + +private: + friend class CodeGenerator; + std::uint32_t m_encoded; +}; + +} // namespace oaknut diff --git a/include/oaknut/impl/reg.hpp b/include/oaknut/impl/reg.hpp new file mode 100644 index 0000000..d8a93b8 --- /dev/null +++ b/include/oaknut/impl/reg.hpp @@ -0,0 +1,138 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +namespace oaknut { + +struct Reg; +struct RReg; +struct ZrReg; +struct WzrReg; +struct XReg; +struct WReg; +struct SpReg; +struct WspReg; +struct XRegSp; +struct XRegWsp; + +struct Reg { + constexpr explicit Reg(bool is_vector_, unsigned bitsize_, int index_) + : m_index(index_) + , m_bitsize(bitsize_) + , m_is_vector(is_vector_) + { + assert(index_ >= -1 && index_ <= 31); + assert(bitsize_ != 0 && (bitsize_ & (bitsize_ - 1)) == 0 && "Bitsize must be a power of two"); + } + + constexpr int index() const { return m_index; } + constexpr unsigned bitsize() const { return m_bitsize; } + constexpr bool is_vector() const { return m_is_vector; } + +private: + int m_index : 8; + unsigned m_bitsize : 8; + bool m_is_vector; +}; + +struct RReg : public Reg { + constexpr explicit RReg(unsigned bitsize_, int index_) + : Reg(false, bitsize_, index_) + { + assert(bitsize_ == 32 || bitsize_ == 64); + } + + XReg toX() const; + WReg toW() const; + + friend class CodeGenerator; +}; + +struct ZrReg : public RReg { + constexpr explicit ZrReg() + : RReg(64, 31) {} +}; + +struct WzrReg : public RReg { + constexpr explicit WzrReg() + : RReg(32, 31) {} +}; + +struct XReg : public RReg { + constexpr explicit XReg(int index_) + : RReg(64, index_) {} + + constexpr /* implicit */ XReg(ZrReg) + : RReg(64, 31) {} + + friend class CodeGenerator; +}; + +struct WReg : public RReg { + constexpr explicit WReg(int index_) + : RReg(32, index_) {} + + constexpr /* implicit */ WReg(WzrReg) + : RReg(32, 31) {} + + friend class CodeGenerator; +}; + +XReg RReg::toX() const +{ + if (index() == -1) + throw "cannot convert SP/WSP to XReg"; + return XReg{index()}; +} + +WReg RReg::toW() const +{ + if (index() == -1) + throw "cannot convert SP/WSP to WReg"; + return WReg{index()}; +} + +struct SpReg : public RReg { + constexpr explicit SpReg() + : RReg(64, -1) {} +}; + +struct WspReg : public RReg { + constexpr explicit WspReg() + : RReg(64, -1) {} +}; + +struct XRegSp : public RReg { + constexpr /* implict */ XRegSp(SpReg) + : RReg(64, -1) {} + + constexpr /* implict */ XRegSp(XReg xr) + : RReg(64, xr.index()) + { + if (xr.index() == 31) + throw "unexpected ZR passed into an XRegSp"; + } + + friend class CodeGenerator; +}; + +struct WRegWsp : public RReg { + constexpr /* implict */ WRegWsp(WspReg) + : RReg(32, -1) {} + + constexpr /* implict */ WRegWsp(WReg wr) + : RReg(32, wr.index()) + { + if (wr.index() == 31) + throw "unexpected WZR passed into an WRegWsp"; + } + + friend class CodeGenerator; +}; + +} // namespace oaknut diff --git a/include/oaknut/impl/string_literal.hpp b/include/oaknut/impl/string_literal.hpp new file mode 100644 index 0000000..6a41582 --- /dev/null +++ b/include/oaknut/impl/string_literal.hpp @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace oaknut { + +template +struct StringLiteral { + constexpr StringLiteral(const char (&str)[N]) + { + std::copy_n(str, N, value); + } + + static constexpr std::size_t strlen = N - 1; + static constexpr std::size_t size = N; + + char value[N]; +}; + +} // namespace oaknut diff --git a/include/oaknut/oaknut.hpp b/include/oaknut/oaknut.hpp new file mode 100644 index 0000000..ecec05f --- /dev/null +++ b/include/oaknut/oaknut.hpp @@ -0,0 +1,248 @@ +// SPDX-FileCopyrightText: 2022 merryhime +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include + +#include "oaknut/impl/enum.hpp" +#include "oaknut/impl/imm.hpp" +#include "oaknut/impl/multi_typed_name.hpp" +#include "oaknut/impl/offset.hpp" +#include "oaknut/impl/reg.hpp" +#include "oaknut/impl/string_literal.hpp" + +namespace oaknut { + +namespace detail { + +template +constexpr std::uint32_t get_bits() +{ + std::uint32_t result = 0; + for (std::size_t i = 0; i < 32; i++) { + for (std::size_t a = 0; a < barg.strlen; a++) { + if (bs.value[i] == barg.value[a]) { + result |= 1 << (31 - i); + } + } + } + return result; +} + +constexpr std::uint32_t pdep(std::uint32_t val, std::uint32_t mask) +{ + std::uint32_t res = 0; + for (std::uint32_t bb = 1; mask; bb += bb) { + if (val & bb) + res |= mask & -mask; + mask &= mask - 1; + } + return res; +} + +} // namespace detail + +class CodeGenerator { +public: + explicit CodeGenerator(std::uint32_t* ptr) + : m_ptr(ptr) + {} + + template + T ptr() + { + static_assert(std::is_pointer_v); + return reinterpret_cast(m_ptr); + } + + void set_ptr(std::uint32_t* ptr) + { + m_ptr = ptr; + } + +#include "oaknut/impl/arm64_mnemonics.inc" + +private: + template + void emit(Ts... args) + { + std::uint32_t encoding = detail::get_bits(); + encoding |= (0 | ... | encode()>(std::forward(args))); + + *m_ptr = encoding; + m_ptr++; + } + +#define OAKNUT_STD_ENCODE(TYPE, ACCESS, SIZE) \ + template \ + std::uint32_t encode(TYPE v) \ + { \ + static_assert(std::popcount(splat) == SIZE); \ + return detail::pdep(static_cast(ACCESS), splat); \ + } + + OAKNUT_STD_ENCODE(RReg, v.index() & 31, 5) + OAKNUT_STD_ENCODE(XReg, v.index() & 31, 5) + OAKNUT_STD_ENCODE(WReg, v.index() & 31, 5) + OAKNUT_STD_ENCODE(XRegSp, v.index() & 31, 5) + OAKNUT_STD_ENCODE(WRegWsp, v.index() & 31, 5) + + OAKNUT_STD_ENCODE(AddSubImm, v.m_encoded, 13) + OAKNUT_STD_ENCODE(BitImm32, v.m_encoded, 12) + OAKNUT_STD_ENCODE(BitImm64, v.m_encoded, 13) + OAKNUT_STD_ENCODE(LslShift<32>, v.m_amount, 12) + OAKNUT_STD_ENCODE(LslShift<64>, v.m_amount, 12) + + OAKNUT_STD_ENCODE(Cond, v, 4) + OAKNUT_STD_ENCODE(AddSubExt, v, 3) + OAKNUT_STD_ENCODE(IndexExt, v, 3) + OAKNUT_STD_ENCODE(AddSubShift, v, 2) + OAKNUT_STD_ENCODE(LogShift, v, 2) + OAKNUT_STD_ENCODE(PstateField, v, 6) + OAKNUT_STD_ENCODE(SystemReg, v, 15) + OAKNUT_STD_ENCODE(AtOp, v, 7) + OAKNUT_STD_ENCODE(BarrierOp, v, 4) + OAKNUT_STD_ENCODE(DcOp, v, 10) + OAKNUT_STD_ENCODE(IcOp, v, 10) + OAKNUT_STD_ENCODE(PrfOp, v, 5) + OAKNUT_STD_ENCODE(TlbiOp, v, 10) + + template + std::uint32_t encode(MovImm16 v) + { + static_assert(std::popcount(splat) == 17 || std::popcount(splat) == 18); + constexpr std::uint32_t mask = (1 << std::popcount(splat)) - 1; + if ((v.m_encoded & mask) != v.m_encoded) + throw "invalid MovImm16"; + return detail::pdep(v.m_encoded, splat); + } + + template + std::uint32_t encode(Imm v) + { + static_assert(std::popcount(splat) >= imm_size); + return detail::pdep(v.value(), splat); + } + + template + std::uint32_t encode(ImmChoice v) + { + static_assert(std::popcount(splat) == 1); + return detail::pdep(v.m_encoded, splat); + } + + template + std::uint32_t encode(AddrOffset v) + { + static_assert(std::popcount(splat) == size - align); + return detail::pdep(v.m_encoded, splat); + } + + template + std::uint32_t encode(PageOffset v) + { + throw "to be implemented"; + } + + template + std::uint32_t encode(SOffset v) + { + static_assert(std::popcount(splat) == size - align); + return detail::pdep(v.m_encoded, splat); + } + + template + std::uint32_t encode(POffset v) + { + static_assert(std::popcount(splat) == size - align); + return detail::pdep(v.m_encoded, splat); + } + + template + std::uint32_t encode(std::uint32_t v) + { + return detail::pdep(v, splat); + } + +#undef OAKNUT_STD_ENCODE + + void addsubext_lsl_correction(AddSubExt& ext, XRegSp) + { + if (ext == AddSubExt::LSL) + ext = AddSubExt::UXTX; + } + void addsubext_lsl_correction(AddSubExt& ext, WRegWsp) + { + if (ext == AddSubExt::LSL) + ext = AddSubExt::UXTW; + } + void addsubext_lsl_correction(AddSubExt& ext, XReg) + { + if (ext == AddSubExt::LSL) + ext = AddSubExt::UXTX; + } + void addsubext_lsl_correction(AddSubExt& ext, WReg) + { + if (ext == AddSubExt::LSL) + ext = AddSubExt::UXTW; + } + + void addsubext_verify_reg_size(AddSubExt ext, RReg rm) + { + if (rm.bitsize() == 32 && (static_cast(ext) & 0b011) != 0b011) + return; + if (rm.bitsize() == 64 && (static_cast(ext) & 0b011) == 0b011) + return; + throw "invalid AddSubExt choice for rm size"; + } + + void indexext_verify_reg_size(IndexExt ext, RReg rm) + { + if (rm.bitsize() == 32 && (static_cast(ext) & 1) == 0) + return; + if (rm.bitsize() == 64 && (static_cast(ext) & 1) == 1) + return; + throw "invalid IndexExt choice for rm size"; + } + + void tbz_verify_reg_size(RReg rt, Imm<6> imm) + { + if (rt.bitsize() == 32 && imm.value() >= 32) + throw "invalid imm choice for rt size"; + } + + std::uint32_t* m_ptr; +}; + +namespace util { + +inline constexpr WReg W0{0}, W1{1}, W2{2}, W3{3}, W4{4}, W5{5}, W6{6}, W7{7}, W8{8}, W9{9}, W10{10}, W11{11}, W12{12}, W13{13}, W14{14}, W15{15}, W16{16}, W17{17}, W18{18}, W19{19}, W20{20}, W21{21}, W22{22}, W23{23}, W24{24}, W25{25}, W26{26}, W27{27}, W28{28}, W29{29}, W30{30}; +inline constexpr XReg X0{0}, X1{1}, X2{2}, X3{3}, X4{4}, X5{5}, X6{6}, X7{7}, X8{8}, X9{9}, X10{10}, X11{11}, X12{12}, X13{13}, X14{14}, X15{15}, X16{16}, X17{17}, X18{18}, X19{19}, X20{20}, X21{21}, X22{22}, X23{23}, X24{24}, X25{25}, X26{26}, X27{27}, X28{28}, X29{29}, X30{30}; +inline constexpr ZrReg ZR{}; +inline constexpr WzrReg WZR{}; +inline constexpr SpReg SP{}; +inline constexpr WspReg WSP{}; + +inline constexpr Cond EQ{Cond::EQ}, NE{Cond::NE}, CS{Cond::CS}, CC{Cond::CC}, MI{Cond::MI}, PL{Cond::PL}, VS{Cond::VS}, VC{Cond::VC}, HI{Cond::HI}, LS{Cond::LS}, GE{Cond::GE}, LT{Cond::LT}, GT{Cond::GT}, LE{Cond::LE}, AL{Cond::AL}, NV{Cond::NV}, HS{Cond::HS}, LO{Cond::LO}; + +inline constexpr auto UXTB{MultiTypedName{}}; +inline constexpr auto UXTH{MultiTypedName{}}; +inline constexpr auto UXTW{MultiTypedName{}}; +inline constexpr auto UXTX{MultiTypedName{}}; +inline constexpr auto SXTB{MultiTypedName{}}; +inline constexpr auto SXTH{MultiTypedName{}}; +inline constexpr auto SXTW{MultiTypedName{}}; +inline constexpr auto SXTX{MultiTypedName{}}; +inline constexpr auto LSL{MultiTypedName{}}; +inline constexpr auto LSR{MultiTypedName{}}; +inline constexpr auto ASR{MultiTypedName{}}; +inline constexpr auto ROR{MultiTypedName{}}; + +inline constexpr PostIndexed POST_INDEXED{}; +inline constexpr PreIndexed PRE_INDEXED{}; + +} // namespace util + +} // namespace oaknut diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..64e8a03 --- /dev/null +++ b/test.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include +#include + +#include "oaknut/oaknut.hpp" + +int main() +{ + const size_t page_size = getpagesize(); + std::printf("page size: %zu\n", page_size); + + std::uint32_t* mem = (std::uint32_t*)mmap(nullptr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_JIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + pthread_jit_write_protect_np(false); + + using namespace oaknut; + using namespace oaknut::util; + + CodeGenerator code{mem}; + code.MOVZ(W0, 42); + code.RET(X30); + + pthread_jit_write_protect_np(true); + sys_icache_invalidate(mem, page_size); + + std::printf("%i\n", ((int (*)())mem)()); + + return 0; +}