项目作者: bozbalci

项目描述 :
LLVM frontend for XPLN, an award-winning CENG444 compiler project
高级语言: C++
项目地址: git://github.com/bozbalci/explain.git
创建时间: 2018-12-20T19:34:53Z
项目社区:https://github.com/bozbalci/explain

开源协议:BSD 2-Clause "Simplified" License

下载


explain

lines of code

explain is an industrial grade compiler for XPLN. It is built using flex, bison and LLVM.

Update: explain has won the “Gazozuna Kompaylır” award!

Features

  • Detailed error reporting with source locations, error recovery during parsing
  • Optimizations (global value numbering, CFG simplification, instruction combining, constant folding and propagation,
    etc.)
  • Pretty-printer for the abstract syntax tree
  • Option to emit LLVM intermediate representation
  • Native code generation for X86, X86-64, PowerPC, PowerPC-64, ARM, MIPS and many more architectures

Requirements

The project was built using the following tooling, earlier versions are not tested:

  • CMake >= 3.13
  • C++ compiler with C++14 core language support (gcc >= 5.1 or Clang >= 3.5)
  • Boost >= 1.60
  • flex >= 2.5
  • bison >= 3.2
  • LLVM >= 7.0.0

Build

  1. $ mkdir build
  2. $ cd build
  3. $ cmake .. && make

On macOS, the CMake script will issue a warning about the installed Bison version. Make sure that Bison 3.2 (or greater)
is used when building this project.

Usage

After compiling, install explain somewhere in your path. To see all available options, invoke explain with --help.

  1. $ explain --help
  2. explain, the industrial grade XPLN compiler
  3. General options:
  4. -h [ --help ] print this help message and exit
  5. -v [ --version ] print version and exit
  6. -i [ --input ] arg input file
  7. -o [ --output ] arg output file
  8. Debugging options:
  9. --trace-scan run scanner in debug mode
  10. --trace-parse run parser in debug mode
  11. Stage selection options:
  12. --emit-ast emit AST in pretty-printed form
  13. --emit-llvm emit LLVM representation only
  14. -c generate object file
  15. If no stage selection option is specified, then every stage will be run and
  16. the linker is run to produce an executable.

Examples

convert: A tour of explain by converting °F to °C

This example is located at examples/convert.xpln.

  1. fun convert(fahr)
  2. return (fahr - 32) * 5 / 9;
  3. endf;
  4. while 1 > 0
  5. input fahr;
  6. result := convert(fahr);
  7. output result;
  8. endw;
  9. return 0;

Compile with explain and run:

  1. $ explain convert.xpln -o convert
  2. $ ./convert
  3. 100
  4. 37.777778
  5. ^C

If you would like to link to a separate C/C++ program, invoke explain with -c to emit an object file. Note that the
top-level function is named xpln_main and a function defined with the name main in XPLN programs is mangled (their
new name would be xpln_mangled_main.)

  1. $ explain convert.xpln -o convert.o -c
  2. $ cat > driver.c
  3. #include <stdio.h>
  4. extern double convert(double);
  5. int main(int argc, char **argv)
  6. {
  7. printf("100 F is approx. %.2lf C\n", convert(100.0));
  8. return 0;
  9. }
  10. ^D
  11. $ cc -o driver driver.c convert.o
  12. $ ./driver
  13. 100 F is approx. 37.78 C

If you would like to emit LLVM code, you can do so by using --emit-llvm. You can then use this file with other
programs in the LLVM toolchain (llc, opt, llvm-as, etc.) for fun and profit.

  1. $ explain convert.xpln -o convert.ll --emit-llvm
  2. $ cat convert.ll
  3. ; ModuleID = 'convert.xpln'
  4. source_filename = "convert.xpln"
  5. target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
  6. target triple = "x86_64-apple-darwin18.0.0"
  7. @ifmt = internal constant [4 x i8] c"%lf\00"
  8. @ofmt = internal constant [5 x i8] c"%lf\0A\00"
  9. declare i32 @scanf(i8*, ...)
  10. declare i32 @printf(i8*, ...)
  11. define double @convert(double %fahr) {
  12. entry:
  13. %0 = fadd double %fahr, -3.200000e+01
  14. %1 = fmul double %0, 5.000000e+00
  15. %2 = fdiv double %1, 9.000000e+00
  16. ret double %2
  17. }
  18. define double @xpln_main() {
  19. entry:
  20. %fahr = alloca double, align 8
  21. br label %cond
  22. cond: ; preds = %cond, %entry
  23. %0 = call i32 (i8*, ...) @scanf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @ifmt, i64 0, i64 0), double* nonnull %fahr)
  24. %fahr1 = load double, double* %fahr, align 8
  25. %1 = call double @convert(double %fahr1)
  26. %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @ofmt, i64 0, i64 0), double %1)
  27. br label %cond
  28. }

To obtain a pretty-printed form of the abstract syntax tree after some basic manipulations, invoke explain with the
--emit-ast flag.

  1. $ explain examples/fibonacci.xpln -o fibonacci.ast --emit-ast
  2. $ cat fibonacci.ast
  3. fun fib
  4. args
  5. arg n
  6. if
  7. or
  8. ==
  9. n
  10. 0
  11. ==
  12. n
  13. 1
  14. then
  15. return
  16. 1
  17. else
  18. return
  19. +
  20. call fib
  21. args
  22. arg
  23. -
  24. n
  25. 1
  26. call fib
  27. args
  28. arg
  29. -
  30. n
  31. 2
  32. fun xpln_main
  33. args
  34. return
  35. call fib
  36. args
  37. arg
  38. 10

stress: General education & stress test for XPLN compilers

This stress test was written by me to challenge other students of Ceng444 to test their compilers against mine. It
features:

  • function definition and call with 64 arguments
  • case-insensitive identifiers
  • function definition and call with a very long name (>1024 chars)
  • trivially optimizable deep nesting (constant propagation and dead code elimination test)
  • iterative implementation of the factorial
  • recursive implementation of Fibonacci numbers
  • iterative calculation of Pi
  • iterative implementation of the Euclidean algorithm for finding the GCD of two numbers
  • iterative algorithm for the modulo operator
  • recursive implementation of exponentiation by squaring

explain produced a 15512 byte x86-64 executable in 0.122 seconds, and the program runs in 0.467 seconds,
producing the following output:

  1. 65.000000
  2. 42.000000
  3. 2432902008176640000.000000
  4. 832040.000000
  5. 3.141593
  6. 101.000000
  7. 2.000000
  8. 3269017.372472

Here is a line-by-line breakdown of the expected results:

  • 64 + 1
  • Just 42
  • Factorial of 20
  • 30th Fibonacci number
  • Pi, calculated using the Gregory-Leibniz series with 100,000,000 iterations
  • Greatest common divisor of 50500 and 100899
  • Remainder of the division 100 / 7
  • e to the 15th power

The stress test files can be found under examples/stress within this repository. The outputs were obtained by the
following series of invocations:

  1. $ explain stress.xpln -o stress.ast --emit-ast
  2. $ explain stress.xpln -o stress.ll --emit-llvm
  3. $ llc -o stress_mips.s -march=mips stress.ll
  4. $ llc -o stress_x86_64.s -march=x86-64 stress.ll

errors: Compiler diagnostics, error reporting and recovery

All of the following examples are under examples/errors.

explain outputs diagnostics where it can. These scenarios include the following:

  • syntax errors (bad_tokens.xpln, recover.xpln)
  • argument count mismatch in function definition and function call (arg_count.xpln)
  • argument redefinition (arg_repeat.xpln)
  • division by zero (div_by_zero.xpln)
  • redefinition of function (fun_redefinition.xpln)
  • missing return statements (return_missing.xpln)
  • usage of undefined variables and functions (undefined.xpln)
  • LLVM function & module verifier errors

The diagnostic output is colored and contains source location information. See the image below:

Diagnostics screenshot

Contributing

If you feel like hacking explain, feel free to open a pull request. If you implement any of the following features
you’d be saving me a lot of time!

  • Highlighting errors like clang does
  • Support for the DWARF debugging standard
  • Support for different optimization levels, and more agressive optimizations like function inlining