在本章节中,我们为语言增加 Debug
信息。
去掉提示词 #
第一步我们先去掉所有的提示输入,这样就完全是一个输入输出的二进制程序了。
@@ -1129,7 +1129,6 @@ static void HandleTopLevelExpression() {
/// top ::= definition | external | expression | ';'
static void MainLoop() {
while (1) {
- fprintf(stderr, "ready> ");
switch (CurTok) {
case tok_eof:
return;
@@ -1184,7 +1183,6 @@ int main() {
BinopPrecedence['*'] = 40; // highest.
// Prime the first token.
- fprintf(stderr, "ready> ");
getNextToken();
禁用 JIT 和 优化相关 #
@@ -1108,17 +1108,8 @@ static void HandleExtern() {
static void HandleTopLevelExpression() {
// Evaluate a top-level expression into an anonymous function.
if (auto FnAST = ParseTopLevelExpr()) {
- if (auto *FnIR = FnAST->codegen()) {
- // We're just doing this to make sure it executes.
- TheExecutionEngine->finalizeObject();
- // JIT the function, returning a function pointer.
- void *FPtr = TheExecutionEngine->getPointerToFunction(FnIR);
-
- // Cast it to the right type (takes no arguments, returns a double) so we
- // can call it as a native function.
- double (*FP)() = (double (*)())(intptr_t)FPtr;
- // Ignore the return value for this.
- (void)FP;
+ if (!F->codegen()) {
+ fprintf(stderr, "Error generating code for top level expr");
}
} else {
// Skip token for error recovery.
@@ -1439,11 +1459,11 @@ int main() {
// target lays out data structures.
TheModule->setDataLayout(TheExecutionEngine->getDataLayout());
OurFPM.add(new DataLayoutPass());
+#if 0
OurFPM.add(createBasicAliasAnalysisPass());
// Promote allocas to registers.
OurFPM.add(createPromoteMemoryToRegisterPass());
@@ -1218,7 +1210,7 @@ int main() {
OurFPM.add(createGVNPass());
// Simplify the control flow graph (deleting unreachable blocks, etc).
OurFPM.add(createCFGSimplificationPass());
-
+ #endif
OurFPM.doInitialization();
// Set the global so the code gen can use this.
DIBuilder #
llvm
使用 BIBuilder
来构建 Debug
信息
DBuilder = new DIBuilder(*TheModule);
KSDbgInfo.TheCU = DBuilder->createCompileUnit(
dwarf::DW_LANG_C, DBuilder->createFile("fib.ks", "."),
"Kaleidoscope Compiler", 0, "", 0);
......
DBuilder->finalize(); // 最终使用 finalize 输出 LR
Source Location #
在原来的逻辑上中,我们直接使用 char
来读取,现在我们需要多记录下当前的位置
struct SourceLocation {
int Line;
int Col;
};
static SourceLocation CurLoc;
static SourceLocation LexLoc = {1, 0};
static int advance() {
int LastChar = getchar();
if (LastChar == '\n' || LastChar == '\r') {
LexLoc.Line++;
LexLoc.Col = 0;
} else
LexLoc.Col++;
return LastChar;
}
ExprAST #
修改 ExprAST
基类,增加 getLine
和 getCol
class ExprAST {
SourceLocation Loc;
public:
ExprAST(SourceLocation Loc = CurLoc) : Loc(Loc) {}
virtual ~ExprAST() = default;
virtual llvm::Value* codegen() = 0;
int getLine() const {
return Loc.Line;
}
int getCol() const {
return Loc.Col;
}
virtual llvm::raw_ostream& dump(llvm::raw_ostream& out, int ind) {
return out << ':' << getLine() << ':' << getCol() << '\n';
}
};
inline llvm::raw_ostream& indent(llvm::raw_ostream& O, int size) {
return O << std::string(size, ' ');
}
DebugInfo #
新增 DebugInfo
inline struct DebugInfo {
llvm::DICompileUnit* TheCU;
llvm::DIType* DblTy;
std::vector<llvm::DIScope*> LexicalBlocks;
void emitLocation(ExprAST* AST);
llvm::DIType* getDoubleTy();
} KSDbgInfo;
增加一些基本函数
void DebugInfo::emitLocation(ExprAST* AST) {
if (!AST)
return Builder->SetCurrentDebugLocation(llvm::DebugLoc());
llvm::DIScope* Scope;
if (LexicalBlocks.empty())
Scope = TheCU;
else
Scope = LexicalBlocks.back();
Builder->SetCurrentDebugLocation(
llvm::DILocation::get(
Scope->getContext(),
AST->getLine(),
AST->getCol(),
Scope));
}
最终效果 #
$ ./cmake-build-debug/kaleidoscope < fib.ks
; ModuleID = 'My awesome JIT'
source_filename = "My awesome JIT"
define double @fib(double %x) !dbg !4 {
entry:
%x1 = alloca double, align 8
call void @llvm.dbg.declare(metadata double* %x1, metadata !9, metadata !DIExpression()), !dbg !10
store double %x, double* %x1, align 8
%x2 = load double, double* %x1, align 8, !dbg !11
%cmptmp = fcmp ult double %x2, 3.000000e+00, !dbg !12
%booltmp = uitofp i1 %cmptmp to double, !dbg !12
%ifcond = fcmp one double %booltmp, 0.000000e+00, !dbg !12
br i1 %ifcond, label %then, label %else, !dbg !12
then: ; preds = %entry
br label %ifcont, !dbg !13
else: ; preds = %entry
%x3 = load double, double* %x1, align 8, !dbg !14
%subtmp = fsub double %x3, 1.000000e+00, !dbg !15
%calltmp = call double @fib(double %subtmp), !dbg !15
%x4 = load double, double* %x1, align 8, !dbg !16
%subtmp5 = fsub double %x4, 2.000000e+00, !dbg !17
%calltmp6 = call double @fib(double %subtmp5), !dbg !17
%addtmp = fadd double %calltmp, %calltmp6, !dbg !17
br label %ifcont, !dbg !17
ifcont: ; preds = %else, %then
%iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ], !dbg !17
ret double %iftmp, !dbg !17
}
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
define double @main() !dbg !18 {
entry:
%calltmp = call double @fib(double 1.000000e+01), !dbg !22
ret double %calltmp, !dbg !22
}
attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0, !2}
!llvm.module.flags = !{!3}
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "Kaleidoscope Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "fib.ks", directory: ".")
!2 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "Kaleidoscope Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = distinct !DISubprogram(name: "fib", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !8)
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !7}
!7 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
!8 = <temporary!> !{}
!9 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !1, line: 1, type: !7)
!10 = !DILocation(line: 1, scope: !4)
!11 = !DILocation(line: 2, column: 4, scope: !4)
!12 = !DILocation(line: 2, column: 7, scope: !4)
!13 = !DILocation(line: 2, column: 14, scope: !4)
!14 = !DILocation(line: 3, column: 9, scope: !4)
!15 = !DILocation(line: 3, column: 10, scope: !4)
!16 = !DILocation(line: 3, column: 14, scope: !4)
!17 = !DILocation(line: 3, column: 15, scope: !4)
!18 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !21)
!19 = !DISubroutineType(types: !20)
!20 = !{!7}
!21 = <temporary!> !{}
!22 = !DILocation(line: 5, column: 2, scope: !18)
这里生成的就是 LR
然后再通过 LLC
编译成二进制即可。
Debug #
采用 lldb
直接对生成的二进制进行断点追踪即可。