Add all asm files to test. Unfortunately, it crashes again. Will
[jitcs.git] / tests / test_asm.cpp
blob06548bc208771398cfc1f252dbe5fb26dead8c89
1 #include "test_asm.h"
2 #include "jitcs_callingconvention.h"
3 #include "jitcs_machine.h"
4 #include "jitcs_tmpalloc.h"
5 #include "jitcs_memmgr.h"
6 #include "jitcs_function.h"
7 #include <stdio.h>
9 static bool readln(FILE* f, std::string& line, size_t& linecount) {
10 char c;
11 line.clear();
12 while (fread(&c, 1, 1, f) == 1) {
13 if (c == '\r') return true;
14 if (c == '\n') { linecount++; return true; }
15 line.append(1, c);
17 return (line.size() > 0);
19 static void trim(std::string& line) {
21 std::string::iterator i = line.begin(), e = line.end();
22 while (i != e && *i == ' ') ++i;
23 line.erase(line.begin(), i);
26 std::string::iterator i = line.begin(), e = line.end();
27 while (i != e && *(e - 1) == ' ') --e;
28 line.erase(e, line.end());
31 void TestAssembler::split(std::string const& line, std::string const& splitter, std::string& pin, std::string& pout) {
32 std::string::size_type pos = line.find(splitter);
33 if (pos != std::string::npos) {
34 pin = line.substr(0, pos);
35 pout = line.substr(pos + splitter.size());
36 trim(pin);
37 trim(pout);
38 } else {
39 pin = line;
40 trim(pin);
41 pout.clear();
44 void TestAssembler::split(std::string const& line, std::string const& splitter, std::vector<std::string>& parts) {
45 std::string worker = line;
46 std::string::size_type pos;
47 while ((pos = worker.find(splitter)) != std::string::npos) {
48 std::string pin = worker.substr(0, pos);
49 trim(pin);
50 parts.push_back(pin);
51 worker = worker.substr(pos + splitter.size());
53 trim(worker);
54 parts.push_back(worker);
56 static bool read_outbytes(std::string const& data, std::vector<jitcs::u8>& out) {
57 jitcs::u8 d = 0;
58 bool second = false;
59 for (std::string::const_iterator i = data.begin(), e = data.end(); i != e; ++i) {
60 char c = *i;
61 if (c == ' ') continue;
62 if (c >= '0' && c <= '9') {
63 d = d * 16 + (c - '0');
64 second = !second;
65 if (!second) out.push_back(d);
66 continue;
68 c = c | 0x20;
69 if (c >= 'a' && c <= 'f') {
70 d = d * 16 + 10 + (c - 'a');
71 second = !second;
72 if (!second) out.push_back(d);
73 continue;
75 return false;
77 return !second;
79 std::string TestAssembler::toLower(std::string const& z) {
80 std::string x = z;
81 for (std::string::iterator i = x.begin(), e = x.end(); i != e; ++i) {
82 if (*i >= 'A' && *i <= 'Z') *i |= 0x20;
84 return x;
87 TestAssembler::TestAssembler(jitcs::RefCounter<jitcs::MemoryMgr> m,
88 jitcs::RefCounter<jitcs::TempAllocator> a,
89 jitcs::RefCounter<jitcs::IMachineInfo> mi_)
90 : mem(m)
91 , alloc(a)
92 , mi(mi_) {
93 setup = false;
94 clear();
95 puts("TestAssembler constructor");
97 TestAssembler::~TestAssembler() {
98 puts("TestAssembler destructor");
101 void TestAssembler::clear() {
102 outbytes.clear();
103 bbnames.clear();
104 vrnames.clear();
105 fnc.reset();
106 curbb = nullptr;
108 const jitcs::VirtualRegister* TestAssembler::findReg(std::string const& n) {
109 std::string n2 = toLower(n);
110 if (constvrnames.find(n2) != constvrnames.end())
111 return constvrnames[n2];
112 if (vrnames.find(n2) != vrnames.end())
113 return vrnames[n2];
114 return nullptr;
116 //void printBytes(std::vector<u8> const& v) {
117 // for (std::vector<u8>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)
118 // printf("%02X", *i);
120 bool TestAssembler::_runTest(jitcs::UnitTest& t, std::string const& outputfile) {
121 std::vector<jitcs::u8> expected = outbytes, result;
122 jitcs::MemoryMgr::CodeAndData cda = fnc->generate(mem, jitcs::Function::Direct_Code_Gen);
123 result.insert(result.begin(), cda.code._ptr, cda.code._ptr + cda.code.size());
124 mem->deallocate(cda);
126 bool ok = true;
127 size_t i, n;
128 if (expected.size() > result.size()) ok = false;
129 if (ok) {
130 for (i = 0, n = expected.size(); i < n; ++i) {
131 if (expected[i] != result[i]) {
132 ok = false; break;
137 if (outputfile.size() > 0) {
138 FILE* f = fopen(outputfile.c_str(), "wb");
139 if (result.size() > 0)
140 fwrite(&result[0], result.size(), 1, f);
141 fclose(f);
144 if (!ok) {
145 char buffer[100];
146 sprintf(buffer, "byte test failed at byte %d", i);
147 _error(t, buffer);
149 clear();
150 return ok;
152 void TestAssembler::_error(jitcs::UnitTest& t, std::string const& text) {
153 std::string msg;
154 if (filename.size() > 0) {
155 msg += "file ";
156 msg += filename;
157 msg += ":";
159 if (funcname.size() > 0) {
160 msg += "fnc ";
161 msg += funcname;
162 msg += ":";
164 if (lineno >= 1) {
165 char buf[20];
166 sprintf(buf, "line %d: ", lineno);
167 msg += buf;
169 msg += text;
170 t.check(msg.c_str(), false);
172 static void _check(jitcs::UnitTest& t, std::string const& text, bool condition) {
173 t.check(text.c_str(), condition);
176 void TestAssembler::checkFile(jitcs::UnitTest& t, std::string const& filename_,
177 std::unordered_set<jitcs::u32>* used_insids,
178 std::string const& outputfile) {
179 if (!setup) {
180 setupInstructionNames(constinsnames);
181 setupRegisterClassNames(constrcnames);
182 setupFixedRegisterNames(constvrnames);
183 setup = true;
185 filename = filename_;
186 funcname = "";
187 lineno = 0;
189 jitcs::StreamAllocator<jitcs::MemoryReference> memstreamer(*alloc, 32);
190 memstream = &memstreamer;
192 FILE* f = fopen(filename.c_str(), "r");
193 if (!f) {
194 _error(t, "cannot open");
195 return;
197 bool dump = false;
198 bool empty = true;
199 std::string line, pin, pout;
200 while (readln(f, line, lineno)) {
201 split(line, "==>", pin, pout);
203 if (pin.substr(0,3) == "<==") {
204 if (!empty) {
205 ibuf.end();
206 if (!_runTest(t, outputfile)) return;
208 empty = true;
209 funcname = pin.substr(3);
210 trim(funcname);
211 } else if (pin.substr(0,5) == "@fun:") {
212 jitcs::FTSubType sub = jitcs::FTS_CDecl;
213 std::vector<jitcs::FTTypeId> restypes, partypes;
214 std::string parms, result;
215 std::vector<std::string> parmvec, resvec;
216 split(pin.substr(5), "->", parms, result);
217 split(parms, ",", parmvec);
218 split(result, ",", resvec);
219 for (size_t i = 0, n = parmvec.size(); i < n; ++i) {
220 std::string type, varname;
221 split(parmvec[i], " ", type, varname);
222 if (type == "int") {
223 partypes.push_back(jitcs::FTT_Int);
224 } else if (type == "void*") {
225 partypes.push_back(jitcs::FTT_Ptr);
226 } else if (type == "ptrdiff_t") {
227 partypes.push_back(jitcs::FTT_PtrInt);
228 } else if (type == "void") {
229 partypes.push_back(jitcs::FTT_Void);
230 } else {
231 _error(t, "invalid param type "+type);
232 return;
235 if (partypes.size() == 1 && partypes[0] == jitcs::FTT_Void) {
236 partypes.clear();
238 for (size_t i = 0, n = resvec.size(); i < n; ++i) {
239 std::string type, varname;
240 split(resvec[i], " ", type, varname);
241 if (type == "int") {
242 restypes.push_back(jitcs::FTT_Int);
243 } else if (type == "void*") {
244 restypes.push_back(jitcs::FTT_Ptr);
245 } else if (type == "ptrdiff_t") {
246 restypes.push_back(jitcs::FTT_PtrInt);
247 } else if (type == "void") {
248 restypes.push_back(jitcs::FTT_Void);
249 } else {
250 _error(t, "invalid result type "+type);
251 return;
254 if (restypes.size() == 1 && restypes[0] == jitcs::FTT_Void) {
255 restypes.clear();
257 if (resvec.size() != 1) {
258 _error(t, "more than one result value");
259 return;
261 jitcs::Slice<jitcs::FTTypeId> resslice = restypes.size() > 0
262 ? jitcs::Slice<jitcs::FTTypeId>(&restypes[0], restypes.size())
263 : jitcs::Slice<jitcs::FTTypeId>(nullptr, 0);
264 jitcs::Slice<jitcs::FTTypeId> parslice = partypes.size() > 0
265 ? jitcs::Slice<jitcs::FTTypeId>(&partypes[0], partypes.size())
266 : jitcs::Slice<jitcs::FTTypeId>(nullptr, 0);
267 std::shared_ptr<const jitcs::CallingConvention> cc
268 = mi->getCC(sub, resslice, parslice);
269 fnc.reset();
270 fnc = std::move(mi->createFnc(alloc, cc));
272 //for (size_t i = 0, n = parmvec.size(); i < n; ++i) {
273 // std::string type, varname;
274 // split(parmvec[i], " ", type, varname);
275 // if (varname.size() > 0) vrnames[toLower(varname)] = fnc->arg(i);
277 //for (size_t i = 0, n = resvec.size(); i < n; ++i) {
278 // std::string type, varname;
279 // split(resvec[i], " ", type, varname);
280 // if (varname.size() > 0) vrnames[toLower(varname)] = fnc->result(i);
282 empty = false;
283 curbb = fnc->getStartBlock()._ptr;
284 ibuf.start(jitcs::RefOrNull<jitcs::BasicBlock>(curbb));
285 } else if (pin.substr(0,1) == ":") {
286 if (empty) {
287 _error(t, "cannot add basic block to empty function");
288 return;
290 std::string n2 = toLower(pin.substr(1));
291 jitcs::BasicBlock* bb = bbnames.find(n2) != bbnames.end() ? bbnames[n2] : fnc->createBasicBlock()._ptr;
292 ibuf.end();
293 curbb = bb;
294 ibuf.start(jitcs::RefOrNull<jitcs::BasicBlock>(curbb));
295 bbnames[pin.substr(1)] = bb;
296 } else if (pin.substr(0,5) == "@var:") {
297 if (empty) {
298 _error(t, "cannot add var to empty function");
299 return;
301 std::string z = toLower(pin.substr(5));
302 trim(z);
303 std::string type, varname;
304 split(z, " ", type, varname);
305 if (varname == "") {
306 _error(t, "unnamed var");
307 return;
309 if (constrcnames.find(type) == constrcnames.end()) {
310 _error(t, "invalid register class for var " + varname);
311 return;
313 vrnames[toLower(varname)] = fnc->createRegister(static_cast<jitcs::RegClassId>(constrcnames[type]))._ptr;
314 } else if (pin.substr(0,10) == "@strategy:") {
315 if (empty) {
316 _error(t, "cannot set flags of empty function");
317 return;
319 } else if (pin == "") {
320 } else {
321 puts("ins:");
322 puts(pin.c_str());
324 std::string ins, parms;
325 std::vector<std::string> parmvec;
326 split(toLower(pin), " ", ins, parms);
327 if (parms != "")
328 split(parms, ",", parmvec);
329 if (constinsnames.find(ins) == constinsnames.end()) {
330 _error(t, "invalid instruction " + ins);
331 return;
333 if (used_insids)
334 used_insids->insert(constinsnames[ins]);
335 const char* x = addInstruction(constinsnames[ins], parmvec);
336 if (x != nullptr) {
337 _error(t, "error in instruction '" + pin + "': " + x);
338 return;
342 if (!read_outbytes(pout, outbytes)) {
343 _error(t, "invalid outbytes");
344 return;
347 if (!empty) {
348 ibuf.end();
349 if (!_runTest(t, outputfile)) return;
351 return;