Files
swift-mirror/lib/IRGen/IRGenDebugInfo.h
Ellis Hoag 8200916129 Fix debug locations to work well with CodeView
Summary:
There are a few problems with how Swift currently emits location
information for CodeView.

1. WinDbg does not work well with column information so all column
locations must be set to zero.

2. Some instructions, e.g., ``a + b``,  will emit ``@llvm.trap()``
and ``unreachable``. Those instructions should have artificial
locations, i.e., they should have a line location of zero.

3. Some instructions, e.g., ``a / b``, will emit ``unreachable``
sandwiched between other code for that instruction. This makes
WinDbg confused and it cannot decide which set of instructions
to break on. Those instructions should have the same line location
as the others.

4. There are several prologue instructions with artificial line
locations that create breaks in the linetables. Those instructions
should have valid line locations, usually at the start of the
function.

5. Case bodies have cleanup instructions with artificial line
locations unless it has a ``do`` block. Those locations should
be the last line in the case block.

Test Plan:
test/DebugInfo/basic.swift
test/DebugInfo/columns.swift
test/DebugInfo/linetable-codeview.swift
test/DebugInfo/line-directive-codeview.swift
2018-07-18 09:54:19 -07:00

199 lines
7.4 KiB
C++

//===--- IRGenDebugInfo.h - Debug Info Support ------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines IR codegen support for debug information.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_DEBUGINFO_H
#define SWIFT_IRGEN_DEBUGINFO_H
#include "DebugTypeInfo.h"
#include "IRGenFunction.h"
namespace llvm {
class DIBuilder;
}
namespace swift {
class ClangImporter;
class IRGenOptions;
enum class SILFunctionTypeRepresentation : uint8_t;
namespace irgen {
class IRBuilder;
class IRGenFunction;
class IRGenModule;
enum IndirectionKind : bool { DirectValue = false, IndirectValue = true };
enum ArtificialKind : bool { RealValue = false, ArtificialValue = true };
/// Helper object that keeps track of the current CompileUnit, File,
/// LexicalScope, and knows how to translate a \c SILLocation into an
/// \c llvm::DebugLoc.
class IRGenDebugInfo {
public:
static IRGenDebugInfo *
createIRGenDebugInfo(const IRGenOptions &Opts, ClangImporter &CI,
IRGenModule &IGM, llvm::Module &M,
StringRef MainOutputFilenameForDebugInfo);
virtual ~IRGenDebugInfo();
/// Finalize the llvm::DIBuilder owned by this object.
void finalize();
/// Update the IRBuilder's current debug location to the location
/// Loc and the lexical scope DS.
void setCurrentLoc(IRBuilder &Builder, const SILDebugScope *DS,
SILLocation Loc);
void clearLoc(IRBuilder &Builder);
/// Push the current debug location onto a stack and initialize the
/// IRBuilder to an empty location.
void pushLoc();
/// Restore the current debug location from the stack.
void popLoc();
/// If we are not emitting CodeView, this does nothing since the ``llvm.trap``
/// instructions should already have an artificial location of zero.
/// In CodeView, since zero is not an artificial location, we emit the
/// location of the unified trap block at the end of the fuction as an
/// artificial inline location pointing to the user's instruction.
void setInlinedTrapLocation(IRBuilder &Builder, const SILDebugScope *Scope);
/// Set the location for SWIFT_ENTRY_POINT_FUNCTION.
void setEntryPointLoc(IRBuilder &Builder);
/// Return the scope for SWIFT_ENTRY_POINT_FUNCTION.
llvm::DIScope *getEntryPointFn();
/// Translate a SILDebugScope into an llvm::DIDescriptor.
llvm::DIScope *getOrCreateScope(const SILDebugScope *DS);
/// Emit debug info for an import declaration.
///
/// The DWARF output for import decls is similar to that of a using
/// directive in C++:
/// import Foundation
/// -->
/// 0: DW_TAG_imported_module
/// DW_AT_import(*1)
/// 1: DW_TAG_module // instead of DW_TAG_namespace.
/// DW_AT_name("Foundation")
///
void emitImport(ImportDecl *D);
/// Emit debug info for the given function.
/// \param DS The parent scope of the function.
/// \param Fn The IR representation of the function.
/// \param Rep The calling convention of the function.
/// \param Ty The signature of the function.
llvm::DISubprogram *emitFunction(const SILDebugScope *DS, llvm::Function *Fn,
SILFunctionTypeRepresentation Rep,
SILType Ty, DeclContext *DeclCtx = nullptr,
GenericEnvironment *GE = nullptr);
/// Emit debug info for a given SIL function.
llvm::DISubprogram *emitFunction(SILFunction &SILFn, llvm::Function *Fn);
/// Convenience function useful for functions without any source
/// location. Internally calls emitFunction, emits a debug
/// scope, and finally sets it using setCurrentLoc.
inline void emitArtificialFunction(IRGenFunction &IGF, llvm::Function *Fn,
SILType SILTy = SILType()) {
emitArtificialFunction(IGF.Builder, Fn, SILTy);
}
void emitArtificialFunction(IRBuilder &Builder,
llvm::Function *Fn, SILType SILTy = SILType());
/// Emit a dbg.declare intrinsic at the current insertion point and
/// the Builder's current debug location.
void emitVariableDeclaration(IRBuilder &Builder,
ArrayRef<llvm::Value *> Storage,
DebugTypeInfo Ty, const SILDebugScope *DS,
ValueDecl *VarDecl, StringRef Name,
unsigned ArgNo = 0,
IndirectionKind Indirection = DirectValue,
ArtificialKind Artificial = RealValue);
/// Emit a dbg.declare or dbg.value intrinsic, depending on Storage.
void emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage,
llvm::DILocalVariable *Var, llvm::DIExpression *Expr,
unsigned Line, unsigned Col, llvm::DILocalScope *Scope,
const SILDebugScope *DS);
enum { NotHeapAllocated = false };
/// Create debug metadata for a global variable.
void emitGlobalVariableDeclaration(llvm::GlobalVariable *Storage,
StringRef Name, StringRef LinkageName,
DebugTypeInfo DebugType,
bool IsLocalToUnit, bool InFixedBuffer,
Optional<SILLocation> Loc);
/// Emit debug metadata for type metadata (for generic types). So meta.
void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
unsigned Depth, unsigned Index, StringRef AssocType);
/// Return the DIBuilder.
llvm::DIBuilder &getBuilder();
/// Decode (and cache) a SourceLoc.
SILLocation::DebugLoc decodeSourceLoc(SourceLoc SL);
};
/// An RAII object that autorestores the debug location.
class AutoRestoreLocation {
IRGenDebugInfo *DI;
IRBuilder &Builder;
llvm::DebugLoc SavedLocation;
public:
AutoRestoreLocation(IRGenDebugInfo *DI, IRBuilder &Builder);
/// Autorestore everything back to normal.
~AutoRestoreLocation();
};
/// An RAII object that temporarily switches to an artificial debug
/// location that has a valid scope, but no line information. This is
/// useful when emitting compiler-generated instructions (e.g.,
/// ARC-inserted calls to release()) that have no source location
/// associated with them. The DWARF specification allows the compiler
/// to use the special line number 0 to indicate code that cannot be
/// attributed to any source location.
class ArtificialLocation : public AutoRestoreLocation {
public:
/// Set the current location to line 0, but within scope DS.
ArtificialLocation(const SILDebugScope *DS, IRGenDebugInfo *DI,
IRBuilder &Builder);
};
/// An RAII object that temporarily switches to an empty
/// location. This is how the function prologue is represented.
class PrologueLocation : public AutoRestoreLocation {
public:
/// Set the current location to an empty location.
PrologueLocation(IRGenDebugInfo *DI, IRBuilder &Builder);
};
} // irgen
} // swift
#endif