1 /*
2 opcodes.c
3
4 opcode searching
5
6 Copyright (C) 2002 Bill Currie <bill@taniwha.org>
7
8 Author: Bill Currie <bill@taniwha.org>
9 Date: 2002/06/01
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20 See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to:
24
25 Free Software Foundation, Inc.
26 59 Temple Place - Suite 330
27 Boston, MA 02111-1307, USA
28
29 */
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40 #include <stdlib.h>
41
42 #include <QF/hash.h>
43
44 #include "opcodes.h"
45 #include "options.h"
46 #include "qfcc.h"
47 #include "statements.h"
48 #include "type.h"
49
50 hashtab_t *opcode_type_table;
51 hashtab_t *opcode_void_table;
52
53 #define ROTL(x,n) ((((unsigned)(x))<<(n))|((unsigned)(x))>>(32-n))
54
55 static uintptr_t
get_hash(const void * _op,void * _tab)56 get_hash (const void *_op, void *_tab)
57 {
58 opcode_t *op = (opcode_t *) _op;
59 uintptr_t hash;
60
61 hash = ROTL (~op->type_a, 8) + ROTL (~op->type_b, 16)
62 + ROTL (~op->type_c, 24);
63 return hash + Hash_String (op->name);
64 }
65
66 static int
compare(const void * _opa,const void * _opb,void * unused)67 compare (const void *_opa, const void *_opb, void *unused)
68 {
69 opcode_t *opa = (opcode_t *) _opa;
70 opcode_t *opb = (opcode_t *) _opb;
71 int cmp;
72
73 cmp = (opa->type_a == opb->type_a)
74 && (opa->type_b == opb->type_b)
75 && (opa->type_c == opb->type_c);
76 return cmp && !strcmp (opa->name, opb->name);
77 }
78
79 static const char *
get_key(const void * op,void * unused)80 get_key (const void *op, void *unused)
81 {
82 return ((opcode_t *) op)->name;
83 }
84
85 static int
check_operand_type(etype_t ot1,etype_t ot2)86 check_operand_type (etype_t ot1, etype_t ot2)
87 {
88 if ((ot1 == ev_void && ot2 != ev_invalid)
89 || ot1 == ot2)
90 return 1;
91 return 0;
92 }
93
94 opcode_t *
opcode_find(const char * name,operand_t * op_a,operand_t * op_b,operand_t * op_c)95 opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
96 operand_t *op_c)
97 {
98 opcode_t search_op;
99 opcode_t *op;
100 opcode_t *sop;
101 void **op_list;
102 int i;
103
104 search_op.name = name;
105 search_op.type_a = op_a ? op_a->type : ev_invalid;
106 search_op.type_b = op_b ? op_b->type : ev_invalid;
107 search_op.type_c = op_c ? op_c->type : ev_invalid;
108 op = Hash_FindElement (opcode_type_table, &search_op);
109 if (op)
110 return op;
111 op_list = Hash_FindList (opcode_void_table, name);
112 if (!op_list)
113 return op;
114 for (i = 0; !op && op_list[i]; i++) {
115 sop = op_list[i];
116 if (check_operand_type (sop->type_a, search_op.type_a)
117 && check_operand_type (sop->type_b, search_op.type_b)
118 && check_operand_type (sop->type_c, search_op.type_c))
119 op = sop;
120 }
121 free (op_list);
122 return op;
123 }
124
125 static void
opcode_free(void * _op,void * unused)126 opcode_free (void *_op, void *unused)
127 {
128 free (_op);
129 }
130
131 void
opcode_init(void)132 opcode_init (void)
133 {
134 opcode_t *op, *mop;
135
136 if (opcode_type_table) {
137 Hash_FlushTable (opcode_void_table);
138 Hash_FlushTable (opcode_type_table);
139 } else {
140 PR_Opcode_Init ();
141 opcode_type_table = Hash_NewTable (1021, 0, opcode_free, 0);
142 Hash_SetHashCompare (opcode_type_table, get_hash, compare);
143 opcode_void_table = Hash_NewTable (1021, get_key, 0, 0);
144 }
145 for (op = pr_opcodes; op->name; op++) {
146 if (op->min_version > options.code.progsversion)
147 continue;
148 mop = malloc (sizeof (opcode_t));
149 *mop = *op;
150 if (options.code.progsversion == PROG_ID_VERSION) {
151 // v6 progs have no concept of integer, but the QF engine
152 // treats the operands of certain operands as integers
153 // irrespective the progs version, so convert the engine's
154 // view of the operands to the prog's view.
155 if (mop->type_a == ev_integer)
156 mop->type_a = ev_float;
157 if (mop->type_b == ev_integer)
158 mop->type_b = ev_float;
159 if (mop->type_c == ev_integer)
160 mop->type_c = ev_float;
161 }
162 Hash_AddElement (opcode_type_table, mop);
163 if (mop->type_a == ev_void || mop->type_b == ev_void
164 || mop->type_c == ev_void)
165 Hash_Add (opcode_void_table, mop);
166 }
167 }
168