diff --git a/clang/test/Frontend/frame-diags.c b/clang/test/Frontend/frame-diags.c new file mode 100644 --- /dev/null +++ b/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); +} diff --git a/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/llvm/include/llvm/CodeGen/MachineFrameInfo.h --- a/llvm/include/llvm/CodeGen/MachineFrameInfo.h +++ b/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; diff --git a/llvm/lib/CodeGen/MachineFrameInfo.cpp b/llvm/lib/CodeGen/MachineFrameInfo.cpp --- a/llvm/lib/CodeGen/MachineFrameInfo.cpp +++ b/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 +#include +#include #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 SOS(Objects); + std::vector 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 " <getLine()<< " of " + <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()); diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/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",