Tool: mp_mpt2c

Overview

MicroprobeTest (mpt) to C loop tool provides a command-line interface (CLI) to convert code snippets to C + inline assembly format. Using a test definition format (Microprobe test (mpt) format), the user can specify the initial state (initialization of the registers), the variables that have to be declared and the code snippet, which might contain references to those variables, branch labels, fixed addresses, etc. Check the Microprobe test (mpt) format for further details.

Note

The microbenchmark generation policy implemented in this tool reproduces exactly the code provided. It resolves any symbolic references (references to data, or branch targets), and only if specified by the user, it also modifies memory accesses to avoid segmentation fault issues. If the --endless flag is provided, the tool wraps the code provided within an endless loop.

Basic usage

> mp_mpt2c -T TARGET -t MPT_DEFINITION_FILE -O MPT_OUTPUT_FILE

where:

Flag/Argument Description
-T TARGET, --target TARGET Target definition string. Check: Command line target definition scheme.
-t MPT_DEFINITION_FILE, --mpt-definition-file MPT_DEFINITION_FILE Microprobe test definition file. Check: Microprobe test (mpt) format.
-O MPT_OUTPUT_FILE, --mpt-output-file MPT_OUTPUT_FILE Output file name.

Full usage

mp_mpt2c.py: INFO: Processing input arguments...
usage: mp_mpt2c.py [-h] [-P SEARCH_PATH [SEARCH_PATH ...]] [-V] [-v] [-d]
                   [-c CONFIG_FILE [CONFIG_FILE ...]] [-C FORCE_CONFIG_FILE]
                   [--dump-configuration-file OUTPUT_CONFIG_FILE]
                   [--dump-full-configuration-file OUTPUT_CONFIG_FILE]
                   [-A ARCHITECTURE_PATHS] [-M MICROARCHITECTURE_PATHS]
                   [-E ENVIRONMENT_PATHS] -T TARGET [--list-architectures]
                   [--list-microarchitectures] [--list-environments]
                   [--traceback] [--profile PROFILE_OUTPUT] -t
                   MPT_DEFINITION_FILE -O C_OUTPUT_FILE
                   [--fix-indirect-branches] [--fix-branch-next]
                   [--fix-memory-references] [--fix-memory-registers]
                   [--endless]

MicroprobeTest (mpt) to C tool

optional arguments:
  -h, --help            show this help message and exit
  -P SEARCH_PATH [SEARCH_PATH ...], --default_paths SEARCH_PATH [SEARCH_PATH ...]
                        Default search paths for microprobe target definitions
  -V, --version         Show Microprobe version and exit
  -v, --verbosity       Verbosity level (Values: [0,1,2,3,4]). Each time this
                        argument is specified the verbosity level is
                        increased. By default, no logging messages are shown.
                        These are the four levels available:
                        
                          -v (1): critical messages
                          -v -v (2): critical and error messages
                          -v -v -v (3): critical, error and warning messages
                          -v -v -v -v (4): critical, error, warning and info messages
                        
                        Specifying more than four verbosity flags, will
                        default to the maximum of four. If you need extra
                        information, enable the debug mode (--debug or -d
                        flags).
  -d, --debug           Enable debug mode in Microprobe framework. Lots of
                        output messages will be generated

Configuration arguments:

  Command arguments related to configuration file handling

  -c CONFIG_FILE [CONFIG_FILE ...], --configuration CONFIG_FILE [CONFIG_FILE ...]
                        Configuration file. The configuration files will be
                        readed in order of appearance. Values are reset by the
                        last configuration file in case of non-list values.
                        List values will be appended (not reset)
  -C FORCE_CONFIG_FILE, --force-configuration FORCE_CONFIG_FILE
                        Force configuration file. Use this configuration file
                        as the default start configuration. This disables any
                        system-wide, or user-provided configuration.
  --dump-configuration-file OUTPUT_CONFIG_FILE
                        Dump a configuration file with the actual
                        configuration used
  --dump-full-configuration-file OUTPUT_CONFIG_FILE
                        Dump a configuration file with the actual
                        configuration used plus all the configuration options
                        not set

Target path arguments:

  Command arguments related to target paths

  -A ARCHITECTURE_PATHS, --architecture-paths ARCHITECTURE_PATHS
                        Search path for architecture definitions. Microprobe
                        will search in these paths for architecture
                        definitions
  -M MICROARCHITECTURE_PATHS, --microarchitecture-paths MICROARCHITECTURE_PATHS
                        Search path for microarchitecture definitions.
                        Microprobe will search in these paths for
                        microarchitecture definitions
  -E ENVIRONMENT_PATHS, --environment-paths ENVIRONMENT_PATHS
                        Search path for environment definitions. Microprobe
                        will search in these paths for environment definitions

Target arguments:

  Command arguments related to target specification and queries

  -T TARGET, --target TARGET
                        Target tuple. Microprobe follows a GCC-like target
                        definition scheme, where a target is defined by a
                        tuple as following:
                        
                          <arch-name>-<uarch-name>-<env-name>
                        
                        where:
                        
                          <arch-name>: is the name of the architecture
                          <uarch-name>: is the name of the microarchitecture
                          <env-name>: is the name of the environment
                        
                        One can use --list-* options to get the list of
                        definitions available in the default search paths or
                        the paths specified by the different --*-paths options
  --list-architectures  Generate a list of architectures available in the
                        defined search paths and exit
  --list-microarchitectures
                        Generate a list of microarchitectures available in the
                        defined search paths and exit
  --list-environments   Generate a list of environments available in the
                        defined search paths and exit

Debug arguments:

  Command arguments related to debugging facilities

  --traceback           show a traceback and starts a python debugger (pdb)
                        when an error occurs. 'pdb' is an interactive python
                        shell that facilitates the debugging of errors
  --profile PROFILE_OUTPUT
                        dump profiling information into given file (see
                        'pstats' module)

Microprobe Test arguments:

  Command arguments related to Microprobe Test (mpt) generation

  -t MPT_DEFINITION_FILE, --mpt-definition-file MPT_DEFINITION_FILE
                        Microprobe test (mpt) definition file

MPT to C arguments:

  Command arguments related to MPT to C tool

  -O C_OUTPUT_FILE, --c-output-file C_OUTPUT_FILE
                        C output file name

Fixing options:

  Command arguments related to fixing options

  --fix-indirect-branches
                        Fix branches without known target
  --fix-branch-next     Force target of branches to be the next sequential
                        instruction
  --fix-memory-references
                        Ensure that registers used by instructions accessing
                        storage are initialized to valid locations
  --fix-memory-registers
                        Fix non-storage instructions touching registers used
                        for storage address computations (implies --fix-
                        memory-referenes flag)
  --endless             Wrap the code generated within an endless loop

Environment variables:

  MICROPROBETEMPLATES    Default path for microprobe templates
  MICROPROBEDEBUG        If set, enable debug
  MICROPROBEDEBUGPASSES  If set, enable debug during passes
  MICROPROBEASMHEXFMT    Assembly hexadecimal format. Options:
                         'all' -> All immediates in hex format
                         'address' -> Address immediates in hex format (default)
                         'none' -> All immediate in integer format

Fix flags

As stated above, this tool does not ensure that the memory address accessed by the assembly code access valid storage regions. For that, one has to declare the appropriate variables and initialize valid register contents. Also, it might be the case that the code still is not correct and extra modifications are required.

Going through the assembly to understand it and manually modify it to make sure it runs correctly can be a tedious task. This tool provides a set of flags that perform predefined modifications on that code with the aim to make sure that at least it will run correctly. One has to take into account that the modifications might change the performance profile of the code. So, we strongly suggest you to validate the code generated to make sure it is still valid for your needs.

In the table below, we summarize the flags that enable extra modification to the code:

Flag Description
--fix-memory-references Fix registers that are used to compute addresses in instruction accessing that access storage locations.
--fix-memory-registers Fix instructions touching registers used for storage address computations. If an instruction modifies a register that is used for storage address computation, the instruction is modified to not modify such register. Instead, a register that minimizes the dependency between instructions is used. Also, load and update or store and update instructions are replaced by their very same implementation without the update. Implies –fix-memory-references flag.
--fix-indirect-branches Fix branches without known target. Any branch with unknown target is replaced by an unconditional branch to the next instruction.
--fix-branch-next Force target of branches to be the next sequential instruction.

Example outputs

Example 1:

Command:

> mp_mpt2c -T riscv_v22-riscv_generic-riscv64_linux_gcc -t example1.mpt -O output.c --endless

Input file example1.mpt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
; Microprobe Test Definition File
[MPT]
mpt_version = 0.5 ;  Format version of this MPT file.

[REGISTERS] ; Section to specify the initial register values

; Format: register = value. E.g.:

; Set GR0, GR1 and GR2 register to 0, 1, 2 values respectively
;GR0 = 0x0


[DATA] ; Section to specify the variables

; Data section default address. Variables will be placed from this address
; if their address is not specified

default_address = 0x0000000010040000

; Variable Declaration
; Format: var_name = [ "type", nelems, address, alignment, init_values ]
; where:
;   - "type": is a string specifying the type of elements in the variable
;   - nelems: is the number of elements in the variable
;   - address : is the address of the variable, if set the address will be
;               fixed, otherwise, it will be computer by microprobe
;   - alignment : alignment requirements of the variable. It should not
;                 conflict with address if specified. It can be set to None
;   - init_values : if it is a single value, all the elements will be
;                   initialized to that value, if it is an array, elements
;                   will be initialized to the values specified in a round-
;                   robin fashion. Two special keywords can be specified:
;                   RNDFP and RNDINT to initialize the elements to random FP
;                   and random INT values
;
; Note that variable names ARE NOT case sensitive. I.e. VAR = Var = var

count	=	[ "int64_t", 1, 0x10040000, 0x8, 3405695742 ]
linkedlist	=	[ "uint8_t", 80, 0x10040010, 0x0, [8, 7, 6, 5, 4, 3, 2, 1, 32, 160, 32, 171, 108, 85, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 48, 160, 32, 171, 108, 85, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 64, 160, 32, 171, 108, 85, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 80, 160, 32, 171, 108, 85, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0] ]
microprobe_stack	=	[ "uint8_t", 4096, None, 0x10, None ]

[CODE] ; Section to specify the code

; Code section default address. Code will be placed from this address
; if the instruction address is not specified

default_address = 0x000000001002fff0

; The code specified after 'instructions' entry (below) is the code that will be
; processed by microprobe. The instruction format is similar to GNU assembler
; format, it also allows the specification of labels (NOT case sensitive) and
; references to the declared variables. It is also possible to specify instruction
; addresses and to do code expansion by referencing other user
; defined entries. Check the example below to see examples of these features.
;
; *****************************************************************************
; ******  Although Microprobe performs some sanity checks, it is the   ********
; ******  responsibility of the user to define correct code.           ********
; ******                                                               ********
; *****************************************************************************

instructions =
  <ELF_ABI_START>:
    JAL x1, c2mpt_function                            
    JAL x1, ELF_ABI_EXIT                              
  0x0000000010030000 <C2MPT_FUNCTION>:
    LUI x12, 65600                                    
    ADDI x12, x12, 0                                  
    LD x15, 8(x12)                                    
    LD x14, 80(x12)                                   
    BEQ x15, x0, C2MPT_FUNCTION+0X24                  
    LD x13, 0(x15)                                    
    LD x15, 8(x15)                                    
    ADD x14, x14, x13                                 
    BNE x15, x0, C2MPT_FUNCTION+0X14                  
    SLLI x14, x14, 1                                  
    SD x14, 80(x12)                                   
    JALR x0, x1, 0                                    
  0x0000000010030030 <MY_SUBROUTINE>:
    SLLI x10, x10, 1                                  
    LUI x15, 65600                                    
    SD x10, 80(x15)                                   
    JALR x0, x1, 0                                    
  <ELF_ABI_EXIT>:
    ADDI x0, x0, 0                                    

Output:

mp_mpt2c.py: INFO: Processing input arguments...
mp_mpt2c.py: INFO: Arguments processed!
mp_mpt2c.py: INFO: Importing target definition...
mp_mpt2c.py: INFO: Start generating '/home/rbertra/workspace/repos/github.com/IBM/microprobe/doc/source/examples_outputs/example_mpt2c.c'
mp_mpt2c.py: INFO: Interpreting assembly...
mp_mpt2c.py: WARNING: Instruction address not needed in 'LUI x12, 65600'
mp_mpt2c.py: WARNING: Instruction address not needed in 'SLLI x10, x10, 1'
mp_mpt2c.py: WARNING: Default data address not needed
mp_mpt2c.py: WARNING: Default code address not needed
mp_mpt2c.py: WARNING: Using endless C wrapper
mp_mpt2c.py: INFO: Creating benchmark synthesizer...
mp_mpt2c.py: INFO: Add register initialization pass
mp_mpt2c.py: INFO: Synthesizing...
mp_mpt2c.py: INFO: '/home/rbertra/workspace/repos/github.com/IBM/microprobe/doc/source/examples_outputs/example_mpt2c.c' generated!

Output file output.c:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
int64_t COUNT  __attribute__ ((aligned (8))) = 3405695742;
uint8_t LINKEDLIST[80]  = {8,7,6,5,4,3,2,1,32,160,32,171,108,85,0,0,8,7,6,5,4,3,2,1,48,160,32,171,108,85,0,0,8,7,6,5,4,3,2,1,64,160,32,171,108,85,0,0,8,7,6,5,4,3,2,1,80,160,32,171,108,85,0,0,8,7,6,5,4,3,2,1,0,0,0,0,0,0,0,0,};
uint8_t MICROPROBE_STACK[4096]  __attribute__ ((aligned (16)));
uint8_t riscv_v22_context_var[600] ;
char riscv_v22_scratch_var[256] ;
void usage(void)
{
printf("Usage:\n");
printf("  -h  Print this help\n");
printf("  -d  Print micro-benchmark description\n");
exit(-1);
}


void description(void)
{
int exit_code = 0;


printf("================================================================================\n");
printf("Microprobe framework general information:\n");
printf("--------------------------------------------------------------------------------\n");
printf("  Microprobe version: 0.5\n");
printf("  Copyright: Copyright 2018 IBM Corporation\n");
printf("  License: Apache Version 2.0\n");
printf("  Authors: Ramon Bertran\n");
printf("  Maintainers: Ramon Bertran\n");
printf("  Email: rbertra@us.ibm.com\n");
printf("  Software status: Development\n");
printf("\n");
printf("Development information:\n");
printf("--------------------------------------------------------------------------------\n");
printf("  No packaged version. Use Git to find the current revision.\n");
printf("\n");
printf("================================================================================\n");
printf("MICRO-BENCHMARK DESCRIPTION\n");
printf("--------------------------------------------------------------------------------\n");
printf("Generation time: 04/28/20 16:48:19 EDT\n");
printf("Generation policy:\n");
printf("  Step: 0 InitializeRegistersPass   Initialize general registers to:  'None' and\n");
printf("                                    FP registers to 'None' and Vector register t\n");
printf("                                    o 'None'\n");
printf("  Step: 1 SimpleBuildingBlockPass   Create a basic block with '19' instructions\n");
printf("  Step: 2    DeclareVariablesPass   Declaring variables: ['(int64_t) COUNT', '(u\n");
printf("                                    int8_t) LINKEDLIST[80]', '(uint8_t) MICROPROB\n");
printf("                                    E_STACK[4096]']\n");
printf("  Step: 3   ReproduceSequencePass            Reproduce instruction sequence\n");
printf("\n");
printf("Configured target:\n");
printf("  Target ISA: riscv_v22\n");
printf("  ISA Description: RISC-V v2.2\n");
printf("  Target Micro-architecture: riscv_generic\n");
printf("  Micro-architecture Description: Generic RISC-V microarchitecture\n");
printf("  Target Environment: riscv64_linux_gcc\n");
printf("  Environment description: RISC-V architecture (64bit addressing mode), Linux operating system, GCC compiler\n");
printf("\n");
printf("Target requirements:\n");
printf("\n");
printf("Warnings (includes not checkable requirements):\n");
printf("  Warning  0 - Pass 002: DeclareVariablesPass did not pass the check test\n");
printf("  Warning  1 - Pass 000: InitializeRegistersPass did not pass the check test\n");
printf("  Warning  2 - Pass 003: ReproduceSequencePass did not pass the check test\n");
printf("\n");
printf("Other Information\n");
printf("\n");


exit(3);
}


void process_parameters(int argc, char **argv, char **envp)
{
if (argc == 1) {printf("Running micro-benchmark...\n"); return;}
if (argc > 2) {usage();}
if (argv[1][0] != '-') {usage();}
if (argv[1][1] == 'h') {usage();}
else if (argv[1][1] == 'd') {description();}
else {usage();}
}


int main(int argc, char **argv, char **envp)
{
process_parameters(argc, argv, envp);
{FILE *devrandom = fopen("/dev/urandom", "r");
fread(&riscv_v22_context_var, sizeof(uint8_t), 600 , devrandom);
fclose(devrandom);}
{for (int i=0;i<256;i=i+256) memcpy(&riscv_v22_scratch_var[i], &riscv_v22_context_var, 256);}
{for (int i=0;i<3600;i=i+600) memcpy(&MICROPROBE_STACK[i], &riscv_v22_context_var, 600);}
{for (int i=3600;i<4096;i=i+496) memcpy(&MICROPROBE_STACK[i], &riscv_v22_context_var, 496);}
__asm__(" riscv_v22_context_var_pcrel_1:AUIPC x31, %pcrel_hi(riscv_v22_context_var) ");
__asm__(" ADDI x31, x31, %pcrel_lo(riscv_v22_context_var_pcrel_1) ");
__asm__(" SD x0, 0x0(x31) ");
__asm__(" SD x1, 0x8(x31) ");
__asm__(" SD x2, 0x10(x31) ");
__asm__(" SD x3, 0x18(x31) ");
__asm__(" SD x4, 0x20(x31) ");
__asm__(" SD x5, 0x28(x31) ");
__asm__(" SD x6, 0x30(x31) ");
__asm__(" SD x7, 0x38(x31) ");
__asm__(" SD x8, 0x40(x31) ");
__asm__(" SD x9, 0x48(x31) ");
__asm__(" SD x10, 0x50(x31) ");
__asm__(" SD x11, 0x58(x31) ");
__asm__(" SD x12, 0x60(x31) ");
__asm__(" SD x13, 0x68(x31) ");
__asm__(" SD x14, 0x70(x31) ");
__asm__(" SD x15, 0x78(x31) ");
__asm__(" SD x16, 0x80(x31) ");
__asm__(" SD x17, 0x88(x31) ");
__asm__(" SD x18, 0x90(x31) ");
__asm__(" SD x19, 0x98(x31) ");
__asm__(" SD x20, 0xa0(x31) ");
__asm__(" SD x21, 0xa8(x31) ");
__asm__(" SD x22, 0xb0(x31) ");
__asm__(" SD x23, 0xb8(x31) ");
__asm__(" SD x24, 0xc0(x31) ");
__asm__(" SD x25, 0xc8(x31) ");
__asm__(" SD x26, 0xd0(x31) ");
__asm__(" SD x27, 0xd8(x31) ");
__asm__(" SD x28, 0xe0(x31) ");
__asm__(" SD x29, 0xe8(x31) ");
__asm__(" SD x30, 0xf0(x31) ");
__asm__(" SD x31, 0xf8(x31) ");
__asm__(" FSD f0, 0x100(x31) ");
__asm__(" FSD f1, 0x108(x31) ");
__asm__(" FSD f2, 0x110(x31) ");
__asm__(" FSD f3, 0x118(x31) ");
__asm__(" FSD f4, 0x120(x31) ");
__asm__(" FSD f5, 0x128(x31) ");
__asm__(" FSD f6, 0x130(x31) ");
__asm__(" FSD f7, 0x138(x31) ");
__asm__(" FSD f8, 0x140(x31) ");
__asm__(" FSD f9, 0x148(x31) ");
__asm__(" FSD f10, 0x150(x31) ");
__asm__(" FSD f11, 0x158(x31) ");
__asm__(" FSD f12, 0x160(x31) ");
__asm__(" FSD f13, 0x168(x31) ");
__asm__(" FSD f14, 0x170(x31) ");
__asm__(" FSD f15, 0x178(x31) ");
__asm__(" FSD f16, 0x180(x31) ");
__asm__(" FSD f17, 0x188(x31) ");
__asm__(" FSD f18, 0x190(x31) ");
__asm__(" FSD f19, 0x198(x31) ");
__asm__(" FSD f20, 0x1a0(x31) ");
__asm__(" FSD f21, 0x1a8(x31) ");
__asm__(" FSD f22, 0x1b0(x31) ");
__asm__(" FSD f23, 0x1b8(x31) ");
__asm__(" FSD f24, 0x1c0(x31) ");
__asm__(" FSD f25, 0x1c8(x31) ");
__asm__(" FSD f26, 0x1d0(x31) ");
__asm__(" FSD f27, 0x1d8(x31) ");
__asm__(" FSD f28, 0x1e0(x31) ");
__asm__(" FSD f29, 0x1e8(x31) ");
__asm__(" FSD f30, 0x1f0(x31) ");
__asm__(" FSD f31, 0x1f8(x31) ");
__asm__(".balign 64");
while(1)
{
__asm__(" ELF_ABI_START:JAL x1, C2MPT_FUNCTION ");
__asm__(" JAL x1, ELF_ABI_EXIT ");
__asm__(" C2MPT_FUNCTION:LUI x12, 65600 ");
__asm__(" ADDI x12, x12, 0x0 ");
__asm__(" LD x15, 0x8(x12) ");
__asm__(" LD x14, 0x50(x12) ");
__asm__(" BEQ x15, x0, C2MPT_FUNCTION+0x24 ");
__asm__(" LD x13, 0x0(x15) ");
__asm__(" LD x15, 0x8(x15) ");
__asm__(" ADD x14, x14, x13 ");
__asm__(" BNE x15, x0, C2MPT_FUNCTION+0x14 ");
__asm__(" SLLI x14, x14, 1 ");
__asm__(" SD x14, 0x50(x12) ");
__asm__(" JALR x0, x1, 0x0 ");
__asm__(" MY_SUBROUTINE:SLLI x10, x10, 1 ");
__asm__(" LUI x15, 65600 ");
__asm__(" SD x10, 0x50(x15) ");
__asm__(" JALR x0, x1, 0x0 ");
__asm__(" ELF_ABI_EXIT:ADDI x0, x0, 0x0 ");
}
__asm__(" riscv_v22_context_var_pcrel_2:AUIPC x31, %pcrel_hi(riscv_v22_context_var) ");
__asm__(" ADDI x31, x31, %pcrel_lo(riscv_v22_context_var_pcrel_2) ");
__asm__(" LD x0, 0x0(x31) ");
__asm__(" LD x1, 0x8(x31) ");
__asm__(" LD x2, 0x10(x31) ");
__asm__(" LD x3, 0x18(x31) ");
__asm__(" LD x4, 0x20(x31) ");
__asm__(" LD x5, 0x28(x31) ");
__asm__(" LD x6, 0x30(x31) ");
__asm__(" LD x7, 0x38(x31) ");
__asm__(" LD x8, 0x40(x31) ");
__asm__(" LD x9, 0x48(x31) ");
__asm__(" LD x10, 0x50(x31) ");
__asm__(" LD x11, 0x58(x31) ");
__asm__(" LD x12, 0x60(x31) ");
__asm__(" LD x13, 0x68(x31) ");
__asm__(" LD x14, 0x70(x31) ");
__asm__(" LD x15, 0x78(x31) ");
__asm__(" LD x16, 0x80(x31) ");
__asm__(" LD x17, 0x88(x31) ");
__asm__(" LD x18, 0x90(x31) ");
__asm__(" LD x19, 0x98(x31) ");
__asm__(" LD x20, 0xa0(x31) ");
__asm__(" LD x21, 0xa8(x31) ");
__asm__(" LD x22, 0xb0(x31) ");
__asm__(" LD x23, 0xb8(x31) ");
__asm__(" LD x24, 0xc0(x31) ");
__asm__(" LD x25, 0xc8(x31) ");
__asm__(" LD x26, 0xd0(x31) ");
__asm__(" LD x27, 0xd8(x31) ");
__asm__(" LD x28, 0xe0(x31) ");
__asm__(" LD x29, 0xe8(x31) ");
__asm__(" LD x30, 0xf0(x31) ");
__asm__(" FLD f0, 0x100(x31) ");
__asm__(" FLD f1, 0x108(x31) ");
__asm__(" FLD f2, 0x110(x31) ");
__asm__(" FLD f3, 0x118(x31) ");
__asm__(" FLD f4, 0x120(x31) ");
__asm__(" FLD f5, 0x128(x31) ");
__asm__(" FLD f6, 0x130(x31) ");
__asm__(" FLD f7, 0x138(x31) ");
__asm__(" FLD f8, 0x140(x31) ");
__asm__(" FLD f9, 0x148(x31) ");
__asm__(" FLD f10, 0x150(x31) ");
__asm__(" FLD f11, 0x158(x31) ");
__asm__(" FLD f12, 0x160(x31) ");
__asm__(" FLD f13, 0x168(x31) ");
__asm__(" FLD f14, 0x170(x31) ");
__asm__(" FLD f15, 0x178(x31) ");
__asm__(" FLD f16, 0x180(x31) ");
__asm__(" FLD f17, 0x188(x31) ");
__asm__(" FLD f18, 0x190(x31) ");
__asm__(" FLD f19, 0x198(x31) ");
__asm__(" FLD f20, 0x1a0(x31) ");
__asm__(" FLD f21, 0x1a8(x31) ");
__asm__(" FLD f22, 0x1b0(x31) ");
__asm__(" FLD f23, 0x1b8(x31) ");
__asm__(" FLD f24, 0x1c0(x31) ");
__asm__(" FLD f25, 0x1c8(x31) ");
__asm__(" FLD f26, 0x1d0(x31) ");
__asm__(" FLD f27, 0x1d8(x31) ");
__asm__(" FLD f28, 0x1e0(x31) ");
__asm__(" FLD f29, 0x1e8(x31) ");
__asm__(" FLD f30, 0x1f0(x31) ");
__asm__(" FLD f31, 0x1f8(x31) ");
__asm__(" LD x31, 0xf8(x31) ");

}