1 /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 #include "instructions.h"
30 struct scm_instruction
{
31 enum scm_opcode opcode
; /* opcode */
32 const char *name
; /* instruction name */
33 signed char len
; /* Instruction length. This may be -1 for
34 the loader (see the `VM_LOADER'
36 signed char npop
; /* The number of values popped. This may be
37 -1 for insns like `call' which can take
38 any number of arguments. */
39 char npush
; /* the number of values pushed */
40 SCM symname
; /* filled in later */
44 SCM_SYMBOL (sym_left_arrow
, "<-");
45 SCM_SYMBOL (sym_bang
, "!");
48 #define OP_HAS_ARITY (1U << 0)
50 #define FOR_EACH_INSTRUCTION_WORD_TYPE(M) \
58 M(U32) /* Unsigned. */ \
59 M(I32) /* Immediate. */ \
60 M(A32) /* Immediate, high bits. */ \
61 M(B32) /* Immediate, low bits. */ \
62 M(N32) /* Non-immediate. */ \
63 M(S32) /* Scheme value (indirected). */ \
65 M(LO32) /* Label with offset. */ \
76 #define ENUM(type) type,
77 FOR_EACH_INSTRUCTION_WORD_TYPE (ENUM
)
81 static SCM word_type_symbols
[] =
83 #define FALSE(type) SCM_BOOL_F,
84 FOR_EACH_INSTRUCTION_WORD_TYPE (FALSE
)
88 #define OP(n,type) ((type) << (n*TYPE_WIDTH))
90 /* The VM_DEFINE_OP macro uses a CPP-based DSL to describe what kinds of
91 arguments each RTL instruction takes. This piece of code is the only
92 bit that actually interprets that language. These macro definitions
93 encode the operand types into bits in a 32-bit integer.
95 (rtl-instruction-list) parses those encoded values into lists of
96 symbols, one for each 32-bit word that the operator takes. (system
97 vm rtl) uses those word types to generate assemblers and
98 disassemblers for the instructions. */
102 #define OP2(type0, type1) \
103 (OP (0, type0) | OP (1, type1))
104 #define OP3(type0, type1, type2) \
105 (OP (0, type0) | OP (1, type1) | OP (2, type2))
106 #define OP4(type0, type1, type2, type3) \
107 (OP (0, type0) | OP (1, type1) | OP (2, type2) | OP (3, type3))
109 #define OP_DST (1 << (TYPE_WIDTH * 5))
111 #define WORD_TYPE(n, word) \
112 (((word) >> ((n) * TYPE_WIDTH)) & ((1 << TYPE_WIDTH) - 1))
114 struct scm_rtl_instruction
{
115 enum scm_rtl_opcode opcode
; /* opcode */
116 const char *name
; /* instruction name */
118 SCM symname
; /* filled in later */
122 #define SCM_VALIDATE_LOOKUP_INSTRUCTION(pos, var, cvar) \
124 cvar = scm_lookup_instruction_by_name (var); \
125 SCM_ASSERT_TYPE (cvar, var, pos, FUNC_NAME, "INSTRUCTION_P"); \
129 static scm_i_pthread_mutex_t itable_lock
= SCM_I_PTHREAD_MUTEX_INITIALIZER
;
132 static const struct scm_instruction
*
133 fetch_instruction_table ()
135 static struct scm_instruction
*table
= NULL
;
137 scm_i_pthread_mutex_lock (&itable_lock
);
138 if (SCM_UNLIKELY (!table
))
140 size_t bytes
= SCM_VM_NUM_INSTRUCTIONS
* sizeof(struct scm_instruction
);
142 table
= malloc (bytes
);
143 memset (table
, 0, bytes
);
144 #define VM_INSTRUCTION_TO_TABLE 1
145 #include <libguile/vm-expand.h>
146 #include <libguile/vm-i-system.i>
147 #include <libguile/vm-i-scheme.i>
148 #include <libguile/vm-i-loader.i>
149 #undef VM_INSTRUCTION_TO_TABLE
150 for (i
= 0; i
< SCM_VM_NUM_INSTRUCTIONS
; i
++)
154 table
[i
].symname
= scm_from_utf8_symbol (table
[i
].name
);
156 table
[i
].symname
= SCM_BOOL_F
;
159 scm_i_pthread_mutex_unlock (&itable_lock
);
164 static const struct scm_rtl_instruction
*
165 fetch_rtl_instruction_table ()
167 static struct scm_rtl_instruction
*table
= NULL
;
169 scm_i_pthread_mutex_lock (&itable_lock
);
170 if (SCM_UNLIKELY (!table
))
172 size_t bytes
= SCM_VM_NUM_INSTRUCTIONS
* sizeof(struct scm_rtl_instruction
);
174 table
= malloc (bytes
);
175 memset (table
, 0, bytes
);
177 #define INIT(opcode, tag, name_, meta_) table[opcode].name = name_; table[opcode].meta = meta_;
178 FOR_EACH_VM_OPERATION (INIT
);
181 for (i
= 0; i
< SCM_VM_NUM_INSTRUCTIONS
; i
++)
185 table
[i
].symname
= scm_from_utf8_symbol (table
[i
].name
);
187 table
[i
].symname
= SCM_BOOL_F
;
190 scm_i_pthread_mutex_unlock (&itable_lock
);
195 static const struct scm_instruction
*
196 scm_lookup_instruction_by_name (SCM name
)
198 static SCM instructions_by_name
= SCM_BOOL_F
;
199 const struct scm_instruction
*table
= fetch_instruction_table ();
202 if (SCM_UNLIKELY (scm_is_false (instructions_by_name
)))
206 instructions_by_name
=
207 scm_make_hash_table (SCM_I_MAKINUM (SCM_VM_NUM_INSTRUCTIONS
));
209 for (i
= 0; i
< SCM_VM_NUM_INSTRUCTIONS
; i
++)
210 if (scm_is_true (table
[i
].symname
))
211 scm_hashq_set_x (instructions_by_name
, table
[i
].symname
,
215 op
= scm_hashq_ref (instructions_by_name
, name
, SCM_UNDEFINED
);
216 if (SCM_I_INUMP (op
))
217 return &table
[SCM_I_INUM (op
)];
223 /* Scheme interface */
225 SCM_DEFINE (scm_instruction_list
, "instruction-list", 0, 0, 0,
228 #define FUNC_NAME s_scm_instruction_list
232 const struct scm_instruction
*ip
= fetch_instruction_table ();
233 for (i
= 0; i
< SCM_VM_NUM_INSTRUCTIONS
; i
++)
235 list
= scm_cons (ip
[i
].symname
, list
);
236 return scm_reverse_x (list
, SCM_EOL
);
240 SCM_DEFINE (scm_rtl_instruction_list
, "rtl-instruction-list", 0, 0, 0,
243 #define FUNC_NAME s_scm_rtl_instruction_list
247 const struct scm_rtl_instruction
*ip
= fetch_rtl_instruction_table ();
248 for (i
= 0; i
< SCM_VM_NUM_INSTRUCTIONS
; i
++)
251 scm_t_uint32 meta
= ip
[i
].meta
;
255 /* Format: (name opcode word0 word1 ...) */
257 if (WORD_TYPE (3, meta
))
259 else if (WORD_TYPE (2, meta
))
261 else if (WORD_TYPE (1, meta
))
263 else if (WORD_TYPE (0, meta
))
271 tail
= scm_cons (word_type_symbols
[WORD_TYPE (3, meta
)], tail
);
273 tail
= scm_cons (word_type_symbols
[WORD_TYPE (2, meta
)], tail
);
275 tail
= scm_cons (word_type_symbols
[WORD_TYPE (1, meta
)], tail
);
277 tail
= scm_cons (word_type_symbols
[WORD_TYPE (0, meta
)], tail
);
279 tail
= scm_cons ((meta
& OP_DST
) ? sym_left_arrow
: sym_bang
, tail
);
280 tail
= scm_cons (scm_from_int (ip
[i
].opcode
), tail
);
281 tail
= scm_cons (ip
[i
].symname
, tail
);
285 list
= scm_cons (tail
, list
);
288 return scm_reverse_x (list
, SCM_EOL
);
292 SCM_DEFINE (scm_instruction_p
, "instruction?", 1, 0, 0,
295 #define FUNC_NAME s_scm_instruction_p
297 return scm_from_bool (scm_lookup_instruction_by_name (obj
) != NULL
);
301 SCM_DEFINE (scm_instruction_length
, "instruction-length", 1, 0, 0,
304 #define FUNC_NAME s_scm_instruction_length
306 const struct scm_instruction
*ip
;
307 SCM_VALIDATE_LOOKUP_INSTRUCTION (1, inst
, ip
);
308 return SCM_I_MAKINUM (ip
->len
);
312 SCM_DEFINE (scm_instruction_pops
, "instruction-pops", 1, 0, 0,
315 #define FUNC_NAME s_scm_instruction_pops
317 const struct scm_instruction
*ip
;
318 SCM_VALIDATE_LOOKUP_INSTRUCTION (1, inst
, ip
);
319 return SCM_I_MAKINUM (ip
->npop
);
323 SCM_DEFINE (scm_instruction_pushes
, "instruction-pushes", 1, 0, 0,
326 #define FUNC_NAME s_scm_instruction_pushes
328 const struct scm_instruction
*ip
;
329 SCM_VALIDATE_LOOKUP_INSTRUCTION (1, inst
, ip
);
330 return SCM_I_MAKINUM (ip
->npush
);
334 SCM_DEFINE (scm_instruction_to_opcode
, "instruction->opcode", 1, 0, 0,
337 #define FUNC_NAME s_scm_instruction_to_opcode
339 const struct scm_instruction
*ip
;
340 SCM_VALIDATE_LOOKUP_INSTRUCTION (1, inst
, ip
);
341 return SCM_I_MAKINUM (ip
->opcode
);
345 SCM_DEFINE (scm_opcode_to_instruction
, "opcode->instruction", 1, 0, 0,
348 #define FUNC_NAME s_scm_opcode_to_instruction
350 scm_t_signed_bits opcode
;
351 SCM ret
= SCM_BOOL_F
;
353 SCM_MAKE_VALIDATE (1, op
, I_INUMP
);
354 opcode
= SCM_I_INUM (op
);
356 if (opcode
>= 0 && opcode
< SCM_VM_NUM_INSTRUCTIONS
)
357 ret
= fetch_instruction_table ()[opcode
].symname
;
359 if (scm_is_false (ret
))
360 scm_wrong_type_arg_msg (FUNC_NAME
, 1, op
, "INSTRUCTION_P");
367 scm_bootstrap_instructions (void)
369 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION
,
370 "scm_init_instructions",
371 (scm_t_extension_init_func
)scm_init_instructions
,
375 word_type_symbols[type] = scm_from_utf8_symbol (#type);
376 FOR_EACH_INSTRUCTION_WORD_TYPE (INIT
)
381 scm_init_instructions (void)
383 #ifndef SCM_MAGIC_SNARFER
384 #include "libguile/instructions.x"