1 /******************************************************************
2 Copyright (c) 2016 The Khronos Group Inc. All Rights Reserved.
3
4 This code is protected by copyright laws and contains material proprietary to the Khronos Group, Inc.
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE that may not be disclosed in whole or in part to
6 third parties, and may not be reproduced, republished, distributed, transmitted, displayed,
7 broadcast or otherwise exploited in any manner without the express prior written permission
8 of Khronos Group. The receipt or possession of this code does not convey any rights to reproduce,
9 disclose, or distribute its contents, or to manufacture, use, or sell anything that it may describe,
10 in whole or in part other than under the terms of the Khronos Adopters Agreement
11 or Khronos Conformance Test Source License Agreement as executed between Khronos and the recipient.
12 ******************************************************************/
13
14 #include <stdio.h>
15 #include <string.h>
16 #include "procs.h"
17 #if !defined(_WIN32)
18 #include <unistd.h>
19 #endif
20
21 #include <iostream>
22 #include <fstream>
23 #include <string>
24 #include <sstream>
25
26 #if defined(_WIN32)
27 const std::string slash = "\\";
28 #else
29 const std::string slash = "/";
30 #endif
31
32 const std::string spvExt = ".spv";
33 std::string gAddrWidth = "";
34 std::string spvBinariesPath = "spirv_bin";
35 std::string spvBinariesPathArg = "--spirv-binaries-path";
36
readBinary(const char * file_name)37 std::vector<unsigned char> readBinary(const char *file_name)
38 {
39 using namespace std;
40
41 ifstream file(file_name, ios::in | ios::binary | ios::ate);
42
43 std::vector<char> tmpBuffer(0);
44
45 if (file.is_open()) {
46 size_t size = file.tellg();
47 tmpBuffer.resize(size);
48 file.seekg(0, ios::beg);
49 file.read(&tmpBuffer[0], size);
50 file.close();
51 } else {
52 log_error("File %s not found\n", file_name);
53 }
54
55 std::vector<unsigned char> result(tmpBuffer.begin(), tmpBuffer.end());
56
57 return result;
58 }
59
60
readSPIRV(const char * file_name)61 std::vector<unsigned char> readSPIRV(const char *file_name)
62 {
63 std::string full_name_str = spvBinariesPath + slash + file_name + spvExt + gAddrWidth;
64 return readBinary(full_name_str.c_str());
65 }
66
getTestDefinitions()67 test_definition *spirvTestsRegistry::getTestDefinitions()
68 {
69 return &testDefinitions[0];
70 }
71
getNumTests()72 size_t spirvTestsRegistry::getNumTests()
73 {
74 return testDefinitions.size();
75 }
76
addTestClass(baseTestClass * test,const char * testName)77 void spirvTestsRegistry::addTestClass(baseTestClass *test, const char *testName)
78 {
79
80 testClasses.push_back(test);
81 test_definition testDef;
82 testDef.func = test->getFunction();
83 testDef.name = testName;
84 testDef.min_version = Version(2, 1);
85 testDefinitions.push_back(testDef);
86 }
87
getInstance()88 spirvTestsRegistry& spirvTestsRegistry::getInstance()
89 {
90 static spirvTestsRegistry instance;
91 return instance;
92 }
93
offline_get_program_with_il(clProgramWrapper & prog,const cl_device_id deviceID,const cl_context context,const char * prog_name)94 static int offline_get_program_with_il(clProgramWrapper &prog,
95 const cl_device_id deviceID,
96 const cl_context context,
97 const char *prog_name)
98 {
99 cl_int err = 0;
100 std::string outputTypeStr = "binary";
101 std::string defaultScript = std::string("..") + slash + std::string("spv_to_binary.py");
102 std::string outputFilename = spvBinariesPath + slash + std::string(prog_name);
103 std::string sourceFilename = outputFilename + spvExt;
104
105 std::string scriptArgs =
106 sourceFilename + " " +
107 outputFilename + " " +
108 gAddrWidth + " " +
109 outputTypeStr + " " +
110 "-cl-std=CL2.0";
111
112 std::string scriptToRunString = defaultScript + scriptArgs;
113
114 // execute script
115 log_info("Executing command: %s\n", scriptToRunString.c_str());
116 fflush(stdout);
117 int returnCode = system(scriptToRunString.c_str());
118 if (returnCode != 0) {
119 log_error("Command finished with error: 0x%x\n", returnCode);
120 return CL_COMPILE_PROGRAM_FAILURE;
121 }
122
123 // read output file
124 std::vector<unsigned char> buffer_vec = readBinary(outputFilename.c_str());
125 size_t file_bytes = buffer_vec.size();
126 if (file_bytes == 0) {
127 log_error("OfflinerCompiler: Failed to open binary file: %s", outputFilename.c_str());
128 return -1;
129 }
130
131 const unsigned char *buffer = &buffer_vec[0];
132 cl_int status = 0;
133 prog = clCreateProgramWithBinary(context, 1, &deviceID, &file_bytes, &buffer, &status, &err);
134 SPIRV_CHECK_ERROR((err || status), "Failed to create program with clCreateProgramWithBinary");
135 return err;
136 }
137
get_program_with_il(clProgramWrapper & prog,const cl_device_id deviceID,const cl_context context,const char * prog_name)138 int get_program_with_il(clProgramWrapper &prog,
139 const cl_device_id deviceID,
140 const cl_context context,
141 const char *prog_name)
142 {
143 cl_int err = 0;
144 if (gCompilationMode == kBinary) {
145 return offline_get_program_with_il(prog, deviceID, context, prog_name);
146 }
147
148 std::vector<unsigned char> buffer_vec = readSPIRV(prog_name);
149
150 int file_bytes = buffer_vec.size();
151 if (file_bytes == 0) {
152 log_error("File %s not found\n", prog_name);
153 return -1;
154 }
155
156 unsigned char *buffer = &buffer_vec[0];
157 prog = clCreateProgramWithIL(context, buffer, file_bytes, &err);
158 SPIRV_CHECK_ERROR(err, "Failed to create program with clCreateProgramWithIL");
159
160 err = clBuildProgram(prog, 1, &deviceID, NULL, NULL, NULL);
161 SPIRV_CHECK_ERROR(err, "Failed to build program");
162
163 return err;
164 }
165
checkAddressWidth(cl_device_id id)166 test_status checkAddressWidth(cl_device_id id)
167 {
168 cl_uint address_bits;
169 cl_uint err = clGetDeviceInfo(id, CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &address_bits, NULL);
170 if(err != CL_SUCCESS){
171 log_error("clGetDeviceInfo failed to get address bits!");
172 return TEST_FAIL;
173 }
174
175 gAddrWidth = address_bits == 32 ? "32" : "64";
176 return TEST_PASS;
177 }
178
printUsage()179 void printUsage() {
180 log_info("Reading SPIR-V files from default '%s' path.\n", spvBinariesPath.c_str());
181 log_info("In case you want to set other directory use '%s' argument.\n", spvBinariesPathArg.c_str());
182 }
183
main(int argc,const char * argv[])184 int main(int argc, const char *argv[])
185 {
186 gReSeed = 1;
187 bool modifiedSpvBinariesPath = false;
188 for (int i = 0; i < argc; ++i) {
189 int argsRemoveNum = 0;
190 if (argv[i] == spvBinariesPathArg) {
191 if (i + 1 == argc) {
192 log_error("Missing value for '%s' argument.\n", spvBinariesPathArg.c_str());
193 return TEST_FAIL;
194 } else {
195 spvBinariesPath = std::string(argv[i + 1]);
196 argsRemoveNum += 2;
197 modifiedSpvBinariesPath = true;
198 }
199 }
200
201 if (argsRemoveNum > 0) {
202 for (int j = i; j < (argc - argsRemoveNum); ++j)
203 argv[j] = argv[j + argsRemoveNum];
204
205 argc -= argsRemoveNum;
206 --i;
207 }
208 }
209 if (modifiedSpvBinariesPath == false) {
210 printUsage();
211 }
212
213 return runTestHarnessWithCheck(argc, argv,
214 spirvTestsRegistry::getInstance().getNumTests(),
215 spirvTestsRegistry::getInstance().getTestDefinitions(),
216 false, 0, checkAddressWidth);
217 }
218