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
|
#include <ejit/ejit.h>
#include <assert.h>
#include "do_jit.h"
/* register allocator had a bug where registers whose last use was midway
* through a loop might get overwritten, here's one case that exposed the bug */
#define X 10
int A[X][X];
int B[X][X];
int C[X][X];
bool do_jit = false;
static void init_matrices(int A[X][X], int B[X][X])
{
int counter = 1;
for (size_t i = 0; i < X; ++i)
for (size_t j = 0; j < X; ++j) {
A[i][j] = counter;
B[i][j] = counter;
C[i][j] = 0;
counter++;
}
}
static int hash(int C[X][X])
{
int h = 0;
for (size_t i = 0; i < X; ++i)
for (size_t j = 0; j < X; ++j) {
h += C[i][j];
}
return h;
}
static struct ejit_func *compile()
{
#define IR EJIT_GPR(0)
#define JR EJIT_GPR(1)
#define KR EJIT_GPR(2)
#define AR EJIT_GPR(3)
#define BR EJIT_GPR(4)
#define CR EJIT_GPR(5)
#define AX EJIT_GPR(6)
#define BX EJIT_GPR(7)
#define CX EJIT_GPR(8)
#define RR EJIT_GPR(9)
#define TMP EJIT_GPR(10)
struct ejit_operand args[3] = {
EJIT_OPERAND_GPR(3, EJIT_TYPE(int *)), /* A */
EJIT_OPERAND_GPR(4, EJIT_TYPE(int *)), /* B */
EJIT_OPERAND_GPR(5, EJIT_TYPE(int *)), /* C */
};
struct ejit_func *f = ejit_create_func(EJIT_VOID, 3, args);
ejit_movi(f, IR, 0);
struct ejit_label out = ejit_label(f);
struct ejit_reloc outer = ejit_bgei(f, IR, X);
ejit_movi(f, JR, 0);
struct ejit_label mid = ejit_label(f);
struct ejit_reloc midder = ejit_bgei(f, JR, X);
ejit_movi(f, RR, 0);
ejit_movi(f, KR, 0);
struct ejit_label in = ejit_label(f);
struct ejit_reloc inner = ejit_bgei(f, KR, X);
/* A[i][k] at addr 4 * (i * 400 + k) */
ejit_movi(f, TMP, X);
ejit_mulr(f, AX, IR, TMP);
ejit_addr(f, AX, AX, KR);
ejit_movi(f, TMP, 4);
ejit_lshi(f, AX, AX, 2);
EJIT_LDXR(f, int, AX, AR, AX);
/* B[k][j] at addr 4 * (k * 400 + j) */
ejit_movi(f, TMP, X);
ejit_mulr(f, BX, KR, TMP);
ejit_addr(f, BX, BX, JR);
ejit_movi(f, TMP, 4);
ejit_lshi(f, BX, BX, 2);
EJIT_LDXR(f, int, BX, BR, BX);
/* R += A[i][k] * B[k][j] */
ejit_mulr(f, TMP, AX, BX);
ejit_addr(f, RR, RR, TMP);
/* increment inner */
ejit_addi(f, KR, KR, 1);
ejit_patch(f, ejit_jmp(f), in);
/* end of inner */
ejit_patch(f, inner, ejit_label(f));
/* C[i][j] at addr 4 * (i * 400 + j) */
ejit_movi(f, TMP, X);
ejit_mulr(f, CX, IR, TMP);
ejit_addr(f, CX, CX, JR);
ejit_lshi(f, CX, CX, 2);
/* C[i][j] = R */
EJIT_STXR(f, int, RR, CX, CR);
/* increment midder */
ejit_addi(f, JR, JR, 1);
ejit_patch(f, ejit_jmp(f), mid);
/* end of midder */
ejit_patch(f, midder, ejit_label(f));
/* increment outer */
ejit_addi(f, IR, IR, 1);
ejit_patch(f, ejit_jmp(f), out);
/* end of outer */
ejit_patch(f, outer, ejit_label(f));
/* return */
ejit_ret(f);
ejit_select_compile_func(f, 11, 0, EJIT_USE64(long), do_jit, true);
return f;
}
int main(int argc, char *argv[])
{
(void)argv;
do_jit = argc > 1;
init_matrices(A, B);
struct ejit_func *f = compile();
struct ejit_arg args[3] = {
EJIT_ARG(A, int *),
EJIT_ARG(B, int *),
EJIT_ARG(C, int *)
};
ejit_run_func(f, 3, args);
assert(hash(C) == 2632750);
ejit_destroy_func(f);
return 0;
}
|