1 /* Jitter: VM-independent instruction header. 2 3 Copyright (C) 2016, 2017, 2019, 2020 Luca Saiu 4 Written by Luca Saiu 5 6 This file is part of Jitter. 7 8 Jitter is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 Jitter is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */ 20 21 22 /* FIXME: this header doesn't need to be included out of the library 23 implementation. It should probably not be installed. */ 24 25 #ifndef JITTER_INSTRUCTION_H_ 26 #define JITTER_INSTRUCTION_H_ 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <stdbool.h> 31 32 #include <jitter/jitter.h> 33 #include <jitter/jitter-hash.h> 34 #include <jitter/jitter-print.h> 35 36 37 /* Register classes. 38 * ************************************************************************** */ 39 40 /* A register class descriptor. Every instance of this struct is a 41 machine-generated, statically-allocated constant. */ 42 struct jitter_register_class 43 { 44 /* The register class identifier, to be cast to an enum 45 vmprefix_register_class_id value. */ 46 jitter_uint register_class_id; 47 48 /* The character uniquely identifying the register class within the VM. For 49 example registers of the class with character 'r' will be called "%r0", 50 "%r1", and so on. */ 51 char character; 52 53 /* A long name for this register class. */ 54 char *lower_case_long_name; 55 char *upper_case_long_name; 56 57 /* How many fast registers exist for this class. */ 58 size_t fast_register_no; 59 60 /* Non-false iff this class admits slow registers as well. */ 61 bool use_slow_registers; 62 }; 63 64 65 /* VM labels as opaque identifiers. 66 * ************************************************************************** */ 67 68 /* Labels are held internally as opaque identifiers, resolved to instruction 69 indices late, right before a program is specialized. The facility for 70 handling a consistent mapping from symbolic to opaque labels is provided for 71 convenience, but labels are used in an opaque form and, in particular, are 72 stored as opaque within instruction parameters. 73 74 Opaque labels are only valid within a single VM routine. Different programs 75 may use the same opaque label identifiers, each referring to its own program 76 points. 77 78 Labels must be allocated only with the functions provided in jitter-routine.h 79 , for a specific program. */ 80 typedef jitter_int jitter_label; 81 82 83 84 85 86 /* Instruction description. 87 * ************************************************************************** */ 88 89 // FIXME: this should be factored with the definitions in jitterc-vm.h . 90 91 enum jitter_parameter_type 92 { 93 /* This is used during program construction, in case we have to 94 destroy a partially initialized program. */ 95 jitter_parameter_type_uninitialized, // FIXME: remove? 96 97 jitter_parameter_type_register_id, 98 jitter_parameter_type_literal, 99 jitter_parameter_type_label 100 }; 101 102 /* The parameter of an unspecialized instruction. Every instance of this struct 103 is malloc-allocated, and its only pointer is within the parameter field of 104 struct jitter_instruction , also always malloc-allocated and referred by 105 programs. This rigid organization makes it easy to deallocate programs with 106 all their elements. */ 107 struct jitter_parameter 108 { 109 /* The parameter type. */ 110 enum jitter_parameter_type type; 111 112 /* The parameter content. Which value is significant depends on the type. */ 113 union 114 { 115 /* An anonymous struct containing data only meaningful for register 116 parameters. */ 117 struct 118 { 119 /* The register class of a register parameter. */ 120 const struct jitter_register_class *register_class; 121 122 /* The register index of a register parameter. */ 123 jitter_register_index register_index; 124 }; 125 126 /* The parameter, as an immediate literal. */ 127 union jitter_word literal; 128 129 /* The parameter as an opaque label identifier. */ 130 jitter_label label; 131 132 /* The parameter, as an 0-based unspecialized instruction index. Opaque 133 labels are all replaced with unspecialized instruction indices by 134 jitter_resolve_labels_in_mutable_routine . */ 135 jitter_label_as_index label_as_index; 136 }; 137 }; 138 139 /* Forward declaration. The actual definition of struct jitter_mutable_routine is in 140 jitter-mutable-routine.h . */ 141 struct jitter_mutable_routine; 142 143 /* Return a pointer to a fresh instruction parameter, allocated according to 144 the conventions above, with the label_name field set to NULL. */ 145 struct jitter_parameter * 146 jitter_make_instruction_parameter (void) 147 __attribute__ ((returns_nonnull)); 148 149 /* Given an already initialized unspecialized instruction parameter return a 150 pointer to a fresh clone of the parameter for the same program. The clone is 151 malloc-allocated following the struct jitter_parameter conventions and shares 152 no structure with the original. This is useful for rewriting. */ 153 struct jitter_parameter* 154 jitter_clone_instruction_parameter (const struct jitter_parameter *original) 155 __attribute__ ((returns_nonnull, nonnull (1))); 156 157 /* Copy the parameter pointed by from over the parameter pointed by to, without 158 destroying *from . 159 160 Rationale: this is convenient for the implementation of 161 jitter_append_parameter_copy , used in instruction rewriting. */ 162 void 163 jitter_copy_instruction_parameter (struct jitter_parameter *to, 164 const struct jitter_parameter *from) 165 __attribute__ ((nonnull (1, 2))); 166 167 /* Free the given instruction parameter, which must be completely initialized 168 and allocated according to the conventions above. */ 169 void 170 jitter_destroy_instruction_parameter (struct jitter_parameter *p) 171 __attribute__ ((nonnull (1))); 172 173 174 175 176 /* Parameter comparison. 177 * ************************************************************************** */ 178 179 /* Compare the two pointed parameters, and return a negative number if the 180 first one is "less" then the second, zero if they are equal, and a positive 181 number if the first is "greater". 182 The exact comparison details are not specified except that comparison works 183 by structure and not by address, and that this function implements a strict 184 order relation (irreflexive, transitive, asymmetric). */ 185 int 186 jitter_compare_instruction_parameters (const struct jitter_parameter *a, 187 const struct jitter_parameter *b) 188 __attribute__ ((pure, nonnull (1, 2))); 189 190 /* Return true iff the two pointed instruction parameters are structurally 191 equal. */ 192 bool 193 jitter_instruction_parameters_equal (const struct jitter_parameter *a, 194 const struct jitter_parameter *b) 195 __attribute__ ((pure, nonnull (1, 2))); 196 197 198 199 200 /* VM instruction parameter printing. 201 * ************************************************************************** */ 202 203 /* A function printing a given VM instruction literal actual parameter to the 204 given print context. The parameter is arbitrarily represented as an unsigned 205 integer to the printer, but is meant to be cast to the appropriate type, 206 which may be signed or pointer. */ 207 typedef void (*jitter_literal_parameter_printer) (jitter_print_context out, 208 jitter_uint arg); 209 210 /* The default VM parameter printer, showing values in hexadecimal according to 211 the C lexicon, including the "0x" prefix. 212 This does not by itself use classes, but the VM routine printer in 213 jitter/jitter-mutable-routine.c does check whether the literal printer is in 214 fact this one, and adds the suitable decoration in that case. Rationale: 215 this printer is generally useful and can be independent from the VM, from 216 whose name the class names depend. */ 217 void 218 jitter_default_literal_parameter_printer (jitter_print_context c, 219 jitter_uint arg); 220 221 222 223 224 /* Meta-instructions. 225 * ************************************************************************** */ 226 227 // FIXME: again, this should be factored with the definitions in jitterc-vm.h . 228 229 // FIXME: Currently there is a big confusion between types and kinds. I should 230 // rationalize this, and rename C types accordingly. 231 232 /* The accepted kind for each meta-instruction parameter. */ 233 // FIXME: I might want to use enum jitterc_instruction_argument_kind instead of this. 234 enum jitter_meta_instruction_parameter_kind 235 { 236 /* The parameter may only be a register id. In practice this is 237 useful for output parameters. */ 238 jitter_meta_instruction_parameter_kind_register, 239 240 /* The parameter may only be a literal fixnum. */ 241 jitter_meta_instruction_parameter_kind_literal_fixnum, 242 243 /* The parameter may only be a literal instruction pointer. */ 244 jitter_meta_instruction_parameter_kind_literal_label, 245 246 /* The parameter may be either a register id or a literal fixnum. This is 247 a common case for input parameters. */ 248 jitter_meta_instruction_parameter_kind_register_or_literal_fixnum, 249 250 /* The parameter is a either a literal label or the id of a register 251 containing an instruction pointer. */ 252 jitter_meta_instruction_parameter_kind_register_or_literal_label, 253 254 /* The parameter is one of 255 (a) a literal fixnum; 256 (b) a literal label. */ 257 jitter_meta_instruction_parameter_kind_literal_fixnum_or_literal_label, 258 259 /* The parameter is one of 260 (a) the id of a register containing an instruction pointer; 261 (b) a literal fixnum; 262 (c) a literal label. */ 263 jitter_meta_instruction_parameter_kind_register_or_literal_fixnum_or_literal_label 264 }; 265 266 /* The type of parameter expected in a certain position for a certain 267 meta-instruction. */ 268 struct jitter_meta_instruction_parameter_type 269 { 270 /* The expected parameter kind. */ 271 enum jitter_meta_instruction_parameter_kind kind; 272 273 /* The expected register class, only meaningful if the kind includes a 274 register; it will be NULL otherwise. */ 275 const struct jitter_register_class *register_class; 276 277 /* A non-NULL pointer to the printer for this parameter. */ 278 const jitter_literal_parameter_printer literal_printer; 279 }; 280 281 /* The descriptor of one meta-instruction. Every instance of this struct is 282 statically allocated at startup, and accessible via 283 vmprefix_lookup_meta_instruction or by indexing vmprefix_meta_instructions with an 284 enum vmprefix_meta_instruction_id . */ 285 struct jitter_meta_instruction 286 { 287 /* The unique id of this meta-instruction. This is actually VM-dependent, but 288 we can use a generic integer type instead of enum 289 vmprefix_meta_instruction_id . The generic type is wide enough to 290 accommodate the id for any VM, and ids are non-negative. */ 291 jitter_uint id; 292 293 /* The name is only for debugging, error messages and human-readable program output. */ 294 const char *name; 295 296 /* How many parameter this instruction has. */ 297 size_t parameter_no; 298 299 /* True if and only if the instruction is a caller. */ 300 bool caller; 301 302 /* True if and only if the instruction is a callee. */ 303 bool callee; 304 305 /* True if and only if the instruction is relocatable. */ 306 bool relocatable; 307 308 /* The type of each parameter, in order. The pointer refers a statically 309 allocated buffer. */ 310 const struct jitter_meta_instruction_parameter_type *parameter_types; 311 }; 312 313 /* Initialize the meta-instruction hash table. */ 314 void 315 jitter_initialize_meta_instructions 316 (struct jitter_hash_table *meta_instruction_string_hash, 317 const struct jitter_meta_instruction *meta_instructions, 318 size_t meta_instruction_no); 319 320 /* Finalize the meta-instruction hash table. No need to finalize the array, 321 which is a global constant. */ 322 void 323 jitter_finalize_meta_instructions (struct jitter_hash_table * 324 meta_instruction_string_hash); 325 326 /* Given a pointer to the meta-instruction hash table and a meta-instruction 327 name return a pointer to the meta-instruction statically-allocated 328 descriptor. Undefined behavior if no such meta-instruction exists. */ 329 const struct jitter_meta_instruction* 330 jitter_lookup_meta_instruction (const struct jitter_hash_table *mi_hash, 331 const char *name); 332 333 334 335 336 /* Instruction representation in an unspecialized program. 337 * ************************************************************************** */ 338 339 /* A VM unspecialized instruction. This representation is inefficient, but 340 much more flexible for rewriting. */ 341 struct jitter_instruction 342 { 343 /* The pointed data structure is some global data structure which is 344 initialized at startup and never freed. Every vmprefix_instruction of 345 the same type points to the same meta_instruction. */ 346 const struct jitter_meta_instruction *meta_instruction; 347 348 /* This points to a malloc-allocated buffer, not shared. */ 349 struct jitter_parameter **parameters; 350 }; 351 352 /* Return a pointer to a fresh instruction, using the given meta-instruction. 353 This allocates the parameter array, (unless the meta-instruction has zero 354 parameters, in which case the parameter array is set to NULL) with the 355 appropriate size according to the meta-instruction, and allocates all 356 parameters, leaving them undefined but with NULL label_name fields. */ 357 struct jitter_instruction * 358 jitter_make_instruction (const struct jitter_meta_instruction * const mi) 359 __attribute__ ((returns_nonnull, nonnull (1))); 360 361 /* Destroy the given instruction, which must have been allocated with malloc 362 following the conventions above, its parameters field if non-NULL and in that 363 case each parameter as well. */ 364 void 365 jitter_destroy_instruction (struct jitter_instruction *i) 366 __attribute__ ((nonnull (1))); 367 368 369 #endif // #ifndef JITTER_INSTRUCTION_H_ 370