paulkirth created this revision.
Herald added subscribers: mgrang, hiraditya.
Herald added a project: All.
paulkirth requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Issue #58168 describes the difficulty diagnosing stack size issues
identified by -Wframe-larger-than. For simple code, its easy to
understand the stack layout, and where space is being allocated, but in
more complex programs, where code may be heavily inlined, unrolled, and
have duplicated code paths it is no longer easy to manually inspect the
source program, and understand where stack space can be attributed.

This patch is a very basic prototype that dumps an ASCI representation
of stack slots, and also prints any available debug information to map
source variables to those slots.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135488

Files:
  clang/test/Frontend/frame-diags.c
  llvm/include/llvm/CodeGen/MachineFrameInfo.h
  llvm/lib/CodeGen/MachineFrameInfo.cpp
  llvm/lib/CodeGen/PrologEpilogInserter.cpp

Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp
===================================================================
--- llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -289,6 +289,7 @@
   if (StackSize > Threshold) {
     DiagnosticInfoStackSize DiagStackSize(F, StackSize, Threshold, DS_Warning);
     F.getContext().diagnose(DiagStackSize);
+    MFI.pretty_print(MF, llvm::errs());
   }
   ORE->emit([&]() {
     return MachineOptimizationRemarkAnalysis(DEBUG_TYPE, "StackSize",
Index: llvm/lib/CodeGen/MachineFrameInfo.cpp
===================================================================
--- llvm/lib/CodeGen/MachineFrameInfo.cpp
+++ llvm/lib/CodeGen/MachineFrameInfo.cpp
@@ -20,9 +20,12 @@
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
+#include <iomanip>
+#include <sstream>
 
 #define DEBUG_TYPE "codegen"
 
@@ -249,6 +252,130 @@
   }
 }
 
+void MachineFrameInfo::pretty_print(const MachineFunction &MF,
+                                    raw_ostream &OS) const {
+  struct Data {
+    int Slot;
+    int Size;
+    int Align;
+    int Offset;
+    bool IsSpillSlot;
+    bool Fixed;
+  };
+  if (Objects.empty())
+    return;
+
+  const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
+  int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
+
+  std::vector<StackObject> SOS(Objects);
+  std::vector<Data> SlotInfo;
+  SlotInfo.reserve(Objects.size());
+
+  for (unsigned i = 0, e = SOS.size(); i != e; ++i) {
+    std::stringstream SS;
+    Data D;
+    const StackObject &SO = SOS[i];
+    if (SO.Size == ~0ULL) {
+      continue;
+    }
+
+    if (SO.Size == 0)
+      D.Fixed = true;
+    else {
+      D.Fixed = i < NumFixedObjects;
+      D.Size = SO.Size;
+    }
+    D.Align = SO.Alignment.value();
+
+    int64_t Off = SO.SPOffset - ValOffset;
+    D.Fixed = (i < NumFixedObjects);
+    D.Offset = Off;
+    SlotInfo.push_back(D);
+  }
+
+  std::sort(SlotInfo.begin(), SlotInfo.end(),
+            [](Data &A, Data &B) { return A.Offset > B.Offset; });
+
+  size_t MaxLine = 75;
+  auto PrintDashed = [&OS, MaxLine]() {
+    OS << "+";
+    for (size_t I = 0; I < MaxLine + 2; ++I) {
+      OS << "-";
+    }
+    OS << "+\n";
+  };
+
+  auto GetFieldInt = [](int Width, int I) {
+    std::stringstream SS;
+    SS << std::setw(Width) << I;
+    return SS.str();
+  };
+  auto GetFieldBool = [](int Width, bool I) {
+    std::stringstream SS;
+    SS << std::setw(Width) << (I ? "T" : "F");
+    return SS.str();
+  };
+  auto GetFieldString = [](int Width, std::string S) {
+    std::stringstream SS;
+    SS << std::setw(Width) << S;
+    return SS.str();
+  };
+  auto GetFieldOffset = [](int I) {
+    std::stringstream SS;
+    SS << "[SP";
+    const auto *Op = (I < 0) ? "" : "+";
+    SS << Op << I << "]";
+    return SS.str();
+  };
+
+  auto PrintRow = [&OS, MaxLine](std::string S) {
+    std::stringstream SS;
+    SS << std::setw(MaxLine) << S;
+    OS << "| " << SS.str() << " |\n";
+  };
+  auto GetBody = [&MaxLine, &GetFieldInt, &GetFieldBool,
+                  &GetFieldOffset](int i, Data &D) {
+    auto Width = MaxLine / 6 - 2;
+    std::stringstream SS;
+    SS << GetFieldInt(Width, i) << " | ";
+    SS << GetFieldInt(Width, D.Size) << " | ";
+    SS << GetFieldInt(Width, D.Align) << " | ";
+    SS << GetFieldBool(Width, D.Fixed) << " | ";
+    SS << GetFieldBool(Width, D.IsSpillSlot) << " | ";
+    SS << std::setw(Width) << GetFieldOffset(D.Offset);
+    return SS.str();
+  };
+  auto GetHeader = [&MaxLine, &GetFieldString]() {
+    auto Width = MaxLine / 6 - 2;
+    std::stringstream SS;
+    SS << GetFieldString(Width, "Slot") << " | ";
+    SS << GetFieldString(Width, "Size") << " | ";
+    SS << GetFieldString(Width, "Align") << " | ";
+    SS << GetFieldString(Width, "Fixed") << " | ";
+    SS << GetFieldString(Width, "Spill") << " | ";
+    SS << GetFieldString(Width, "Offset");
+    return SS.str();
+  };
+  PrintDashed();
+  PrintRow(MF.getName().str());
+  PrintDashed();
+  PrintRow(GetHeader());
+
+  int i = 0;
+  for (auto L : SlotInfo) {
+    std::stringstream SS;
+    auto Body = GetBody(i++, L);
+    PrintDashed();
+    PrintRow(Body);
+  }
+  PrintDashed();
+  for (auto &DI : MF.getVariableDbgInfo()) {
+    OS << "Variable: " << DI.Var->getName()  << " (line " <<DI.Var->getLine()<< " of "
+     <<DI.Var->getFilename()<<") in Slot: " << DI.Slot << "\n";
+  }
+}
+
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void MachineFrameInfo::dump(const MachineFunction &MF) const {
   print(MF, dbgs());
Index: llvm/include/llvm/CodeGen/MachineFrameInfo.h
===================================================================
--- llvm/include/llvm/CodeGen/MachineFrameInfo.h
+++ llvm/include/llvm/CodeGen/MachineFrameInfo.h
@@ -814,6 +814,7 @@
   /// Used by the MachineFunction printer to print information about
   /// stack objects. Implemented in MachineFunction.cpp.
   void print(const MachineFunction &MF, raw_ostream &OS) const;
+  void pretty_print(const MachineFunction &MF, raw_ostream &OS) const;
 
   /// dump - Print the function to stderr.
   void dump(const MachineFunction &MF) const;
Index: clang/test/Frontend/frame-diags.c
===================================================================
--- /dev/null
+++ clang/test/Frontend/frame-diags.c
@@ -0,0 +1,40 @@
+// TODO: This is not really a functional test yet, and needs to be rewritten. 
+// currently its just a copy of backend-diagnostics.c, and all of the run/test 
+// logic needs to be updated.
+//
+//
+// REQUIRES: x86-registered-target
+// Play around with backend reporting:
+// _REGULAR_: Regular behavior, no warning switch enabled.
+// _PROMOTE_: Promote warning to error.
+// _IGNORE_: Drop backend warning.
+//
+// RUN: not %clang_cc1 %s -fwarn-stack-size=0 -no-integrated-as -S -o - -triple=i386-apple-darwin 2> %t.err
+// RUN: FileCheck < %t.err %s --check-prefix=REGULAR --check-prefix=ASM
+// RUN: not %clang_cc1 %s -fwarn-stack-size=0 -no-integrated-as -S -o - -triple=i386-apple-darwin -Werror=frame-larger-than 2> %t.err
+// RUN: FileCheck < %t.err %s --check-prefix=PROMOTE --check-prefix=ASM
+// RUN: not %clang_cc1 %s -fwarn-stack-size=0 -no-integrated-as -S -o - -triple=i386-apple-darwin -Wno-frame-larger-than 2> %t.err
+// RUN: FileCheck < %t.err %s --check-prefix=IGNORE --check-prefix=ASM
+//
+// RUN: %clang_cc1 %s -S -o - -triple=i386-apple-darwin -verify -no-integrated-as
+
+extern void doIt(char *);
+extern void compareIt(char *, char *);
+extern int getNum(long);
+
+// REGULAR: warning: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning'
+// PROMOTE: error: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning'
+// IGNORE-NOT: stack frame size ([[#]]) exceeds limit ([[#]]) in 'stackSizeWarning'
+void stackSizeWarning(void) {
+  {
+    char buffer[80];
+    doIt(buffer);
+  }
+  char buffer2[80];
+  int a = 0;
+  long b = 1;
+  doIt(buffer2);
+  // compareIt(buffer, buffer2);
+  getNum(a);
+  getNum(b);
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to