diff options
| author | rajdakin <rajdakin@gmail.com> | 2024-03-07 17:48:35 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-07 17:48:35 +0100 |
| commit | 4096869c50722c69854a36016265fa86e7836089 (patch) | |
| tree | 6543d0220f1dac1cf13b99706e57ebe9785f726a /src | |
| parent | 3cd87e68c78590ee94bd49a81b9a19680665cbc3 (diff) | |
| download | box64-4096869c50722c69854a36016265fa86e7836089.tar.gz box64-4096869c50722c69854a36016265fa86e7836089.zip | |
[ARM] Added immediate encoding (#1340)
Diffstat (limited to 'src')
| -rw-r--r-- | src/dynarec/arm64/arm64_immenc.c | 85 | ||||
| -rw-r--r-- | src/dynarec/arm64/arm64_immenc.h | 8 |
2 files changed, 93 insertions, 0 deletions
diff --git a/src/dynarec/arm64/arm64_immenc.c b/src/dynarec/arm64/arm64_immenc.c new file mode 100644 index 00000000..5cedf22e --- /dev/null +++ b/src/dynarec/arm64/arm64_immenc.c @@ -0,0 +1,85 @@ +#include <stdint.h> +#include "arm64_immenc.h" + +#define one (uint64_t)1 + +// Returns the packed valid-N-imms-immr (1-1-6-6 bits); returns 0 if bitmask is not encodable +int convert_bitmask(uint64_t bitmask) { + if (!bitmask || !~bitmask) return 0; + + uint64_t size, mask, pat; + + for (size = 6; size > 1; --size) { + mask = (one << (1 << (size - 1))) - 1; + pat = bitmask & mask; + // printf("%016lX/%lu: %016lX %016lX %2d\n", bitmask, size, mask, pat, (1 << (size - 1))); + if (pat != ((bitmask >> (1 << (size - 1))) & mask)) { + // printf("%016lX/%lu: %016lX %016lX xx\n", bitmask, size, pat, (bitmask >> (1 << (size - 1))) & mask); + break; + } + } + mask = (size >= 6) ? ((uint64_t)-1) : ((one << (1 << size)) - 1); + pat = bitmask & mask; + for (uint64_t i = 1; i < 7 - size; ++i) { + uint64_t boff = i * (1 << size); + if (((bitmask >> boff) & mask) != pat) { + // printf("%016lX/%lu: no %lu %lu %016lX %016lX %016lX\n", bitmask, size, i, size, boff, mask, pat); + return 0; + } + } + // Note that here, pat != 0 and ~pat & (1 << size) != 0 (otherwise size = 1 and bitmask = all 0 or all 1) + int immr = 0; + uint64_t last_bit = one << ((1 << size) - 1); + // printf("%016lX/%lu: %016lX %016lX %lu\n", bitmask, size, mask, pat, last_bit); + if (pat & 1) { + while (pat & last_bit) { + pat = ((pat - last_bit) << 1) + 1; + ++immr; + } + } else { + immr = 1 << size; + while (!(pat & 1)) { + pat >>= 1; + --immr; + } + } + // printf("%016lX/%lu: %016lX %016lX %lu %d\n", bitmask, size, mask, pat, last_bit, immr); + if (pat & (pat + 1)) return 0; // Not 0...01...1 + int to = 1; + while (pat & (one << to)) ++to; + + return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr; +} + +#if 0 +#include <unordered_set> +int main() { + std::unordered_set<uint64_t> okvals; + uint64_t val; + for (int n = 1; n < 7; ++n) { + int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F); + for (int nones = 0; nones < (1 << n) - 1; ++nones) { + val = (one << (nones + 1)) - 1; + for (int j = 0; j < 6 - n; ++j) { + val = val + (val << (1 << (n + j))); + } + for (int immr = 0; immr < (1 << n); ++immr) { + int exp = ((imms0 + nones) << 6) + immr; + int got = convert_bitmask(val); + if (exp != got) { + printf("0x%016lX: expected %04X, got %04X\n", val, exp, got); + } + okvals.emplace(val); + val = (val >> 1) + ((val & 1) << 63); + } + } + } +#pragma omp parallel for + for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) { + int got = convert_bitmask(val); + if (!!got != (okvals.find(val) != okvals.cend())) { + printf("0x%016lX: expected %s, got %04X\n", val, (!!got ? "0000" : "non0"), got); + } + } +} +#endif diff --git a/src/dynarec/arm64/arm64_immenc.h b/src/dynarec/arm64/arm64_immenc.h new file mode 100644 index 00000000..898df236 --- /dev/null +++ b/src/dynarec/arm64/arm64_immenc.h @@ -0,0 +1,8 @@ +#ifndef __ARM64_IMMENC_H__ +#define __ARM64_IMMENC_H__ + +#include <stdint.h> + +int convert_bitmask(uint64_t bitmask); + +#endif // __ARM64_IMMENC_H__ |