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