Evaldo
Evaldo

Reputation: 67

LLVM doesn't generate CFG

I have the program foo.c that I compile with clang -c -emit-llvm foo.c -o foo.bc. It return a foo.bc. So, I run opt -dot-cfg foo.bc for obtain a .dot CFG. But, I receive a warning:

WARNING: You're attempting to print out a bitcode file. This is inadvisable as it may cause display problems. If you REALLY want to taste LLVM bitcode first-hand, you can force output with the -f option.

If I use -f, I get an unreadable file.

Upvotes: 3

Views: 4258

Answers (2)

pill sam
pill sam

Reputation: 31

fix for Nuullll's answer

clang -Xclang -disable-O0-optnone -S -emit-llvm foo.c -o foo.ll 

you need to add -Xclang before -disable-O0-optnone

Upvotes: 1

Nuullll
Nuullll

Reputation: 316

Update

  1. The WARNING is about the bitcode output of opt, which is not related to the dot output. You can use -disable-output to disable bitcode output or use -S to generate human-readable .ll file to suppress the warning.
  2. clang sets optimization level to -O0 by default, therefore each function is attached with the optnone attribute, preventing most optimization passes from operating the function.
  3. opt enables the new Pass Manager (explanation here, a little outdated though) recently, and optional passes (IIUC, those doesn't impact functionality) will be automatically skipped if the target function has optnone.
  4. -dot-cfg is an optional pass.

So your function has optnone attrubite because it was compiled under -O0, and the CFGPrinter skips it, so you don't get any dot file output.

Your have several choices:

  1. Disable optnone attribute generation under -O0:
clang -S -emit-llvm foo.c -o foo.ll -disable-O0-optnone
  1. Remove optnone attributes in foo.ll manually, and save it.
  2. Switch back to the legacy Pass Manager when using opt:
opt -dot-cfg foo.ll -disable-output -enable-new-pm=0

Note: The legacy Pass Manager does respect the optnone attribute, but it is done by explicitly adding a skipFunction() in the passes that really want to do so. CFGPrinter doesn't handle optnone so in legacy pass manager pipeline, the dot file can be dumped as expected.

BTW, the dot output will be directly written to a file whose name starts with a . (if you don't specify the -cfg-dot-filename-prefix argument for opt). Try ls -a!

See this for opt implementation details:

static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
                              BranchProbabilityInfo *BPI, uint64_t MaxFreq,
                              bool CFGOnly = false) {
  std::string Filename =
      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
  errs() << "Writing '" << Filename << "'...";

  std::error_code EC;
  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);

  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
  CFGInfo.setHeatColors(ShowHeatColors);
  CFGInfo.setEdgeWeights(ShowEdgeWeight);
  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);

  if (!EC)
    WriteGraph(File, &CFGInfo, CFGOnly);
  else
    errs() << "  error opening file for writing!";
  errs() << "\n";
}

Upvotes: 10

Related Questions