From 27140841c380bc4986e50d21f9a9c63e3bab5833 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Tue, 14 Nov 2023 17:10:51 +0100 Subject: [PATCH 01/17] [RISC-V] Implement Compiler::mapRegNumToDwarfReg --- src/coreclr/jit/unwindriscv64.cpp | 204 +++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 39f2e1c5f58b9..39acf2035b766 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -20,8 +20,208 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #if defined(FEATURE_CFI_SUPPORT) short Compiler::mapRegNumToDwarfReg(regNumber reg) { - NYI_RISCV64("mapRegNumToDwarfReg-----unimplemented on RISCV64 yet----"); - return 0; + short dwarfReg = DWARF_REG_ILLEGAL; + + switch (reg) + { + case REG_R0: + dwarfReg = 0; + break; + case REG_RA: + dwarfReg = 1; + break; + case REG_SP: + dwarfReg = 2; + break; + case REG_GP: + dwarfReg = 3; + break; + case REG_TP: + dwarfReg = 4; + break; + case REG_T0: + dwarfReg = 5; + break; + case REG_T1: + dwarfReg = 6; + break; + case REG_T2: + dwarfReg = 7; + break; + case REG_FP: + dwarfReg = 8; + break; + case REG_S1: + dwarfReg = 9; + break; + case REG_A0: + dwarfReg = 10; + break; + case REG_A1: + dwarfReg = 11; + break; + case REG_A2: + dwarfReg = 12; + break; + case REG_A3: + dwarfReg = 13; + break; + case REG_A4: + dwarfReg = 14; + break; + case REG_A5: + dwarfReg = 15; + break; + case REG_A6: + dwarfReg = 16; + break; + case REG_A7: + dwarfReg = 17; + break; + case REG_S2: + dwarfReg = 18; + break; + case REG_S3: + dwarfReg = 19; + break; + case REG_S4: + dwarfReg = 20; + break; + case REG_S5: + dwarfReg = 21; + break; + case REG_S6: + dwarfReg = 22; + break; + case REG_S7: + dwarfReg = 23; + break; + case REG_S8: + dwarfReg = 24; + break; + case REG_S9: + dwarfReg = 25; + break; + case REG_S10: + dwarfReg = 26; + break; + case REG_S11: + dwarfReg = 27; + break; + case REG_T3: + dwarfReg = 28; + break; + case REG_T4: + dwarfReg = 29; + break; + case REG_T5: + dwarfReg = 30; + break; + case REG_T6: + dwarfReg = 31; + break; + case REG_F0: + dwarfReg = 32; + break; + case REG_F1: + dwarfReg = 33; + break; + case REG_F2: + dwarfReg = 34; + break; + case REG_F3: + dwarfReg = 35; + break; + case REG_F4: + dwarfReg = 36; + break; + case REG_F5: + dwarfReg = 37; + break; + case REG_F6: + dwarfReg = 38; + break; + case REG_F7: + dwarfReg = 39; + break; + case REG_F8: + dwarfReg = 40; + break; + case REG_F9: + dwarfReg = 41; + break; + case REG_F10: + dwarfReg = 42; + break; + case REG_F11: + dwarfReg = 43; + break; + case REG_F12: + dwarfReg = 44; + break; + case REG_F13: + dwarfReg = 45; + break; + case REG_F14: + dwarfReg = 46; + break; + case REG_F15: + dwarfReg = 47; + break; + case REG_F16: + dwarfReg = 48; + break; + case REG_F17: + dwarfReg = 49; + break; + case REG_F18: + dwarfReg = 50; + break; + case REG_F19: + dwarfReg = 51; + break; + case REG_F20: + dwarfReg = 52; + break; + case REG_F21: + dwarfReg = 53; + break; + case REG_F22: + dwarfReg = 54; + break; + case REG_F23: + dwarfReg = 55; + break; + case REG_F24: + dwarfReg = 56; + break; + case REG_F25: + dwarfReg = 57; + break; + case REG_F26: + dwarfReg = 58; + break; + case REG_F27: + dwarfReg = 59; + break; + case REG_F28: + dwarfReg = 60; + break; + case REG_F29: + dwarfReg = 61; + break; + case REG_F30: + dwarfReg = 62; + break; + case REG_F31: + dwarfReg = 63; + break; + + default: + NYI("CFI codes"); + } + + return dwarfReg; } #endif // FEATURE_CFI_SUPPORT From abb371ec66677856439ef6eff1ab10071f5e13d1 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Thu, 16 Nov 2023 15:11:12 +0100 Subject: [PATCH 02/17] [RISC-V] Add BAD_CODE definition --- src/coreclr/jit/instr.h | 2 ++ src/coreclr/jit/instrsriscv64.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index 4ee2a249a489e..8bee87a63c289 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -8,6 +8,8 @@ #ifdef TARGET_LOONGARCH64 #define BAD_CODE 0XFFFFFFFF +#elif TARGET_RISCV64 +#define BAD_CODE 0X00000000 #else #define BAD_CODE 0x0BADC0DE // better not match a real encoding! #endif diff --git a/src/coreclr/jit/instrsriscv64.h b/src/coreclr/jit/instrsriscv64.h index 502a08d716469..9a82a1378d95e 100644 --- a/src/coreclr/jit/instrsriscv64.h +++ b/src/coreclr/jit/instrsriscv64.h @@ -31,7 +31,7 @@ // clang-format off // RV32I & RV64I -INST(invalid, "INVALID", 0, 0x00000000) +INST(invalid, "INVALID", 0, BAD_CODE) INST(nop, "nop", 0, 0x00000013) //// R_R From 9cd08a4f30c1ef267f26cd35c2ca1bb574bcab70 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Thu, 16 Nov 2023 15:56:13 +0100 Subject: [PATCH 03/17] [RISC-V] Implement GetUnwindSizeFromUnwindHeader --- src/coreclr/jit/unwindriscv64.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 39acf2035b766..9435e777e722c 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -412,8 +412,35 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { - NYI_RISCV64("GetUnwindSizeFromUnwindHeader-----unimplemented on RISCV64 yet----"); - return 0; + // 0x00 -> INVALID + // 0x1F -> 48b -> +2B + // 0x3F -> 64b -> +4B + // 0x7F -> >=80b -> +4B or more + // 0x7F : 0xFF -> unused right now + + unsigned size = 1; // 32b + + switch (b1) + { + case 0x00: + size = 0; // INVALID! + break; + case 0x1F: // 48b + size = 2; + break; + case 0x3F: // 64b + size = 4; + break; + case 0x5F: // 48b + size = 2; + break; + case 0x7F: // >=80b + size = 4; + break; + } + + assert(1 <= size && size <= 4); + return size; } #endif // DEBUG From d0b1e3a6f8fbc30e93c36ae8243526edde339985 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 20 Nov 2023 15:56:01 +0100 Subject: [PATCH 04/17] [RISC-V] Implement UnwindPrologCodes::Dump --- src/coreclr/jit/unwindriscv64.cpp | 78 ++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 9435e777e722c..dcb69b1a52623 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -120,6 +120,7 @@ short Compiler::mapRegNumToDwarfReg(regNumber reg) case REG_T6: dwarfReg = 31; break; + case REG_F0: dwarfReg = 32; break; @@ -412,33 +413,28 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { - // 0x00 -> INVALID - // 0x1F -> 48b -> +2B - // 0x3F -> 64b -> +4B - // 0x7F -> >=80b -> +4B or more - // 0x7F : 0xFF -> unused right now - - unsigned size = 1; // 32b - - switch (b1) - { - case 0x00: - size = 0; // INVALID! - break; - case 0x1F: // 48b - size = 2; - break; - case 0x3F: // 64b - size = 4; - break; - case 0x5F: // 48b - size = 2; - break; - case 0x7F: // >=80b - size = 4; - break; - } - + // replaced temporary by arm64 table + static BYTE s_UnwindSize[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10-1F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20-2F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30-3F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40-4F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50-5F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60-6F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70-7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80-8F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90-9F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0-AF + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0-BF + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0-CF + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, // D0-DF + 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F0-FF + }; + + unsigned size = s_UnwindSize[b1]; assert(1 <= size && size <= 4); return size; } @@ -1280,7 +1276,33 @@ void UnwindPrologCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindPrologCodes::Dump(int indent) { - NYI_RISCV64("Dump-----unimplemented on RISCV64 yet----"); + printf("%*sUnwindPrologCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s uwiComp: 0x%08p\n", indent, "", dspPtr(uwiComp)); + printf("%*s &upcMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&upcMemLocal[0])); + printf("%*s upcMem: 0x%08p\n", indent, "", dspPtr(upcMem)); + printf("%*s upcMemSize: %d\n", indent, "", upcMemSize); + printf("%*s upcCodeSlot: %d\n", indent, "", upcCodeSlot); + printf("%*s upcHeaderSlot: %d\n", indent, "", upcHeaderSlot); + printf("%*s upcEpilogSlot: %d\n", indent, "", upcEpilogSlot); + printf("%*s upcUnwindBlockSlot: %d\n", indent, "", upcUnwindBlockSlot); + + if (upcMemSize > 0) + { + printf("%*s codes:", indent, ""); + for (int i = 0; i < upcMemSize; i++) + { + printf(" %02x", upcMem[i]); + if (i == upcCodeSlot) + printf(" <-C"); + else if (i == upcHeaderSlot) + printf(" <-H"); + else if (i == upcEpilogSlot) + printf(" <-E"); + else if (i == upcUnwindBlockSlot) + printf(" <-U"); + } + printf("\n"); + } } #endif // DEBUG From e6ef7babb338ab138d63ae13783e592b29bae4bf Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 20 Nov 2023 16:06:18 +0100 Subject: [PATCH 05/17] [RISC-V] Implement UnwindEpilogCodes::Dump --- src/coreclr/jit/unwindriscv64.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index dcb69b1a52623..ed6afbed382e8 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -1341,7 +1341,25 @@ void UnwindEpilogCodes::EnsureSize(int requiredSize) #ifdef DEBUG void UnwindEpilogCodes::Dump(int indent) { - NYI_RISCV64("Dump-----unimplemented on RISCV64 yet----"); + printf("%*sUnwindEpilogCodes @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s uwiComp: 0x%08p\n", indent, "", dspPtr(uwiComp)); + printf("%*s &uecMemLocal[0]: 0x%08p\n", indent, "", dspPtr(&uecMemLocal[0])); + printf("%*s uecMem: 0x%08p\n", indent, "", dspPtr(uecMem)); + printf("%*s uecMemSize: %d\n", indent, "", uecMemSize); + printf("%*s uecCodeSlot: %d\n", indent, "", uecCodeSlot); + printf("%*s uecFinalized: %s\n", indent, "", dspBool(uecFinalized)); + + if (uecMemSize > 0) + { + printf("%*s codes:", indent, ""); + for (int i = 0; i < uecMemSize; i++) + { + printf(" %02x", uecMem[i]); + if (i == uecCodeSlot) + printf(" <-C"); // Indicate the current pointer + } + printf("\n"); + } } #endif // DEBUG From 8686b272546ebf38f46de33cfdb886cb9ab796fb Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 20 Nov 2023 16:16:52 +0100 Subject: [PATCH 06/17] [RISC-V] Implement UnwindEpilogInfo::Dump --- src/coreclr/jit/unwindriscv64.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index ed6afbed382e8..151cc4de1bfcb 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -1416,7 +1416,15 @@ void UnwindEpilogInfo::FinalizeOffset() #ifdef DEBUG void UnwindEpilogInfo::Dump(int indent) { - NYI_RISCV64("Dump-----unimplemented on RISCV64 yet----"); + printf("%*sUnwindEpilogInfo @0x%08p, size:%d:\n", indent, "", dspPtr(this), sizeof(*this)); + printf("%*s uwiComp: 0x%08p\n", indent, "", dspPtr(uwiComp)); + printf("%*s epiNext: 0x%08p\n", indent, "", dspPtr(epiNext)); + printf("%*s epiEmitLocation: 0x%08p\n", indent, "", dspPtr(epiEmitLocation)); + printf("%*s epiStartOffset: 0x%x\n", indent, "", epiStartOffset); + printf("%*s epiMatches: %s\n", indent, "", dspBool(epiMatches)); + printf("%*s epiStartIndex: %d\n", indent, "", epiStartIndex); + + epiCodes.Dump(indent + 2); } #endif // DEBUG From 2e63acc543339d3ad9fb1e9d9dbd9a6c013322ef Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 20 Nov 2023 16:22:39 +0100 Subject: [PATCH 07/17] [Risc-V] Implement UnwindFragmentInfo::Dump --- src/coreclr/jit/unwindriscv64.cpp | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 151cc4de1bfcb..74742f6d2b2bb 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -1961,7 +1961,39 @@ void UnwindFragmentInfo::Allocate( #ifdef DEBUG void UnwindFragmentInfo::Dump(int indent) { - NYI_RISCV64("Dump-----unimplemented on RISCV64 yet----"); + unsigned count; + UnwindEpilogInfo* pEpi; + + count = 0; + for (pEpi = ufiEpilogList; pEpi != NULL; pEpi = pEpi->epiNext) + { + ++count; + } + + printf("%*sUnwindFragmentInfo #%d, @0x%08p, size:%d:\n", indent, "", ufiNum, dspPtr(this), sizeof(*this)); + printf("%*s uwiComp: 0x%08p\n", indent, "", dspPtr(uwiComp)); + printf("%*s ufiNext: 0x%08p\n", indent, "", dspPtr(ufiNext)); + printf("%*s ufiEmitLoc: 0x%08p\n", indent, "", dspPtr(ufiEmitLoc)); + printf("%*s ufiHasPhantomProlog: %s\n", indent, "", dspBool(ufiHasPhantomProlog)); + printf("%*s %d epilog%s\n", indent, "", count, (count != 1) ? "s" : ""); + printf("%*s ufiEpilogList: 0x%08p\n", indent, "", dspPtr(ufiEpilogList)); + printf("%*s ufiEpilogLast: 0x%08p\n", indent, "", dspPtr(ufiEpilogLast)); + printf("%*s ufiCurCodes: 0x%08p\n", indent, "", dspPtr(ufiCurCodes)); + printf("%*s ufiSize: %u\n", indent, "", ufiSize); + printf("%*s ufiSetEBit: %s\n", indent, "", dspBool(ufiSetEBit)); + printf("%*s ufiNeedExtendedCodeWordsEpilogCount: %s\n", indent, "", dspBool(ufiNeedExtendedCodeWordsEpilogCount)); + printf("%*s ufiCodeWords: %u\n", indent, "", ufiCodeWords); + printf("%*s ufiEpilogScopes: %u\n", indent, "", ufiEpilogScopes); + printf("%*s ufiStartOffset: 0x%x\n", indent, "", ufiStartOffset); + printf("%*s ufiInProlog: %s\n", indent, "", dspBool(ufiInProlog)); + printf("%*s ufiInitialized: 0x%08x\n", indent, "", ufiInitialized); + + ufiPrologCodes.Dump(indent + 2); + + for (pEpi = ufiEpilogList; pEpi != NULL; pEpi = pEpi->epiNext) + { + pEpi->Dump(indent + 2); + } } #endif // DEBUG From 133b96e21a82cb0aca136851bf20c77030980ca2 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 20 Nov 2023 16:27:17 +0100 Subject: [PATCH 08/17] [RISC-V] Implement UnwindInfo::HotColdSplitCodes --- src/coreclr/jit/unwindriscv64.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 74742f6d2b2bb..b3414bf741533 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -2036,7 +2036,18 @@ void UnwindInfo::InitUnwindInfo(Compiler* comp, emitLocation* startLoc, emitLoca void UnwindInfo::HotColdSplitCodes(UnwindInfo* puwi) { - NYI_RISCV64("HotColdSplitCodes-----unimplemented on RISCV64 yet----"); + // Ensure that there is exactly a single fragment in both the hot and the cold sections + assert(&uwiFragmentFirst == uwiFragmentLast); + assert(&puwi->uwiFragmentFirst == puwi->uwiFragmentLast); + assert(uwiFragmentLast->ufiNext == NULL); + assert(puwi->uwiFragmentLast->ufiNext == NULL); + + // The real prolog is in the hot section, so this, cold, section has a phantom prolog + uwiFragmentLast->ufiHasPhantomProlog = true; + uwiFragmentLast->CopyPrologCodes(puwi->uwiFragmentLast); + + // Now split the epilog codes + uwiFragmentLast->SplitEpilogCodes(uwiFragmentLast->ufiEmitLoc, puwi->uwiFragmentLast); } // Split the function or funclet into fragments that are no larger than 512K, From 231773ff5248ed9269d6ca28377710a4f73ce87b Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Tue, 21 Nov 2023 09:33:39 +0100 Subject: [PATCH 09/17] [RISC-V] Implement UnwindInfo::Dump --- src/coreclr/jit/unwindriscv64.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index b3414bf741533..eabde5291f25a 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -2260,7 +2260,26 @@ void UnwindInfo::AddFragment(emitLocation* emitLoc) void UnwindInfo::Dump(bool isHotCode, int indent) { - NYI_RISCV64("Dump-----unimplemented on RISCV64 yet----"); + unsigned count; + UnwindFragmentInfo* pFrag; + + count = 0; + for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) + { + ++count; + } + + printf("%*sUnwindInfo %s@0x%08p, size:%d:\n", indent, "", isHotCode ? "" : "COLD ", dspPtr(this), sizeof(*this)); + printf("%*s uwiComp: 0x%08p\n", indent, "", dspPtr(uwiComp)); + printf("%*s %d fragment%s\n", indent, "", count, (count != 1) ? "s" : ""); + printf("%*s uwiFragmentLast: 0x%08p\n", indent, "", dspPtr(uwiFragmentLast)); + printf("%*s uwiEndLoc: 0x%08p\n", indent, "", dspPtr(uwiEndLoc)); + printf("%*s uwiInitialized: 0x%08x\n", indent, "", uwiInitialized); + + for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) + { + pFrag->Dump(indent + 2); + } } #endif // DEBUG From c5c3633437ccfdd34792eab47dc06466d99afd1e Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Wed, 22 Nov 2023 16:32:36 +0100 Subject: [PATCH 10/17] [RISC-V] Partly fix for previous implementation of GetUnwindSizeFromUnwindHeader --- src/coreclr/jit/unwindriscv64.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index eabde5291f25a..1aaae13a0aa37 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -219,7 +219,7 @@ short Compiler::mapRegNumToDwarfReg(regNumber reg) break; default: - NYI("CFI codes"); + NYI("CFI codes"); // e.g. V-extension } return dwarfReg; @@ -413,7 +413,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { - // replaced temporary by arm64 table static BYTE s_UnwindSize[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F @@ -428,9 +427,9 @@ unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90-9F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0-AF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0-BF - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0-CF - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, // D0-DF - 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF + 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, // C0-CF + 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 1, // D0-DF + 4, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F0-FF }; @@ -1087,13 +1086,11 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode void UnwindPrologCodes::SetFinalSize(int headerBytes, int epilogBytes) { -#if 0 // TODO COMMENTED OUT BECAUSE s_UnwindSize is not set #ifdef DEBUG // We're done adding codes. Check that we didn't accidentally create a bigger prolog. unsigned codeSize = GetCodeSizeFromUnwindCodes(true); assert(codeSize <= MAX_PROLOG_SIZE_BYTES); #endif // DEBUG -#endif int prologBytes = Size(); From 27a9bde1cc58ce6f3a114ec30c80a159e14ee472 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Thu, 23 Nov 2023 10:34:21 +0100 Subject: [PATCH 11/17] [RISC-V] Mark s_UnwindSize as const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz SowiƄski --- src/coreclr/jit/unwindriscv64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 1aaae13a0aa37..334f6159a4982 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -413,7 +413,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { - static BYTE s_UnwindSize[256] = { + static const BYTE s_UnwindSize[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10-1F From b663275caee236a44acb52ecdf38f03bf3fd1ea1 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Thu, 23 Nov 2023 10:58:16 +0100 Subject: [PATCH 12/17] [RISC-V] Replace NULL with nullptr in new functions --- src/coreclr/jit/unwindriscv64.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 334f6159a4982..f76c44930501e 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -120,7 +120,6 @@ short Compiler::mapRegNumToDwarfReg(regNumber reg) case REG_T6: dwarfReg = 31; break; - case REG_F0: dwarfReg = 32; break; @@ -1962,7 +1961,7 @@ void UnwindFragmentInfo::Dump(int indent) UnwindEpilogInfo* pEpi; count = 0; - for (pEpi = ufiEpilogList; pEpi != NULL; pEpi = pEpi->epiNext) + for (pEpi = ufiEpilogList; pEpi != nullptr; pEpi = pEpi->epiNext) { ++count; } @@ -1987,7 +1986,7 @@ void UnwindFragmentInfo::Dump(int indent) ufiPrologCodes.Dump(indent + 2); - for (pEpi = ufiEpilogList; pEpi != NULL; pEpi = pEpi->epiNext) + for (pEpi = ufiEpilogList; pEpi != nullptr; pEpi = pEpi->epiNext) { pEpi->Dump(indent + 2); } @@ -2036,8 +2035,8 @@ void UnwindInfo::HotColdSplitCodes(UnwindInfo* puwi) // Ensure that there is exactly a single fragment in both the hot and the cold sections assert(&uwiFragmentFirst == uwiFragmentLast); assert(&puwi->uwiFragmentFirst == puwi->uwiFragmentLast); - assert(uwiFragmentLast->ufiNext == NULL); - assert(puwi->uwiFragmentLast->ufiNext == NULL); + assert(uwiFragmentLast->ufiNext == nullptr); + assert(puwi->uwiFragmentLast->ufiNext == nullptr); // The real prolog is in the hot section, so this, cold, section has a phantom prolog uwiFragmentLast->ufiHasPhantomProlog = true; @@ -2261,7 +2260,7 @@ void UnwindInfo::Dump(bool isHotCode, int indent) UnwindFragmentInfo* pFrag; count = 0; - for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) + for (pFrag = &uwiFragmentFirst; pFrag != nullptr; pFrag = pFrag->ufiNext) { ++count; } @@ -2273,7 +2272,7 @@ void UnwindInfo::Dump(bool isHotCode, int indent) printf("%*s uwiEndLoc: 0x%08p\n", indent, "", dspPtr(uwiEndLoc)); printf("%*s uwiInitialized: 0x%08x\n", indent, "", uwiInitialized); - for (pFrag = &uwiFragmentFirst; pFrag != NULL; pFrag = pFrag->ufiNext) + for (pFrag = &uwiFragmentFirst; pFrag != nullptr; pFrag = pFrag->ufiNext) { pFrag->Dump(indent + 2); } From f0d364e593b9933c2cc92bae75d1a17eeed53606 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Fri, 24 Nov 2023 09:35:26 +0100 Subject: [PATCH 13/17] [RISC-V] Fix formatting and shorten mapRegNumToDwarfReg --- src/coreclr/jit/instrsriscv64.h | 2 +- src/coreclr/jit/unwindriscv64.cpp | 222 +++--------------------------- 2 files changed, 18 insertions(+), 206 deletions(-) diff --git a/src/coreclr/jit/instrsriscv64.h b/src/coreclr/jit/instrsriscv64.h index 9a82a1378d95e..f38f3752e2782 100644 --- a/src/coreclr/jit/instrsriscv64.h +++ b/src/coreclr/jit/instrsriscv64.h @@ -9,7 +9,7 @@ * ld/st/cmp -- load/store/compare instruction * encode -- encoding 1 * -******************************************************************************/ + ******************************************************************************/ #if !defined(TARGET_RISCV64) #error Unexpected target type diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index f76c44930501e..6b51643dfaeed 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -22,203 +22,15 @@ short Compiler::mapRegNumToDwarfReg(regNumber reg) { short dwarfReg = DWARF_REG_ILLEGAL; - switch (reg) + // On RISC-V registers from R0 to F31 + // can be mapped directly to dwarf structure + if (reg >= REG_R0 && reg <= REG_F31) { - case REG_R0: - dwarfReg = 0; - break; - case REG_RA: - dwarfReg = 1; - break; - case REG_SP: - dwarfReg = 2; - break; - case REG_GP: - dwarfReg = 3; - break; - case REG_TP: - dwarfReg = 4; - break; - case REG_T0: - dwarfReg = 5; - break; - case REG_T1: - dwarfReg = 6; - break; - case REG_T2: - dwarfReg = 7; - break; - case REG_FP: - dwarfReg = 8; - break; - case REG_S1: - dwarfReg = 9; - break; - case REG_A0: - dwarfReg = 10; - break; - case REG_A1: - dwarfReg = 11; - break; - case REG_A2: - dwarfReg = 12; - break; - case REG_A3: - dwarfReg = 13; - break; - case REG_A4: - dwarfReg = 14; - break; - case REG_A5: - dwarfReg = 15; - break; - case REG_A6: - dwarfReg = 16; - break; - case REG_A7: - dwarfReg = 17; - break; - case REG_S2: - dwarfReg = 18; - break; - case REG_S3: - dwarfReg = 19; - break; - case REG_S4: - dwarfReg = 20; - break; - case REG_S5: - dwarfReg = 21; - break; - case REG_S6: - dwarfReg = 22; - break; - case REG_S7: - dwarfReg = 23; - break; - case REG_S8: - dwarfReg = 24; - break; - case REG_S9: - dwarfReg = 25; - break; - case REG_S10: - dwarfReg = 26; - break; - case REG_S11: - dwarfReg = 27; - break; - case REG_T3: - dwarfReg = 28; - break; - case REG_T4: - dwarfReg = 29; - break; - case REG_T5: - dwarfReg = 30; - break; - case REG_T6: - dwarfReg = 31; - break; - case REG_F0: - dwarfReg = 32; - break; - case REG_F1: - dwarfReg = 33; - break; - case REG_F2: - dwarfReg = 34; - break; - case REG_F3: - dwarfReg = 35; - break; - case REG_F4: - dwarfReg = 36; - break; - case REG_F5: - dwarfReg = 37; - break; - case REG_F6: - dwarfReg = 38; - break; - case REG_F7: - dwarfReg = 39; - break; - case REG_F8: - dwarfReg = 40; - break; - case REG_F9: - dwarfReg = 41; - break; - case REG_F10: - dwarfReg = 42; - break; - case REG_F11: - dwarfReg = 43; - break; - case REG_F12: - dwarfReg = 44; - break; - case REG_F13: - dwarfReg = 45; - break; - case REG_F14: - dwarfReg = 46; - break; - case REG_F15: - dwarfReg = 47; - break; - case REG_F16: - dwarfReg = 48; - break; - case REG_F17: - dwarfReg = 49; - break; - case REG_F18: - dwarfReg = 50; - break; - case REG_F19: - dwarfReg = 51; - break; - case REG_F20: - dwarfReg = 52; - break; - case REG_F21: - dwarfReg = 53; - break; - case REG_F22: - dwarfReg = 54; - break; - case REG_F23: - dwarfReg = 55; - break; - case REG_F24: - dwarfReg = 56; - break; - case REG_F25: - dwarfReg = 57; - break; - case REG_F26: - dwarfReg = 58; - break; - case REG_F27: - dwarfReg = 59; - break; - case REG_F28: - dwarfReg = 60; - break; - case REG_F29: - dwarfReg = 61; - break; - case REG_F30: - dwarfReg = 62; - break; - case REG_F31: - dwarfReg = 63; - break; - - default: - NYI("CFI codes"); // e.g. V-extension + dwarfReg = static_cast(reg); + } + else + { + NYI("CFI codes"); // e.g. V-extension } return dwarfReg; @@ -366,8 +178,8 @@ void Compiler::unwindSaveReg(regNumber reg, int offset) { // save_reg: 11010000 | 000xxxxx | zzzzzzzz: save reg r(1 + #X) at [sp + #Z * 8], offset <= 2047 - assert(reg == REG_RA || - (REG_FP <= reg && reg <= REG_S11)); // first legal register: RA, last legal register: S11 + assert(reg == REG_RA || (REG_FP <= reg && reg <= REG_S11)); // first legal register: RA, last legal register: + // S11 BYTE x = (BYTE)(reg - REG_RA); assert(0 <= x && x <= 0x1B); @@ -413,7 +225,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { static const BYTE s_UnwindSize[256] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F + // 0 1 2 3 4 5 6 7 8 9 A B C D E F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10-1F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20-2F @@ -515,7 +327,7 @@ void DumpUnwindInfo(Compiler* comp, // pHeader is not guaranteed to be aligned. We put four 0xFF end codes at the end // to provide padding, and round down to get a multiple of 4 bytes in size. DWORD UNALIGNED* pdw = (DWORD UNALIGNED*)pHeader; - DWORD dw; + DWORD dw; dw = *pdw++; @@ -1148,9 +960,9 @@ void UnwindPrologCodes::AppendEpilog(UnwindEpilogInfo* pEpi) int epiSize = pEpi->Size(); memcpy_s(&upcMem[upcEpilogSlot], upcMemSize - upcEpilogSlot - 3, pEpi->GetCodes(), - epiSize); // -3 to avoid writing to the alignment padding - assert(pEpi->GetStartIndex() == - upcEpilogSlot - upcCodeSlot); // Make sure we copied it where we expected to copy it. + epiSize); // -3 to avoid writing to the alignment padding + assert(pEpi->GetStartIndex() == upcEpilogSlot - upcCodeSlot); // Make sure we copied it where we expected to copy + // it. upcEpilogSlot += epiSize; assert(upcEpilogSlot <= upcMemSize - 3); @@ -1771,8 +1583,8 @@ void UnwindFragmentInfo::Finalize(UNATIVE_OFFSET functionLength) // Start writing the header - noway_assert(headerFunctionLength <= - 0x3FFFFU); // We create fragments to prevent this from firing, so if it hits, we have an internal error + noway_assert(headerFunctionLength <= 0x3FFFFU); // We create fragments to prevent this from firing, so if it hits, + // we have an internal error if ((headerEpilogCount > UW_MAX_EPILOG_COUNT) || (headerCodeWords > UW_MAX_CODE_WORDS_COUNT)) { From a51dbe25412158a2f029c7d89edec8f20ec08867 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Fri, 24 Nov 2023 10:08:04 +0100 Subject: [PATCH 14/17] [RISC-V] Apply format.linux.x64.patch --- src/coreclr/jit/unwindriscv64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 6b51643dfaeed..e40d4849b17e2 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -327,7 +327,7 @@ void DumpUnwindInfo(Compiler* comp, // pHeader is not guaranteed to be aligned. We put four 0xFF end codes at the end // to provide padding, and round down to get a multiple of 4 bytes in size. DWORD UNALIGNED* pdw = (DWORD UNALIGNED*)pHeader; - DWORD dw; + DWORD dw; dw = *pdw++; From 0d47fafef2a76556941f4542d9c9c16146a342dc Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Fri, 24 Nov 2023 10:18:16 +0100 Subject: [PATCH 15/17] [RISC-V] Add braces according to coding standard in jit --- src/coreclr/jit/unwindriscv64.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index e40d4849b17e2..566fd039fb225 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -1101,13 +1101,21 @@ void UnwindPrologCodes::Dump(int indent) { printf(" %02x", upcMem[i]); if (i == upcCodeSlot) + { printf(" <-C"); + } else if (i == upcHeaderSlot) + { printf(" <-H"); + } else if (i == upcEpilogSlot) + { printf(" <-E"); + } else if (i == upcUnwindBlockSlot) + { printf(" <-U"); + } } printf("\n"); } @@ -1164,7 +1172,9 @@ void UnwindEpilogCodes::Dump(int indent) { printf(" %02x", uecMem[i]); if (i == uecCodeSlot) + { printf(" <-C"); // Indicate the current pointer + } } printf("\n"); } From 3beb303b554d81f2f964f6052b4113a13e63422b Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Fri, 24 Nov 2023 13:05:16 +0100 Subject: [PATCH 16/17] [RISC-V] Correct array of unwind sizes --- src/coreclr/jit/unwindriscv64.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 566fd039fb225..94f76208730c6 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -225,21 +225,21 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) { static const BYTE s_UnwindSize[256] = { - // 0 1 2 3 4 5 6 7 8 9 A B C D E F + // array of unwind sizes, in bytes 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10-1F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20-2F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30-3F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40-4F + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 40-4F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50-5F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60-6F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70-7F - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80-8F + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 80-8F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90-9F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0-AF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0-BF 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, // C0-CF - 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 1, // D0-DF + 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 1, // D0-DF 4, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F0-FF }; From 363c1e5579a604c2b92f6587d4fc41bd61237c74 Mon Sep 17 00:00:00 2001 From: Tymoteusz Wenerski Date: Mon, 27 Nov 2023 11:31:21 +0100 Subject: [PATCH 17/17] [RISC-V] Fix s_UnwindSize: 0xDE=2, 0xDD=3 --- src/coreclr/jit/unwindriscv64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/unwindriscv64.cpp b/src/coreclr/jit/unwindriscv64.cpp index 94f76208730c6..b78eb04c228e9 100644 --- a/src/coreclr/jit/unwindriscv64.cpp +++ b/src/coreclr/jit/unwindriscv64.cpp @@ -239,7 +239,7 @@ unsigned GetUnwindSizeFromUnwindHeader(BYTE b1) 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0-AF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0-BF 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, // C0-CF - 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 1, // D0-DF + 3, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 1, // D0-DF 4, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F0-FF };