1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2020 Valve Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker #include "aco_ir.h"
7*61046927SAndroid Build Coastguard Worker
8*61046927SAndroid Build Coastguard Worker #include <llvm-c/Target.h>
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include "framework.h"
11*61046927SAndroid Build Coastguard Worker #include <getopt.h>
12*61046927SAndroid Build Coastguard Worker #include <map>
13*61046927SAndroid Build Coastguard Worker #include <set>
14*61046927SAndroid Build Coastguard Worker #include <stdarg.h>
15*61046927SAndroid Build Coastguard Worker #include <stdio.h>
16*61046927SAndroid Build Coastguard Worker #include <string.h>
17*61046927SAndroid Build Coastguard Worker #include <string>
18*61046927SAndroid Build Coastguard Worker #include <unistd.h>
19*61046927SAndroid Build Coastguard Worker #include <vector>
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker static const char* help_message =
22*61046927SAndroid Build Coastguard Worker "Usage: %s [-h] [-l --list] [--no-check] [TEST [TEST ...]]\n"
23*61046927SAndroid Build Coastguard Worker "\n"
24*61046927SAndroid Build Coastguard Worker "Run ACO unit test(s). If TEST is not provided, all tests are run.\n"
25*61046927SAndroid Build Coastguard Worker "\n"
26*61046927SAndroid Build Coastguard Worker "positional arguments:\n"
27*61046927SAndroid Build Coastguard Worker " TEST Run TEST. If TEST ends with a '.', run tests with names\n"
28*61046927SAndroid Build Coastguard Worker " starting with TEST. The test variant (after the '/') can\n"
29*61046927SAndroid Build Coastguard Worker " be omitted to run all variants\n"
30*61046927SAndroid Build Coastguard Worker "\n"
31*61046927SAndroid Build Coastguard Worker "optional arguments:\n"
32*61046927SAndroid Build Coastguard Worker " -h, --help Show this help message and exit.\n"
33*61046927SAndroid Build Coastguard Worker " -l --list List unit tests.\n"
34*61046927SAndroid Build Coastguard Worker " --no-check Print test output instead of checking it.\n";
35*61046927SAndroid Build Coastguard Worker
36*61046927SAndroid Build Coastguard Worker std::map<std::string, TestDef> *tests = NULL;
37*61046927SAndroid Build Coastguard Worker FILE* output = NULL;
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker static TestDef current_test;
40*61046927SAndroid Build Coastguard Worker static unsigned tests_written = 0;
41*61046927SAndroid Build Coastguard Worker static FILE* checker_stdin = NULL;
42*61046927SAndroid Build Coastguard Worker static char* checker_stdin_data = NULL;
43*61046927SAndroid Build Coastguard Worker static size_t checker_stdin_size = 0;
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker static char* output_data = NULL;
46*61046927SAndroid Build Coastguard Worker static size_t output_size = 0;
47*61046927SAndroid Build Coastguard Worker static size_t output_offset = 0;
48*61046927SAndroid Build Coastguard Worker
49*61046927SAndroid Build Coastguard Worker static char current_variant[64] = {0};
50*61046927SAndroid Build Coastguard Worker static std::set<std::string>* variant_filter = NULL;
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker bool test_failed = false;
53*61046927SAndroid Build Coastguard Worker bool test_skipped = false;
54*61046927SAndroid Build Coastguard Worker static char fail_message[256] = {0};
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker void
write_test()57*61046927SAndroid Build Coastguard Worker write_test()
58*61046927SAndroid Build Coastguard Worker {
59*61046927SAndroid Build Coastguard Worker if (!checker_stdin) {
60*61046927SAndroid Build Coastguard Worker /* not entirely correct, but shouldn't matter */
61*61046927SAndroid Build Coastguard Worker tests_written++;
62*61046927SAndroid Build Coastguard Worker return;
63*61046927SAndroid Build Coastguard Worker }
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker fflush(output);
66*61046927SAndroid Build Coastguard Worker if (output_offset == output_size && !test_skipped && !test_failed)
67*61046927SAndroid Build Coastguard Worker return;
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker char* data = output_data + output_offset;
70*61046927SAndroid Build Coastguard Worker uint32_t size = output_size - output_offset;
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker fwrite("test", 1, 4, checker_stdin);
73*61046927SAndroid Build Coastguard Worker fwrite(current_test.name, 1, strlen(current_test.name) + 1, checker_stdin);
74*61046927SAndroid Build Coastguard Worker fwrite(current_variant, 1, strlen(current_variant) + 1, checker_stdin);
75*61046927SAndroid Build Coastguard Worker fwrite(current_test.source_file, 1, strlen(current_test.source_file) + 1, checker_stdin);
76*61046927SAndroid Build Coastguard Worker if (test_failed || test_skipped) {
77*61046927SAndroid Build Coastguard Worker const char* res = test_failed ? "failed" : "skipped";
78*61046927SAndroid Build Coastguard Worker fwrite("\x01", 1, 1, checker_stdin);
79*61046927SAndroid Build Coastguard Worker fwrite(res, 1, strlen(res) + 1, checker_stdin);
80*61046927SAndroid Build Coastguard Worker fwrite(fail_message, 1, strlen(fail_message) + 1, checker_stdin);
81*61046927SAndroid Build Coastguard Worker } else {
82*61046927SAndroid Build Coastguard Worker fwrite("\x00", 1, 1, checker_stdin);
83*61046927SAndroid Build Coastguard Worker }
84*61046927SAndroid Build Coastguard Worker fwrite(&size, 4, 1, checker_stdin);
85*61046927SAndroid Build Coastguard Worker fwrite(data, 1, size, checker_stdin);
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker tests_written++;
88*61046927SAndroid Build Coastguard Worker output_offset += size;
89*61046927SAndroid Build Coastguard Worker }
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker bool
set_variant(const char * name)92*61046927SAndroid Build Coastguard Worker set_variant(const char* name)
93*61046927SAndroid Build Coastguard Worker {
94*61046927SAndroid Build Coastguard Worker if (variant_filter && !variant_filter->count(name))
95*61046927SAndroid Build Coastguard Worker return false;
96*61046927SAndroid Build Coastguard Worker
97*61046927SAndroid Build Coastguard Worker write_test();
98*61046927SAndroid Build Coastguard Worker test_failed = false;
99*61046927SAndroid Build Coastguard Worker test_skipped = false;
100*61046927SAndroid Build Coastguard Worker strncpy(current_variant, name, sizeof(current_variant) - 1);
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker printf("Running '%s/%s'\n", current_test.name, name);
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker return true;
105*61046927SAndroid Build Coastguard Worker }
106*61046927SAndroid Build Coastguard Worker
107*61046927SAndroid Build Coastguard Worker void
fail_test(const char * fmt,...)108*61046927SAndroid Build Coastguard Worker fail_test(const char* fmt, ...)
109*61046927SAndroid Build Coastguard Worker {
110*61046927SAndroid Build Coastguard Worker va_list args;
111*61046927SAndroid Build Coastguard Worker va_start(args, fmt);
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker test_failed = true;
114*61046927SAndroid Build Coastguard Worker vsnprintf(fail_message, sizeof(fail_message), fmt, args);
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker va_end(args);
117*61046927SAndroid Build Coastguard Worker }
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker void
skip_test(const char * fmt,...)120*61046927SAndroid Build Coastguard Worker skip_test(const char* fmt, ...)
121*61046927SAndroid Build Coastguard Worker {
122*61046927SAndroid Build Coastguard Worker va_list args;
123*61046927SAndroid Build Coastguard Worker va_start(args, fmt);
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker test_skipped = true;
126*61046927SAndroid Build Coastguard Worker vsnprintf(fail_message, sizeof(fail_message), fmt, args);
127*61046927SAndroid Build Coastguard Worker
128*61046927SAndroid Build Coastguard Worker va_end(args);
129*61046927SAndroid Build Coastguard Worker }
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker void
run_test(TestDef def)132*61046927SAndroid Build Coastguard Worker run_test(TestDef def)
133*61046927SAndroid Build Coastguard Worker {
134*61046927SAndroid Build Coastguard Worker current_test = def;
135*61046927SAndroid Build Coastguard Worker output_data = NULL;
136*61046927SAndroid Build Coastguard Worker output_size = 0;
137*61046927SAndroid Build Coastguard Worker output_offset = 0;
138*61046927SAndroid Build Coastguard Worker test_failed = false;
139*61046927SAndroid Build Coastguard Worker test_skipped = false;
140*61046927SAndroid Build Coastguard Worker memset(current_variant, 0, sizeof(current_variant));
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker if (checker_stdin)
143*61046927SAndroid Build Coastguard Worker output = open_memstream(&output_data, &output_size);
144*61046927SAndroid Build Coastguard Worker else
145*61046927SAndroid Build Coastguard Worker output = stdout;
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker current_test.func();
148*61046927SAndroid Build Coastguard Worker write_test();
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Worker if (checker_stdin)
151*61046927SAndroid Build Coastguard Worker fclose(output);
152*61046927SAndroid Build Coastguard Worker free(output_data);
153*61046927SAndroid Build Coastguard Worker }
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker int
check_output(char ** argv)156*61046927SAndroid Build Coastguard Worker check_output(char** argv)
157*61046927SAndroid Build Coastguard Worker {
158*61046927SAndroid Build Coastguard Worker fflush(stdout);
159*61046927SAndroid Build Coastguard Worker fflush(stderr);
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker fclose(checker_stdin);
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker int stdin_pipe[2];
164*61046927SAndroid Build Coastguard Worker pipe(stdin_pipe);
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker pid_t child_pid = fork();
167*61046927SAndroid Build Coastguard Worker if (child_pid == -1) {
168*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s: fork() failed: %s\n", argv[0], strerror(errno));
169*61046927SAndroid Build Coastguard Worker return 99;
170*61046927SAndroid Build Coastguard Worker } else if (child_pid != 0) {
171*61046927SAndroid Build Coastguard Worker /* Evaluate test output externally using Python */
172*61046927SAndroid Build Coastguard Worker dup2(stdin_pipe[0], STDIN_FILENO);
173*61046927SAndroid Build Coastguard Worker close(stdin_pipe[0]);
174*61046927SAndroid Build Coastguard Worker close(stdin_pipe[1]);
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker execlp(ACO_TEST_PYTHON_BIN, ACO_TEST_PYTHON_BIN, ACO_TEST_SOURCE_DIR "/check_output.py",
177*61046927SAndroid Build Coastguard Worker NULL);
178*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s: execlp() failed: %s\n", argv[0], strerror(errno));
179*61046927SAndroid Build Coastguard Worker return 99;
180*61046927SAndroid Build Coastguard Worker } else {
181*61046927SAndroid Build Coastguard Worker /* Feed input data to the Python process. Writing large streams to
182*61046927SAndroid Build Coastguard Worker * stdin will block eventually, so this is done in a forked process
183*61046927SAndroid Build Coastguard Worker * to let the test checker process chunks of data as they arrive */
184*61046927SAndroid Build Coastguard Worker write(stdin_pipe[1], checker_stdin_data, checker_stdin_size);
185*61046927SAndroid Build Coastguard Worker close(stdin_pipe[0]);
186*61046927SAndroid Build Coastguard Worker close(stdin_pipe[1]);
187*61046927SAndroid Build Coastguard Worker _exit(0);
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker }
190*61046927SAndroid Build Coastguard Worker
191*61046927SAndroid Build Coastguard Worker bool
match_test(std::string name,std::string pattern)192*61046927SAndroid Build Coastguard Worker match_test(std::string name, std::string pattern)
193*61046927SAndroid Build Coastguard Worker {
194*61046927SAndroid Build Coastguard Worker if (name.length() < pattern.length())
195*61046927SAndroid Build Coastguard Worker return false;
196*61046927SAndroid Build Coastguard Worker if (pattern.back() == '.')
197*61046927SAndroid Build Coastguard Worker name.resize(pattern.length());
198*61046927SAndroid Build Coastguard Worker return name == pattern;
199*61046927SAndroid Build Coastguard Worker }
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker int
main(int argc,char ** argv)202*61046927SAndroid Build Coastguard Worker main(int argc, char** argv)
203*61046927SAndroid Build Coastguard Worker {
204*61046927SAndroid Build Coastguard Worker int print_help = 0;
205*61046927SAndroid Build Coastguard Worker int do_list = 0;
206*61046927SAndroid Build Coastguard Worker int do_check = 1;
207*61046927SAndroid Build Coastguard Worker const struct option opts[] = {{"help", no_argument, &print_help, 1},
208*61046927SAndroid Build Coastguard Worker {"list", no_argument, &do_list, 1},
209*61046927SAndroid Build Coastguard Worker {"no-check", no_argument, &do_check, 0},
210*61046927SAndroid Build Coastguard Worker {NULL, 0, NULL, 0}};
211*61046927SAndroid Build Coastguard Worker
212*61046927SAndroid Build Coastguard Worker int c;
213*61046927SAndroid Build Coastguard Worker while ((c = getopt_long(argc, argv, "hl", opts, NULL)) != -1) {
214*61046927SAndroid Build Coastguard Worker switch (c) {
215*61046927SAndroid Build Coastguard Worker case 'h': print_help = 1; break;
216*61046927SAndroid Build Coastguard Worker case 'l': do_list = 1; break;
217*61046927SAndroid Build Coastguard Worker case 0: break;
218*61046927SAndroid Build Coastguard Worker case '?':
219*61046927SAndroid Build Coastguard Worker default: fprintf(stderr, "%s: Invalid argument\n", argv[0]); return 99;
220*61046927SAndroid Build Coastguard Worker }
221*61046927SAndroid Build Coastguard Worker }
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker if (print_help) {
224*61046927SAndroid Build Coastguard Worker fprintf(stderr, help_message, argv[0]);
225*61046927SAndroid Build Coastguard Worker return 99;
226*61046927SAndroid Build Coastguard Worker }
227*61046927SAndroid Build Coastguard Worker
228*61046927SAndroid Build Coastguard Worker if (!tests)
229*61046927SAndroid Build Coastguard Worker tests = new std::map<std::string, TestDef>;
230*61046927SAndroid Build Coastguard Worker
231*61046927SAndroid Build Coastguard Worker if (do_list) {
232*61046927SAndroid Build Coastguard Worker for (auto test : *tests)
233*61046927SAndroid Build Coastguard Worker printf("%s\n", test.first.c_str());
234*61046927SAndroid Build Coastguard Worker return 99;
235*61046927SAndroid Build Coastguard Worker }
236*61046927SAndroid Build Coastguard Worker
237*61046927SAndroid Build Coastguard Worker std::vector<std::pair<std::string, std::string>> names;
238*61046927SAndroid Build Coastguard Worker for (int i = optind; i < argc; i++) {
239*61046927SAndroid Build Coastguard Worker std::string name = argv[i];
240*61046927SAndroid Build Coastguard Worker std::string variant;
241*61046927SAndroid Build Coastguard Worker size_t pos = name.find('/');
242*61046927SAndroid Build Coastguard Worker if (pos != std::string::npos) {
243*61046927SAndroid Build Coastguard Worker variant = name.substr(pos + 1);
244*61046927SAndroid Build Coastguard Worker name = name.substr(0, pos);
245*61046927SAndroid Build Coastguard Worker }
246*61046927SAndroid Build Coastguard Worker names.emplace_back(std::pair<std::string, std::string>(name, variant));
247*61046927SAndroid Build Coastguard Worker }
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker if (do_check)
250*61046927SAndroid Build Coastguard Worker checker_stdin = open_memstream(&checker_stdin_data, &checker_stdin_size);
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker LLVMInitializeAMDGPUTargetInfo();
253*61046927SAndroid Build Coastguard Worker LLVMInitializeAMDGPUTarget();
254*61046927SAndroid Build Coastguard Worker LLVMInitializeAMDGPUTargetMC();
255*61046927SAndroid Build Coastguard Worker LLVMInitializeAMDGPUDisassembler();
256*61046927SAndroid Build Coastguard Worker
257*61046927SAndroid Build Coastguard Worker aco::init();
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker for (auto pair : *tests) {
260*61046927SAndroid Build Coastguard Worker bool found = names.empty();
261*61046927SAndroid Build Coastguard Worker bool all_variants = names.empty();
262*61046927SAndroid Build Coastguard Worker std::set<std::string> variants;
263*61046927SAndroid Build Coastguard Worker for (const std::pair<std::string, std::string>& name : names) {
264*61046927SAndroid Build Coastguard Worker if (match_test(pair.first, name.first)) {
265*61046927SAndroid Build Coastguard Worker found = true;
266*61046927SAndroid Build Coastguard Worker if (name.second.empty())
267*61046927SAndroid Build Coastguard Worker all_variants = true;
268*61046927SAndroid Build Coastguard Worker else
269*61046927SAndroid Build Coastguard Worker variants.insert(name.second);
270*61046927SAndroid Build Coastguard Worker }
271*61046927SAndroid Build Coastguard Worker }
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker if (found) {
274*61046927SAndroid Build Coastguard Worker variant_filter = all_variants ? NULL : &variants;
275*61046927SAndroid Build Coastguard Worker printf("Running '%s'\n", pair.first.c_str());
276*61046927SAndroid Build Coastguard Worker run_test(pair.second);
277*61046927SAndroid Build Coastguard Worker }
278*61046927SAndroid Build Coastguard Worker }
279*61046927SAndroid Build Coastguard Worker if (!tests_written) {
280*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s: No matching tests\n", argv[0]);
281*61046927SAndroid Build Coastguard Worker return 99;
282*61046927SAndroid Build Coastguard Worker }
283*61046927SAndroid Build Coastguard Worker
284*61046927SAndroid Build Coastguard Worker if (checker_stdin) {
285*61046927SAndroid Build Coastguard Worker printf("\n");
286*61046927SAndroid Build Coastguard Worker return check_output(argv);
287*61046927SAndroid Build Coastguard Worker } else {
288*61046927SAndroid Build Coastguard Worker printf("Tests ran\n");
289*61046927SAndroid Build Coastguard Worker return 99;
290*61046927SAndroid Build Coastguard Worker }
291*61046927SAndroid Build Coastguard Worker }
292