Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
compiler_a64.c
1/* Copyright (c) 2020 tevador <tevador@gmail.com> */
2/* See LICENSE for licensing information */
3
4#include <string.h>
5#include <assert.h>
6
7#include "compiler.h"
8#include "program.h"
9#include "virtual_memory.h"
10#include "unreachable.h"
11
12#define EMIT(p,x) do { \
13 memcpy(p, x, sizeof(x)); \
14 p += sizeof(x); \
15 } while (0)
16#define EMIT_U32(p,x) *((uint32_t*)(p)) = x; p += sizeof(uint32_t)
17#define EMIT_IMM32(p,x) \
18 EMIT_U32(p, 0x9280000c | \
19 ((x <= INT32_MAX) << 30) | \
20 (((x <= INT32_MAX) ? (x & 0xFFFF) : (~x & 0xFFFF)) << 5)); \
21 EMIT_U32(p, 0xf2a0000c | \
22 (((x >> 16) & 0xFFFF) << 5));
23
24#ifdef HASHX_COMPILER_A64
25
26/* Largest compiled instruction (BRANCH) */
27#define COMP_MAX_INSTR_SIZE 24
28
29static const uint8_t a64_prologue[] = {
30 0x07, 0x1c, 0x40, 0xf9, /* ldr x7, [x0, #56] */
31 0x06, 0x18, 0x40, 0xf9, /* ldr x6, [x0, #48] */
32 0x05, 0x14, 0x40, 0xf9, /* ldr x5, [x0, #40] */
33 0x04, 0x10, 0x40, 0xf9, /* ldr x4, [x0, #32] */
34 0x03, 0x0c, 0x40, 0xf9, /* ldr x3, [x0, #24] */
35 0x02, 0x08, 0x40, 0xf9, /* ldr x2, [x0, #16] */
36 0x01, 0x04, 0x40, 0xf9, /* ldr x1, [x0, #8] */
37 0xe8, 0x03, 0x00, 0xaa, /* mov x8, x0 */
38 0x00, 0x00, 0x40, 0xf9, /* ldr x0, [x0] */
39 0xe9, 0x03, 0x1f, 0x2a, /* mov w9, wzr */
40};
41
42static const uint8_t a64_epilogue[] = {
43 0x00, 0x01, 0x00, 0xf9, /* str x0, [x8] */
44 0x01, 0x05, 0x00, 0xf9, /* str x1, [x8, #8] */
45 0x02, 0x09, 0x00, 0xf9, /* str x2, [x8, #16] */
46 0x03, 0x0d, 0x00, 0xf9, /* str x3, [x8, #24] */
47 0x04, 0x11, 0x00, 0xf9, /* str x4, [x8, #32] */
48 0x05, 0x15, 0x00, 0xf9, /* str x5, [x8, #40] */
49 0x06, 0x19, 0x00, 0xf9, /* str x6, [x8, #48] */
50 0x07, 0x1d, 0x00, 0xf9, /* str x7, [x8, #56] */
51 0xc0, 0x03, 0x5f, 0xd6, /* ret */
52};
53
54bool hashx_compile_a64(const hashx_program* program, uint8_t* code) {
55 if (!hashx_vm_rw(code, COMP_CODE_SIZE))
56 return false;
57 uint8_t* pos = code;
58 uint8_t* target = NULL;
59 int creg = -1;
60 EMIT(pos, a64_prologue);
61 for (size_t i = 0; i < program->code_size; ++i) {
62 if (pos + COMP_MAX_INSTR_SIZE > code + COMP_CODE_SIZE)
63 return false;
64 const instruction* instr = &program->code[i];
65 switch (instr->opcode)
66 {
67 case INSTR_UMULH_R:
68 EMIT_U32(pos, 0x9bc07c00 |
69 (instr->src << 16) |
70 (instr->dst << 5) |
71 (instr->dst));
72 if (target != NULL) {
73 creg = instr->dst;
74 }
75 break;
76 case INSTR_SMULH_R:
77 EMIT_U32(pos, 0x9b407c00 |
78 (instr->src << 16) |
79 (instr->dst << 5) |
80 (instr->dst));
81 if (target != NULL) {
82 creg = instr->dst;
83 }
84 break;
85 case INSTR_MUL_R:
86 assert(creg != instr->dst);
87 EMIT_U32(pos, 0x9b007c00 |
88 (instr->src << 16) |
89 (instr->dst << 5) |
90 (instr->dst));
91 break;
92 case INSTR_SUB_R:
93 assert(creg != instr->dst);
94 EMIT_U32(pos, 0xcb000000 |
95 (instr->src << 16) |
96 (instr->dst << 5) |
97 (instr->dst));
98 break;
99 case INSTR_XOR_R:
100 assert(creg != instr->dst);
101 EMIT_U32(pos, 0xca000000 |
102 (instr->src << 16) |
103 (instr->dst << 5) |
104 (instr->dst));
105 break;
106 case INSTR_ADD_RS:
107 assert(creg != instr->dst);
108 EMIT_U32(pos, 0x8b000000 |
109 (instr->src << 16) |
110 (instr->imm32 << 10) |
111 (instr->dst << 5) |
112 (instr->dst));
113 break;
114 case INSTR_ROR_C:
115 assert(creg != instr->dst);
116 EMIT_U32(pos, 0x93c00000 |
117 (instr->dst << 16) |
118 (instr->imm32 << 10) |
119 (instr->dst << 5) |
120 (instr->dst));
121 break;
122 case INSTR_ADD_C:
123 assert(creg != instr->dst);
124 EMIT_IMM32(pos, instr->imm32);
125 EMIT_U32(pos, 0x8b0c0000 |
126 (instr->dst << 5) |
127 (instr->dst));
128 break;
129 case INSTR_XOR_C:
130 assert(creg != instr->dst);
131 EMIT_IMM32(pos, instr->imm32);
132 EMIT_U32(pos, 0xca0c0000 |
133 (instr->dst << 5) |
134 (instr->dst));
135 break;
136 case INSTR_TARGET:
137 target = pos;
138 break;
139 case INSTR_BRANCH:
140 EMIT_IMM32(pos, instr->imm32);
141 EMIT_U32(pos, 0x2a00012b | (creg << 16));
142 EMIT_U32(pos, 0x6a0c017f);
143 EMIT_U32(pos, 0x5a891129);
144 EMIT_U32(pos, 0x54000000 |
145 ((((uint32_t)(target - pos)) >> 2) & 0x7FFFF) << 5);
146 target = NULL;
147 creg = -1;
148 break;
149 default:
150 UNREACHABLE;
151 }
152 }
153 if (pos + sizeof a64_epilogue > code + COMP_CODE_SIZE)
154 return false;
155 EMIT(pos, a64_epilogue);
156 if (!hashx_vm_rx(code, COMP_CODE_SIZE))
157 return false;
158#ifdef __GNUC__
159 __builtin___clear_cache((void*)code, (void*)pos);
160#endif
161 return true;
162}
163
164#endif