-
Notifications
You must be signed in to change notification settings - Fork 1
/
synthetic.c
181 lines (137 loc) · 5.05 KB
/
synthetic.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
/*
* (C) Iain Fraser - GPLv3
* Sythentic generic machine instructions.
*/
#include <stdarg.h>
#include "emitter.h"
#include "machine.h"
#include "frame.h"
void assign( struct machine_ops* mop, struct emitter* e, struct machine* m, vreg_operand d, vreg_operand s ) {
mop->move( e, m, d.value, s.value );
mop->move( e, m, d.type, s.type );
}
void loadim( struct machine_ops* mop, struct emitter* e, struct machine* m, int reg, int value ) {
operand r = OP_TARGETREG( reg );
operand v = OP_TARGETIMMED( value );
mop->move( e, m, r, v );
}
void pushn( struct machine_ops* mop, struct emitter* e, struct machine* m, int nr_operands, ... ){
va_list ap;
const operand stack = OP_TARGETREG( m->sp );
va_start( ap, nr_operands );
if( nr_operands == 1 && mop->push ){
mop->push( e, m, va_arg( ap, operand ) );
} else {
for( int i = 0; i < nr_operands; i++ )
mop->move( e, m, OP_TARGETDADDR( m->sp, -4 * ( i + 1 ) ), va_arg( ap, operand ) );
mop->add( e, m, stack, stack, OP_TARGETIMMED( -4 * nr_operands ) );
}
va_end( ap );
}
void popn( struct machine_ops* mop, struct emitter* e, struct machine* m, int nr_operands, ... ){
va_list ap;
const operand stack = OP_TARGETREG( m->sp );
va_start( ap, nr_operands );
if( nr_operands == 1 && mop->pop ){
mop->pop( e, m, va_arg( ap, operand ) );
} else {
for( int i = 0; i < nr_operands; i++ )
mop->move( e, m, va_arg( ap, operand ), OP_TARGETDADDR( m->sp, 4 * i ) );
mop->add( e, m, stack, stack, OP_TARGETIMMED( 4 * nr_operands ) );
}
va_end( ap );
}
void address_of( struct machine_ops *mop, struct emitter *e, struct machine *m,
operand d,
operand s ){
assert( ISO_DADDR( s ) );
mop->add( e, m, d, OP_TARGETREG( s.base ),
OP_TARGETIMMED( s.offset ) );
}
void vreg_fill( struct machine_ops *mop, struct emitter *e, struct frame *f,
int vreg ){
vreg_operand on = vreg_to_operand( f, vreg, false );
vreg_operand off = vreg_to_operand( f, vreg, true );
if( ISO_REG( on.value ) )
mop->move( e, f->m, on.value, off.value );
if( ISO_REG( on.type ) )
mop->move( e, f->m, on.type, off.type );
}
void vreg_type_fill( struct machine_ops *mop, struct emitter *e
, struct frame * f
, int vreg ){
vreg_operand on = vreg_to_operand( f, vreg, false );
vreg_operand off = vreg_to_operand( f, vreg, true );
if( ISO_REG( on.type ) )
mop->move( e, f->m, on.type, off.type );
}
void vreg_spill( struct machine_ops *mop, struct emitter *e, struct frame *f,
int vreg ){
vreg_operand on = vreg_to_operand( f, vreg, false );
vreg_operand off = vreg_to_operand( f, vreg, true );
if( ISO_REG( on.value ) )
mop->move( e, f->m, off.value, on.value );
if( ISO_REG( on.type ) )
mop->move( e, f->m, off.type, on.type );
}
/*
* Code that predated JFuncs. Can probably be removed now.
*/
// this function could be inline
void syn_memcpyw( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand s, operand size ){
operand iter = OP_TARGETREG( acquire_temp( mop, e, m ) );
operand src = OP_TARGETREG( acquire_temp( mop, e, m ) );
operand dst = OP_TARGETREG( acquire_temp( mop, e, m ) );
// init iterator
mop->move( e, m, iter, OP_TARGETIMMED( 0 ) );
mop->move( e, m, src, s );
mop->move( e, m, dst, d );
// start loop
e->ops->label_local( e, 0 );
mop->beq( e, m, iter, size, LBL_NEXT( 0 ) );
// copy
mop->move( e, m, OP_TARGETDADDR( dst.reg, 0 ), OP_TARGETDADDR( src.reg, 0 ) );
// update pointers
mop->add( e, m, dst, dst, OP_TARGETIMMED( -4 ) ); // TODO: this is incorrect in general but correct for copyargs
mop->add( e, m, src, src, OP_TARGETIMMED( -4 ) );
// update iterator
mop->add( e, m, iter, iter, OP_TARGETIMMED( 1 ) );
mop->b( e, m, LBL_PREV( 0 ) );
e->ops->label_local( e, 0 );
release_tempn( mop, e, m, 3 );
}
void syn_memsetw( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand v, operand size ){
operand iter = OP_TARGETREG( acquire_temp( mop, e, m ) );
operand dst = OP_TARGETREG( acquire_temp( mop, e, m ) );
// init iterator
mop->move( e, m, iter, OP_TARGETIMMED( 0 ) );
mop->move( e, m, dst, d );
// start loop
e->ops->label_local( e, 0 );
mop->beq( e, m, iter, size, LBL_NEXT( 0 ) );
// copy
mop->move( e, m, OP_TARGETDADDR( dst.reg, 0 ), v );
// update pointers
mop->add( e, m, dst, dst, OP_TARGETIMMED( 4 ) );
// update iterator
mop->add( e, m, iter, iter, OP_TARGETIMMED( 1 ) );
mop->b( e, m, LBL_PREV( 0 ) );
e->ops->label_local( e, 0 );
release_tempn( mop, e, m, 2 );
}
void syn_min( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand s, operand t ){
mop->blt( e, m, s, t, LBL_NEXT( 0 ) );
mop->move( e, m, d, t );
mop->b( e, m, LBL_NEXT( 1 ) );
e->ops->label_local( e, 0 );
mop->move( e, m, d, s );
e->ops->label_local( e, 1 );
}
void syn_max( struct machine_ops* mop, struct emitter* e, struct machine* m, operand d, operand s, operand t ){
mop->blt( e, m, s, t, LBL_NEXT( 0 ) );
mop->move( e, m, d, t );
mop->b( e, m, LBL_NEXT( 1 ) );
e->ops->label_local( e, 0 );
mop->move( e, m, d, s );
e->ops->label_local( e, 1 );
}