Monero
bytecode_machine.hpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2019, tevador <tevador@gmail.com>
3 
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8  * Redistributions of source code must retain the above copyright
9  notice, this list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright
11  notice, this list of conditions and the following disclaimer in the
12  documentation and/or other materials provided with the distribution.
13  * Neither the name of the copyright holder nor the
14  names of its contributors may be used to endorse or promote products
15  derived from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #pragma once
30 
31 #include "common.hpp"
32 #include "intrin_portable.h"
33 #include "instruction.hpp"
34 #include "program.hpp"
35 
36 namespace randomx {
37 
38  //register file in machine byte order
44  };
45 
47  union {
50  };
51  union {
52  const int_reg_t* isrc;
53  const rx_vec_f128* fsrc;
54  };
55  union {
58  };
60  union {
63  };
65  };
66 
67 #define OPCODE_CEIL_DECLARE(curr, prev) constexpr int ceil_ ## curr = ceil_ ## prev + RANDOMX_FREQ_ ## curr;
68  constexpr int ceil_NULL = 0;
69  OPCODE_CEIL_DECLARE(IADD_RS, NULL);
70  OPCODE_CEIL_DECLARE(IADD_M, IADD_RS);
71  OPCODE_CEIL_DECLARE(ISUB_R, IADD_M);
72  OPCODE_CEIL_DECLARE(ISUB_M, ISUB_R);
73  OPCODE_CEIL_DECLARE(IMUL_R, ISUB_M);
74  OPCODE_CEIL_DECLARE(IMUL_M, IMUL_R);
75  OPCODE_CEIL_DECLARE(IMULH_R, IMUL_M);
76  OPCODE_CEIL_DECLARE(IMULH_M, IMULH_R);
77  OPCODE_CEIL_DECLARE(ISMULH_R, IMULH_M);
78  OPCODE_CEIL_DECLARE(ISMULH_M, ISMULH_R);
79  OPCODE_CEIL_DECLARE(IMUL_RCP, ISMULH_M);
80  OPCODE_CEIL_DECLARE(INEG_R, IMUL_RCP);
81  OPCODE_CEIL_DECLARE(IXOR_R, INEG_R);
82  OPCODE_CEIL_DECLARE(IXOR_M, IXOR_R);
83  OPCODE_CEIL_DECLARE(IROR_R, IXOR_M);
84  OPCODE_CEIL_DECLARE(IROL_R, IROR_R);
85  OPCODE_CEIL_DECLARE(ISWAP_R, IROL_R);
86  OPCODE_CEIL_DECLARE(FSWAP_R, ISWAP_R);
87  OPCODE_CEIL_DECLARE(FADD_R, FSWAP_R);
88  OPCODE_CEIL_DECLARE(FADD_M, FADD_R);
89  OPCODE_CEIL_DECLARE(FSUB_R, FADD_M);
90  OPCODE_CEIL_DECLARE(FSUB_M, FSUB_R);
91  OPCODE_CEIL_DECLARE(FSCAL_R, FSUB_M);
92  OPCODE_CEIL_DECLARE(FMUL_R, FSCAL_R);
93  OPCODE_CEIL_DECLARE(FDIV_M, FMUL_R);
94  OPCODE_CEIL_DECLARE(FSQRT_R, FDIV_M);
95  OPCODE_CEIL_DECLARE(CBRANCH, FSQRT_R);
96  OPCODE_CEIL_DECLARE(CFROUND, CBRANCH);
97  OPCODE_CEIL_DECLARE(ISTORE, CFROUND);
98  OPCODE_CEIL_DECLARE(NOP, ISTORE);
99 #undef OPCODE_CEIL_DECLARE
100 
101 #define RANDOMX_EXE_ARGS InstructionByteCode& ibc, int& pc, uint8_t* scratchpad, ProgramConfiguration& config
102 #define RANDOMX_GEN_ARGS Instruction& instr, int i, InstructionByteCode& ibc
103 
104  class BytecodeMachine;
105 
107 
109  public:
111  for (unsigned i = 0; i < RegistersCount; ++i) {
112  registerUsage[i] = -1;
113  }
114  nreg = &regFile;
115  }
116 
118  beginCompilation(regFile);
119  for (unsigned i = 0; i < RANDOMX_PROGRAM_SIZE; ++i) {
120  auto& instr = program(i);
121  auto& ibc = bytecode[i];
122  compileInstruction(instr, i, ibc);
123  }
124  }
125 
127  for (int pc = 0; pc < RANDOMX_PROGRAM_SIZE; ++pc) {
128  auto& ibc = bytecode[pc];
129  executeInstruction(ibc, pc, scratchpad, config);
130  }
131  }
132 
134 #ifdef RANDOMX_GEN_TABLE
135  {
136  auto generator = genTable[instr.opcode];
137  (this->*generator)(instr, i, ibc);
138  }
139 #else
140  ;
141 #endif
142 
144 
146  *ibc.idst += (*ibc.isrc << ibc.shift) + ibc.imm;
147  }
148 
150  *ibc.idst += load64(getScratchpadAddress(ibc, scratchpad));
151  }
152 
154  *ibc.idst -= *ibc.isrc;
155  }
156 
158  *ibc.idst -= load64(getScratchpadAddress(ibc, scratchpad));
159  }
160 
162  *ibc.idst *= *ibc.isrc;
163  }
164 
166  *ibc.idst *= load64(getScratchpadAddress(ibc, scratchpad));
167  }
168 
170  *ibc.idst = mulh(*ibc.idst, *ibc.isrc);
171  }
172 
174  *ibc.idst = mulh(*ibc.idst, load64(getScratchpadAddress(ibc, scratchpad)));
175  }
176 
178  *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(*ibc.isrc));
179  }
180 
182  *ibc.idst = smulh(unsigned64ToSigned2sCompl(*ibc.idst), unsigned64ToSigned2sCompl(load64(getScratchpadAddress(ibc, scratchpad))));
183  }
184 
186  *ibc.idst = ~(*ibc.idst) + 1; //two's complement negative
187  }
188 
190  *ibc.idst ^= *ibc.isrc;
191  }
192 
194  *ibc.idst ^= load64(getScratchpadAddress(ibc, scratchpad));
195  }
196 
198  *ibc.idst = rotr(*ibc.idst, *ibc.isrc & 63);
199  }
200 
202  *ibc.idst = rotl(*ibc.idst, *ibc.isrc & 63);
203  }
204 
206  int_reg_t temp = *ibc.isrc;
207  *(int_reg_t*)ibc.isrc = *ibc.idst;
208  *ibc.idst = temp;
209  }
210 
212  *ibc.fdst = rx_swap_vec_f128(*ibc.fdst);
213  }
214 
216  *ibc.fdst = rx_add_vec_f128(*ibc.fdst, *ibc.fsrc);
217  }
218 
221  *ibc.fdst = rx_add_vec_f128(*ibc.fdst, fsrc);
222  }
223 
225  *ibc.fdst = rx_sub_vec_f128(*ibc.fdst, *ibc.fsrc);
226  }
227 
230  *ibc.fdst = rx_sub_vec_f128(*ibc.fdst, fsrc);
231  }
232 
234  const rx_vec_f128 mask = rx_set1_vec_f128(0x80F0000000000000);
235  *ibc.fdst = rx_xor_vec_f128(*ibc.fdst, mask);
236  }
237 
239  *ibc.fdst = rx_mul_vec_f128(*ibc.fdst, *ibc.fsrc);
240  }
241 
244  config,
246  );
247  *ibc.fdst = rx_div_vec_f128(*ibc.fdst, fsrc);
248  }
249 
251  *ibc.fdst = rx_sqrt_vec_f128(*ibc.fdst);
252  }
253 
255  *ibc.idst += ibc.imm;
256  if ((*ibc.idst & ibc.memMask) == 0) {
257  pc = ibc.target;
258  }
259  }
260 
262  rx_set_rounding_mode(rotr(*ibc.isrc, ibc.imm) % 4);
263  }
264 
266  store64(scratchpad + ((*ibc.idst + ibc.imm) & ibc.memMask), *ibc.isrc);
267  }
268  protected:
271  const rx_vec_f128 xexponentMask = rx_load_vec_f128((const double*)&config.eMask);
272  x = rx_and_vec_f128(x, xmantissaMask);
273  x = rx_or_vec_f128(x, xexponentMask);
274  return x;
275  }
276 
277  private:
278  static const int_reg_t zero;
281 
282  static void* getScratchpadAddress(InstructionByteCode& ibc, uint8_t* scratchpad) {
283  uint32_t addr = (*ibc.isrc + ibc.imm) & ibc.memMask;
284  return scratchpad + addr;
285  }
286 
287 #ifdef RANDOMX_GEN_TABLE
288  static InstructionGenBytecode genTable[256];
289 
290  void gen_IADD_RS(RANDOMX_GEN_ARGS);
291  void gen_IADD_M(RANDOMX_GEN_ARGS);
292  void gen_ISUB_R(RANDOMX_GEN_ARGS);
293  void gen_ISUB_M(RANDOMX_GEN_ARGS);
294  void gen_IMUL_R(RANDOMX_GEN_ARGS);
295  void gen_IMUL_M(RANDOMX_GEN_ARGS);
296  void gen_IMULH_R(RANDOMX_GEN_ARGS);
297  void gen_IMULH_M(RANDOMX_GEN_ARGS);
298  void gen_ISMULH_R(RANDOMX_GEN_ARGS);
299  void gen_ISMULH_M(RANDOMX_GEN_ARGS);
300  void gen_IMUL_RCP(RANDOMX_GEN_ARGS);
301  void gen_INEG_R(RANDOMX_GEN_ARGS);
302  void gen_IXOR_R(RANDOMX_GEN_ARGS);
303  void gen_IXOR_M(RANDOMX_GEN_ARGS);
304  void gen_IROR_R(RANDOMX_GEN_ARGS);
305  void gen_IROL_R(RANDOMX_GEN_ARGS);
306  void gen_ISWAP_R(RANDOMX_GEN_ARGS);
307  void gen_FSWAP_R(RANDOMX_GEN_ARGS);
308  void gen_FADD_R(RANDOMX_GEN_ARGS);
309  void gen_FADD_M(RANDOMX_GEN_ARGS);
310  void gen_FSUB_R(RANDOMX_GEN_ARGS);
311  void gen_FSUB_M(RANDOMX_GEN_ARGS);
312  void gen_FSCAL_R(RANDOMX_GEN_ARGS);
313  void gen_FMUL_R(RANDOMX_GEN_ARGS);
314  void gen_FDIV_M(RANDOMX_GEN_ARGS);
315  void gen_FSQRT_R(RANDOMX_GEN_ARGS);
316  void gen_CBRANCH(RANDOMX_GEN_ARGS);
317  void gen_CFROUND(RANDOMX_GEN_ARGS);
318  void gen_ISTORE(RANDOMX_GEN_ARGS);
319  void gen_NOP(RANDOMX_GEN_ARGS);
320 #endif
321  };
322 }
InstructionType type
Definition: bytecode_machine.hpp:59
static void exe_IADD_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:149
static void exe_IXOR_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:189
static void exe_IROR_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:197
Definition: allocator.cpp:35
static void exe_IMUL_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:161
uint32_t memMask
Definition: bytecode_machine.hpp:64
int16_t target
Definition: bytecode_machine.hpp:61
int i
Definition: pymoduletest.py:23
static void exe_FMUL_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:238
void(BytecodeMachine::* InstructionGenBytecode)(RANDOMX_GEN_ARGS)
Definition: bytecode_machine.hpp:106
constexpr uint64_t dynamicMantissaMask
Definition: common.hpp:173
Definition: intrin_portable.h:534
static void exe_FSQRT_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:250
#define RANDOMX_EXE_ARGS
Definition: bytecode_machine.hpp:101
constexpr int ceil_NULL
Definition: bytecode_machine.hpp:68
unsigned short uint16_t
Definition: stdint.h:125
Definition: cryptonote_config.h:220
FORCE_INLINE rx_vec_f128 rx_set_vec_f128(uint64_t x1, uint64_t x0)
Definition: intrin_portable.h:614
FORCE_INLINE rx_vec_f128 rx_and_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:635
static void exe_FSUB_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:228
unsigned char uint8_t
Definition: stdint.h:124
uint64_t imm
Definition: bytecode_machine.hpp:56
uint64_t rotl(uint64_t a, unsigned int b)
Definition: instructions_portable.cpp:99
int64_t smulh(int64_t a, int64_t b)
Definition: instructions_portable.cpp:125
static void exe_ISTORE(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:265
static void exe_IMUL_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:165
FORCE_INLINE rx_vec_f128 rx_or_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:642
static FORCE_INLINE uint64_t load64(const void *src)
Definition: endian.h:50
NativeRegisterFile * nreg
Definition: bytecode_machine.hpp:280
constexpr int64_t unsigned64ToSigned2sCompl(uint64_t x)
Definition: intrin_portable.h:38
const int_reg_t * isrc
Definition: bytecode_machine.hpp:52
static void exe_ISUB_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:157
static void exe_FSWAP_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:211
Definition: program.hpp:39
FORCE_INLINE rx_vec_f128 rx_add_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:566
rx_vec_f128 a[RegisterCountFlt]
Definition: bytecode_machine.hpp:43
static void exe_INEG_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:185
static void exe_IMULH_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:173
static void exe_FADD_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:219
unsigned int uint32_t
Definition: stdint.h:126
static void executeBytecode(InstructionByteCode bytecode[RANDOMX_PROGRAM_SIZE], uint8_t *scratchpad, ProgramConfiguration &config)
Definition: bytecode_machine.hpp:126
signed short int16_t
Definition: stdint.h:122
FORCE_INLINE rx_vec_f128 rx_set1_vec_f128(uint64_t x)
Definition: intrin_portable.h:621
static void executeInstruction(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.cpp:40
static void exe_ISMULH_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:177
int_reg_t * idst
Definition: bytecode_machine.hpp:48
Definition: program.hpp:44
static void exe_IADD_RS(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:145
#define RANDOMX_PROGRAM_SIZE
Definition: configuration.h:56
rx_vec_f128 * fdst
Definition: bytecode_machine.hpp:49
static void exe_FADD_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:215
unsigned __int64 uint64_t
Definition: stdint.h:136
constexpr int RegisterCountFlt
Definition: common.hpp:157
rx_vec_f128 e[RegisterCountFlt]
Definition: bytecode_machine.hpp:42
Definition: bytecode_machine.hpp:108
static void exe_CFROUND(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:261
FORCE_INLINE rx_vec_f128 rx_xor_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:628
FORCE_INLINE rx_vec_f128 rx_swap_vec_f128(rx_vec_f128 a)
Definition: intrin_portable.h:559
static void exe_ISMULH_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:181
FORCE_INLINE rx_vec_f128 rx_mul_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:580
#define RANDOMX_GEN_ARGS
Definition: bytecode_machine.hpp:102
uint64_t int_reg_t
Definition: common.hpp:140
static void exe_FSCAL_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:233
static void exe_FDIV_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:242
FORCE_INLINE rx_vec_f128 rx_div_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:587
const rx_vec_f128 * fsrc
Definition: bytecode_machine.hpp:53
InstructionType
Definition: instruction.hpp:42
FORCE_INLINE rx_vec_f128 rx_load_vec_f128(const double *pd)
Definition: intrin_portable.h:547
int_reg_t r[RegistersCount]
Definition: bytecode_machine.hpp:40
static void exe_IXOR_M(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:193
static void exe_IMULH_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:169
uint64_t mulh(uint64_t a, uint64_t b)
Definition: instructions_portable.cpp:108
constexpr int RegistersCount
Definition: common.hpp:156
Definition: bytecode_machine.hpp:46
signed __int64 int64_t
Definition: stdint.h:135
void beginCompilation(NativeRegisterFile &regFile)
Definition: bytecode_machine.hpp:110
int registerUsage[RegistersCount]
Definition: bytecode_machine.hpp:279
OPCODE_CEIL_DECLARE(IADD_RS, NULL)
void rx_set_rounding_mode(uint32_t mode)
Definition: instructions_portable.cpp:141
static FORCE_INLINE void store64(void *dst, uint64_t w)
Definition: endian.h:86
uint64_t rotr(uint64_t a, unsigned int b)
Definition: instructions_portable.cpp:92
static void exe_FSUB_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:224
int64_t simm
Definition: bytecode_machine.hpp:57
static void exe_IROL_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:201
static void exe_ISWAP_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:205
FORCE_INLINE rx_vec_f128 rx_sqrt_vec_f128(rx_vec_f128 a)
Definition: intrin_portable.h:594
uint16_t shift
Definition: bytecode_machine.hpp:62
Definition: bytecode_machine.hpp:39
rx_vec_f128 f[RegisterCountFlt]
Definition: bytecode_machine.hpp:41
static rx_vec_f128 maskRegisterExponentMantissa(ProgramConfiguration &config, rx_vec_f128 x)
Definition: bytecode_machine.hpp:269
void compileInstruction(RANDOMX_GEN_ARGS)
Definition: bytecode_machine.cpp:81
void compileProgram(Program &program, InstructionByteCode bytecode[RANDOMX_PROGRAM_SIZE], NativeRegisterFile &regFile)
Definition: bytecode_machine.hpp:117
static void exe_CBRANCH(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:254
FORCE_INLINE rx_vec_f128 rx_sub_vec_f128(rx_vec_f128 a, rx_vec_f128 b)
Definition: intrin_portable.h:573
static const int_reg_t zero
Definition: bytecode_machine.hpp:278
FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void *addr)
Definition: intrin_portable.h:709
static void exe_ISUB_R(RANDOMX_EXE_ARGS)
Definition: bytecode_machine.hpp:153
static void * getScratchpadAddress(InstructionByteCode &ibc, uint8_t *scratchpad)
Definition: bytecode_machine.hpp:282