about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-03-07 17:48:35 +0100
committerGitHub <noreply@github.com>2024-03-07 17:48:35 +0100
commit4096869c50722c69854a36016265fa86e7836089 (patch)
tree6543d0220f1dac1cf13b99706e57ebe9785f726a /src
parent3cd87e68c78590ee94bd49a81b9a19680665cbc3 (diff)
downloadbox64-4096869c50722c69854a36016265fa86e7836089.tar.gz
box64-4096869c50722c69854a36016265fa86e7836089.zip
[ARM] Added immediate encoding (#1340)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/arm64_immenc.c85
-rw-r--r--src/dynarec/arm64/arm64_immenc.h8
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__