Home | History | Annotate | Download | only in cfg
      1 // Copyright (c) 2015-2016 The Khronos Group Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <cstdio>
     16 #include <cstring>
     17 #include <sstream>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include "spirv-tools/libspirv.h"
     22 #include "tools/cfg/bin_to_dot.h"
     23 #include "tools/io.h"
     24 
     25 // Prints a program usage message to stdout.
     26 static void print_usage(const char* argv0) {
     27   printf(
     28       R"(%s - Show the control flow graph in GraphiViz "dot" form. EXPERIMENTAL
     29 
     30 Usage: %s [options] [<filename>]
     31 
     32 The SPIR-V binary is read from <filename>. If no file is specified,
     33 or if the filename is "-", then the binary is read from standard input.
     34 
     35 Options:
     36 
     37   -h, --help      Print this help.
     38   --version       Display version information.
     39 
     40   -o <filename>   Set the output filename.
     41                   Output goes to standard output if this option is
     42                   not specified, or if the filename is "-".
     43 )",
     44       argv0, argv0);
     45 }
     46 
     47 static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_2;
     48 
     49 int main(int argc, char** argv) {
     50   const char* inFile = nullptr;
     51   const char* outFile = nullptr;  // Stays nullptr if printing to stdout.
     52 
     53   for (int argi = 1; argi < argc; ++argi) {
     54     if ('-' == argv[argi][0]) {
     55       switch (argv[argi][1]) {
     56         case 'h':
     57           print_usage(argv[0]);
     58           return 0;
     59         case 'o': {
     60           if (!outFile && argi + 1 < argc) {
     61             outFile = argv[++argi];
     62           } else {
     63             print_usage(argv[0]);
     64             return 1;
     65           }
     66         } break;
     67         case '-': {
     68           // Long options
     69           if (0 == strcmp(argv[argi], "--help")) {
     70             print_usage(argv[0]);
     71             return 0;
     72           } else if (0 == strcmp(argv[argi], "--version")) {
     73             printf("%s EXPERIMENTAL\n", spvSoftwareVersionDetailsString());
     74             printf("Target: %s\n",
     75                    spvTargetEnvDescription(kDefaultEnvironment));
     76             return 0;
     77           } else {
     78             print_usage(argv[0]);
     79             return 1;
     80           }
     81         } break;
     82         case 0: {
     83           // Setting a filename of "-" to indicate stdin.
     84           if (!inFile) {
     85             inFile = argv[argi];
     86           } else {
     87             fprintf(stderr, "error: More than one input file specified\n");
     88             return 1;
     89           }
     90         } break;
     91         default:
     92           print_usage(argv[0]);
     93           return 1;
     94       }
     95     } else {
     96       if (!inFile) {
     97         inFile = argv[argi];
     98       } else {
     99         fprintf(stderr, "error: More than one input file specified\n");
    100         return 1;
    101       }
    102     }
    103   }
    104 
    105   // Read the input binary.
    106   std::vector<uint32_t> contents;
    107   if (!ReadFile<uint32_t>(inFile, "rb", &contents)) return 1;
    108   spv_context context = spvContextCreate(kDefaultEnvironment);
    109   spv_diagnostic diagnostic = nullptr;
    110 
    111   std::stringstream ss;
    112   auto error =
    113       BinaryToDot(context, contents.data(), contents.size(), &ss, &diagnostic);
    114   if (error) {
    115     spvDiagnosticPrint(diagnostic);
    116     spvDiagnosticDestroy(diagnostic);
    117     spvContextDestroy(context);
    118     return error;
    119   }
    120   std::string str = ss.str();
    121   WriteFile(outFile, "w", str.data(), str.size());
    122 
    123   spvDiagnosticDestroy(diagnostic);
    124   spvContextDestroy(context);
    125 
    126   return 0;
    127 }
    128