├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── README.md ├── doc ├── support-new-libc-func.md └── support.md ├── include └── ravel │ ├── assembler │ ├── assembler.h │ ├── object_file.h │ ├── parser.h │ └── preprocessor.h │ ├── container_utils.h │ ├── error.h │ ├── instructions.h │ ├── interpreter │ ├── cache.h │ ├── interpreter.h │ └── libc_sim.h │ ├── linker │ ├── interpretable.h │ └── linker.h │ ├── ravel.h │ └── simulator.h ├── src ├── CMakeLists.txt ├── assembler │ ├── assembler.cpp │ ├── parser.cpp │ └── preprocessor.cpp ├── interpreter │ ├── cache.cpp │ ├── interpreter.cpp │ └── libc_sim.cpp ├── linker │ └── linker.cpp ├── main.cpp └── simulator.cpp └── test ├── asm ├── a_plus_b.s ├── a_plus_b_1.s ├── a_plus_b_func.s ├── hello_world.s └── loop.s ├── c ├── basic │ ├── fibonacci.c │ ├── io.c │ ├── mem.c │ └── multi_file │ │ ├── bultin.c │ │ ├── bultin.h │ │ └── main.c ├── mx │ ├── heapsort.c │ ├── horse3.c │ ├── humble.c │ ├── magic.c │ └── tak.c ├── oj │ └── 1003.c └── sorting │ ├── bubble_sort.c │ ├── merge_sort.c │ ├── quick_sort.c │ ├── selection_sort.c │ ├── sorting.in │ └── sorting.out ├── optim ├── binary_tree.ans ├── binary_tree.c ├── binary_tree.in ├── dijkstra.ans ├── dijkstra.c ├── dijkstra.in ├── humble.ans ├── humble.c ├── humble.in ├── kruskal.ans ├── kruskal.c ├── kruskal.in ├── lca.ans ├── lca.c ├── lca.in ├── lunatic.ans ├── lunatic.c ├── lunatic.in ├── maxflow.ans ├── maxflow.c ├── maxflow.in ├── pi.ans ├── pi.c ├── pi.in ├── segtree.ans ├── segtree.c ├── segtree.in ├── sha_1.ans ├── sha_1.c └── sha_1.in ├── run_tests.py └── test-ravel-sim.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | cmake-build-*/ 3 | cmake-arm/ 4 | .DS_Store 5 | build/ 6 | test.s 7 | builtin.s 8 | builtin.c 9 | test.c 10 | test.in 11 | test.out 12 | test.ll 13 | a.out 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: true 2 | language: cpp 3 | dist: bionic 4 | 5 | compiler: 6 | - clang 7 | - gcc 8 | os: 9 | - linux 10 | 11 | script: 12 | - mkdir build 13 | - cd build 14 | - cmake .. && make -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ravel) 2 | 3 | cmake_minimum_required(VERSION 3.10) 4 | 5 | add_subdirectory(src) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ravel 2 | 3 | | master | dev| 4 | |--- |--- | 5 | |[![Build Status](https://travis-ci.com/Engineev/ravel.svg?token=t7LhMb4BZCM8Q58kCnsH&branch=master)](https://travis-ci.com/Engineev/ravel) |[![Build Status](https://travis-ci.com/Engineev/ravel.svg?token=t7LhMb4BZCM8Q58kCnsH&branch=dev)](https://travis-ci.com/Engineev/ravel) 6 | 7 | 8 | ## Introduction 9 | 10 | **ravel** is a RISC-V simulator written for the compiler course taught at 11 | Shanghai Jiao Tong University, and the students in this course are usually second-year 12 | undergraduates at ACM Honers Class. In this course, students are required to 13 | implement a toy compiler that turns Mx* (a toy language used in the course) to 14 | RISC-V assembly. This simulator is used to test the correctness of the 15 | implementation and measure the quality of the optimization. 16 | 17 | ## Getting started 18 | The only prerequisites are CMake (>= 3.12) and a cpp-17 supporting compiler. 19 | You can install the simulator with the following commands. 20 | ```shell script 21 | git clone https://github.com/Engineev/ravel.git 22 | cd ravel 23 | mkdir build 24 | cd build 25 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/opt # or any directory you want 26 | make 27 | make install 28 | export PATH="/usr/local/opt/bin:$PATH" # optional 29 | ``` 30 | 31 | The easiest way to start a simulation is to use the OJ mode, that is, 32 | ```shell script 33 | ravel --oj-mode 34 | ``` 35 | Under this mode, the simulator takes `test.s` and `builtin.s` as the source 36 | code, `test.in` as the input and redirect the program output into `test.out`. 37 | The results (e.g. exit code) of the simulation will still be outputted directly 38 | to `stdout`. This is equivalent to 39 | ```shell script 40 | ravel --input-file=test.in --output-file=test.out test.s builtin.s 41 | # By default, cache is disabled. You can use --enable-cache to turn it on. 42 | ``` 43 | 44 | If you'd like to see the instructions being executed, you may pass in command 45 | line option `--print-instructions`, but note that this will significantly slow down the 46 | simulation. Also, if `--keep-debug-info` is passed in, **ravel** will perform more checks on 47 | memory accesses and will print additional information like the call stack when an error occurred. 48 | 49 | ## Ravel as a static library 50 | It's possible to use **ravel** as a static library. In fact, `make insatll` will also install the library 51 | `libravel-sim.a` into `${CMAKE_INSTALL_PREFIX}/lib` and the corresponding headers into 52 | `${CMAKE_INSTALL_PREFIX}/include`. See [./test/test-ravel-sim.cpp](./test/test-ravel-sim.cpp) for a minimal example. 53 | If you installed **ravel** into `/usr/local/opt`, then you can build the test with 54 | ```shell script 55 | g++ -std=c++17 ./test/test-ravel-sim.cpp -I/usr/local/opt/include -L/usr/local/opt/lib/ -lravel-sim 56 | ``` 57 | 58 | 59 | ## Support 60 | 61 | In short, if the assembly resembles the one generated with the following 62 | command, 63 | ```shell script 64 | riscv32-unknown-linux-gnu-gcc -S -std=c99 -fno-section-anchors main.c 65 | ``` 66 | where the build of `gcc` is configured with 67 | ```shell script 68 | ./configure --prefix=/opt/riscv --with-arch=rv32ima --with-abi=ilp32 69 | ``` 70 | then in most cases it is supported by the simulator. 71 | 72 | [comment]: <> (For LLVM users, the command should be ) 73 | 74 | [comment]: <> (```shell script) 75 | 76 | [comment]: <> (llc --march=riscv32 --mattr=+m main.ll) 77 | 78 | [comment]: <> (```) 79 | See [this](https://github.com/riscv/riscv-gnu-toolchain) for information on the 80 | risc-v toolchain. For detail on supported directives, instructions and libc 81 | functions, see [doc/support.md](./doc/support.md). 82 | 83 | ## Computing the running time 84 | The output of **ravel** contains a `time` filed. This is computed in the 85 | following way. For each type of instructions, the number of execution is 86 | recorded during the interpretation, and `time` is computed by a weighted 87 | summation. The default weights are listed in the following table. 88 | You can change the weights by passing in command line options like 89 | `-wsimple=2`. By default, cache is disabled. You may enable it by passing in 90 | `--enable-cache`. 91 | 92 | | Type | Weight | 93 | |--- |--- | 94 | |simple | 1 95 | |cache | 4 96 | |mul | 4 97 | |br | 8 98 | |div | 8 99 | |mem | 64 100 | |libcIO | 64 101 | |libcMem | function-dependent 102 | 103 | Note: Unconditional jumps are viewed as simple instructions. 104 | 105 | ## Pronunciation 106 | 107 | This project is named after the French composer Maurice Ravel, so the most correct way to pronounce the project name 108 | in English is /rəˈvɛl/ or /ræˈvɛl/, though I'm also OK with the pronunciation /ˈravəl/. 109 | 110 | In any case, how about checking this colorful [piano concerto](https://youtu.be/cJOW5mlhH_Y) by Ravel? 111 | 112 | -------------------------------------------------------------------------------- /doc/support-new-libc-func.md: -------------------------------------------------------------------------------- 1 | # How to add support for libc functions 2 | 3 | When **ravel** see instructions like `call malloc`, it will invoke a piece of C++ code which simulate the corresponding 4 | libc function. In other words, **ravel** doesn't have assembly implementation for the libc function in it. More 5 | precisely, this is implemented as follows. 6 | 7 | Recall that `call` is a pseudo-instruction, and it will be translated by the assembler (and also **ravel**) into 8 | `auipc` and `jalr`. In **ravel**, we assign each libc function a special dummy address. When the interpreter find the 9 | `pc` is pointing to one of these addresses, it knows a libc function has been invoked and then simulate it. 10 | 11 | A **ravel** interpretable consists of two parts, a header and the actual instructions. The first `12` bytes of the 12 | header correspond the assembly code 13 | ```asm 14 | .text 15 | _start: 16 | call main ; this will be decomposed into 2 instructions 17 | nop ; stands for the end of interpretation 18 | ``` 19 | The other bytes are placeholders for libc functions. The size of the header is determined by 20 | `ravel::LibcFuncEndAddr`, whose default value is `64` (cf. `src/linker/interpretable.h`). If the needed libc functions 21 | are too many to be fitted into the header, one can adjust `ravel::LibcFuncEndAddr` to any larger integer divisible by 22 | `16`. 23 | 24 | In order to add support for a new libc function. One needs to first assign it an address in `ravel::libc::Func` in 25 | `src/linker/interpretable.h`, and update the function `ravel::libc::getName2Pos`, which is in the same file. Then 26 | one needs to implement it in `ravel::Interpreter::simulateLibCFunc` in `src/interpreter/interpreter.cpp`. It's 27 | encouraged to mimic they way the other libc functions are implemented and put the actual implementation in 28 | `src/interpreter/libc_sim.h` and `src/interpreter/libc_sim.cpp`. 29 | -------------------------------------------------------------------------------- /doc/support.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | Reference: https://michaeljclark.github.io/asm 4 | 5 | ## Directives 6 | 7 | Unsupported directives will be ignored. 8 | In `.section` directives, arguments like `.rodata.str1.4,"aMS",@progbits,1` 9 | will be treated as `.rodata`. Section names such as `.sdata` will be treated 10 | as `.data` 11 | 12 | | Directive | Arguments 13 | |:--- |:--- 14 | |`.text` | 15 | |`.data` | 16 | |`.rodata` | 17 | |`.bss` | 18 | |`.section` | {`.text`, `.data`, `.rodata`, `.bss`} 19 | |`.align` | {`2`, `4`, `8`, `16`} 20 | |`.p2align` | {`1`, `2`, `3`, `4`} 21 | |`.globl` | symbol 22 | |`.comm` | symbol, size, align 23 | |`.zero` | integer 24 | |`.string` | string 25 | |`.asciz` | string 26 | |`.word` | integer 27 | 28 | ## Labels 29 | 30 | Local labels are not supported. 31 | 32 | ## Relocation Functions 33 | 34 | `%hi(symbol)`, `%lo(symbol)`, `%pcrel_hi(symbol)` and `%pcrel_lo(symbol)` 35 | are supported. 36 | 37 | ## Pseudo-instructions 38 | 39 | `offset` can be a label. 40 | 41 | | Pseudo-instruction | 42 | |:---| 43 | | `la rd, symbol` 44 | | `l{b, h, w} rd, symbol` 45 | | `s{b, h, w} rd, symbol, rt` 46 | | `nop` 47 | | `li rd, imm` 48 | | `mv rd, rs` 49 | | `not rd, rs` 50 | | `neg rd, rs` 51 | | `{seqz, snez, sltz, sgtz} rd, rs` 52 | | `{beqz, bnez, blez, bgez, bltz, btz} rs, offset` 53 | | `{bgt, ble, bgtu, bleu} rs, rt, offset` 54 | | `j offset` 55 | | `jr offset` 56 | | `ret` 57 | | `call offset` 58 | | `tail offset` 59 | 60 | ## Instructions 61 | 62 | RV32I base instruction set and RV32M standard extension are supported except 63 | `FENCE`, `FENCE.I`, `ECALL`, `EBREAK`, and CSR instructions. 64 | 65 | ## Libc Functions 66 | Currently, the following libc functions are supported. If you need other libc 67 | functions, you may open an issue. You can also check the instructions in `doc/support-new-libc-func.md` and 68 | add the needed libc function yourself. 69 | 70 | | Function signature | 71 | |:---| 72 | |`puts` 73 | |`scanf` (partially supported) 74 | |`sscanf` (partially supported) 75 | |`printf` (partially supported) 76 | |`sprintf` (partially supported) 77 | |`putchar` 78 | |`malloc` 79 | |`calloc` 80 | |`free` 81 | |`memcpy` 82 | |`strlen` 83 | |`strcpy` 84 | |`strcat` 85 | |`strcmp` 86 | |`memset` 87 | 88 | -------------------------------------------------------------------------------- /include/ravel/assembler/assembler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ravel/assembler/object_file.h" 6 | 7 | namespace ravel { 8 | 9 | ObjectFile assemble(const std::string &src); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /include/ravel/assembler/object_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ravel/container_utils.h" 12 | #include "ravel/instructions.h" 13 | 14 | namespace ravel { 15 | 16 | struct RelocationFunction { 17 | enum Type { 18 | HI, 19 | LO, 20 | PCREL_HI, 21 | PCREL_LO, 22 | }; 23 | 24 | RelocationFunction(Type type, std::string symbol, int offset = 0) 25 | : type(type), symbol(std::move(symbol)), offset(offset) {} 26 | 27 | Type type; 28 | std::string symbol; 29 | int offset; 30 | }; 31 | 32 | } // namespace ravel 33 | 34 | namespace ravel { 35 | // `ObjectFile` contains the following fields: 36 | // * `std::vector storage`: the content of the object file, including 37 | // initialized and uninitialized data. Note that instructions are encoded in 38 | // by their positions in `instructions`. 39 | // * std::unordered_map symbolTable 40 | // * std::unordered_set globalSymbol 41 | // * std::unordered_map 42 | // containsExternalLabel: In the object file, some instructions still 43 | // contain external labels which are going to be resolved in the linking 44 | // phrase. This map contains their ID and the name of label. 45 | // * std::unordered_map> containsRelocationFunc: 47 | // Some instructions contains relocation functions such as %hi and this map 48 | // contains them and the relocation functions. 49 | // 50 | // Layout: text, data, rodata, bss 51 | class ObjectFile { 52 | public: 53 | using Id = ravel::Id; 54 | 55 | ObjectFile(std::vector storage, 56 | std::vector> insts, 57 | std::unordered_map inst2Pos, 58 | std::unordered_map symbolTable, 59 | std::unordered_set globalSymbol, 60 | std::unordered_map 61 | containsExternalLabel, 62 | std::unordered_map 63 | containsRelocationFunc, 64 | std::vector> toBeStored) 65 | : storage(std::move(storage)), insts(std::move(insts)), 66 | inst2Pos(std::move(inst2Pos)), symbolTable(std::move(symbolTable)), 67 | globalSymbol(std::move(globalSymbol)), 68 | containsExternalLabel(std::move(containsExternalLabel)), 69 | containsRelocationFunc(std::move(containsRelocationFunc)), 70 | toBeStored(std::move(toBeStored)) {} 71 | 72 | const Id &getId() const { return id; } 73 | 74 | const std::vector &getStorage() const { return storage; } 75 | 76 | const std::vector> &getInsts() const { 77 | return insts; 78 | } 79 | 80 | const std::unordered_map & 81 | getInst2Pos() const { 82 | return inst2Pos; 83 | } 84 | 85 | const std::unordered_map &getSymbolTable() const { 86 | return symbolTable; 87 | } 88 | 89 | const std::unordered_set &getGlobalSymbol() const { 90 | return globalSymbol; 91 | } 92 | 93 | const std::unordered_map & 94 | getContainsExternalLabel() const { 95 | return containsExternalLabel; 96 | } 97 | 98 | const std::unordered_map & 99 | getContainsRelocationFunc() const { 100 | return containsRelocationFunc; 101 | } 102 | 103 | const std::vector> & 104 | getToBeStored() const { 105 | return toBeStored; 106 | } 107 | 108 | private: 109 | Id id; 110 | std::vector storage; 111 | std::vector> insts; 112 | std::unordered_map inst2Pos; 113 | 114 | std::unordered_map symbolTable; 115 | std::unordered_set globalSymbol; 116 | std::unordered_map containsExternalLabel; 117 | std::unordered_map 118 | containsRelocationFunc; 119 | std::vector> toBeStored; 120 | }; 121 | 122 | } // namespace ravel 123 | -------------------------------------------------------------------------------- /include/ravel/assembler/parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ravel/instructions.h" 9 | 10 | // utilities 11 | namespace ravel { 12 | 13 | std::string strip(std::string str); 14 | 15 | // split a string into words 16 | std::vector split(const std::string &s, 17 | const std::string &delimiters = " \t"); 18 | 19 | std::vector tokenize(const std::string &line); 20 | 21 | bool isDirective(const std::string &str); 22 | 23 | bool isLabel(const std::string &str); 24 | 25 | // If [line] emits or makes current a new section, then return 26 | // the name of the section 27 | std::optional getSectionName(const std::string &line); 28 | 29 | std::string opType2Name(inst::Instruction::OpType op); 30 | 31 | inst::Instruction::OpType name2OpType(std::string name); 32 | 33 | std::size_t regName2regNumber(const std::string &name); 34 | 35 | std::string regNumber2regName(const std::size_t &num); 36 | 37 | std::pair parseBaseOffset(const std::string &str); 38 | 39 | std::string toString(const std::shared_ptr &inst); 40 | 41 | // return the section name (e.g. .text) 42 | std::string parseSectionDerivative(const std::string &line); 43 | 44 | std::uint32_t parseImm(const std::string &str); 45 | 46 | std::string handleEscapeCharacters(const std::string &str); 47 | 48 | } // namespace ravel 49 | -------------------------------------------------------------------------------- /include/ravel/assembler/preprocessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ravel { 7 | 8 | // Split the source file into lines. 9 | // Remove comments. 10 | // Trim each line. 11 | // Make each label to occupy an entire line. 12 | // Remove empty lines. 13 | // Translate pseudo instructions. 14 | std::vector preprocess(const std::string &src); 15 | 16 | } // namespace ravel 17 | -------------------------------------------------------------------------------- /include/ravel/container_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ravel { 8 | 9 | template bool isIn(const Set &s, const V &val) { 10 | return s.find(val) != s.end(); 11 | } 12 | 13 | template 14 | void append(Container &container, const Container &values) { 15 | container.insert(container.end(), values.begin(), values.end()); 16 | } 17 | 18 | template 19 | std::optional::mapped_type> get(Map &&mp, 20 | const Key &key) { 21 | auto iter = mp.find(key); 22 | if (iter == mp.end()) 23 | return std::nullopt; 24 | return mp.at(key); 25 | } 26 | 27 | } // namespace ravel 28 | 29 | namespace ravel { 30 | 31 | template class Id { 32 | template friend struct std::hash; 33 | 34 | public: 35 | Id() { 36 | static int currentId = 1; 37 | val = currentId++; 38 | } 39 | 40 | bool operator==(const Id &rhs) const { return val == rhs.val; } 41 | 42 | bool operator!=(const Id &rhs) const { return !(*this == rhs); } 43 | 44 | private: 45 | int val; 46 | }; 47 | 48 | } // namespace ravel 49 | 50 | namespace std { 51 | template struct hash> { 52 | using Key = ravel::Id; 53 | 54 | std::size_t operator()(const Key &k) const { return std::hash()(k.val); } 55 | }; 56 | } // namespace std 57 | -------------------------------------------------------------------------------- /include/ravel/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ravel { 8 | 9 | class Exception : public std::exception { 10 | public: 11 | explicit Exception(std::string msg) : msg(std::move(msg)) {} 12 | Exception(const Exception &o) noexcept { msg = o.msg; } 13 | ~Exception() override = default; 14 | 15 | const char *what() const noexcept override { return msg.c_str(); } 16 | 17 | void setMsg(const std::string &msg_) { msg = msg_; } 18 | 19 | private: 20 | std::string msg; 21 | }; 22 | 23 | class LinkError : public Exception { 24 | public: 25 | explicit LinkError(const std::string &msg) 26 | : Exception("Link error: " + msg) {} 27 | }; 28 | 29 | class UnresolvableSymbol : public LinkError { 30 | public: 31 | explicit UnresolvableSymbol(const std::string &symbol) 32 | : LinkError("can not resolve symbol " + symbol) {} 33 | }; 34 | 35 | class DuplicatedSymbols : public LinkError { 36 | public: 37 | explicit DuplicatedSymbols(const std::string &symbol) 38 | : LinkError("duplicated symbols: " + symbol) {} 39 | }; 40 | 41 | class NotSupportedError : public Exception { 42 | public: 43 | using Exception::Exception; 44 | }; 45 | 46 | class InvalidAddress : public Exception { 47 | public: 48 | explicit InvalidAddress(std::size_t address) : Exception("") { 49 | std::stringstream ss; 50 | ss << std::hex << address; 51 | msg = ss.str(); 52 | } 53 | 54 | const char *what() const noexcept override { return msg.c_str(); } 55 | 56 | private: 57 | std::string msg; 58 | }; 59 | 60 | class Timeout : public Exception { 61 | using Exception::Exception; 62 | }; 63 | 64 | class RuntimeError : public Exception { 65 | using Exception::Exception; 66 | }; 67 | 68 | } // namespace ravel -------------------------------------------------------------------------------- /include/ravel/instructions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ravel/container_utils.h" 11 | 12 | namespace ravel::inst { 13 | 14 | class Instruction { 15 | public: 16 | // clang-format off 17 | enum OpType { 18 | LUI, AUIPC, // ImmConstruction 19 | JAL, // JumpLink 20 | JALR, // JumpLinkReg 21 | BEQ, BNE, BLT, BGE, BLTU, BGEU, // Branch 22 | LB, LH, LW, LBU, LHU, SB, SH, SW, // MemAccess 23 | ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, // ArithRegImm 24 | ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, // ArithRegReg 25 | // TODO: fence ... 26 | MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU, // MArith 27 | }; 28 | // clang-format on 29 | 30 | using Id = ravel::Id; 31 | 32 | public: 33 | explicit Instruction(OpType type) : op(type) {} 34 | Instruction(OpType type, std::string comment) 35 | : op(type), comment(std::move(comment)) {} 36 | virtual ~Instruction() = default; 37 | 38 | OpType getOp() const { return op; } 39 | 40 | const Id &getId() const { return id; } 41 | 42 | const std::string &getComment() const { return comment; } 43 | 44 | private: 45 | Id id; 46 | OpType op; 47 | std::string comment; 48 | }; 49 | 50 | } // namespace ravel::inst 51 | 52 | namespace ravel::inst { 53 | 54 | class ImmConstruction : public Instruction { 55 | public: 56 | ImmConstruction(OpType op, std::size_t dest, std::uint32_t imm) 57 | : Instruction(op), dest(dest), imm(imm) { 58 | assert((imm >> 20u) == 0 || ((-imm) >> 20u) == 0); 59 | } 60 | 61 | size_t getDest() const { return dest; } 62 | std::uint32_t getImm() const { return imm; } 63 | 64 | private: 65 | std::size_t dest; 66 | std::uint32_t imm; 67 | }; 68 | 69 | class ArithRegReg : public Instruction { 70 | public: 71 | ArithRegReg(OpType op, std::size_t dest, std::size_t src1, std::size_t src2) 72 | : Instruction(op), dest(dest), src1(src1), src2(src2) {} 73 | 74 | size_t getDest() const { return dest; } 75 | size_t getSrc1() const { return src1; } 76 | size_t getSrc2() const { return src2; } 77 | 78 | private: 79 | std::size_t dest, src1, src2; 80 | }; 81 | 82 | class ArithRegImm : public Instruction { 83 | public: 84 | ArithRegImm(OpType type, size_t dest, size_t src, int imm) 85 | : Instruction(type), dest(dest), src(src), imm(imm) {} 86 | 87 | size_t getDest() const { return dest; } 88 | 89 | size_t getSrc() const { return src; } 90 | 91 | int getImm() const { return imm; } 92 | 93 | private: 94 | std::size_t dest, src; 95 | int imm; 96 | }; 97 | 98 | class MemAccess : public Instruction { 99 | public: 100 | MemAccess(OpType type, std::size_t reg, std::size_t base, int offset) 101 | : Instruction(type), reg(reg), base(base), offset(offset) {} 102 | 103 | size_t getReg() const { return reg; } 104 | 105 | size_t getBase() const { return base; } 106 | 107 | int getOffset() const { return offset; } 108 | 109 | private: 110 | std::size_t reg, base; 111 | int offset; 112 | }; 113 | 114 | class JumpLink : public Instruction { 115 | public: 116 | JumpLink(std::size_t dest, int offset, std::string comment = "") 117 | : Instruction(JAL, std::move(comment)), dest(dest), offset(offset) {} 118 | 119 | size_t getDest() const { return dest; } 120 | int getOffset() const { return offset; } 121 | 122 | private: 123 | std::size_t dest; 124 | int offset; 125 | }; 126 | 127 | class JumpLinkReg : public Instruction { 128 | public: 129 | JumpLinkReg(std::size_t dest, std::size_t base, int offset) 130 | : Instruction(JALR), dest(dest), base(base), offset(offset) {} 131 | 132 | size_t getDest() const { return dest; } 133 | size_t getBase() const { return base; } 134 | int getOffset() const { return offset; } 135 | 136 | private: 137 | std::size_t dest; 138 | std::size_t base; 139 | int offset; 140 | }; 141 | 142 | class Branch : public Instruction { 143 | public: 144 | Branch(OpType op, std::size_t src1, std::size_t src2, int offset, 145 | std::string comment = "") 146 | : Instruction(op, std::move(comment)), src1(src1), src2(src2), 147 | offset(offset) {} 148 | 149 | size_t getSrc1() const { return src1; } 150 | size_t getSrc2() const { return src2; } 151 | int getOffset() const { return offset; } 152 | 153 | private: 154 | std::size_t src1, src2; 155 | int offset; 156 | }; 157 | 158 | class MArith : public Instruction { 159 | public: 160 | MArith(Instruction::OpType op, std::size_t dest, std::size_t src1, 161 | std::size_t src2) 162 | : Instruction(op), dest(dest), src1(src1), src2(src2) {} 163 | 164 | size_t getDest() const { return dest; } 165 | size_t getSrc1() const { return src1; } 166 | size_t getSrc2() const { return src2; } 167 | 168 | private: 169 | std::size_t dest, src1, src2; 170 | }; 171 | 172 | } // namespace ravel::inst 173 | -------------------------------------------------------------------------------- /include/ravel/interpreter/cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace ravel { 11 | 12 | class Cache { 13 | struct Line; 14 | 15 | public: 16 | Cache(std::byte *storageBegin, std::byte *storageEnd) 17 | : storageBegin(storageBegin), storageEnd(storageEnd) { 18 | assert(storageEnd >= storageBegin); 19 | lines.resize(16); 20 | } 21 | 22 | void tick() { ++cycles; } 23 | 24 | std::uint32_t fetchWord(std::size_t addr); 25 | 26 | void disable() { disabled = true; } 27 | 28 | std::pair getMemory() { 29 | return {storageBegin, storageEnd}; 30 | } 31 | 32 | std::pair getHitMiss() const { return {hit, miss}; } 33 | 34 | std::byte &operator[](std::size_t addr) { 35 | fetchWord(addr); 36 | assert(addr < std::size_t(storageEnd - storageBegin)); 37 | return storageBegin[addr]; 38 | } 39 | 40 | std::size_t storageSize() const { return storageEnd - storageBegin; } 41 | 42 | private: 43 | Line &getEmptyLine(); 44 | 45 | private: 46 | static constexpr std::size_t SizePow = 6; 47 | static constexpr std::uint32_t Mask = std::uint32_t(-1) << SizePow; 48 | 49 | std::byte *const storageBegin; 50 | std::byte *const storageEnd; 51 | 52 | std::size_t cycles = 32; 53 | struct Line { 54 | std::size_t addr = 0; 55 | std::size_t lastUsed = 0; 56 | bool valid = false; 57 | }; 58 | std::vector lines; 59 | bool disabled = false; 60 | std::size_t victimIdx = 7; 61 | 62 | std::size_t hit = 0; 63 | std::size_t miss = 0; 64 | }; 65 | 66 | } // namespace ravel -------------------------------------------------------------------------------- /include/ravel/interpreter/interpreter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "cache.h" 12 | #include "ravel/linker/interpretable.h" 13 | 14 | namespace ravel { 15 | 16 | struct InstWeight { 17 | InstWeight() = default; 18 | 19 | std::size_t simple = 1; 20 | std::size_t mul = 4; 21 | std::size_t cache = 4; 22 | std::size_t br = 8; 23 | std::size_t div = 8; 24 | std::size_t mem = 64; 25 | std::size_t libcIO = 64; 26 | std::size_t libcMem = 128; 27 | }; 28 | 29 | struct InstCnt { 30 | std::size_t simple = 0; 31 | std::size_t mul = 0; 32 | std::size_t cache = 0; 33 | std::size_t br = 0; 34 | std::size_t div = 0; 35 | std::size_t mem = 0; 36 | std::size_t libcIO = 0; 37 | std::size_t libcMem = 0; 38 | }; 39 | 40 | class Interpreter { 41 | public: 42 | Interpreter(const Interpretable &interpretable, std::uint32_t *externalRegs, 43 | std::byte *externalStorageBegin, std::byte *externalStorageEnd, 44 | FILE *in, FILE *out, InstWeight instWeight) 45 | : interpretable(interpretable), externalRegs(externalRegs), 46 | cache(externalStorageBegin, externalStorageEnd), in(in), out(out), 47 | instWeight(instWeight) { 48 | std::copy(externalRegs, externalRegs + 32, regs.begin()); 49 | } 50 | 51 | ~Interpreter() { 52 | if (externalRegs) 53 | std::copy(regs.begin(), regs.end(), externalRegs.value()); 54 | } 55 | 56 | void interpret(); 57 | 58 | void disableCache() { cache.disable(); } 59 | 60 | void setKeepDebugInfo(bool val) { keepDebugInfo = val; } 61 | 62 | std::uint32_t getReturnCode() const; 63 | 64 | bool hasMemoryLeak() const { return !malloced.empty(); } 65 | 66 | std::size_t getTimeConsumed() const { 67 | return instCnt.simple * instWeight.simple + instCnt.mul * instWeight.mul + 68 | instCnt.cache * instWeight.cache + instCnt.br * instWeight.br + 69 | instCnt.div * instWeight.div + instCnt.mem * instWeight.mem + 70 | instCnt.libcIO * instWeight.libcIO + 71 | instCnt.libcMem * instWeight.libcMem; 72 | } 73 | 74 | const InstCnt &getInstCnt() const { return instCnt; } 75 | 76 | void enablePrintInstructions() { printInstructions = true; } 77 | 78 | void setTimeout(std::size_t newTimeout) { timeout = newTimeout; } 79 | 80 | private: 81 | void load(); 82 | 83 | void simulate(const std::shared_ptr &inst); 84 | 85 | void simulateLibCFunc(libc::Func funcN); 86 | 87 | private: 88 | const Interpretable &interpretable; 89 | 90 | std::optional externalRegs; 91 | std::array regs = {0}; 92 | std::int32_t pc = 0; 93 | Cache cache; 94 | std::size_t heapPtr = 0; 95 | std::unordered_set malloced; 96 | std::unordered_set invalidAddress; 97 | 98 | FILE *in; 99 | FILE *out; 100 | InstWeight instWeight; 101 | InstCnt instCnt; 102 | bool printInstructions = false; 103 | bool keepDebugInfo = false; 104 | std::size_t timeout = (std::size_t)-1; 105 | }; 106 | 107 | } // namespace ravel 108 | -------------------------------------------------------------------------------- /include/ravel/interpreter/libc_sim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* How to add support for a new libc function 4 | * 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // IO 16 | namespace ravel::libc { 17 | 18 | void puts(std::array ®s, std::byte *storage, 19 | std::byte *storageEnd, FILE *fp); 20 | 21 | void scanf(std::array ®s, std::byte *storage, 22 | std::byte *storageEnd, FILE *fp); 23 | 24 | void sscanf(std::array ®s, std::byte *storage); 25 | 26 | void sprintf(std::array ®s, std::byte *storage); 27 | 28 | void printf(std::array ®s, const std::byte *storage, 29 | std::byte *storageEnd, FILE *fp); 30 | 31 | void putchar(std::array ®s, FILE *fp); 32 | 33 | } // namespace ravel::libc 34 | 35 | namespace ravel::libc { 36 | 37 | void malloc(std::array ®s, std::byte *storage, 38 | std::byte *storageEnd, std::size_t &heapPtr, 39 | std::unordered_set &malloced, 40 | std::unordered_set &invalidAddress, 41 | std::size_t &instCnt, bool zeroInit = false); 42 | 43 | void free(const std::array ®s, 44 | std::unordered_set &malloced); 45 | 46 | void memcpy(std::array ®s, std::byte *storage, 47 | std::byte *storageEnd, std::size_t &instCnt); 48 | 49 | void strlen(std::array ®s, const std::byte *storage); 50 | 51 | void strcpy(std::array ®s, std::byte *storage, 52 | std::byte *storageEnd, std::size_t &instCnt); 53 | 54 | void strcat(std::array ®s, std::byte *storage, 55 | std::byte *storageEnd, std::size_t &instCnt); 56 | 57 | void strcmp(std::array ®s, std::byte *storage); 58 | 59 | void memset(std::array ®s, std::byte *storage, 60 | std::byte *storageEnd, std::size_t &instCnt); 61 | 62 | } // namespace ravel::libc 63 | -------------------------------------------------------------------------------- /include/ravel/linker/interpretable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ravel/instructions.h" 9 | 10 | namespace ravel { 11 | 12 | // The format of an interpretable: 13 | // An interpretable consists of two parts: a header and the content. 14 | // 15 | // Header: lic::LibcFuncEndAddr bytes 16 | // The first 12 bytes of the header are the assembly code: 17 | // .text 18 | // _start: 19 | // call main ; this will be decomposed into 2 instructions 20 | // nop ; stands for the end of interpretation 21 | // The other bytes are just placeholders for C library functions. When the 22 | // program jumps to an address between 12 and lic::LibcFuncEndAddr, it will be 23 | // viewed as calling a corresponding C library function. 24 | class Interpretable { 25 | public: 26 | static constexpr std::size_t Start = 0; 27 | static constexpr std::size_t End = 8; 28 | static constexpr std::size_t LibcFuncStart = 12; 29 | static constexpr std::size_t LibcFuncEnd = 48; 30 | 31 | Interpretable(std::vector storage, 32 | std::vector> insts) 33 | : storage(std::move(storage)), insts(std::move(insts)) {} 34 | 35 | const std::vector &getStorage() const { return storage; } 36 | const std::vector> &getInsts() const { 37 | return insts; 38 | } 39 | 40 | private: 41 | std::vector storage; 42 | std::vector> insts; 43 | }; 44 | 45 | namespace libc { 46 | 47 | constexpr std::size_t LibcFuncEndAddr = 64; 48 | static_assert(LibcFuncEndAddr % 16 == 0); 49 | 50 | enum Func { 51 | // The minimum value should be at least 12 52 | 53 | // When we count instructions, the following functions have type libcIO, ... 54 | PUTS = 12, 55 | SCANF = 14, 56 | SSCANF = 16, 57 | PRINTF = 18, 58 | SPRINTF = 20, 59 | PUTCHAR = 22, 60 | 61 | // ... and the following functions have type libcMem. 62 | MALLOC = 24, 63 | FREE = 26, 64 | MEMCPY = 28, 65 | STRLEN = 30, 66 | STRCPY = 32, 67 | STRCAT = 34, 68 | STRCMP = 36, 69 | MEMSET = 38, 70 | CALLOC = 40, 71 | 72 | // The maximum value cannot be larger than LibcFuncEndAddr - 2 73 | }; 74 | 75 | inline const std::unordered_map &getName2Pos() { 76 | using namespace std::string_literals; 77 | // clang-format off 78 | static std::unordered_map mp = { 79 | // IO 80 | {"puts", PUTS}, 81 | {"scanf", SCANF}, 82 | {"__isoc99_scanf", SCANF}, 83 | {"sscanf", SSCANF}, 84 | {"__isoc99_sscanf", SSCANF}, 85 | {"printf", PRINTF}, 86 | {"sprintf", SPRINTF}, 87 | {"putchar", PUTCHAR}, 88 | 89 | // mem 90 | {"malloc", MALLOC}, 91 | {"free", FREE}, 92 | {"memcpy", MEMCPY}, 93 | {"strlen", STRLEN}, 94 | {"strcpy", STRCPY}, 95 | {"strcat", STRCAT}, 96 | {"strcmp", STRCMP}, 97 | {"memset", MEMSET}, 98 | {"calloc", CALLOC}, 99 | }; 100 | // clang-format on 101 | return mp; 102 | } 103 | 104 | } // namespace libc 105 | 106 | } // namespace ravel 107 | -------------------------------------------------------------------------------- /include/ravel/linker/linker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "interpretable.h" 7 | #include "ravel/assembler/object_file.h" 8 | 9 | namespace ravel { 10 | 11 | Interpretable link(const std::vector &objects); 12 | 13 | } // namespace ravel 14 | -------------------------------------------------------------------------------- /include/ravel/ravel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ravel/assembler/assembler.h" 4 | #include "ravel/assembler/object_file.h" 5 | #include "ravel/assembler/parser.h" 6 | #include "ravel/assembler/preprocessor.h" 7 | 8 | #include "ravel/interpreter/cache.h" 9 | #include "ravel/interpreter/interpreter.h" 10 | #include "ravel/interpreter/libc_sim.h" 11 | 12 | #include "ravel/linker/interpretable.h" 13 | #include "ravel/linker/linker.h" 14 | 15 | #include "ravel/container_utils.h" 16 | #include "ravel/error.h" 17 | #include "ravel/instructions.h" 18 | #include "ravel/simulator.h" 19 | -------------------------------------------------------------------------------- /include/ravel/simulator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ravel/assembler/assembler.h" 11 | #include "ravel/interpreter/interpreter.h" 12 | #include "ravel/linker/linker.h" 13 | 14 | namespace ravel { 15 | 16 | struct Config { 17 | Config() = default; 18 | 19 | bool printInsts = false; 20 | bool cacheEnabled = false; 21 | bool keepDebugInfo = false; 22 | std::string inputFile; 23 | std::string outputFile; 24 | std::vector sources; 25 | InstWeight instWeight = InstWeight(); 26 | // exits when # of instructions executed exceeds `timeout` 27 | std::size_t timeout = (std::size_t)-1; 28 | 29 | std::size_t maxStorageSize = 512 * 1024 * 1024; 30 | 31 | // use external registers and memory 32 | std::uint32_t *externalRegs = nullptr; 33 | std::byte *externalStorageBegin = nullptr; 34 | std::byte *externalStorageEnd = nullptr; 35 | }; 36 | 37 | class Simulator { 38 | public: 39 | explicit Simulator(Config config_); 40 | 41 | std::size_t simulate(); 42 | 43 | private: 44 | Interpretable buildInterpretable(); 45 | 46 | std::pair getIOFile() const; 47 | 48 | void printResult(const Interpreter &interpreter) const; 49 | 50 | private: 51 | Config config; 52 | std::variant, std::uint32_t *> regs; 53 | std::variant, std::pair> 54 | storage; 55 | }; 56 | 57 | } // namespace ravel 58 | 59 | namespace ravel { 60 | 61 | std::size_t simulate(const std::string &src, std::uint32_t *regs, 62 | std::byte *storageBegin, std::byte *storageEnd); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | ${CMAKE_SOURCE_DIR}/include/ravel/assembler/assembler.h 3 | ${CMAKE_SOURCE_DIR}/include/ravel/assembler/object_file.h 4 | ${CMAKE_SOURCE_DIR}/include/ravel/assembler/parser.h 5 | ${CMAKE_SOURCE_DIR}/include/ravel/assembler/preprocessor.h 6 | 7 | ${CMAKE_SOURCE_DIR}/include/ravel/interpreter/cache.h 8 | ${CMAKE_SOURCE_DIR}/include/ravel/interpreter/interpreter.h 9 | ${CMAKE_SOURCE_DIR}/include/ravel/interpreter/libc_sim.h 10 | 11 | ${CMAKE_SOURCE_DIR}/include/ravel/linker/interpretable.h 12 | ${CMAKE_SOURCE_DIR}/include/ravel/linker/linker.h 13 | 14 | ${CMAKE_SOURCE_DIR}/include/ravel/container_utils.h 15 | ${CMAKE_SOURCE_DIR}/include/ravel/error.h 16 | ${CMAKE_SOURCE_DIR}/include/ravel/instructions.h 17 | ${CMAKE_SOURCE_DIR}/include/ravel/ravel.h 18 | ${CMAKE_SOURCE_DIR}/include/ravel/simulator.h 19 | ) 20 | 21 | set(SOURCES 22 | assembler/assembler.cpp 23 | assembler/parser.cpp 24 | assembler/preprocessor.cpp 25 | 26 | interpreter/cache.cpp 27 | interpreter/interpreter.cpp 28 | interpreter/libc_sim.cpp 29 | 30 | linker/linker.cpp 31 | 32 | simulator.cpp 33 | ) 34 | 35 | add_library(ravel-sim ${HEADERS} ${SOURCES}) 36 | target_compile_features(ravel-sim PUBLIC cxx_std_17) 37 | target_include_directories(ravel-sim 38 | PUBLIC 39 | $ 40 | $ 41 | ) 42 | if (UNIX) 43 | target_compile_options(ravel-sim PRIVATE -O2 -Wall) 44 | endif () 45 | include(GNUInstallDirs) 46 | install(TARGETS ravel-sim 47 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 48 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 49 | ) 50 | install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/ravel" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 51 | 52 | 53 | add_executable(ravel main.cpp) 54 | target_link_libraries(ravel PRIVATE ravel-sim) 55 | target_compile_features(ravel PRIVATE cxx_std_17) 56 | if (UNIX) 57 | target_compile_options(ravel PRIVATE -O2 -Wall) 58 | endif () 59 | 60 | install(TARGETS ravel DESTINATION ${CMAKE_INSTALL_BINDIR}) 61 | 62 | -------------------------------------------------------------------------------- /src/assembler/assembler.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/assembler/assembler.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "ravel/assembler/object_file.h" 17 | #include "ravel/assembler/parser.h" 18 | #include "ravel/assembler/preprocessor.h" 19 | #include "ravel/container_utils.h" 20 | #include "ravel/error.h" 21 | #include "ravel/instructions.h" 22 | 23 | // Here, we describe the implementation of the assembler. For details about 24 | // the resulted [ObjectFile], see object_file.h. 25 | // We assume each line contains either a directive, a label, or and 26 | // instruction. See the function [preprocess] in parser.cpp for detail on 27 | // preprocessing. 28 | // The assembling process consists of two passes. In the first pass, 29 | // spaces are allocated, and labels and directives are handled. In the second 30 | // pass, instructions are parsed. 31 | // TODO: 32 | // * local labels (numerical labels) are not supported yet 33 | 34 | namespace ravel { 35 | 36 | enum class Section { ERROR = 0, TEXT, DATA, RODATA, BSS }; 37 | 38 | struct LabelPos { 39 | LabelPos(Section section, size_t pos) : section(section), pos(pos) {} 40 | 41 | Section section; 42 | std::size_t pos; 43 | }; 44 | 45 | int roundUp(int number, int multiple) { 46 | assert(multiple > 0); 47 | int remainder = number % multiple; 48 | if (remainder == 0) 49 | return number; 50 | return number + multiple - remainder; 51 | } 52 | 53 | } // namespace ravel 54 | 55 | namespace ravel { 56 | namespace { 57 | 58 | class AssemblerPass1 { 59 | public: 60 | // If `forceSingleFile` is true, then no external symbols are allowed. 61 | explicit AssemblerPass1(std::vector src) : src(std::move(src)) {} 62 | 63 | std::tuple /* storage */, 64 | std::unordered_map /* labelName2Pos */, 65 | std::unordered_set /* globalSymbols */, 66 | std::vector> /* toBeStored */> 67 | operator()() { 68 | for (auto &line : src) { 69 | if (isDirective(line)) { 70 | handleDerivative(line); 71 | continue; 72 | } 73 | if (isLabel(line)) { 74 | handleLabel(line); 75 | continue; 76 | } 77 | assert(curSection == Section::TEXT); 78 | text.resize(text.size() + 4); 79 | } 80 | 81 | // merge the result 82 | text.resize(roundUp(text.size(), 16)); 83 | data.resize(roundUp(data.size(), 16)); 84 | rodata.resize(roundUp(rodata.size(), 16)); 85 | bss.resize(roundUp(bss.size(), 16)); 86 | 87 | std::vector storage; 88 | storage.insert(storage.end(), text.begin(), text.end()); 89 | for (auto &[label, position] : toBeStored) 90 | position += storage.size(); 91 | storage.insert(storage.end(), data.begin(), data.end()); 92 | storage.insert(storage.end(), rodata.begin(), rodata.end()); 93 | storage.insert(storage.end(), bss.begin(), bss.end()); 94 | 95 | std::unordered_map labelName2Pos; 96 | 97 | for (auto &[labelName, secPos] : labelName2SecPos) { 98 | std::size_t pos = 0; 99 | switch (secPos.section) { // The fall-through is intended here. 100 | case Section::BSS: 101 | pos += rodata.size(); 102 | case Section::RODATA: 103 | pos += data.size(); 104 | case Section::DATA: 105 | pos += text.size(); 106 | case Section::TEXT: 107 | pos += secPos.pos; 108 | break; 109 | default: 110 | assert(false); 111 | } 112 | labelName2Pos.emplace(labelName, pos); 113 | } 114 | 115 | return {storage, labelName2Pos, globalSymbols, toBeStored}; 116 | } 117 | 118 | private: 119 | std::vector &getCurSecStorage() { 120 | switch (curSection) { 121 | case Section::TEXT: 122 | return text; 123 | case Section::DATA: 124 | return data; 125 | case Section::RODATA: 126 | return rodata; 127 | case Section::BSS: 128 | return bss; 129 | default: 130 | assert(false); 131 | } 132 | } 133 | 134 | void handleDerivative(const std::string &line) { 135 | auto tokens = tokenize(line); 136 | assert(!tokens.empty()); 137 | 138 | if (tokens[0] == ".text") { 139 | curSection = Section::TEXT; 140 | return; 141 | } 142 | if (tokens[0] == ".data") { 143 | curSection = Section::DATA; 144 | return; 145 | } 146 | if (tokens[0] == ".rodata") { 147 | curSection = Section::RODATA; 148 | return; 149 | } 150 | if (tokens[0] == ".bss") { 151 | curSection = Section::BSS; 152 | return; 153 | } 154 | if (tokens[0] == ".section") { 155 | auto sec = parseSectionDerivative(line); 156 | if (sec == ".text") 157 | curSection = Section ::TEXT; 158 | else if (sec == ".data") 159 | curSection = Section ::DATA; 160 | else if (sec == ".rodata") 161 | curSection = Section ::RODATA; 162 | else if (sec == ".bss") 163 | curSection = Section ::BSS; 164 | else { 165 | std::cerr << "Ignoring directive: " << line << std::endl; 166 | } 167 | return; 168 | } 169 | if (curSection == Section::ERROR) { 170 | std::cerr << "Ignoring directive: " << line << std::endl; 171 | return; 172 | } 173 | 174 | auto &storage = getCurSecStorage(); 175 | 176 | if (tokens[0] == ".align" || tokens[0] == ".p2align") { 177 | auto p = std::stoul(tokens.at(1)); 178 | auto alignment = 1u << p; 179 | storage.resize(roundUp(storage.size(), alignment)); 180 | return; 181 | } 182 | if (tokens[0] == ".globl") { 183 | globalSymbols.emplace(tokens.at(1)); 184 | return; 185 | } 186 | if (tokens[0] == ".comm") { 187 | auto label = tokens.at(1); 188 | std::size_t size = std::stoul(tokens.at(2)); 189 | std::size_t alignment = std::stoul(tokens.at(3)); 190 | bss.resize(roundUp(bss.size(), alignment)); 191 | auto pos = bss.size(); 192 | bss.resize(bss.size() + size); 193 | labelName2SecPos.emplace(label, LabelPos(Section::BSS, pos)); 194 | return; 195 | } 196 | if (tokens[0] == ".zero") { 197 | std::size_t size = std::stoul(tokens.at(1)); 198 | storage.resize(storage.size() + size, (std::byte)0); 199 | return; 200 | } 201 | 202 | if (tokens.at(0) == ".string" || tokens.at(0) == ".asciz") { 203 | assert(curSection != Section::TEXT); 204 | auto iter = line.begin(); 205 | iter += tokens[0].length(); 206 | while (std::isspace(*iter)) 207 | ++iter; 208 | assert(*iter == '"'); 209 | ++iter; 210 | std::string str(iter, line.end() - 1); 211 | str = handleEscapeCharacters(str); 212 | auto curPos = storage.size(); 213 | storage.resize(storage.size() + str.size() + 1); 214 | std::strcpy((char *)(storage.data() + curPos), str.c_str()); 215 | storage.back() = (std::byte)0; 216 | return; 217 | } 218 | if (tokens.at(0) == ".word") { 219 | assert(curSection != Section::TEXT); 220 | assert(tokens.size() == 2); 221 | auto curPos = storage.size(); 222 | storage.resize(storage.size() + 4); 223 | if (!std::isdigit(tokens.at(1).front()) && 224 | tokens.at(1).front() != '-') { // .word label 225 | assert(curSection == Section::DATA); 226 | toBeStored.emplace_back(tokens.at(1), curPos); 227 | return; 228 | } 229 | std::int32_t val = std::stoi(tokens.at(1), nullptr, 0); 230 | *(std::int32_t *)(storage.data() + curPos) = val; 231 | return; 232 | } 233 | 234 | std::cerr << "Ignoring directive: " << line << std::endl; 235 | } 236 | 237 | void handleLabel(std::string label) { 238 | assert(tokenize(label).size() == 1); 239 | label.pop_back(); // remove ':' 240 | if (isIn(labelName2SecPos, label)) { 241 | throw DuplicatedSymbols(label); 242 | } 243 | labelName2SecPos.emplace(label, 244 | LabelPos(curSection, getCurSecStorage().size())); 245 | } 246 | 247 | private: 248 | const std::vector src; 249 | Section curSection = Section::ERROR; 250 | 251 | std::vector text, data, rodata, bss; 252 | // cf. ObjectFile 253 | std::unordered_set globalSymbols; 254 | std::unordered_map labelName2SecPos; 255 | std::vector> toBeStored; 256 | }; 257 | 258 | class AssemblerPass2 { 259 | public: 260 | AssemblerPass2( 261 | const std::vector &src, std::vector &storage, 262 | const std::unordered_map &labelName2Pos) 263 | : src(src), storage(storage), labelName2Pos(labelName2Pos) {} 264 | 265 | auto operator()() { 266 | bool isText = false; 267 | for (auto &line : src) { 268 | auto tokens = tokenize(line); 269 | 270 | if (line == ".text") { 271 | isText = true; 272 | continue; 273 | } 274 | if (line == ".data" || line == ".rodata" || line == ".bss") { 275 | isText = false; 276 | continue; 277 | } 278 | if (tokens.at(0) == ".section") { 279 | auto secName = parseSectionDerivative(line); 280 | isText = secName == ".text"; 281 | continue; 282 | } 283 | if (!isText) 284 | continue; 285 | parseCurrentLine(line); 286 | } 287 | 288 | return std::make_tuple(insts, inst2Pos, containsExternalLabel, 289 | containsRelocationFunc); 290 | } 291 | 292 | private: 293 | void parseCurrentLine(const std::string &line) { 294 | auto tokens = tokenize(line); 295 | if (isDirective(line)) { 296 | if (tokens.at(0) != ".align" && tokens.at(0) != ".p2align") 297 | return; 298 | auto alignment = std::stoul(tokens.at(1)); 299 | curPos = roundUp(curPos, 1u << alignment); 300 | return; 301 | } 302 | if (isLabel(line)) { 303 | assert(tokens.size() == 1); 304 | return; 305 | } 306 | try { 307 | handleInst(line); 308 | } catch (NotSupportedError &e) { 309 | throw NotSupportedError(std::string(e.what()) + " Line: " + line); 310 | } 311 | } 312 | 313 | // If [str] is a number, then return it. 314 | // If [str] is a non-external label, then compute the offset if possible 315 | std::optional getOffset(std::string str) const { 316 | if (std::isdigit(str.front()) && std::isdigit(str.back())) { 317 | return std::stoi(str, nullptr, 0); 318 | } 319 | // is a label 320 | if (std::isdigit(str.front())) { 321 | throw NotSupportedError("local label has not been supported yet"); 322 | } 323 | auto pos = get(labelName2Pos, str); 324 | if (!pos) 325 | return std::nullopt; 326 | return (std::int64_t)pos.value() - (std::int64_t)curPos; 327 | } 328 | 329 | void handleInst(const std::string &line) { 330 | auto tokens = tokenize(line); 331 | std::shared_ptr inst; 332 | try { 333 | inst = parseInst(tokens); 334 | } catch (Exception &e) { 335 | e.setMsg("When parsing \"" + line + "\", get: " + e.what()); 336 | throw ; 337 | } 338 | assert(curPos + 3 < storage.size()); 339 | *(std::uint32_t *)(storage.data() + curPos) = insts.size(); 340 | insts.emplace_back(inst); 341 | inst2Pos.emplace(inst->getId(), curPos); 342 | curPos += 4; 343 | } 344 | 345 | std::shared_ptr 346 | parseInst(const std::vector &tokens) { 347 | assert(!tokens.empty()); 348 | 349 | inst::Instruction::OpType op; 350 | try { 351 | op = name2OpType(tokens[0]); 352 | } catch (std::out_of_range &e) { 353 | throw NotSupportedError("Unknown op: " + tokens[0]); 354 | } 355 | 356 | if (op == inst::Instruction::LUI || op == inst::Instruction::AUIPC) { 357 | auto dest = regName2regNumber(tokens.at(1)); 358 | auto immStr = tokens.at(2); 359 | if (immStr.front() == '%') { 360 | auto inst = std::make_shared(op, dest, 0); 361 | containsRelocationFunc.emplace(inst->getId(), 362 | parseRelocationFunction(immStr)); 363 | return inst; 364 | } 365 | return std::make_shared(op, dest, 366 | parseImm(immStr)); 367 | } 368 | 369 | static std::unordered_set arithRegReg = { 370 | "add", "sub", "sll", "slt", "sltu", "xor", "srl", "sra", "or", "and"}; 371 | if (isIn(arithRegReg, tokens[0])) { 372 | auto dest = regName2regNumber(tokens.at(1)); 373 | auto src1 = regName2regNumber(tokens.at(2)); 374 | auto src2 = regName2regNumber(tokens.at(3)); 375 | return std::make_shared(op, dest, src1, src2); 376 | } 377 | 378 | static std::unordered_set arithRegImmInsts = { 379 | "addi", "slti", "sltiu", "xori", "ori", "andi", "slli", "srli", "srai"}; 380 | if (isIn(arithRegImmInsts, tokens.at(0))) { 381 | auto dest = regName2regNumber(tokens.at(1)); 382 | auto rc = regName2regNumber(tokens.at(2)); 383 | auto immStr = tokens.at(3); 384 | if (immStr.front() == '%') { 385 | auto inst = std::make_shared(op, dest, rc, 0); 386 | containsRelocationFunc.emplace(inst->getId(), 387 | parseRelocationFunction(immStr)); 388 | return inst; 389 | } 390 | return std::make_shared(op, dest, rc, 391 | parseImm(immStr)); 392 | } 393 | 394 | static std::unordered_set memAccessInsts = { 395 | "lb", "lh", "lw", "lbu", "lhu", "sb", "sh", "sw"}; 396 | if (isIn(memAccessInsts, tokens[0])) { 397 | auto reg = regName2regNumber(tokens.at(1)); 398 | auto baseOffsetStr = tokens.at(2); 399 | if (baseOffsetStr.front() == '%') { // e.g. %lo(l)(a5) 400 | auto addrTokens = split(baseOffsetStr, "()"); 401 | assert(addrTokens.front() == "%lo" || 402 | addrTokens.front() == "%pcrel_lo"); 403 | auto relocation = addrTokens.at(0) + "(" + addrTokens.at(1) + ")"; 404 | auto base = regName2regNumber(addrTokens.back()); 405 | auto inst = std::make_shared(op, reg, base, 0); 406 | containsRelocationFunc.emplace(inst->getId(), 407 | parseRelocationFunction(relocation)); 408 | return inst; 409 | } 410 | 411 | auto [base, offset] = parseBaseOffset(tokens.at(2)); 412 | return std::make_shared(op, reg, base, offset); 413 | } 414 | 415 | if (op == inst::Instruction::JAL) { 416 | auto dest = regName2regNumber(tokens.at(1)); 417 | auto offsetOpt = getOffset(tokens.at(2)); 418 | if (offsetOpt) 419 | return std::make_shared(dest, offsetOpt.value() / 2, 420 | tokens.at(2)); 421 | auto inst = std::make_shared(dest, 0, tokens[2]); 422 | containsExternalLabel.emplace(inst->getId(), tokens[2]); 423 | return inst; 424 | } 425 | 426 | if (op == inst::Instruction::JALR) { 427 | auto dest = regName2regNumber(tokens.at(1)); 428 | auto baseOffsetStr = tokens.at(2); 429 | if (baseOffsetStr.front() == '%') { // e.g. %lo(l)(a5) 430 | auto addrTokens = split(baseOffsetStr, "()"); 431 | assert(addrTokens.front() == "%lo" || 432 | addrTokens.front() == "%pcrel_lo"); 433 | auto relocation = addrTokens.at(0) + "(" + addrTokens.at(1) + ")"; 434 | auto base = regName2regNumber(addrTokens.back()); 435 | auto inst = std::make_shared(dest, base, 0); 436 | containsRelocationFunc.emplace(inst->getId(), 437 | parseRelocationFunction(relocation)); 438 | return inst; 439 | } 440 | auto [base, offset] = parseBaseOffset(tokens.at(2)); 441 | return std::make_shared(dest, base, offset); 442 | } 443 | 444 | static std::unordered_set branchInsts = { 445 | "beq", "bne", "blt", "bge", "bltu", "bgeu"}; 446 | if (isIn(branchInsts, tokens[0])) { 447 | auto src1 = regName2regNumber(tokens.at(1)); 448 | auto src2 = regName2regNumber(tokens.at(2)); 449 | auto offsetOpt = getOffset(tokens.at(3)); 450 | if (offsetOpt) 451 | return std::make_shared(op, src1, src2, offsetOpt.value(), 452 | tokens[3]); 453 | // external 454 | auto inst = std::make_shared(op, src1, src2, 0, tokens[3]); 455 | containsExternalLabel.emplace(inst->getId(), tokens.at(3)); 456 | return inst; 457 | } 458 | 459 | static std::unordered_set mArithInsts = { 460 | "mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"}; 461 | if (isIn(mArithInsts, tokens[0])) { 462 | auto dest = regName2regNumber(tokens.at(1)); 463 | auto src1 = regName2regNumber(tokens.at(2)); 464 | auto src2 = regName2regNumber(tokens.at(3)); 465 | return std::make_shared(op, dest, src1, src2); 466 | } 467 | 468 | throw NotSupportedError("Unknown instruction"); 469 | } 470 | 471 | static RelocationFunction parseRelocationFunction(const std::string &str) { 472 | assert(str.front() == '%'); 473 | auto tokens = split(str, "()+"); 474 | assert(tokens.size() == 2 || tokens.size() == 3); 475 | auto func = tokens.front(); 476 | auto symbol = tokens[1]; 477 | if (func == "%hi" || func == "%lo") { 478 | int offset = 0; 479 | if (tokens.size() == 3) 480 | offset = parseImm(tokens.back()); 481 | return RelocationFunction(func == "%hi" ? RelocationFunction::HI 482 | : RelocationFunction::LO, 483 | symbol, offset); 484 | } 485 | if (func != "%pcrel_hi" && func != "%pcrel_lo") { 486 | throw NotSupportedError("Unsupported relocation function: " + func); 487 | } 488 | return RelocationFunction(func == "%pcrel_hi" 489 | ? RelocationFunction::PCREL_HI 490 | : RelocationFunction::PCREL_LO, 491 | symbol); 492 | } 493 | 494 | private: 495 | const std::vector &src; 496 | std::size_t curPos = 0; 497 | 498 | std::vector &storage; 499 | std::vector> insts; 500 | std::unordered_map inst2Pos; 501 | 502 | const std::unordered_map &labelName2Pos; 503 | // When we encounter an instruction which contains an external label, then 504 | // we add the instruction ID and the label name into `containsExternalLabel`. 505 | std::unordered_map containsExternalLabel; 506 | std::unordered_map 507 | containsRelocationFunc; 508 | }; 509 | 510 | } // namespace 511 | } // namespace ravel 512 | 513 | namespace ravel { 514 | 515 | ObjectFile assemble(const std::string &src) { 516 | auto lines = preprocess(src); 517 | auto [storage, labelName2Pos, globalSymbols, toBeStored] = 518 | AssemblerPass1(lines)(); 519 | auto [insts, inst2Pos, containsExternalLabel, containsRelocationFunc] = 520 | AssemblerPass2(lines, storage, labelName2Pos)(); 521 | 522 | std::unordered_map symTable; 523 | for (auto &[label, pos] : labelName2Pos) 524 | symTable.emplace(label, pos); 525 | return {std::move(storage), 526 | std::move(insts), 527 | std::move(inst2Pos), 528 | std::move(symTable), 529 | std::move(globalSymbols), 530 | std::move(containsExternalLabel), 531 | std::move(containsRelocationFunc), 532 | std::move(toBeStored)}; 533 | } 534 | 535 | } // namespace ravel -------------------------------------------------------------------------------- /src/assembler/parser.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/assembler/parser.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ravel/container_utils.h" 10 | #include "ravel/error.h" 11 | 12 | namespace ravel { 13 | 14 | std::string strip(std::string str) { 15 | auto whitespaces = " \t\n\r\f\v"; 16 | str.erase(str.find_last_not_of(whitespaces) + 1); 17 | str.erase(0, str.find_first_not_of(whitespaces)); 18 | return str; 19 | } 20 | 21 | std::vector split(const std::string &s, 22 | const std::string &delimiters) { 23 | std::vector words; 24 | 25 | std::size_t next = -1; 26 | do { 27 | auto current = next + 1; 28 | next = s.find_first_of(delimiters, current); 29 | if (next > current) // no empty word 30 | words.emplace_back(s.substr(current, next - current)); 31 | } while (next != std::string::npos); 32 | 33 | // myList.erase( 34 | // std::remove_if(myList.begin(), myList.end(), IsMarkedToDelete), 35 | // myList.end()); 36 | words.erase(std::remove(words.begin(), words.end(), ""), words.end()); 37 | 38 | return words; 39 | } 40 | 41 | std::vector tokenize(const std::string &line) { 42 | auto tokens = split(line, " ,\t"); 43 | if (tokens.at(0) == ".string") { 44 | tokens = {".string", strip(line.substr(7))}; 45 | } 46 | return tokens; 47 | } 48 | 49 | bool isDirective(const std::string &str) { 50 | auto words = split(str); 51 | return words.at(0).at(0) == '.' && words.at(0).back() != ':'; 52 | } 53 | 54 | bool isLabel(const std::string &str) { return str.back() == ':'; } 55 | 56 | std::optional getSectionName(const std::string &line) { 57 | if (line == ".text" || line == ".data" || line == ".rodata" || line == ".bss") 58 | return line; 59 | auto words = split(line, " \t"); 60 | if (words.at(0) != ".section") 61 | return std::nullopt; 62 | return words.at(1); 63 | } 64 | 65 | std::string opType2Name(inst::Instruction::OpType op) { 66 | using namespace std::string_literals; 67 | static std::unordered_map mp{ 68 | {inst::Instruction::LUI, "LUI"s}, 69 | {inst::Instruction::AUIPC, "AUIPC"s}, 70 | {inst::Instruction::JAL, "JAL"s}, 71 | {inst::Instruction::JALR, "JALR"s}, 72 | {inst::Instruction::BEQ, "BEQ"s}, 73 | {inst::Instruction::BNE, "BNE"s}, 74 | {inst::Instruction::BLT, "BLT"s}, 75 | {inst::Instruction::BGE, "BGE"s}, 76 | {inst::Instruction::BLTU, "BLTU"s}, 77 | {inst::Instruction::BGEU, "BGEU"s}, 78 | {inst::Instruction::LB, "LB"s}, 79 | {inst::Instruction::LH, "LH"s}, 80 | {inst::Instruction::LW, "LW"s}, 81 | {inst::Instruction::LBU, "LBU"s}, 82 | {inst::Instruction::LHU, "LHU"s}, 83 | {inst::Instruction::SB, "SB"s}, 84 | {inst::Instruction::SH, "SH"s}, 85 | {inst::Instruction::SW, "SW"s}, 86 | {inst::Instruction::ADDI, "ADDI"s}, 87 | {inst::Instruction::SLTI, "SLTI"s}, 88 | {inst::Instruction::SLTIU, "SLTIU"s}, 89 | {inst::Instruction::XORI, "XORI"s}, 90 | {inst::Instruction::ORI, "ORI"s}, 91 | {inst::Instruction::ANDI, "ANDI"s}, 92 | {inst::Instruction::SLLI, "SLLI"s}, 93 | {inst::Instruction::SRLI, "SRLI"s}, 94 | {inst::Instruction::SRAI, "SRAI"s}, 95 | {inst::Instruction::ADD, "ADD"s}, 96 | {inst::Instruction::SUB, "SUB"s}, 97 | {inst::Instruction::SLL, "SLL"s}, 98 | {inst::Instruction::SLT, "SLT"s}, 99 | {inst::Instruction::SLTU, "SLTU"s}, 100 | {inst::Instruction::XOR, "XOR"s}, 101 | {inst::Instruction::SRL, "SRL"s}, 102 | {inst::Instruction::SRA, "SRA"s}, 103 | {inst::Instruction::OR, "OR"s}, 104 | {inst::Instruction::AND, "AND"s}, 105 | {inst::Instruction::MUL, "MUL"s}, 106 | {inst::Instruction::MULH, "MULH"s}, 107 | {inst::Instruction::MULHSU, "MULHSU"s}, 108 | {inst::Instruction::MULHU, "MULHU"s}, 109 | {inst::Instruction::DIV, "DIV"s}, 110 | {inst::Instruction::DIVU, "DIVU"s}, 111 | {inst::Instruction::REM, "REM"s}, 112 | {inst::Instruction::REMU, "REMU"s}, 113 | }; 114 | auto name = mp.at(op); 115 | for (auto &c : name) 116 | c = tolower(c); 117 | return name; 118 | } 119 | 120 | inst::Instruction::OpType name2OpType(std::string name) { 121 | using namespace std::string_literals; 122 | static std::unordered_map mp{ 123 | {"LUI"s, inst::Instruction::LUI}, 124 | {"AUIPC"s, inst::Instruction::AUIPC}, 125 | {"JAL"s, inst::Instruction::JAL}, 126 | {"JALR"s, inst::Instruction::JALR}, 127 | {"BEQ"s, inst::Instruction::BEQ}, 128 | {"BNE"s, inst::Instruction::BNE}, 129 | {"BLT"s, inst::Instruction::BLT}, 130 | {"BGE"s, inst::Instruction::BGE}, 131 | {"BLTU"s, inst::Instruction::BLTU}, 132 | {"BGEU"s, inst::Instruction::BGEU}, 133 | {"LB"s, inst::Instruction::LB}, 134 | {"LH"s, inst::Instruction::LH}, 135 | {"LW"s, inst::Instruction::LW}, 136 | {"LBU"s, inst::Instruction::LBU}, 137 | {"LHU"s, inst::Instruction::LHU}, 138 | {"SB"s, inst::Instruction::SB}, 139 | {"SH"s, inst::Instruction::SH}, 140 | {"SW"s, inst::Instruction::SW}, 141 | {"ADDI"s, inst::Instruction::ADDI}, 142 | {"SLTI"s, inst::Instruction::SLTI}, 143 | {"SLTIU"s, inst::Instruction::SLTIU}, 144 | {"XORI"s, inst::Instruction::XORI}, 145 | {"ORI"s, inst::Instruction::ORI}, 146 | {"ANDI"s, inst::Instruction::ANDI}, 147 | {"SLLI"s, inst::Instruction::SLLI}, 148 | {"SRLI"s, inst::Instruction::SRLI}, 149 | {"SRAI"s, inst::Instruction::SRAI}, 150 | {"ADD"s, inst::Instruction::ADD}, 151 | {"SUB"s, inst::Instruction::SUB}, 152 | {"SLL"s, inst::Instruction::SLL}, 153 | {"SLT"s, inst::Instruction::SLT}, 154 | {"SLTU"s, inst::Instruction::SLTU}, 155 | {"XOR"s, inst::Instruction::XOR}, 156 | {"SRL"s, inst::Instruction::SRL}, 157 | {"SRA"s, inst::Instruction::SRA}, 158 | {"OR"s, inst::Instruction::OR}, 159 | {"AND"s, inst::Instruction::AND}, 160 | {"MUL"s, inst::Instruction::MUL}, 161 | {"MULH"s, inst::Instruction::MULH}, 162 | {"MULHSU"s, inst::Instruction::MULHSU}, 163 | {"MULHU"s, inst::Instruction::MULHU}, 164 | {"DIV"s, inst::Instruction::DIV}, 165 | {"DIVU"s, inst::Instruction::DIVU}, 166 | {"REM"s, inst::Instruction::REM}, 167 | {"REMU"s, inst::Instruction::REMU}, 168 | }; 169 | 170 | for (auto &c : name) { 171 | c = toupper((unsigned char)c); 172 | } 173 | 174 | return mp.at(name); 175 | } 176 | 177 | std::size_t regName2regNumber(const std::string &name) { 178 | if (name.at(0) == 'x') { 179 | if (name.size() == 1 || !std::isdigit(name.at(1))) { 180 | throw Exception("Unknown register: " + name); 181 | } 182 | return (std::size_t)std::stoi(name.substr(1)); 183 | } 184 | 185 | static std::vector names = { 186 | "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", 187 | "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", 188 | "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; 189 | assert(names.size() == 32); 190 | for (std::size_t i = 0; i < names.size(); ++i) { 191 | if (names[i] == name) 192 | return i; 193 | } 194 | 195 | if (name != "fp") 196 | throw Exception("Unknown register: " + name); 197 | return 8; 198 | } 199 | 200 | std::pair parseBaseOffset(const std::string &str) { 201 | std::stringstream ss(str); 202 | int offset; 203 | ss >> offset; 204 | auto ch = (char)ss.get(); 205 | assert(ch == '('); 206 | std::string regName; 207 | ss >> regName; 208 | assert(regName.back() == ')'); 209 | regName.pop_back(); 210 | auto reg = regName2regNumber(regName); 211 | return {reg, offset}; 212 | } 213 | 214 | std::string toString(const std::shared_ptr &inst) { 215 | auto getName = [](std::size_t num) { return regNumber2regName(num); }; 216 | auto opName = opType2Name(inst->getOp()); 217 | if (auto p = std::dynamic_pointer_cast(inst)) { 218 | return opName + " " + getName(p->getDest()) + ", " + 219 | std::to_string(p->getImm()); 220 | } 221 | if (auto p = std::dynamic_pointer_cast(inst)) { 222 | return opName + " " + getName(p->getDest()) + ", " + getName(p->getSrc1()) + 223 | ", " + getName(p->getSrc2()); 224 | } 225 | if (auto p = std::dynamic_pointer_cast(inst)) { 226 | return opName + " " + getName(p->getDest()) + ", " + getName(p->getSrc()) + 227 | ", " + std::to_string(p->getImm()); 228 | } 229 | if (auto p = std::dynamic_pointer_cast(inst)) { 230 | return opName + " " + getName(p->getReg()) + ", " + 231 | std::to_string(p->getOffset()) + "(" + getName(p->getBase()) + ")"; 232 | } 233 | if (auto p = std::dynamic_pointer_cast(inst)) { 234 | return opName + " " + getName(p->getDest()) + ", " + 235 | std::to_string(p->getOffset()); 236 | } 237 | if (auto p = std::dynamic_pointer_cast(inst)) { 238 | return opName + " " + getName(p->getDest()) + ", " + 239 | std::to_string(p->getOffset()) + "(" + getName(p->getBase()) + ")"; 240 | } 241 | if (auto p = std::dynamic_pointer_cast(inst)) { 242 | return opName + " " + getName(p->getSrc1()) + ", " + getName(p->getSrc2()) + 243 | ", " + std::to_string(p->getOffset()); 244 | } 245 | if (auto p = std::dynamic_pointer_cast(inst)) { 246 | return opName + " " + getName(p->getDest()) + ", " + getName(p->getSrc1()) + 247 | ", " + getName(p->getSrc2()); 248 | } 249 | 250 | assert(false); 251 | } 252 | 253 | std::string regNumber2regName(const std::size_t &num) { 254 | static std::vector names = { 255 | "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", 256 | "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", 257 | "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; 258 | return names.at(num); 259 | } 260 | 261 | std::string parseSectionDerivative(const std::string &line) { 262 | auto tokens = split(line, " \t,."); 263 | assert(tokens.at(0) == "section"); 264 | auto name = tokens.at(1); 265 | if (name.front() == 's') { 266 | assert(name == "sdata" || name == "srodata" || name == "sbss"); 267 | name = name.substr(1); 268 | } 269 | return "." + name; 270 | } 271 | 272 | std::uint32_t parseImm(const std::string &str) { 273 | return std::stoul(str, nullptr, 0); 274 | } 275 | 276 | std::string handleEscapeCharacters(const std::string &str) { 277 | static std::unordered_map escape = { 278 | {'\'', '\''}, {'\"', '\"'}, {'\\', '\\'}, {'n', '\n'}, {'r', '\r'}, 279 | {'t', '\t'}, {'b', '\b'}, {'f', '\f'}, {'v', '\v'}, 280 | }; 281 | 282 | std::string res; 283 | for (std::size_t i = 0; i < str.length(); ++i) { 284 | if (str[i] != '\\') { 285 | res.push_back(str[i]); 286 | continue; 287 | } 288 | ++i; 289 | assert(i < str.length()); 290 | 291 | if (auto chOpt = get(escape, str[i])) { 292 | res.push_back(chOpt.value()); 293 | continue; 294 | } 295 | if (std::isdigit(str[i])) { 296 | int n = 0; 297 | for (int k = 0; k < 3 && i < str.length(); ++k, ++i) { 298 | char ch = str[i]; 299 | if (!isdigit(ch) || ch - '0' >= 8) 300 | break; 301 | n *= 8; 302 | n += ch - '0'; 303 | } 304 | --i; 305 | assert(0 <= n && n <= 255); 306 | res.push_back((char)n); 307 | continue; 308 | } 309 | assert(false && "Unsupported escape characters"); 310 | } 311 | return res; 312 | } 313 | 314 | } // namespace ravel 315 | -------------------------------------------------------------------------------- /src/assembler/preprocessor.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/assembler/preprocessor.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ravel/assembler/parser.h" 11 | #include "ravel/container_utils.h" 12 | #include "ravel/error.h" 13 | 14 | namespace ravel { 15 | namespace { 16 | 17 | std::vector splitIntoLines(const std::string &src) { 18 | std::vector lines; 19 | 20 | std::stringstream ss(src); 21 | for (std::string line; std::getline(ss, line, '\n');) 22 | lines.push_back(line); 23 | 24 | return lines; 25 | } 26 | 27 | std::string removeComments(const std::string &line) { 28 | // be careful with the case: .string "#" 29 | // remove comments 30 | std::size_t pos = std::string::npos; 31 | bool inString = false; 32 | for (std::size_t i = 0; i < line.size(); ++i) { 33 | auto ch = line[i]; 34 | if (!inString && ch == '#') { 35 | pos = i; 36 | break; 37 | } 38 | if (ch == '"') { 39 | inString = !inString; 40 | continue; 41 | } 42 | if (inString && ch == '\\') { 43 | ++i; 44 | continue; 45 | } 46 | } 47 | if (pos == std::string::npos) 48 | return line; 49 | return line.substr(0, pos); 50 | } 51 | 52 | std::vector extractLabels(std::vector lines) { 53 | auto bak = lines; 54 | lines.clear(); 55 | std::regex re("[.a-zA-Z0-9_]*:", std::regex_constants::ECMAScript); 56 | for (const auto &line : bak) { 57 | std::smatch matchRes; 58 | std::regex_search(line, matchRes, re); 59 | if (matchRes.empty()) { 60 | lines.emplace_back(line); 61 | continue; 62 | } 63 | assert(matchRes.size() == 1); // at most one label per line 64 | if (matchRes[0].first != line.begin()) { 65 | lines.emplace_back(line); 66 | continue; 67 | } 68 | lines.emplace_back(matchRes[0].first, matchRes[0].second); 69 | assert(matchRes[0].second >= matchRes[0].first); 70 | if (std::size_t(matchRes[0].second - matchRes[0].first) == line.length()) 71 | continue; 72 | lines.emplace_back(matchRes[0].second, line.cend()); 73 | lines.back() = strip(lines.back()); 74 | if (lines.back().empty()) 75 | lines.pop_back(); 76 | } 77 | return lines; 78 | } 79 | 80 | std::string translatePseudoInstruction(const std::string &line) { 81 | using namespace std::string_literals; 82 | auto tokens = tokenize(line); 83 | auto opname = tokens.at(0); 84 | if (opname == "li" || opname == "call" || opname == "tail") { 85 | assert(false); 86 | } 87 | if (opname == "nop") { 88 | return "addi x0, x0, 0"s; 89 | } 90 | if (opname == "mv") { 91 | return "addi "s + tokens.at(1) + "," + tokens.at(2) + ",0"; 92 | } 93 | if (opname == "not") { 94 | return "xori "s + tokens.at(1) + ", " + tokens.at(2) + ", -1"; 95 | } 96 | if (opname == "neg") { 97 | return "sub "s + tokens.at(1) + ", x0, " + tokens.at(2); 98 | } 99 | if (opname == "seqz") { 100 | return "sltiu " + tokens.at(1) + ", " + tokens.at(2) + ", 1"; 101 | } 102 | if (opname == "snez") { 103 | return "sltu " + tokens.at(1) + ", x0, " + tokens.at(2); 104 | } 105 | if (opname == "sltz") { 106 | return "slt " + tokens.at(1) + ", " + tokens.at(2) + ", x0"; 107 | } 108 | if (opname == "sgtz") { 109 | return "slt " + tokens.at(1) + ", x0, " + tokens.at(2); 110 | } 111 | 112 | if (opname == "sgt") { 113 | return "slt " + tokens.at(1) + ", " + tokens.at(3) + ", " + tokens.at(2); 114 | } 115 | 116 | static const std::unordered_map branchPair = { 117 | {"bgt", "blt"}, {"ble", "bge"}, {"bgtu", "bltu"}, {"bleu", "bgeu"}}; 118 | if (auto op = get(branchPair, opname)) { 119 | return op.value() + " " + tokens.at(2) + "," + tokens.at(1) + "," + 120 | tokens.at(3); 121 | } 122 | if (opname.front() == 'b' && opname.back() == 'z') { 123 | static const std::unordered_set BranchZero = { 124 | "beqz", "bnez", "bgtz", "bltz", "blez", "bgez", 125 | }; 126 | assert(isIn(BranchZero, opname)); 127 | opname.pop_back(); 128 | bool reverse = isIn(branchPair, opname); 129 | if (reverse) 130 | opname = branchPair.at(opname); 131 | auto rs1 = tokens.at(1); 132 | auto rs2 = "x0"s; 133 | if (reverse) 134 | std::swap(rs1, rs2); 135 | return opname + " " + rs1 + ", " + rs2 + ", " + tokens.at(2); 136 | } 137 | 138 | if (opname == "j") { 139 | return "jal x0, "s + tokens.at(1); 140 | } 141 | if (opname == "jal" && tokens.size() == 2) { 142 | return "jal x1, "s + tokens[1]; 143 | } 144 | if (opname == "jr") { 145 | return "jalr x0, 0(" + tokens.at(1) + ")"; 146 | } 147 | if (opname == "jalr" && tokens.size() == 2) { 148 | return "jalr x1, 0(" + tokens.at(1) + ")"; 149 | } 150 | if (opname == "ret") { 151 | return "jalr x0, 0(x1)"s; 152 | } 153 | 154 | return line; 155 | } 156 | 157 | std::vector 158 | translatePseudoInstructions(std::vector lines) { 159 | std::mt19937_64 eng(std::random_device{}()); 160 | std::uniform_int_distribution randomChar('a', 'z'); 161 | std::string prefix; 162 | for (int i = 0; i < 8; ++i) 163 | prefix.push_back(randomChar(eng)); 164 | prefix += "_pseudo_inst_label_"; 165 | std::size_t newLabelCnt = 0; 166 | auto newLabel = [&prefix, &newLabelCnt] { 167 | return prefix + std::to_string(newLabelCnt++); 168 | }; 169 | 170 | auto bak = lines; 171 | lines.clear(); 172 | for (auto &lineBak : bak) { 173 | if (isLabel(lineBak) || isDirective(lineBak)) { 174 | lines.emplace_back(lineBak); 175 | continue; 176 | } 177 | auto tokens = tokenize(lineBak); 178 | auto op = tokens.front(); 179 | 180 | // la, l{b|h|w}, s{b|h|w|d} 181 | static const std::unordered_set Mem = {"lb", "lh", "lw", 182 | "sb", "sh", "sw"}; 183 | // Note: Non-pseudo loads are for the form: lw rd, offset(reg) 184 | if (op == "la" || (isIn(Mem, op) && tokens.at(2).back() != ')')) { 185 | auto label = newLabel(); 186 | auto rd = tokens.at(1); 187 | auto symbol = tokens.at(2); 188 | lines.emplace_back(label + ":"); 189 | if (op == "la") { 190 | lines.emplace_back("auipc " + rd + ", %pcrel_hi(" + symbol + ")"); 191 | lines.emplace_back("addi " + rd + ", " + rd + ", %pcrel_lo(" + label + 192 | ")"); 193 | continue; 194 | } 195 | if (op.front() == 'l') { 196 | lines.emplace_back("auipc " + rd + ", %pcrel_hi(" + symbol + ")"); 197 | lines.emplace_back(op + " " + rd + ", %pcrel_lo(" + label + ")(" + rd + 198 | ")"); 199 | continue; 200 | } 201 | if (op.front() == 's') { 202 | auto rt = tokens.at(3); 203 | lines.emplace_back("auipc " + rt + ", %pcrel_hi(" + symbol + ")"); 204 | lines.emplace_back(op + " " + rd + ", %pcrel_lo(" + label + ")(" + rt + 205 | ")"); 206 | continue; 207 | } 208 | assert(false); 209 | } 210 | 211 | // li 212 | if (op == "li") { 213 | auto rd = tokens.at(1); 214 | auto imm = std::stoi(tokens.at(2), nullptr, 0); 215 | auto uImm = std::uint32_t(imm) >> 12u; 216 | auto lImm = std::uint32_t(imm) & 0xfffu; 217 | if (uImm != 0) { // large imm 218 | lines.emplace_back("lui " + rd + ", " + std::to_string(uImm)); 219 | lines.emplace_back("ori " + rd + ", " + rd + ", " + 220 | std::to_string(lImm)); 221 | } else { 222 | lines.emplace_back("addi " + rd + ", zero, " + std::to_string(lImm)); 223 | } 224 | continue; 225 | } 226 | 227 | // call, tail 228 | if (op == "call" || op == "tail") { 229 | using namespace std::string_literals; 230 | auto funcName = tokens.at(1); 231 | auto label = newLabel(); 232 | lines.emplace_back(label + ":"); 233 | lines.emplace_back("auipc x6, %pcrel_hi(" + funcName + ")"); 234 | lines.emplace_back("jalr "s + (op == "call" ? "x1"s : "x0"s) + 235 | ", %pcrel_lo(" + label + ")(x6)"); 236 | continue; 237 | } 238 | 239 | lines.emplace_back(translatePseudoInstruction(lineBak)); 240 | } 241 | 242 | return lines; 243 | } 244 | 245 | } // namespace 246 | 247 | std::vector preprocess(const std::string &src) { 248 | auto lines = splitIntoLines(src); 249 | for (auto &line : lines) { 250 | line = removeComments(line); 251 | line = strip(line); 252 | } 253 | lines = extractLabels(std::move(lines)); 254 | // remove empty lines 255 | lines.erase(std::remove_if(lines.begin(), lines.end(), 256 | [](auto &l) { return l.empty(); }), 257 | lines.end()); 258 | return translatePseudoInstructions(std::move(lines)); 259 | } 260 | 261 | } // namespace ravel -------------------------------------------------------------------------------- /src/interpreter/cache.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/interpreter/cache.h" 2 | 3 | #include "ravel/error.h" 4 | 5 | namespace ravel { 6 | 7 | std::uint32_t Cache::fetchWord(std::size_t addr) { 8 | std::size_t memorySize = storageEnd - storageBegin; 9 | if (addr + 4 > memorySize) { 10 | throw InvalidAddress(addr); 11 | } 12 | if (disabled) { 13 | miss++; 14 | return *(std::uint32_t *)(storageBegin + addr); 15 | } 16 | for (auto &line : lines) { 17 | if (!line.valid) 18 | continue; 19 | if ((Mask & addr) != (Mask & line.addr)) 20 | continue; 21 | // hit 22 | line.lastUsed = cycles; 23 | hit++; 24 | return *(std::uint32_t *)(storageBegin + addr); 25 | } 26 | // miss 27 | auto &line = getEmptyLine(); 28 | line.lastUsed = cycles; 29 | line.valid = true; 30 | line.addr = addr & Mask; 31 | miss++; 32 | return *(std::uint32_t *)(storageBegin + addr); 33 | } 34 | 35 | Cache::Line &Cache::getEmptyLine() { 36 | std::size_t resIdx = lines.size(); 37 | for (std::size_t i = 0; i < lines.size(); ++i) { 38 | if (!lines[i].valid) 39 | return lines[i]; 40 | if (cycles >= lines[i].lastUsed + 32) 41 | resIdx = i; 42 | } 43 | if (resIdx != lines.size()) 44 | return lines[resIdx]; 45 | auto &res = lines[0]; 46 | victimIdx += 7; 47 | victimIdx %= 16; 48 | res.valid = false; 49 | return res; 50 | } 51 | 52 | } // namespace ravel 53 | -------------------------------------------------------------------------------- /src/interpreter/interpreter.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/interpreter/interpreter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ravel/assembler/parser.h" 12 | #include "ravel/error.h" 13 | #include "ravel/interpreter/libc_sim.h" 14 | 15 | namespace ravel { 16 | namespace { 17 | 18 | template 19 | const T &spc(const std::shared_ptr &inst) { 20 | return static_cast(*inst); 21 | } 22 | 23 | } // namespace 24 | 25 | void Interpreter::simulate(const std::shared_ptr &inst) { 26 | // Do NOT use dynamic cast. It is too time-consuming 27 | using Op = inst::Instruction::OpType; 28 | auto op = inst->getOp(); 29 | 30 | // has been moved to Interpreter::interpret() 31 | // struct Raii { 32 | // Raii(std::function func) : func(std::move(func)) {} 33 | // ~Raii() { func(); } 34 | // std::function func; 35 | // }; 36 | // auto resetZero = Raii([this] { regs[0] = 0; }); 37 | // auto pcAdd4 = Raii([this] { pc += 4; }); 38 | 39 | // ArithRegReg & ArithRegImm 40 | if (bool isArithRegReg = 41 | inst::Instruction::ADD <= op && op <= inst::Instruction::AND, 42 | isArithRegImm = 43 | inst::Instruction::ADDI <= op && op <= inst::Instruction::SRAI; 44 | isArithRegReg || isArithRegImm) { 45 | ++instCnt.simple; 46 | std::uint32_t rs1, rs2; 47 | std::size_t destNumber; 48 | if (isArithRegReg) { 49 | auto &p = spc(inst); 50 | destNumber = p.getDest(); 51 | rs1 = regs[p.getSrc1()]; 52 | rs2 = regs[p.getSrc2()]; 53 | } else { 54 | auto &p = spc(inst); 55 | destNumber = p.getDest(); 56 | rs1 = regs[p.getSrc()]; 57 | rs2 = p.getImm(); 58 | } 59 | auto &dest = regs[destNumber]; 60 | 61 | switch (op) { 62 | case Op::ADD: 63 | case Op::ADDI: 64 | dest = rs1 + rs2; 65 | return; 66 | case Op::SUB: 67 | dest = (std::int32_t)rs1 - (std::int32_t)rs2; 68 | return; 69 | case Op::SLL: 70 | case Op::SLLI: 71 | dest = rs1 << rs2; 72 | return; 73 | case Op::SLT: 74 | case Op::SLTI: 75 | dest = (std::int32_t)rs1 < (std::int32_t)rs2; 76 | return; 77 | case Op::SLTU: 78 | case Op::SLTIU: 79 | dest = rs1 < rs2; 80 | return; 81 | case Op::XOR: 82 | case Op::XORI: 83 | dest = rs1 ^ rs2; 84 | return; 85 | case Op::SRL: 86 | case Op::SRLI: 87 | dest = rs1 >> rs2; 88 | return; 89 | case Op::SRA: 90 | case Op::SRAI: 91 | dest = (std::int32_t)rs1 >> rs2; 92 | return; 93 | case Op::OR: 94 | case Op::ORI: 95 | dest = rs1 | rs2; 96 | return; 97 | case Op::AND: 98 | case Op::ANDI: 99 | dest = rs1 & rs2; 100 | return; 101 | default: 102 | assert(false); 103 | } 104 | } 105 | 106 | // MemAccess 107 | if (Op::LB <= op && op <= Op::SW) { 108 | auto &p = spc(inst); 109 | std::size_t vAddr = regs[p.getBase()] + p.getOffset(); 110 | if (keepDebugInfo && (isIn(invalidAddress, vAddr) || vAddr == 0)) { 111 | // Accessing 0x0 is always invalid since an instruction is stored there. 112 | // Perform this check since many students use 0x0 as the actual value of 113 | // null. 114 | throw InvalidAddress(vAddr); 115 | } 116 | 117 | std::byte *addr = cache.getMemory().first + vAddr; 118 | assert(addr < cache.getMemory().second); 119 | // To avoid memory access error when accessing with byte or half-word, we 120 | // need to change the address to a proper one. 121 | // For example, we need to access a memory at one byte below the stack 122 | // pointer, we cannot fetch a word from the address, since will cause a 123 | // memory access error. Instead, we need to fetch a word from the address 124 | // 4 bytes below the stack pointer, and then extract the byte we need. 125 | std::size_t fetchFrom = vAddr; 126 | switch (op) { 127 | case Op::SB: 128 | case Op::LB: 129 | case Op::LBU: 130 | fetchFrom &= ~0b11; // align to 4 bytes 131 | break; 132 | case Op::SH: 133 | case Op::LH: 134 | case Op::LHU: 135 | if (vAddr % 4 == 3) { 136 | fetchFrom -= 2; 137 | } else { 138 | fetchFrom &= ~0b11; 139 | } 140 | break; 141 | } 142 | cache.fetchWord(fetchFrom); 143 | std::tie(instCnt.cache, instCnt.mem) = cache.getHitMiss(); 144 | switch (op) { 145 | case Op::SB: 146 | *(std::uint8_t *)addr = regs[p.getReg()]; 147 | return; 148 | case Op::SH: 149 | *(std::uint16_t *)addr = regs[p.getReg()]; 150 | return; 151 | case Op::SW: 152 | *(std::uint32_t *)addr = regs[p.getReg()]; 153 | return; 154 | case Op::LB: 155 | regs[p.getReg()] = *(std::int8_t *)addr; 156 | return; 157 | case Op::LH: 158 | regs[p.getReg()] = *(std::int16_t *)addr; 159 | return; 160 | case Op::LW: 161 | regs[p.getReg()] = *(std::int32_t *)addr; 162 | return; 163 | case Op::LBU: 164 | (std::uint32_t &)regs[p.getReg()] = *(std::uint8_t *)addr; 165 | return; 166 | case Op::LHU: 167 | (std::uint32_t &)regs[p.getReg()] = *(std::uint16_t *)addr; 168 | return; 169 | default: 170 | assert(false); 171 | } 172 | } 173 | 174 | if (Op::BEQ <= op && op <= Op::BGEU) { 175 | ++instCnt.br; 176 | auto &p = spc(inst); 177 | std::int32_t rs1 = regs[p.getSrc1()]; 178 | std::int32_t rs2 = regs[p.getSrc2()]; 179 | bool shouldJump; 180 | switch (inst->getOp()) { 181 | case Op::BEQ: 182 | shouldJump = rs1 == rs2; 183 | break; 184 | case Op::BNE: 185 | shouldJump = rs1 != rs2; 186 | break; 187 | case Op::BLT: 188 | shouldJump = rs1 < rs2; 189 | break; 190 | case Op::BGE: 191 | shouldJump = rs1 >= rs2; 192 | break; 193 | case Op::BLTU: 194 | shouldJump = (std::uint32_t)rs1 < (std::uint32_t)rs2; 195 | break; 196 | case Op::BGEU: 197 | shouldJump = (std::uint32_t)rs1 >= (std::uint32_t)rs2; 198 | break; 199 | default: 200 | assert(false); 201 | } 202 | if (shouldJump) 203 | pc += p.getOffset() - 4; 204 | return; 205 | } 206 | 207 | if (Op::MUL <= op && op <= Op::REMU) { 208 | if (Op::MUL <= op && op <= Op::MULHU) 209 | ++instCnt.mul; 210 | else 211 | ++instCnt.div; 212 | 213 | auto &p = spc(inst); 214 | auto destNumber = p.getDest(); 215 | auto &dest = regs[destNumber]; 216 | std::uint32_t rs1 = regs[p.getSrc1()]; 217 | std::uint32_t rs2 = regs[p.getSrc2()]; 218 | switch (op) { 219 | case Op::MUL: 220 | dest = (std::int32_t)rs1 * (std::int32_t)rs2; 221 | return; 222 | case Op::MULH: { 223 | // Note: uint32 -> int32 -> int64 != uint32 -> int64 224 | std::int32_t r1 = rs1, r2 = rs2; 225 | std::int64_t res = (std::int64_t)r1 * (std::int64_t)r2; 226 | dest = (std::uint32_t)(res >> 32u); 227 | return; 228 | } 229 | case Op::MULHSU: { 230 | std::int32_t r1 = rs1; 231 | std::int64_t res = (std::int64_t)r1 * (std::uint64_t)rs2; 232 | dest = (std::uint32_t)(res >> 32u); 233 | return; 234 | } 235 | case Op::MULHU: 236 | dest = (std::uint32_t)(((std::uint64_t)rs1 * (std::uint64_t)rs2) >> 32u); 237 | return; 238 | case Op::DIV: 239 | dest = (std::int32_t)rs1 / (std::int32_t)rs2; 240 | return; 241 | case Op::DIVU: 242 | dest = (std::uint32_t)rs1 / (std::uint32_t)rs2; 243 | return; 244 | case Op::REM: 245 | dest = (std::int32_t)rs1 % (std::int32_t)rs2; 246 | return; 247 | case Op::REMU: 248 | dest = (std::uint32_t)rs1 % (std::uint32_t)rs2; 249 | return; 250 | default: 251 | assert(false); 252 | } 253 | return; 254 | } 255 | 256 | switch (op) { 257 | case inst::Instruction::LUI: { 258 | ++instCnt.simple; 259 | auto &p = spc(inst); 260 | regs[p.getDest()] = p.getImm() << 12u; 261 | return; 262 | } 263 | 264 | case inst::ImmConstruction::AUIPC: { 265 | ++instCnt.simple; 266 | auto &p = spc(inst); 267 | std::int32_t offset = (std::uint32_t)p.getImm() << 12u; 268 | regs[p.getDest()] = pc + offset; 269 | return; 270 | } 271 | 272 | case Op::JAL: { 273 | ++instCnt.simple; 274 | auto &p = spc(inst); 275 | auto offset = p.getOffset() * 2; 276 | regs[p.getDest()] = pc + 4; 277 | pc += offset - 4; 278 | return; 279 | } 280 | 281 | case Op::JALR: { 282 | ++instCnt.simple; 283 | auto &p = spc(inst); 284 | regs[p.getDest()] = pc + 4; 285 | auto addr = regs[p.getBase()] + p.getOffset(); 286 | addr &= ~1u; 287 | pc = addr - 4; 288 | return; 289 | } 290 | 291 | default: 292 | assert(false); 293 | } 294 | 295 | assert(false); 296 | } 297 | 298 | std::uint32_t Interpreter::getReturnCode() const { 299 | return 0xffffu & regs.at(regName2regNumber("a0")); 300 | } 301 | 302 | void Interpreter::load() { 303 | std::copy(interpretable.getStorage().begin(), 304 | interpretable.getStorage().end(), cache.getMemory().first); 305 | heapPtr = interpretable.getStorage().size(); 306 | assert(heapPtr < cache.storageSize() / 2); 307 | pc = Interpretable::Start; 308 | regs.at(regName2regNumber("sp")) = cache.storageSize(); 309 | } 310 | 311 | namespace { 312 | struct DebugStackFrame { 313 | void addInstruction(std::shared_ptr inst) { 314 | lastFewInstructions.emplace(std::move(inst)); 315 | if (lastFewInstructions.size() > MaxSize) 316 | lastFewInstructions.pop(); 317 | } 318 | 319 | static constexpr std::size_t MaxSize = 8; 320 | std::queue> lastFewInstructions; 321 | }; 322 | } // namespace 323 | 324 | namespace { 325 | 326 | void printInstWithComment(const std::shared_ptr &inst) { 327 | std::cerr << toString(inst); 328 | if (!inst->getComment().empty()) 329 | std::cerr << " # " << inst->getComment(); 330 | std::cerr << std::endl; 331 | } 332 | 333 | std::optional 334 | getModifiedReg(const std::shared_ptr &inst) { 335 | auto op = inst->getOp(); 336 | if (inst::Instruction::LUI <= op && op <= inst::Instruction::AUIPC) { 337 | return spc(inst).getDest(); 338 | } 339 | if (op == inst::Instruction::JAL) 340 | return spc(inst).getDest(); 341 | if (op == inst::Instruction::JALR) 342 | return spc(inst).getDest(); 343 | if (inst::Instruction::LB <= op && op <= inst::Instruction::LHU) 344 | return spc(inst).getReg(); 345 | if (inst::Instruction::ADDI <= op && op <= inst::Instruction::SRAI) 346 | return spc(inst).getDest(); 347 | if (inst::Instruction::ADD <= op && op <= inst::Instruction::AND) 348 | return spc(inst).getDest(); 349 | if (inst::Instruction::MUL <= op && op <= inst::Instruction::REMU) 350 | return spc(inst).getDest(); 351 | return std::nullopt; 352 | } 353 | 354 | } // namespace 355 | 356 | void Interpreter::interpret() { 357 | load(); 358 | std::size_t numInsts = 0; 359 | 360 | std::stack debugStack; 361 | debugStack.emplace(); 362 | 363 | try { 364 | while (pc != Interpretable::End) { 365 | if (!(0 <= pc && (std::uint32_t)pc < cache.storageSize())) { 366 | throw InvalidAddress(pc); 367 | } 368 | ++numInsts; 369 | if (numInsts > timeout) { 370 | throw Timeout(""); 371 | } 372 | cache.tick(); 373 | if (Interpretable::LibcFuncStart <= (std::uint32_t)pc && 374 | (std::uint32_t)pc < Interpretable::LibcFuncEnd) { 375 | if (printInstructions) { 376 | std::cerr << "call libc-" << pc << std::endl; 377 | } 378 | if (keepDebugInfo) { 379 | debugStack.pop(); 380 | } 381 | simulateLibCFunc(libc::Func(pc)); 382 | if (printInstructions) { 383 | std::cerr << "\t\t# return value = " << regs.at(10) << std::endl; 384 | } 385 | pc = regs[1]; 386 | // force the calling convention 387 | int callerSaved[] = {1, 5, 6, 7, /* 10, */ 11, 12, 13, 14, 388 | 15, 16, 17, 28, 29, 30, 31}; 389 | for (auto reg : callerSaved) 390 | regs[reg] += 0x1234; 391 | continue; 392 | } 393 | 394 | auto instIdx = *(std::uint32_t *)(cache.getMemory().first + pc); 395 | // We no longer take the mem/cache access in the IF stage into 396 | // consideration 397 | const auto &inst = interpretable.getInsts().at(instIdx); 398 | 399 | if (keepDebugInfo) { 400 | debugStack.top().addInstruction(inst); 401 | if (inst->getOp() == inst::Instruction::JALR) { 402 | // ret -> jalr x0, x1, 0 403 | const auto &jalr = spc(inst); 404 | if (jalr.getDest() == 0 && jalr.getBase() == 1 && 405 | jalr.getOffset() == 0) 406 | debugStack.pop(); 407 | else 408 | debugStack.emplace(); 409 | } 410 | } 411 | std::size_t modifiedReg = -1; 412 | std::uint64_t oldVal = -1; 413 | if (printInstructions) { 414 | printInstWithComment(inst); 415 | if (auto opt = getModifiedReg(inst)) { 416 | modifiedReg = opt.value(); 417 | oldVal = regs.at(modifiedReg); 418 | } 419 | } 420 | 421 | simulate(inst); 422 | 423 | if (printInstructions) { 424 | if (modifiedReg != -1) { 425 | std::cerr << "\t\t# " << regNumber2regName(modifiedReg) << ": " 426 | << oldVal << " -> " << regs.at(modifiedReg) << std::endl; 427 | } else if (inst::Instruction::SB <= inst->getOp() && 428 | inst->getOp() <= inst::Instruction::SW) { 429 | auto reg = spc(inst).getReg(); 430 | std::cerr << "\t\t# stored value = " << regs.at(reg) << std::endl; 431 | } 432 | } 433 | 434 | regs[0] = 0; 435 | pc += 4; 436 | } 437 | } catch (std::exception &e) { 438 | if (!keepDebugInfo) 439 | throw; 440 | std::cerr << "\nSome error occurred.\n"; 441 | std::cerr << "Printing the register state..."; 442 | for (std::size_t i = 0; i < 32; ++i) { 443 | if (i % 8 == 0) 444 | std::cerr << "\n"; 445 | std::cerr << std::setw(4) << regNumber2regName(i) << " = " 446 | << std::setw(11) << regs.at(i) << ",\t"; 447 | } 448 | std::cerr << "\n\nPrinting the call stack...\n"; 449 | while (!debugStack.empty()) { 450 | auto &frame = debugStack.top().lastFewInstructions; 451 | std::cerr << "\t...\n"; 452 | while (!frame.empty()) { 453 | std::cerr << "\t"; 454 | printInstWithComment(frame.front()); 455 | frame.pop(); 456 | } 457 | debugStack.pop(); 458 | if (!debugStack.empty()) 459 | std::cerr << "from ...\n"; 460 | } 461 | std::cerr << std::endl; 462 | throw; 463 | } 464 | } 465 | 466 | void Interpreter::simulateLibCFunc(libc::Func funcN) { 467 | if (libc::PUTS <= funcN && funcN <= libc::PUTCHAR) 468 | ++instCnt.libcIO; 469 | else if (libc::MALLOC <= funcN && funcN <= libc::CALLOC) { 470 | // the actual update to instCnt is function-dependent. See the 471 | // implementations of each function for details 472 | ++instCnt.libcMem; 473 | } else 474 | assert(false); 475 | 476 | switch (funcN) { 477 | case libc::PUTS: 478 | libc::puts(regs, cache.getMemory().first, cache.getMemory().second, out); 479 | return; 480 | case libc::SCANF: 481 | libc::scanf(regs, cache.getMemory().first, cache.getMemory().second, in); 482 | return; 483 | case libc::SSCANF: 484 | libc::sscanf(regs, cache.getMemory().first); 485 | case libc::PRINTF: 486 | libc::printf(regs, cache.getMemory().first, cache.getMemory().second, out); 487 | return; 488 | case libc::SPRINTF: 489 | libc::sprintf(regs, cache.getMemory().first); 490 | return; 491 | case libc::PUTCHAR: 492 | libc::putchar(regs, out); 493 | return; 494 | case libc::MALLOC: 495 | libc::malloc(regs, cache.getMemory().first, cache.getMemory().second, 496 | heapPtr, malloced, invalidAddress, instCnt.libcMem); 497 | return; 498 | case libc::CALLOC: 499 | libc::malloc(regs, cache.getMemory().first, cache.getMemory().second, 500 | heapPtr, malloced, invalidAddress, instCnt.libcMem, true); 501 | return; 502 | case libc::FREE: 503 | libc::free(regs, malloced); 504 | return; 505 | case libc::MEMCPY: 506 | libc::memcpy(regs, cache.getMemory().first, cache.getMemory().second, 507 | instCnt.libcMem); 508 | return; 509 | case libc::STRLEN: 510 | libc::strlen(regs, cache.getMemory().first); 511 | return; 512 | case libc::STRCPY: 513 | libc::strcpy(regs, cache.getMemory().first, cache.getMemory().second, 514 | instCnt.libcMem); 515 | return; 516 | case libc::STRCAT: 517 | libc::strcat(regs, cache.getMemory().first, cache.getMemory().second, 518 | instCnt.libcMem); 519 | return; 520 | case libc::STRCMP: 521 | libc::strcmp(regs, cache.getMemory().first); 522 | return; 523 | case libc::MEMSET: 524 | libc::memset(regs, cache.getMemory().first, cache.getMemory().second, 525 | instCnt.libcMem); 526 | return; 527 | default: 528 | assert(false); 529 | } 530 | assert(false); 531 | } 532 | 533 | } // namespace ravel 534 | -------------------------------------------------------------------------------- /src/interpreter/libc_sim.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/interpreter/libc_sim.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ravel/container_utils.h" 11 | #include "ravel/error.h" 12 | 13 | // IO 14 | namespace ravel::libc { 15 | namespace { 16 | 17 | std::size_t countFormatSigns(const std::string &fmtStr) { 18 | std::size_t cnt = 0; 19 | for (auto iter = fmtStr.begin(); iter != fmtStr.end(); ++iter) { 20 | auto ch = *iter; 21 | if (ch != '%') 22 | continue; 23 | ++cnt; 24 | if (iter + 1 != fmtStr.end() && *(iter + 1) == '%') 25 | ++iter; 26 | } 27 | return cnt; 28 | } 29 | 30 | // return the formatted string and the number of characters written (if 31 | // successful) or -1 if an error occurred 32 | std::pair sprintfImpl(const std::string &fmtStr, 33 | const std::vector &args, 34 | const std::byte *storage) { 35 | std::string formattedStr; 36 | std::size_t curArgIdx = 0; 37 | for (std::size_t i = 0; i < fmtStr.size(); ++i) { 38 | auto ch = fmtStr[i]; 39 | if (ch != '%') { 40 | formattedStr.push_back(ch); 41 | continue; 42 | } 43 | assert(i + 1 < fmtStr.size()); 44 | ++i; 45 | ch = fmtStr[i]; 46 | if (ch == '%') { 47 | formattedStr.push_back('%'); 48 | continue; 49 | } 50 | if (ch == 'd') { 51 | formattedStr += std::to_string((std::int32_t)args.at(curArgIdx++)); 52 | continue; 53 | } 54 | if (ch == 's') { 55 | formattedStr += 56 | std::string((const char *)(storage + args.at(curArgIdx++))); 57 | continue; 58 | } 59 | throw RuntimeError("Invalid format string: " + fmtStr); 60 | } 61 | 62 | return {formattedStr, (int)formattedStr.size()}; 63 | } 64 | } // namespace 65 | 66 | void puts(std::array ®s, std::byte *storage, 67 | std::byte *storageEnd, FILE *fp) { 68 | std::size_t pos = regs[10]; 69 | regs[10] = std::fputs((const char *)(storage + pos), fp); 70 | std::fputc('\n', fp); 71 | } 72 | 73 | void scanf(std::array ®s, std::byte *storage, 74 | std::byte *storageEnd, FILE *fp) { 75 | auto fmtStr = (const char *)(storage + regs[10]); 76 | std::size_t assigned = 0; 77 | bool succeeded = true; 78 | for (auto iter = fmtStr; *iter != '\0' && succeeded; ++iter) { 79 | auto fmtCh = *iter; 80 | if (isspace(fmtCh)) { 81 | int ch = std::fgetc(fp); 82 | while (std::isspace(ch)) 83 | ch = std::getc(fp); 84 | std::ungetc(ch, fp); 85 | continue; 86 | } 87 | 88 | if (fmtCh == '%') { 89 | ++iter; 90 | fmtCh = *iter; 91 | if (regs[11 + assigned] >= storageEnd - storage) 92 | throw InvalidAddress(regs[11 + assigned]); 93 | if (fmtCh == 'd') { 94 | succeeded = 95 | std::fscanf(fp, "%d", (int *)(storage + regs[11 + assigned])); 96 | } else if (fmtCh == 's') { 97 | succeeded = 98 | std::fscanf(fp, "%s", (char *)(storage + regs[11 + assigned])); 99 | } else { 100 | assert(false); 101 | } 102 | assigned += succeeded; 103 | continue; 104 | } 105 | 106 | char ch = std::fgetc(fp); 107 | while (std::isspace(ch)) 108 | ch = std::fgetc(fp); 109 | succeeded = ch == fmtCh; 110 | } 111 | regs[10] = assigned; 112 | } 113 | 114 | void sscanf(std::array ®s, std::byte *storage) { 115 | auto buffer = (const char *)(storage + regs[10]); 116 | auto fmtStr = (const char *)(storage + regs[11]); 117 | std::size_t assigned = 0; 118 | bool succeeded = true; 119 | auto bufferIter = buffer; 120 | for (auto iter = fmtStr; *iter != '\0' && succeeded; ++iter) { 121 | auto fmtCh = *iter; 122 | if (isspace(fmtCh)) { 123 | int ch = *bufferIter; 124 | while (std::isspace(ch)) { 125 | ++bufferIter; 126 | ch = *bufferIter; 127 | } 128 | --bufferIter; 129 | continue; 130 | } 131 | 132 | if (fmtCh == '%') { 133 | ++iter; 134 | fmtCh = *iter; 135 | assert(fmtCh == 'd'); 136 | succeeded = 137 | std::sscanf(bufferIter, "%d", (int *)(storage + regs[12 + assigned])); 138 | assigned += succeeded; 139 | continue; 140 | } 141 | 142 | char ch = *bufferIter; 143 | while (std::isspace(ch)) { 144 | ++bufferIter; 145 | ch = *bufferIter; 146 | } 147 | succeeded = ch == fmtCh; 148 | } 149 | regs[10] = assigned; 150 | } 151 | 152 | void printf(std::array ®s, const std::byte *storage, 153 | std::byte *storageEnd, FILE *fp) { 154 | auto fmtStr = std::string((const char *)(storage + regs[10])); 155 | std::size_t nFormatSigns = countFormatSigns(fmtStr); 156 | std::vector arguments(regs.begin() + 11, 157 | regs.begin() + 11 + nFormatSigns); 158 | assert(arguments.size() <= 7); 159 | auto [formattedStr, nSuccChars] = sprintfImpl(fmtStr, arguments, storage); 160 | std::fprintf(fp, "%s", formattedStr.c_str()); 161 | regs[10] = nSuccChars; 162 | } 163 | 164 | void sprintf(std::array ®s, std::byte *storage) { 165 | std::size_t bufferVAddr = regs[10]; 166 | auto fmtStr = std::string((const char *)(storage + regs[11])); 167 | std::size_t nFormatSigns = countFormatSigns(fmtStr); 168 | std::vector arguments(regs.begin() + 12, 169 | regs.begin() + 12 + nFormatSigns); 170 | assert(arguments.size() <= 6); 171 | auto [formattedStr, nSuccChars] = sprintfImpl(fmtStr, arguments, storage); 172 | std::sprintf((char *)(storage + bufferVAddr), "%s", formattedStr.c_str()); 173 | regs[10] = nSuccChars; 174 | } 175 | 176 | void putchar(std::array ®s, FILE *fp) { 177 | regs[10] = std::putc(regs[10], fp); 178 | } 179 | 180 | } // namespace ravel::libc 181 | 182 | namespace ravel::libc { 183 | namespace { 184 | // When a function manipulates a large block of memory, the instCnt should be 185 | // increased by more than once. 186 | // Hence, we use the rule: instCnt += size / MemSizeFactor 187 | constexpr std::size_t MemSizeFactor = 512; 188 | } // namespace 189 | 190 | void malloc(std::array ®s, std::byte *storage, 191 | std::byte *storageEnd, std::size_t &heapPtr, 192 | std::unordered_set &malloced, 193 | std::unordered_set &invalidAddress, 194 | std::size_t &instCnt, bool zeroInit) { 195 | auto size = (std::size_t)regs[10]; 196 | instCnt += size / MemSizeFactor; 197 | regs[10] = heapPtr; 198 | malloced.emplace(heapPtr); 199 | heapPtr += size; 200 | if (zeroInit) { 201 | std::fill(storage + regs[10], storage + heapPtr, std::byte(0)); 202 | } 203 | invalidAddress.emplace(heapPtr++); 204 | if (heapPtr % 2) { 205 | invalidAddress.emplace(heapPtr++); 206 | } 207 | if (heapPtr >= storageEnd - storage) { 208 | throw RuntimeError("Running out of memory"); 209 | } 210 | } 211 | 212 | void free(const std::array ®s, 213 | std::unordered_set &malloced) { 214 | std::size_t addr = regs[10]; 215 | assert(isIn(malloced, addr)); 216 | malloced.erase(malloced.find(addr)); 217 | } 218 | 219 | void memcpy(std::array ®s, std::byte *storage, 220 | std::byte *storageEnd, std::size_t &instCnt) { 221 | std::size_t dest = regs[10]; 222 | std::size_t src = regs[11]; 223 | std::size_t cnt = regs[12]; 224 | instCnt += cnt / MemSizeFactor; 225 | assert(src + cnt < storageEnd - storage && dest + cnt < storageEnd - storage); 226 | std::memcpy(storage + dest, storage + src, cnt); 227 | } 228 | 229 | void strlen(std::array ®s, const std::byte *storage) { 230 | std::size_t strPos = regs[10]; 231 | regs[10] = std::strlen((char *)storage + strPos); 232 | } 233 | 234 | void strcpy(std::array ®s, std::byte *storage, 235 | std::byte *storageEnd, std::size_t &instCnt) { 236 | std::size_t dest = regs[10], src = regs[11]; 237 | std::size_t size = std::strlen((char *)storage + src); 238 | instCnt += size / MemSizeFactor; 239 | std::strcpy((char *)storage + dest, (char *)storage + src); 240 | } 241 | 242 | void strcat(std::array ®s, std::byte *storage, 243 | std::byte *storageEnd, std::size_t &instCnt) { 244 | auto dest = (char *)(storage + regs[10]); 245 | auto src = (const char *)(storage + regs[11]); 246 | std::size_t size = std::strlen(src); 247 | instCnt += size / MemSizeFactor; 248 | std::strcat(dest, src); 249 | } 250 | 251 | void strcmp(std::array ®s, std::byte *storage) { 252 | auto lhs = (const char *)(storage + regs[10]); 253 | auto rhs = (const char *)(storage + regs[11]); 254 | regs[10] = std::strcmp(lhs, rhs); 255 | } 256 | 257 | void memset(std::array ®s, std::byte *storage, 258 | std::byte *storageEnd, std::size_t &instCnt) { 259 | std::size_t dest = regs[10]; 260 | int ch = regs[11]; 261 | std::size_t cnt = regs[12]; 262 | instCnt += cnt / MemSizeFactor; 263 | std::memset(storage + dest, ch, cnt); 264 | } 265 | 266 | } // namespace ravel::libc -------------------------------------------------------------------------------- /src/linker/linker.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/linker/linker.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ravel/assembler/assembler.h" 13 | #include "ravel/assembler/parser.h" 14 | #include "ravel/container_utils.h" 15 | #include "ravel/error.h" 16 | 17 | namespace ravel { 18 | namespace { 19 | class SymbolTable { 20 | public: 21 | std::size_t resolve(const std::string &symbol) const { 22 | auto opt = get(globalSymTable, symbol); 23 | if (opt) 24 | return opt.value(); 25 | throw UnresolvableSymbol(symbol); 26 | } 27 | 28 | std::size_t resolve(ObjectFile::Id objId, const std::string &symbol) const { 29 | auto opt = get(objSymTables.at(objId), symbol); 30 | if (opt) 31 | return opt.value(); 32 | return resolve(symbol); 33 | } 34 | 35 | void addGlobalSymbol(const std::string &sym, std::size_t pos) { 36 | if (isIn(globalSymTable, sym)) 37 | throw DuplicatedSymbols(sym); 38 | globalSymTable.emplace(sym, pos); 39 | } 40 | 41 | void 42 | addObjSymTable(ObjectFile::Id objId, std::size_t basePos, 43 | const std::unordered_map &symTable, 44 | const std::unordered_set &globalSymbols) { 45 | std::unordered_map newTable; 46 | for (auto &[sym, pos] : symTable) { 47 | newTable.emplace(sym, basePos + pos); 48 | if (isIn(globalSymbols, sym)) 49 | addGlobalSymbol(sym, basePos + pos); 50 | } 51 | objSymTables.emplace(objId, newTable); 52 | } 53 | 54 | private: 55 | std::unordered_map> 57 | objSymTables; 58 | std::unordered_map globalSymTable; 59 | }; 60 | 61 | // We need to merge the object files into one interpretable file, resolve 62 | // external symbols and compute relocation functions. For simplicity, we shall 63 | // identify an object file by its position in `objects`. 64 | // 65 | // First, we allocate spaces and build the symbol table. Also, we record the 66 | // starting position of each object file. Note that we add an extra object file 67 | // containing `_start` and some placeholders for libc functions. 68 | // (cf. `void Linker::prepare()`) 69 | // 70 | // Then, we merge the object files. Namely, we merge the `storage`s and 71 | // instructions of the object files and encode the instructions in the right 72 | // way. We will record from which object file each instruction comes from, and 73 | // a mapping from positions to `pcrel_hi` (if there is one). These will be 74 | // helpful in the next phase. 75 | // (cf. `void mergeObjects(const ObjectFile & obj)`) 76 | // 77 | // After that, we resolve global symbols and compute the relocation functions. 78 | // These will be done in a single pass since we will replace instructions in 79 | // `insts`, whence change the instruction ID. 80 | // (cf. `void handleRelocationFuncsAndExternalSymbols()`) 81 | // 82 | // Finally, we handle directives such as `.word symbol`. 83 | class Linker { 84 | public: 85 | explicit Linker(const std::vector &objectsList) { 86 | for (const auto &obj : objectsList) 87 | objects.emplace(obj.getId(), obj); 88 | } 89 | 90 | Interpretable link() { 91 | prepare(); 92 | for (auto &[_, obj] : objects) 93 | mergeObject(obj); 94 | handleRelocationFuncsAndExternalSymbols(); 95 | 96 | for (auto &[objId, obj] : objects) { 97 | auto startPos = startingPosition.at(objId); 98 | for (auto [label, pos] : obj.getToBeStored()) { 99 | std::uint32_t addr = symTable.resolve(objId, label); 100 | pos += startPos; 101 | *(std::uint32_t *)(storage.data() + pos) = addr; 102 | } 103 | } 104 | 105 | return {storage, insts}; 106 | } 107 | 108 | private: 109 | static ObjectFile makeStartObj() { 110 | std::string src = ".text\n_start:\ncall main\nnop"; 111 | for (int i = 0; i < libc::LibcFuncEndAddr - (3 * 4); i += 4) { 112 | src += "\nnop"; 113 | } 114 | 115 | auto res = assemble(src); 116 | assert(res.getStorage().size() == libc::LibcFuncEndAddr); 117 | return res; 118 | } 119 | 120 | void prepare() { 121 | auto startObj = makeStartObj(); 122 | objects.emplace(startObj.getId(), startObj); 123 | for (const auto &[name, pos] : libc::getName2Pos()) { 124 | symTable.addGlobalSymbol(name, pos); 125 | } 126 | 127 | for (auto &[id, obj] : objects) { 128 | std::size_t basePos = storage.size(); 129 | startingPosition[id] = basePos; 130 | symTable.addObjSymTable(id, basePos, obj.getSymbolTable(), 131 | obj.getGlobalSymbol()); 132 | storage.resize(storage.size() + obj.getStorage().size()); 133 | } 134 | } 135 | 136 | void mergeObject(const ObjectFile &obj) { 137 | auto basePos = startingPosition.at(obj.getId()); 138 | std::copy(obj.getStorage().begin(), obj.getStorage().end(), 139 | storage.begin() + basePos); 140 | for (const auto &inst : obj.getInsts()) { 141 | auto pos = basePos + obj.getInst2Pos().at(inst->getId()); 142 | assert(pos + 3 < storage.size()); 143 | *(std::uint32_t *)(storage.data() + pos) = insts.size(); 144 | insts.emplace_back(inst); 145 | inst2ObjId.emplace(inst->getId(), obj.getId()); 146 | if (auto opt = get(obj.getContainsRelocationFunc(), inst->getId()); 147 | opt && opt.value().type == RelocationFunction::PCREL_HI) { 148 | pos2Relocation.emplace(pos, opt.value()); 149 | } 150 | } 151 | } 152 | 153 | void handleRelocationFuncsAndExternalSymbols() { 154 | for (auto &inst : insts) { 155 | auto instId = inst->getId(); // make a copy of the instruction ID 156 | auto objId = inst2ObjId.at(instId); 157 | const auto &obj = objects.at(objId); 158 | if (isIn(obj.getContainsExternalLabel(), instId)) { 159 | assert(false); 160 | // TODO: Does external label outsides relocation function really exist? 161 | } 162 | if (isIn(obj.getContainsRelocationFunc(), instId)) { 163 | // `inst` may have been replaced in the previous stage, so pass in the 164 | // instruction ID explicitly 165 | inst = computeRelocationFunction(inst, instId, obj); 166 | } 167 | } 168 | } 169 | 170 | std::shared_ptr 171 | computeRelocationFunction(const std::shared_ptr &inst, 172 | inst::Instruction::Id instId, 173 | const ObjectFile &obj) const { 174 | auto relocation = obj.getContainsRelocationFunc().at(instId); 175 | auto imm = 176 | symTable.resolve(obj.getId(), relocation.symbol) + relocation.offset; 177 | if (relocation.type == RelocationFunction::HI) { 178 | return replaceImm(inst, imm >> 12u); 179 | } 180 | if (relocation.type == RelocationFunction::LO) { 181 | return replaceImm(inst, imm & 0xfffu); 182 | } 183 | auto basePos = startingPosition.at(obj.getId()); 184 | if (relocation.type == RelocationFunction::PCREL_HI) { 185 | auto instPos = basePos + obj.getInst2Pos().at(instId); 186 | auto offset = imm - instPos; 187 | return replaceImm(inst, offset >> 12u); 188 | } 189 | assert(relocation.type == RelocationFunction::PCREL_LO); 190 | auto pcrelHiPos = imm; 191 | auto pcrelHi = pos2Relocation.at(pcrelHiPos); 192 | auto pcrelHiImm = 193 | symTable.resolve(obj.getId(), pcrelHi.symbol) + pcrelHi.offset; 194 | auto offset = pcrelHiImm - pcrelHiPos; 195 | return replaceImm(inst, offset & 0xfffu); 196 | } 197 | 198 | static std::shared_ptr 199 | replaceImm(const std::shared_ptr &inst, 200 | std::uint32_t imm) { 201 | if (auto p = std::dynamic_pointer_cast(inst)) { 202 | return std::make_shared(p->getOp(), p->getDest(), 203 | imm); 204 | } 205 | if (auto p = std::dynamic_pointer_cast(inst)) { 206 | return std::make_shared(p->getOp(), p->getDest(), 207 | p->getSrc(), imm); 208 | } 209 | if (auto p = std::dynamic_pointer_cast(inst)) { 210 | return std::make_shared(p->getOp(), p->getReg(), 211 | p->getBase(), imm); 212 | } 213 | if (auto p = std::dynamic_pointer_cast(inst)) { 214 | return std::make_shared(p->getDest(), p->getBase(), 215 | imm); 216 | } 217 | assert(false); 218 | } 219 | 220 | private: 221 | std::unordered_map objects; 222 | std::unordered_map startingPosition; 223 | SymbolTable symTable; 224 | std::unordered_map inst2ObjId; 225 | std::unordered_map pos2Relocation; 226 | 227 | std::vector storage; 228 | std::vector> insts; 229 | }; 230 | 231 | } // namespace 232 | 233 | } // namespace ravel 234 | 235 | namespace ravel { 236 | 237 | Interpretable link(const std::vector &objects) { 238 | Linker linker(objects); 239 | return linker.link(); 240 | } 241 | 242 | } // namespace ravel 243 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ravel/assembler/parser.h" 8 | #include "ravel/container_utils.h" 9 | #include "ravel/error.h" 10 | #include "ravel/simulator.h" 11 | 12 | namespace ravel { 13 | 14 | bool starts_with(const std::string &str, const std::string &prefix) { 15 | if (prefix.size() > str.size()) 16 | return false; 17 | return prefix == str.substr(0, prefix.size()); 18 | } 19 | 20 | class ArgParser { 21 | public: 22 | explicit ArgParser(const std::vector &args) : args(args) {} 23 | 24 | Config parse() { 25 | if (std::find(args.begin(), args.end(), "--oj-mode") != args.end()) { 26 | config.cacheEnabled = false; 27 | config.sources = {readSource("test.s"), readSource("builtin.s")}; 28 | config.inputFile = "test.in"; 29 | config.outputFile = "test.out"; 30 | } 31 | 32 | for (auto iter = args.begin() + 1; iter != args.end(); ++iter) { 33 | auto arg = *iter; 34 | if (arg == "--oj-mode") 35 | continue; 36 | 37 | if (arg.front() != '-') { // source code 38 | config.sources.emplace_back(readSource(arg)); 39 | continue; 40 | } 41 | if (arg == "--enable-cache") { 42 | config.cacheEnabled = true; 43 | continue; 44 | } 45 | if (arg == "--keep-debug-info") { 46 | config.keepDebugInfo = true; 47 | continue; 48 | } 49 | if (starts_with(arg, "--timeout")) { 50 | auto tokens = split(arg, "="); 51 | config.timeout = std::stoul(tokens.at(1)); 52 | continue; 53 | } 54 | if (starts_with(arg, "-w")) { 55 | handleInstWeight(arg); 56 | continue; 57 | } 58 | if (starts_with(arg, "--input-file")) { 59 | auto tokens = split(arg, "="); 60 | if (tokens.size() == 1) 61 | tokens.emplace_back(""); 62 | config.inputFile = tokens.at(1); 63 | continue; 64 | } 65 | if (starts_with(arg, "--output-file")) { 66 | auto tokens = split(arg, "="); 67 | if (tokens.size() == 1) 68 | tokens.emplace_back(""); 69 | config.outputFile = tokens.at(1); 70 | continue; 71 | } 72 | if (starts_with(arg, "--print-instructions")) { 73 | config.printInsts = true; 74 | continue; 75 | } 76 | std::cerr << "Unknown command line argument: " << arg << std::endl; 77 | exit(1); 78 | } 79 | return config; 80 | } 81 | 82 | private: 83 | std::string readSource(const std::string &filename) { 84 | std::ifstream t(filename); 85 | if (!t) { 86 | throw Exception("Can not find file " + filename); 87 | } 88 | std::string src((std::istreambuf_iterator(t)), 89 | std::istreambuf_iterator()); 90 | return src; 91 | } 92 | 93 | void handleInstWeight(const std::string &arg) { 94 | assert(starts_with(arg, "-w")); 95 | auto tokens = split(arg.substr(2), "="); 96 | std::size_t weight = std::stoul(tokens.at(1)); 97 | auto type = tokens.at(0); 98 | if (type == "simple") 99 | config.instWeight.simple = weight; 100 | else if (type == "mul") 101 | config.instWeight.mul = weight; 102 | else if (type == "br") 103 | config.instWeight.br = weight; 104 | else if (type == "div") 105 | config.instWeight.div = weight; 106 | else if (type == "mem") 107 | config.instWeight.mem = weight; 108 | else if (type == "libcIO") 109 | config.instWeight.libcIO = weight; 110 | else if (type == "libcMem") 111 | config.instWeight.libcMem = weight; 112 | else 113 | assert(false); 114 | } 115 | 116 | private: 117 | const std::vector &args; 118 | Config config{}; 119 | }; 120 | 121 | } // namespace ravel 122 | 123 | int main(int argc, char *argv[]) { 124 | using namespace ravel; 125 | std::vector args; 126 | args.reserve(argc); 127 | for (int i = 0; i < argc; ++i) 128 | args.emplace_back(argv[i]); 129 | Config config = ArgParser(args).parse(); 130 | 131 | Simulator simulator(config); 132 | simulator.simulate(); 133 | 134 | return 0; 135 | } -------------------------------------------------------------------------------- /src/simulator.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/simulator.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ravel/error.h" 8 | 9 | namespace ravel { 10 | 11 | Interpretable Simulator::buildInterpretable() { 12 | auto startTp = std::chrono::high_resolution_clock::now(); 13 | 14 | std::vector objs; 15 | for (auto &src : config.sources) 16 | objs.emplace_back(assemble(src)); 17 | 18 | auto buildEndTp = std::chrono::high_resolution_clock::now(); 19 | auto time = std::chrono::duration_cast(buildEndTp - 20 | startTp) 21 | .count(); 22 | auto interp = link(objs); 23 | std::cerr << "\nBuild finished in " << time << " ms\n"; 24 | return interp; 25 | } 26 | 27 | std::pair Simulator::getIOFile() const { 28 | auto in = config.inputFile.empty() 29 | ? stdin 30 | : std::fopen(config.inputFile.c_str(), "r"); 31 | auto out = config.outputFile.empty() 32 | ? stdout 33 | : std::fopen(config.outputFile.c_str(), "w"); 34 | assert(in && out); 35 | return {in, out}; 36 | } 37 | 38 | void Simulator::printResult(const Interpreter &interpreter) const { 39 | std::cout << std::endl; 40 | std::cout << "exit code: " << interpreter.getReturnCode() << std::endl; 41 | std::cout << "memory leak: " << interpreter.hasMemoryLeak() << std::endl; 42 | std::cout << "time: " << interpreter.getTimeConsumed() << std::endl; 43 | std::cout << "# instructions:\n"; 44 | auto iCnt = interpreter.getInstCnt(); 45 | std::cout << "# simple = " << iCnt.simple 46 | << " (including unconditional jump)\n"; 47 | std::cout << "# mul = " << iCnt.mul << std::endl; 48 | std::cout << "# cache = " << iCnt.cache << std::endl; 49 | std::cout << "# br = " << iCnt.br << std::endl; 50 | std::cout << "# div = " << iCnt.div << std::endl; 51 | std::cout << "# mem = " << iCnt.mem << " (a.k.a cache miss)" << std::endl; 52 | std::cout << "# libcIO = " << iCnt.libcIO << std::endl; 53 | std::cout << "# libcMem = " << iCnt.libcMem << std::endl; 54 | } 55 | 56 | std::size_t Simulator::simulate() { 57 | auto interp = buildInterpretable(); 58 | auto [in, out] = getIOFile(); 59 | std::shared_ptr close(nullptr, [in = in, out = out](void *) { 60 | if (in != stdin) 61 | std::fclose(in); 62 | if (out != stdout) 63 | std::fclose(out); 64 | }); 65 | 66 | auto starTp = std::chrono::high_resolution_clock::now(); 67 | 68 | auto regsPtr = 69 | regs.index() == 0 ? std::get<0>(regs).data() : std::get<1>(regs); 70 | auto storagePtr = storage.index() == 0 71 | ? std::make_pair(&std::get<0>(storage).front(), 72 | &std::get<0>(storage).back() + 1) 73 | : std::get<1>(storage); 74 | 75 | Interpreter interpreter{interp, regsPtr, storagePtr.first, storagePtr.second, 76 | in, out, config.instWeight}; 77 | 78 | interpreter.setTimeout(config.timeout); 79 | interpreter.setKeepDebugInfo(config.keepDebugInfo); 80 | if (!config.cacheEnabled) 81 | interpreter.disableCache(); 82 | if (config.printInsts) 83 | interpreter.enablePrintInstructions(); 84 | interpreter.interpret(); 85 | printResult(interpreter); 86 | 87 | auto endTp = std::chrono::high_resolution_clock::now(); 88 | auto time = 89 | std::chrono::duration_cast(endTp - starTp) 90 | .count(); 91 | std::cerr << "\nInterpretation finished in " << time << " ms\n"; 92 | 93 | return interpreter.getTimeConsumed(); 94 | } 95 | 96 | Simulator::Simulator(Config config_) : config(std::move(config_)) { 97 | if (config.externalRegs) { 98 | regs = config.externalRegs; 99 | } else { 100 | regs = std::array(); 101 | } 102 | 103 | if (config.externalStorageBegin) { 104 | assert(config.externalStorageBegin < config.externalStorageEnd); 105 | assert(config.externalStorageEnd - config.externalStorageBegin < 106 | config.maxStorageSize); 107 | storage = 108 | std::make_pair(config.externalStorageBegin, config.externalStorageEnd); 109 | } else { 110 | storage = std::vector(config.maxStorageSize); 111 | } 112 | } 113 | 114 | std::size_t simulate(const std::string &src, std::uint32_t *regs, 115 | std::byte *storageBegin, std::byte *storageEnd) { 116 | Config config; 117 | config.cacheEnabled = true; 118 | config.sources.emplace_back(src); 119 | config.externalRegs = regs; 120 | config.externalStorageBegin = storageBegin; 121 | config.externalStorageEnd = storageEnd; 122 | 123 | Simulator simulator(config); 124 | auto timeConsumed = simulator.simulate(); 125 | return timeConsumed; 126 | } 127 | 128 | } // namespace ravel -------------------------------------------------------------------------------- /test/asm/a_plus_b.s: -------------------------------------------------------------------------------- 1 | # #include 2 | # 3 | # int main() { 4 | # int a, b; 5 | # scanf("%d %d", &a, &b); 6 | # printf("%d\n", a + b); 7 | # return 0; 8 | # } 9 | .file "main.c" 10 | .option nopic 11 | .text 12 | .section .rodata 13 | .align 2 14 | .LC0: 15 | .string "%d %d" 16 | .align 2 17 | .LC1: 18 | .string "%d\n" 19 | .text 20 | .align 2 21 | .globl main 22 | .type main, @function 23 | main: 24 | addi sp,sp,-32 25 | sw ra,28(sp) 26 | sw s0,24(sp) 27 | addi s0,sp,32 28 | addi a4,s0,-24 29 | addi a5,s0,-20 30 | mv a2,a4 31 | mv a1,a5 32 | lui a5,%hi(.LC0) 33 | addi a0,a5,%lo(.LC0) 34 | call __isoc99_scanf 35 | lw a4,-20(s0) 36 | lw a5,-24(s0) 37 | add a5,a4,a5 38 | mv a1,a5 39 | lui a5,%hi(.LC1) 40 | addi a0,a5,%lo(.LC1) 41 | call printf 42 | li a5,0 43 | mv a0,a5 44 | lw ra,28(sp) 45 | lw s0,24(sp) 46 | addi sp,sp,32 47 | jr ra 48 | .size main, .-main 49 | .ident "GCC: (GNU) 9.2.0" 50 | .section .note.GNU-stack,"",@progbits 51 | -------------------------------------------------------------------------------- /test/asm/a_plus_b_1.s: -------------------------------------------------------------------------------- 1 | # int main() { 2 | # int a = 1; 3 | # int b = 2; 4 | # int c = a + b; 5 | # return c; 6 | # } 7 | 8 | .file "main.c" 9 | .option nopic 10 | .text 11 | .align 2 12 | .globl main 13 | .type main, @function 14 | main: 15 | addi sp,sp,-32 16 | sw s0,28(sp) 17 | addi s0,sp,32 18 | li a5,1 19 | sw a5,-20(s0) 20 | li a5,2 21 | sw a5,-24(s0) 22 | lw a4,-20(s0) 23 | lw a5,-24(s0) 24 | add a5,a4,a5 25 | sw a5,-28(s0) 26 | lw a5,-28(s0) 27 | mv a0,a5 28 | lw s0,28(sp) 29 | addi sp,sp,32 30 | jr ra 31 | .size main, .-main 32 | .ident "GCC: (GNU) 9.2.0" 33 | .section .note.GNU-stack,"",@progbits -------------------------------------------------------------------------------- /test/asm/a_plus_b_func.s: -------------------------------------------------------------------------------- 1 | # int foo(int a, int b) { 2 | # return a + b; 3 | # } 4 | # 5 | # int main() { 6 | # return foo(1, 2); 7 | # } 8 | 9 | .file "main.c" 10 | .option nopic 11 | .text 12 | .align 2 13 | .globl foo 14 | .type foo, @function 15 | foo: 16 | addi sp,sp,-32 17 | sw s0,28(sp) 18 | addi s0,sp,32 19 | sw a0,-20(s0) 20 | sw a1,-24(s0) 21 | lw a4,-20(s0) 22 | lw a5,-24(s0) 23 | add a5,a4,a5 24 | mv a0,a5 25 | lw s0,28(sp) 26 | addi sp,sp,32 27 | jr ra 28 | .size foo, .-foo 29 | .align 2 30 | .globl main 31 | .type main, @function 32 | main: 33 | addi sp,sp,-16 34 | sw ra,12(sp) 35 | sw s0,8(sp) 36 | addi s0,sp,16 37 | li a1,2 38 | li a0,1 39 | call foo 40 | mv a5,a0 41 | mv a0,a5 42 | lw ra,12(sp) 43 | lw s0,8(sp) 44 | addi sp,sp,16 45 | jr ra 46 | .size main, .-main 47 | .ident "GCC: (GNU) 9.2.0" 48 | .section .note.GNU-stack,"",@progbits -------------------------------------------------------------------------------- /test/asm/hello_world.s: -------------------------------------------------------------------------------- 1 | # int main() { 2 | # printf("Hello, world!\n"); 3 | # return 0; 4 | # } 5 | .file "main.c" 6 | .option nopic 7 | .text 8 | .section .rodata 9 | .align 2 10 | .LC0: 11 | .string "Hello, world!" 12 | .text 13 | .align 2 14 | .globl main 15 | .type main, @function 16 | main: 17 | addi sp,sp,-16 18 | sw ra,12(sp) 19 | sw s0,8(sp) 20 | addi s0,sp,16 21 | lui a5,%hi(.LC0) 22 | addi a0,a5,%lo(.LC0) 23 | call puts 24 | li a5,0 25 | mv a0,a5 26 | lw ra,12(sp) 27 | lw s0,8(sp) 28 | addi sp,sp,16 29 | jr ra 30 | .size main, .-main 31 | .ident "GCC: (GNU) 9.2.0" 32 | .section .note.GNU-stack,"",@progbits -------------------------------------------------------------------------------- /test/asm/loop.s: -------------------------------------------------------------------------------- 1 | # int main() { 2 | # int s = 0; 3 | # for (int i = 0; i < 10; ++i) { 4 | # s += i; 5 | # } 6 | # return s; 7 | # } 8 | .file "main.c" 9 | .option nopic 10 | .text 11 | .align 2 12 | .globl main 13 | .type main, @function 14 | main: 15 | addi sp,sp,-32 16 | sw s0,28(sp) 17 | addi s0,sp,32 18 | sw zero,-20(s0) 19 | sw zero,-24(s0) 20 | j .L2 21 | .L3: 22 | lw a4,-20(s0) 23 | lw a5,-24(s0) 24 | add a5,a4,a5 25 | sw a5,-20(s0) 26 | lw a5,-24(s0) 27 | addi a5,a5,1 28 | sw a5,-24(s0) 29 | .L2: 30 | lw a4,-24(s0) 31 | li a5,9 32 | ble a4,a5,.L3 33 | lw a5,-20(s0) 34 | mv a0,a5 35 | lw s0,28(sp) 36 | addi sp,sp,32 37 | jr ra 38 | .size main, .-main 39 | .ident "GCC: (GNU) 9.2.0" 40 | .section .note.GNU-stack,"",@progbits 41 | -------------------------------------------------------------------------------- /test/c/basic/fibonacci.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) { 4 | if (n == 0 || n == 1) 5 | return 1; 6 | return fib(n - 1) + fib(n - 2); 7 | } 8 | 9 | int main() { 10 | int n; 11 | scanf("%d", &n); 12 | printf("%d\n", fib(n)); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/c/basic/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | input: 3 | 1 2 3 4 4 | Hello, world 5 6! 5 | output: 6 | 1 7 | 2 8 | 3 4 9 | Hello, world 11! 10 | */ 11 | 12 | #include 13 | 14 | int global; 15 | 16 | int main() { 17 | int local; 18 | scanf("%d", &local); 19 | printf("%d\n", local); 20 | 21 | scanf("%d", &global); 22 | printf("%d\n", global); 23 | 24 | scanf("%d%d", &local, &global); 25 | printf("%d %d\n", local, global); 26 | 27 | scanf("Hello, world %d %d!", &local, &global); 28 | printf("Hello, world %d!", local + global); 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /test/c/basic/mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const int N = 100; 5 | 6 | int main() { 7 | int *a = malloc(sizeof(int) * N); 8 | for (int i = 0; i < N; ++i) 9 | a[i] = i; 10 | for (int i = 0; i < N; ++i) 11 | printf("%d", a[i]); 12 | free(a); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /test/c/basic/multi_file/bultin.c: -------------------------------------------------------------------------------- 1 | #include "bultin.h" 2 | 3 | void string_add(char * buffer, char * str1, char * str2) { 4 | size_t len1 = strlen(str1); 5 | strcpy(buffer, str1); 6 | strcpy(buffer + len1, str2); 7 | } 8 | 9 | void string_substring(char * buffer, char * str, size_t l, size_t r) { 10 | memcpy(buffer, str + l, r - l); 11 | } 12 | -------------------------------------------------------------------------------- /test/c/basic/multi_file/bultin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void string_add(char * buffer, char * str1, char * str2); 6 | 7 | void string_substring(char * buffer, char * str, size_t l, size_t r); 8 | 9 | int string_parseInt(char * str); 10 | -------------------------------------------------------------------------------- /test/c/basic/multi_file/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "bultin.h" 5 | 6 | int main() { 7 | char buffer[256] = {0}; 8 | string_add(buffer, "Hello, ", "world!"); 9 | puts(buffer); 10 | memset(buffer, 0, sizeof(buffer)); 11 | string_substring(buffer, "Hello, world!\n", 1, 4); 12 | puts(buffer); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /test/c/mx/heapsort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int n; 5 | int *a; 6 | 7 | void exchange(int x, int y) { 8 | int t = a[x]; 9 | a[x] = a[y]; 10 | a[y] = t; 11 | } 12 | 13 | int makeHeap() { 14 | int i; 15 | int t; 16 | int j; 17 | i = (n - 1) / 2; 18 | t = 0; 19 | j = 0; 20 | while (i >= 0) { 21 | j = i * 2; 22 | if (i * 2 + 1 < n && a[i * 2 + 1] < a[i * 2]) 23 | j = i * 2 + 1; 24 | if (a[i] > a[j]) { 25 | exchange(i, j); 26 | } 27 | i = i - 1; 28 | } 29 | return 0; 30 | } 31 | 32 | int adjustHeap(int n) { 33 | int i; 34 | int j; 35 | int t; 36 | i = 0; 37 | j = 0; 38 | t = 0; 39 | while (i * 2 < n) { 40 | j = i * 2; 41 | if (i * 2 + 1 < n && a[i * 2 + 1] < a[i * 2]) 42 | j = i * 2 + 1; 43 | if (a[i] > a[j]) { 44 | int t = a[i]; 45 | a[i] = a[j]; 46 | a[j] = t; 47 | i = j; 48 | } else 49 | break; 50 | } 51 | return 0; 52 | } 53 | 54 | int heapSort() { 55 | int t; 56 | int k; 57 | t = 0; 58 | for (k = 0; k < n; k = k + 1) { 59 | t = a[0]; 60 | a[0] = a[n - k - 1]; 61 | a[n - k - 1] = t; 62 | adjustHeap(n - k - 1); 63 | } 64 | return 0; 65 | } 66 | 67 | int main() { 68 | int i; 69 | scanf("%d", &n); 70 | a = malloc(sizeof(int) * n); 71 | 72 | for (i = 0; i < n; i = i + 1) 73 | a[i] = i; 74 | makeHeap(); 75 | heapSort(); 76 | for (i = 0; i < n; i = i + n / 10) 77 | printf("%d ", a[i]); 78 | printf("\n"); 79 | return 0; 80 | } 81 | 82 | /*!! metadata: 83 | === comment === 84 | heapsort-5100379110-daibo.mx 85 | === is_public === 86 | True 87 | === assert === 88 | output 89 | === timeout === 90 | 0.5 91 | === input === 92 | 543 93 | === phase === 94 | optim pretest 95 | === output === 96 | 542 488 434 380 326 272 218 164 110 56 2 97 | === exitcode === 98 | 99 | 100 | !!*/ 101 | -------------------------------------------------------------------------------- /test/c/mx/horse3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int N; 6 | int head; 7 | int startx; 8 | int starty; 9 | int targetx; 10 | int targety; 11 | int x; 12 | int y; 13 | int xlist[12000]; 14 | int ylist[12000]; 15 | int tail; 16 | int ok; 17 | int now; 18 | int dx[8]; 19 | int dy[9]; 20 | int **step; 21 | int i; 22 | int j; 23 | 24 | void origin(int N) { 25 | head = 0; 26 | tail = 0; 27 | step = malloc(sizeof(int *) * N); 28 | for (i = 0; i < N; i++) { 29 | step[i] = malloc(sizeof(int) * N); 30 | for (j = 0; j < N; j++) 31 | step[i][j] = 0; 32 | } 33 | } 34 | 35 | bool check(int a) { return ((a < N) && (a >= 0)); } 36 | 37 | void addList(int x, int y) { 38 | if (check(x) && check(y) && step[x][y] == -1) { 39 | tail++; 40 | xlist[tail] = x; 41 | ylist[tail] = y; 42 | step[x][y] = now + 1; 43 | if ((x == targetx) && (y == targety)) 44 | ok = 1; 45 | } 46 | } 47 | int main() { 48 | origin(106); 49 | scanf("%d", &N); 50 | targety = N - 1; 51 | targetx = targety; 52 | for (i = 0; i < N; i++) 53 | for (j = 0; j < N; j++) 54 | step[i][j] = -1; 55 | dx[0] = -2; 56 | dy[0] = -1; 57 | dx[1] = -2; 58 | dy[1] = 1; 59 | dx[2] = 2; 60 | dy[2] = -1; 61 | dx[3] = 2; 62 | dy[3] = 1; 63 | dx[4] = -1; 64 | dy[4] = -2; 65 | dx[5] = -1; 66 | dy[5] = 2; 67 | dx[6] = 1; 68 | dy[6] = -2; 69 | dx[7] = 1; 70 | dy[7] = 2; 71 | while (head <= tail) { 72 | x = xlist[head]; 73 | y = ylist[head]; 74 | now = step[x][y]; 75 | for (j = 0; j < 8; j++) 76 | addList(x + dx[j], y + dy[j]); 77 | if (ok == 1) 78 | break; 79 | head++; 80 | } 81 | if (ok == 1) 82 | printf("%d\n", step[targetx][targety]); 83 | else 84 | printf("no solution!\n"); 85 | return 0; 86 | } 87 | 88 | // clang-format off 89 | /*!! metadata: 90 | === comment === 91 | horse3-5100309153-yanghuan.mx 92 | === input === 93 | 103 94 | === assert === 95 | output 96 | === timeout === 97 | 0.4 98 | === output === 99 | 67 100 | === phase === 101 | codegen pretest 102 | === is_public === 103 | True 104 | 105 | !!*/ 106 | 107 | -------------------------------------------------------------------------------- /test/c/mx/humble.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // USACO 3.1.3 humble 5 | int MAXK = 105; 6 | int MAXN = 100005; 7 | 8 | int main() { 9 | int point = 0; 10 | int k; 11 | int MIN; 12 | int K; 13 | int N; 14 | int i; 15 | int *primes = malloc(sizeof(int) * MAXK); 16 | int *pindex = malloc(sizeof(int) * MAXK); 17 | int *ans = malloc(sizeof(int) * MAXN); 18 | scanf("%d%d", &K, &N); 19 | for (i = 0; i < K; ++i) { 20 | scanf("%d", &primes[i]); 21 | pindex[i] = 0; 22 | } 23 | ans[0] = 1; 24 | while (point <= N) { 25 | MIN = 2139062143; 26 | for (i = 0; i < K; ++i) { 27 | while (ans[point] >= primes[i] * ans[pindex[i]]) 28 | pindex[i]++; 29 | if (primes[i] * ans[pindex[i]] < MIN) { 30 | MIN = primes[i] * ans[pindex[i]]; 31 | k = i; 32 | } 33 | } 34 | ans[++point] = MIN; 35 | } 36 | printf("%d\n", ans[N]); 37 | return 0; 38 | } 39 | 40 | /*!! metadata: 41 | === comment === 42 | humble-5140519064-yurongyou.txt 43 | === is_public === 44 | True 45 | === assert === 46 | output 47 | === timeout === 48 | 1.0 49 | === input === 50 | 100 100000 51 | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 52 | 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 53 | 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 54 | 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 55 | 457 461 463 467 479 487 491 499 503 509 521 523 541 56 | === phase === 57 | codegen extended 58 | === output === 59 | 284456 60 | === exitcode === 61 | 62 | 63 | !!*/ 64 | -------------------------------------------------------------------------------- /test/c/mx/magic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define N 3 5 | 6 | int make[N][N]; 7 | int color[10]; 8 | int count[1]; 9 | int i; 10 | int j; 11 | 12 | void origin() { 13 | for (i = 0; i < N; i++) { 14 | for (j = 0; j < N; j++) 15 | make[i][j] = 0; 16 | } 17 | } 18 | 19 | int search(int x, int y, int z) { 20 | int s; 21 | int i; 22 | int j; 23 | if ((y > 0 || y < 0) || x == 0 || 24 | make[x - 1][0] + make[x - 1][1] + make[x - 1][2] == 15) { 25 | if (x == 2 && y == 2) { 26 | make[2][2] = 45 - z; 27 | s = make[0][0] + make[0][1] + make[0][2]; 28 | if (make[1][0] + make[1][1] + make[1][2] == s && 29 | make[2][0] + make[2][1] + make[2][2] == s && 30 | make[0][0] + make[1][0] + make[2][0] == s && 31 | make[0][1] + make[1][1] + make[2][1] == s && 32 | make[0][2] + make[1][2] + make[2][2] == s && 33 | make[0][0] + make[1][1] + make[2][2] == s && 34 | make[2][0] + make[1][1] + make[0][2] == s) { 35 | count[0] = count[0] + 1; 36 | for (i = 0; i <= 2; i++) { 37 | for (j = 0; j <= 2; j++) { 38 | printf("%d", make[i][j]); 39 | printf(" "); 40 | } 41 | printf("\n"); 42 | } 43 | printf("\n"); 44 | } 45 | } else { 46 | if (y == 2) { 47 | make[x][y] = 15 - make[x][0] - make[x][1]; 48 | if (make[x][y] > 0 && make[x][y] < 10 && color[make[x][y]] == 0) { 49 | color[make[x][y]] = 1; 50 | if (y == 2) 51 | search(x + 1, 0, z + make[x][y]); 52 | else 53 | search(x, y + 1, z + make[x][y]); 54 | color[make[x][y]] = 0; 55 | } 56 | } else { 57 | for (i = 1; i <= 9; i++) { 58 | if (color[i] == 0) { 59 | color[i] = 1; 60 | make[x][y] = i; 61 | if (y == 2) 62 | search(x + 1, 0, z + i); 63 | else 64 | search(x, y + 1, z + i); 65 | make[x][y] = 0; 66 | color[i] = 0; 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | int main() { 75 | count[0] = 0; 76 | origin(); 77 | search(0, 0, 0); 78 | printf("%d", count[0]); 79 | return 0; 80 | } 81 | 82 | /*!! metadata: 83 | === comment === 84 | magic-5100309153-yanghuan.mx 85 | === input === 86 | 87 | === assert === 88 | output 89 | === timeout === 90 | 0.1 91 | === output === 92 | 2 7 6 93 | 9 5 1 94 | 4 3 8 95 | 96 | 2 9 4 97 | 7 5 3 98 | 6 1 8 99 | 100 | 4 3 8 101 | 9 5 1 102 | 2 7 6 103 | 104 | 4 9 2 105 | 3 5 7 106 | 8 1 6 107 | 108 | 6 1 8 109 | 7 5 3 110 | 2 9 4 111 | 112 | 6 7 2 113 | 1 5 9 114 | 8 3 4 115 | 116 | 8 1 6 117 | 3 5 7 118 | 4 9 2 119 | 120 | 8 3 4 121 | 1 5 9 122 | 6 7 2 123 | 124 | 8 125 | === phase === 126 | codegen pretest 127 | === is_public === 128 | True 129 | 130 | !!*/ 131 | -------------------------------------------------------------------------------- /test/c/mx/tak.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int tak(int x, int y, int z) { 4 | if (y < x) 5 | return 1 + tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y)); 6 | else 7 | return z; 8 | } 9 | 10 | int main() { 11 | int a; 12 | int b; 13 | int c; 14 | scanf("%d", &a); 15 | scanf("%d", &b); 16 | scanf("%d", &c); 17 | printf("%d\n", tak(a, b, c)); 18 | return 0; 19 | } 20 | 21 | /*!! metadata: 22 | === comment === 23 | tak-5090379042-jiaxiao.mx 24 | === input === 25 | 18 26 | 12 27 | 6 28 | === assert === 29 | output 30 | === timeout === 31 | 0.1 32 | === output === 33 | 13 34 | === phase === 35 | codegen pretest 36 | === is_public === 37 | True 38 | 39 | !!*/ 40 | -------------------------------------------------------------------------------- /test/c/oj/1003.c: -------------------------------------------------------------------------------- 1 | // https://acm.sjtu.edu.cn/OnlineJudge/problem/1003 2 | 3 | #include 4 | 5 | int l; 6 | int dish[100][100]; 7 | 8 | int isFinished() { 9 | for (int i = 0; i < l; ++i) { 10 | for (int j = 0; j < l; ++j) { 11 | if (!dish[i][j]) 12 | return 0; 13 | } 14 | } 15 | return 1; 16 | } 17 | 18 | void step() { 19 | int kx[4] = {1, -1, 0, 0}; 20 | int ky[4] = {0, 0, 1, -1}; 21 | 22 | for (int i = 0; i < l; ++i) { 23 | for (int j = 0; j < l; ++j) { 24 | if (dish[i][j] != 1) 25 | continue; 26 | for (int k = 0; k < 4; ++k) { 27 | int nx = i + kx[k], ny = j + ky[k]; 28 | if (nx < 0 || ny < 0 || nx == l || ny == l) 29 | continue; 30 | if (dish[nx][ny] == 0) 31 | dish[nx][ny] = -1; 32 | } 33 | } 34 | } 35 | 36 | for (int i = 0; i < l; ++i) { 37 | for (int j = 0; j < l; ++j) { 38 | if (dish[i][j] == -1) 39 | dish[i][j] = 1; 40 | } 41 | } 42 | } 43 | 44 | int main() { 45 | scanf("%d", &l); 46 | 47 | for (int i = 0; i < l; ++i) { 48 | for (int j = 0; j < l; ++j) { 49 | scanf("%d", &dish[i][j]); 50 | } 51 | } 52 | 53 | int rounds = 0; 54 | while (!isFinished()) { 55 | step(); 56 | ++rounds; 57 | } 58 | 59 | printf("%d\n", rounds); 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /test/c/sorting/bubble_sort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void bubble_sort(int *a, int n) { 5 | for (int i = 0; i < n - 1; ++i) { 6 | for (int j = 0; j < n - i - 1; ++j) { 7 | if (a[j] > a[j + 1]) { 8 | int t = a[j]; 9 | a[j] = a[j + 1]; 10 | a[j + 1] = t; 11 | } 12 | } 13 | } 14 | } 15 | 16 | int main() { 17 | int n; 18 | scanf("%d", &n); 19 | int *a = malloc(sizeof(int) * n); 20 | for (int i = 0; i < n; ++i) 21 | scanf("%d", &a[i]); 22 | 23 | bubble_sort(a, n); 24 | 25 | for (int i = 0; i < n; ++i) 26 | printf("%d ", a[i]); 27 | printf("\n"); 28 | 29 | free(a); 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /test/c/sorting/merge_sort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const size_t int_sz = sizeof(int); 6 | 7 | void merge(int *buffer, int *l, size_t l_size, int *r, size_t r_size) { 8 | if (l_size == 0) { 9 | memcpy(buffer, r, r_size * int_sz); 10 | return; 11 | } 12 | if (r_size == 0) { 13 | memcpy(buffer, l, l_size * int_sz); 14 | return; 15 | } 16 | if (*l < *r) { 17 | *buffer = *l; 18 | merge(buffer + 1, l + 1, l_size - 1, r, r_size); 19 | return; 20 | } 21 | *buffer = *r; 22 | merge(buffer + 1, l, l_size, r + 1, r_size - 1); 23 | } 24 | 25 | void merge_sort(int *a, size_t n) { 26 | if (n == 1) 27 | return; 28 | size_t m = n / 2; 29 | merge_sort(a, m); 30 | merge_sort(a + m, n - m); 31 | int *buffer = malloc(sizeof(int) * n); 32 | merge(buffer, a, m, a + m, n - m); 33 | memcpy(a, buffer, n * int_sz); 34 | free(buffer); 35 | } 36 | 37 | int main() { 38 | int n; 39 | scanf("%d", &n); 40 | int *a = malloc(sizeof(int) * n); 41 | for (int i = 0; i < n; ++i) 42 | scanf("%d", &a[i]); 43 | 44 | merge_sort(a, n); 45 | 46 | for (int i = 0; i < n; ++i) 47 | printf("%d ", a[i]); 48 | printf("\n"); 49 | 50 | free(a); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /test/c/sorting/quick_sort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void swap(int *a, int *b) { 5 | int t = *a; 6 | *a = *b; 7 | *b = t; 8 | } 9 | 10 | int partition(int *a, int p, int r) { 11 | int pivot = a[r]; 12 | int i = p - 1; 13 | for (int j = p; j < r; ++j) { 14 | if (a[j] <= pivot) { 15 | ++i; 16 | swap(a + i, a + j); 17 | } 18 | } 19 | swap(a + i + 1, a + r); 20 | return i + 1; 21 | } 22 | 23 | void quick_sort(int *a, int p, int r) { 24 | if (p >= r) 25 | return; 26 | int q = partition(a, p, r); 27 | quick_sort(a, p, q - 1); 28 | quick_sort(a, q + 1, r); 29 | } 30 | 31 | int main() { 32 | int n; 33 | scanf("%d", &n); 34 | int *a = malloc(sizeof(int) * n); 35 | for (int i = 0; i < n; ++i) 36 | scanf("%d", &a[i]); 37 | 38 | quick_sort(a, 0, n - 1); 39 | 40 | for (int i = 0; i < n; ++i) 41 | printf("%d ", a[i]); 42 | printf("\n"); 43 | 44 | free(a); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /test/c/sorting/selection_sort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void selection_sort(int *a, int n) { 6 | for (int i = 0; i < n - 1; ++i) { 7 | int min_pos = i; 8 | for (int j = i + 1; j < n; ++j) { 9 | if (a[j] < a[min_pos]) 10 | min_pos = j; 11 | } 12 | int t = a[i]; 13 | a[i] = a[min_pos]; 14 | a[min_pos] = t; 15 | } 16 | } 17 | 18 | int main() { 19 | int n; 20 | scanf("%d", &n); 21 | int *a = malloc(sizeof(int) * n); 22 | for (int i = 0; i < n; ++i) 23 | scanf("%d", &a[i]); 24 | 25 | selection_sort(a, n); 26 | 27 | for (int i = 0; i < n; ++i) 28 | printf("%d ", a[i]); 29 | printf("\n"); 30 | 31 | free(a); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /test/c/sorting/sorting.in: -------------------------------------------------------------------------------- 1 | 100 2 | 58 18 71 22 37 93 47 50 3 9 53 95 45 14 74 48 44 20 12 73 29 10 19 28 87 20 27 85 56 87 18 11 55 15 19 10 69 69 29 70 96 69 53 10 30 87 73 26 21 95 19 24 3 25 10 9 67 25 79 41 10 9 48 96 11 44 69 62 47 31 64 21 50 31 11 34 15 51 4 65 71 55 92 49 8 26 27 36 96 4 77 47 4 2 66 41 15 78 7 56 3 | -------------------------------------------------------------------------------- /test/c/sorting/sorting.out: -------------------------------------------------------------------------------- 1 | 2 3 3 4 4 4 7 8 9 9 9 10 10 10 10 10 11 11 11 12 14 15 15 15 18 18 19 19 19 20 20 21 21 22 24 25 25 26 26 27 27 28 29 29 30 31 31 34 36 37 41 41 44 44 45 47 47 47 48 48 49 50 50 51 53 53 55 55 56 56 58 62 64 65 66 67 69 69 69 69 70 71 71 73 73 74 77 78 79 85 87 87 87 92 93 95 95 96 96 96 -------------------------------------------------------------------------------- /test/optim/binary_tree.ans: -------------------------------------------------------------------------------- 1 | 0: 4 2 | 1: 4 3 | 2: 6 4 | 3: 4 5 | 4: 4 6 | 6: 2 7 | 7: 3 8 | 8: 2 9 | 10: 1 10 | 11: 4 11 | 13: 2 12 | 14: 6 13 | 15: 2 14 | 18: 4 15 | 19: 3 16 | 20: 1 17 | 21: 5 18 | 22: 1 19 | 24: 3 20 | 25: 3 21 | 26: 2 22 | 27: 2 23 | 30: 5 24 | 33: 16 25 | 35: 2 26 | 36: 1 27 | 39: 4 28 | 40: 1 29 | 41: 8 30 | 42: 7 31 | 43: 2 32 | 44: 2 33 | 46: 5 34 | 47: 1 35 | 48: 2 36 | 51: 2 37 | 55: 5 38 | 57: 2 39 | 60: 1 40 | 63: 2 41 | 64: 1 42 | 65: 2 43 | 66: 2 44 | 67: 2 45 | 68: 1 46 | 69: 1 47 | 75: 1 48 | 76: 2 49 | 77: 2 50 | 78: 1 51 | 80: 4 52 | 81: 5 53 | 82: 2 54 | 83: 1 55 | 84: 2 56 | 86: 4 57 | 87: 2 58 | 89: 5 59 | 90: 6 60 | 91: 4 61 | 92: 6 62 | 93: 1 63 | 94: 1 64 | 97: 5 65 | 99: 1 66 | 102: 1 67 | 105: 1 68 | 106: 2 69 | 107: 5 70 | 108: 2 71 | 109: 5 72 | 111: 3 73 | 112: 7 74 | 115: 2 75 | 116: 5 76 | 117: 2 77 | 118: 1 78 | 119: 1 79 | 120: 3 80 | 121: 3 81 | 122: 8 82 | 126: 2 83 | 127: 1 84 | -------------------------------------------------------------------------------- /test/optim/binary_tree.c: -------------------------------------------------------------------------------- 1 | // By Yunwei Ren, ACM 2017 2 | // binary search tree 3 | // 4 | 5 | #include 6 | #include 7 | //#include 8 | 9 | struct Node { 10 | struct Node *pnt; 11 | struct Node **children; 12 | int key; 13 | int duplicate; 14 | }; 15 | 16 | struct Node *constructNode(int key, struct Node *pnt, struct Node *lchild, 17 | struct Node *rchild) { 18 | struct Node *node = malloc(sizeof(struct Node)); 19 | node->children = malloc(sizeof(struct Node *) * 2); 20 | node->key = key; 21 | node->duplicate = 1; 22 | node->pnt = pnt; 23 | node->children[0] = lchild; 24 | node->children[1] = rchild; 25 | return node; 26 | } 27 | 28 | struct Node *root = NULL; 29 | 30 | int insertImpl(struct Node *cur, struct Node *pnt, int childId, int key) { 31 | if (cur == NULL) { 32 | cur = constructNode(key, pnt, NULL, NULL); 33 | pnt->children[childId] = cur; 34 | return 0; 35 | } 36 | if (cur->key == key) { 37 | ++cur->duplicate; 38 | return 1; 39 | } 40 | int id = 0; 41 | if (cur->key < key) 42 | id = 1; 43 | return insertImpl(cur->children[id], cur, id, key); 44 | } 45 | 46 | // return 1 if isIn 47 | int insert(int key) { 48 | if (root != NULL) 49 | return insertImpl(root, NULL, -1, key); 50 | root = constructNode(key, NULL, NULL, NULL); 51 | return 0; 52 | } 53 | 54 | struct Node *findLargest(struct Node *cur) { 55 | if (cur->children[1] == NULL) 56 | return cur; 57 | return findLargest(cur->children[1]); 58 | } 59 | 60 | int eraseImpl(struct Node *cur, struct Node *pnt, int childId, int key) { 61 | if (cur == NULL) 62 | return 0; 63 | if (cur->key > key) 64 | return eraseImpl(cur->children[0], cur, 0, key); 65 | if (cur->key < key) 66 | return eraseImpl(cur->children[1], cur, 1, key); 67 | --cur->duplicate; 68 | if (cur->duplicate > 0) 69 | return 1; 70 | // assert(cur->duplicate == 0); 71 | if (cur->children[0] == NULL) { 72 | if (pnt != NULL) 73 | pnt->children[childId] = cur->children[1]; 74 | if (cur->children[1] != NULL) 75 | cur->children[1]->pnt = pnt; 76 | if (key == root->key) 77 | root = cur->children[1]; 78 | return 1; 79 | } 80 | struct Node *replacement = findLargest(cur->children[0]); 81 | if (key == root->key) 82 | root = replacement; 83 | // assert(replacement->children[1] == NULL); 84 | if (replacement->key != cur->children[0]->key) { 85 | replacement->pnt->children[1] = replacement->children[0]; 86 | if (replacement->children[0] != NULL) 87 | replacement->children[0]->pnt = replacement->pnt; 88 | } 89 | if (pnt != NULL) 90 | pnt->children[childId] = replacement; 91 | replacement->pnt = pnt; 92 | replacement->children[1] = cur->children[1]; 93 | if (cur->children[1] != NULL) 94 | cur->children[1]->pnt = replacement; 95 | if (replacement->key != cur->children[0]->key) { 96 | replacement->children[0] = cur->children[0]; 97 | cur->children[0]->pnt = replacement; 98 | } 99 | return 1; 100 | } 101 | 102 | // return 1 if isIn 103 | int erase(int key) { 104 | if (root == NULL) 105 | return 0; 106 | return eraseImpl(root, NULL, -1, key); 107 | } 108 | 109 | void printTree(struct Node *cur) { 110 | if (cur == NULL) 111 | return; 112 | printTree(cur->children[0]); 113 | printf("%d: %d\n", cur->key, cur->duplicate); 114 | printTree(cur->children[1]); 115 | } 116 | 117 | int MAX = 128; 118 | int MaxRandInt = ~(1 << 31); 119 | int seed; 120 | 121 | // In mx, we do not have unsigned int. Hence, we only use the least 122 | // 31 bits of an integer here. 123 | int randInt31() { 124 | int x = seed; 125 | x = x ^ (x << 13); 126 | x &= ~(1 << 31); 127 | x = x ^ (x >> 17); 128 | x = x ^ (x << 5); 129 | x &= ~(1 << 31); 130 | seed = x; 131 | return x; 132 | } 133 | 134 | // probability = p / PM 135 | int randOp(int n) { 136 | if (randInt31() < n) { 137 | return 1; 138 | } 139 | return 2; 140 | } 141 | 142 | void generateOperations(int n, int t) { 143 | int i; 144 | for (i = 0; i < t; ++i) { 145 | int value = randInt31() % MAX; 146 | if (randOp(n) == 1) { 147 | insert(value); 148 | } else { 149 | erase(value); 150 | } 151 | } 152 | } 153 | 154 | int main() { 155 | scanf("%d", &seed); 156 | int m = 50000; 157 | generateOperations(8 * (MaxRandInt / 10), m); 158 | generateOperations(2 * (MaxRandInt / 10), 2 * m); 159 | generateOperations(4 * (MaxRandInt / 10), m); 160 | printTree(root); 161 | return 0; 162 | } -------------------------------------------------------------------------------- /test/optim/binary_tree.in: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /test/optim/dijkstra.ans: -------------------------------------------------------------------------------- 1 | 0 50 23 22 13 36 26 41 50 28 39 20 29 25 30 29 29 11 29 26 42 37 13 40 7 33 13 35 26 22 19 26 29 26 31 25 23 27 37 35 30 26 11 44 45 24 33 24 36 27 44 43 35 27 23 34 26 35 31 43 56 38 35 49 43 26 15 40 30 34 30 29 45 18 32 25 41 33 30 18 42 28 36 37 24 35 18 25 39 22 43 38 26 20 12 31 35 34 39 2 2 | 29 0 20 20 21 16 20 21 38 19 51 10 13 16 14 6 22 20 21 21 41 28 4 29 19 14 25 24 15 31 27 16 26 32 32 28 22 27 15 19 20 32 23 30 31 24 13 24 28 18 35 30 11 18 18 36 17 25 39 26 39 28 16 27 27 17 27 21 36 15 30 18 36 30 23 1 40 9 27 30 28 23 36 26 16 26 28 15 29 27 42 47 16 17 21 22 30 25 27 14 3 | 50 78 0 68 50 57 55 60 57 40 73 62 50 62 51 51 54 50 61 48 68 58 12 53 44 58 50 61 55 61 35 66 60 62 69 56 39 65 55 56 70 47 61 67 50 61 54 63 57 48 65 71 51 48 58 55 47 74 52 53 83 44 56 72 62 51 63 48 58 58 68 51 44 39 53 41 62 49 55 62 48 50 70 58 56 47 24 36 54 55 62 76 56 45 51 56 57 58 51 52 4 | 41 52 17 0 24 44 4 45 38 14 60 36 15 11 16 22 38 23 28 28 48 23 19 27 33 34 39 37 26 28 42 41 39 27 37 30 35 33 23 32 37 35 28 32 31 50 42 30 35 13 30 44 22 13 26 31 12 39 47 34 49 34 36 50 36 12 34 40 31 35 34 32 38 44 18 12 30 20 37 27 28 31 31 32 23 21 33 31 43 29 37 50 27 33 18 17 37 20 25 30 5 | 31 49 22 31 0 35 35 35 37 20 47 33 21 17 22 28 36 3 21 18 34 29 5 33 31 21 37 27 13 14 28 39 21 33 23 17 29 19 29 22 34 33 33 36 37 43 32 16 28 19 36 49 28 19 15 21 18 45 45 33 46 40 23 37 35 18 24 28 37 22 22 21 37 32 24 18 44 26 37 33 34 20 37 29 16 27 39 29 47 21 42 30 14 27 4 23 27 26 31 33 6 | 37 41 25 20 15 0 20 5 37 29 41 28 24 26 25 31 22 18 36 27 39 38 18 35 9 24 15 8 25 27 21 21 10 16 16 28 24 32 22 3 38 28 28 41 30 24 13 29 31 20 30 14 21 28 25 30 27 30 33 24 49 46 26 37 24 27 13 31 20 25 35 16 50 20 33 27 25 19 32 31 27 15 30 24 31 36 28 23 34 13 34 34 17 22 17 16 27 19 37 39 7 | 37 48 13 29 20 40 0 41 34 10 56 32 11 7 12 18 34 19 24 24 44 19 15 23 29 30 35 33 22 24 38 37 35 23 33 26 31 29 19 28 33 31 24 28 27 46 38 26 31 9 26 40 18 9 22 27 8 35 43 30 45 30 32 46 32 8 30 36 27 31 30 28 34 40 14 8 26 16 33 23 24 27 27 28 19 17 29 27 39 25 33 46 23 29 14 13 33 16 21 26 8 | 39 52 30 33 26 38 30 0 32 27 54 38 19 25 20 26 41 17 32 22 42 37 13 30 27 28 33 31 20 22 36 44 33 39 12 31 36 27 17 26 38 41 28 36 25 40 36 24 36 20 26 52 16 26 20 25 26 45 41 40 53 44 30 44 43 25 36 35 42 29 30 26 45 38 32 26 34 14 41 27 22 25 25 34 27 31 43 35 55 33 48 44 21 32 12 11 31 14 32 34 9 | 25 46 25 36 28 33 28 28 0 26 53 25 4 23 5 11 31 16 17 29 36 33 12 31 22 9 28 25 1 20 34 31 27 30 33 14 17 25 24 20 35 39 25 21 26 39 30 22 23 18 32 43 20 25 27 32 24 40 45 21 34 43 11 25 32 24 29 16 34 10 23 13 44 33 30 18 41 18 26 33 23 20 32 21 12 33 34 20 44 18 33 43 2 22 17 18 38 21 34 19 10 | 37 38 28 41 21 36 28 38 32 0 48 22 17 23 18 24 39 24 30 21 49 35 26 13 25 23 31 28 15 32 37 27 38 38 44 16 21 26 15 31 32 29 22 34 25 42 33 24 35 16 41 50 11 24 18 34 24 36 35 35 48 22 25 39 22 24 36 30 18 24 29 24 50 36 30 24 44 9 39 33 22 23 43 18 25 7 19 33 40 31 23 51 16 30 25 29 30 32 11 32 11 | 44 70 36 46 26 43 36 33 38 33 0 46 38 43 39 35 16 29 31 42 41 46 31 12 20 30 26 40 22 40 32 44 47 51 45 35 22 45 36 41 53 37 46 48 31 37 45 42 36 15 53 57 33 45 39 47 44 41 41 26 51 55 16 46 48 31 39 21 48 31 48 34 63 31 50 39 52 42 43 46 28 41 50 42 26 40 39 44 32 44 40 54 23 33 30 36 31 39 44 38 12 | 32 55 15 32 18 36 31 39 42 25 49 0 17 27 18 21 21 18 19 25 38 32 20 33 17 20 23 28 12 29 29 6 36 36 38 25 25 31 19 29 10 22 21 34 37 34 33 28 26 22 39 34 15 22 22 30 21 15 41 23 45 18 22 36 42 28 25 27 40 21 34 24 47 28 27 5 37 13 22 28 34 24 44 32 14 32 33 30 19 31 45 41 13 12 19 33 34 32 31 12 13 | 26 42 21 32 26 30 34 31 44 29 52 33 0 26 1 7 27 12 13 27 43 30 10 36 20 20 26 22 33 23 32 33 30 26 32 26 28 28 35 25 43 39 24 17 37 37 27 25 20 28 45 39 31 28 24 46 27 42 41 32 45 41 22 41 28 27 25 27 30 21 19 21 42 31 32 27 39 35 22 30 34 24 44 29 8 36 41 16 46 14 29 39 18 18 13 32 36 35 34 15 14 | 30 41 6 22 13 33 25 34 27 3 49 25 4 0 5 11 27 12 17 17 37 12 8 16 22 23 28 26 15 17 31 30 28 16 26 19 24 22 12 21 26 24 17 21 20 39 31 19 24 2 19 33 11 2 15 20 1 28 36 23 38 23 25 39 25 1 23 29 20 24 23 21 27 33 7 1 29 9 26 16 17 20 20 21 12 10 22 20 32 18 26 39 16 22 7 6 26 9 14 19 15 | 40 41 42 31 32 32 35 30 45 41 53 40 40 38 0 47 54 35 39 46 51 48 33 35 37 24 43 40 42 35 49 32 42 25 42 49 32 40 40 35 50 40 39 16 41 54 45 37 46 33 55 38 38 38 43 53 37 41 40 36 49 58 26 40 42 39 24 31 29 25 43 28 63 48 43 33 54 41 21 38 38 35 48 36 34 48 49 34 45 13 28 38 17 48 32 41 55 44 33 42 16 | 23 56 14 28 19 42 30 47 45 38 45 43 39 35 40 0 20 22 35 37 52 30 24 46 13 32 19 42 26 32 25 48 26 32 42 31 29 37 42 37 39 32 17 48 49 30 39 34 40 22 49 49 38 37 34 40 36 48 37 43 57 41 34 45 21 36 21 39 36 33 39 36 56 24 25 28 47 36 21 24 46 36 42 44 30 45 34 9 58 28 44 49 27 11 23 41 35 44 49 8 17 | 28 54 33 42 24 27 33 32 38 31 49 30 27 28 25 25 0 14 15 29 41 30 16 36 27 14 33 24 6 25 39 28 32 35 34 19 22 30 32 25 40 44 30 41 31 40 29 27 20 23 37 41 28 30 26 45 29 37 36 26 39 41 16 30 46 29 35 21 39 15 33 18 48 38 35 23 41 31 46 30 28 25 38 26 10 38 39 31 41 32 24 41 7 36 15 34 15 37 39 30 18 | 28 46 19 28 23 32 32 32 41 17 44 30 18 14 19 25 33 0 18 15 31 26 2 30 34 25 40 24 29 11 25 36 18 30 20 14 29 16 26 25 31 30 30 33 34 40 29 13 25 16 33 46 25 16 12 34 15 42 42 37 50 37 27 39 32 15 21 32 34 26 19 18 34 29 21 15 41 23 34 30 31 17 34 26 13 24 36 26 44 18 39 27 22 24 1 20 24 23 28 30 19 | 13 50 27 29 26 17 21 22 48 31 52 24 28 28 29 33 22 24 0 32 48 40 19 43 20 33 26 9 26 28 32 22 19 25 25 38 33 33 26 12 34 38 24 45 41 25 14 30 35 21 39 31 22 30 29 41 29 31 44 39 57 42 35 30 33 29 22 40 29 34 36 12 51 31 35 29 26 36 34 31 38 11 41 20 32 38 29 32 35 22 43 43 26 24 18 27 36 30 41 15 20 | 26 43 18 30 25 21 25 26 27 5 49 26 16 22 17 23 38 14 29 0 37 24 10 18 23 10 29 26 20 19 33 32 28 28 34 21 18 24 14 21 28 34 25 33 20 40 31 21 14 14 31 35 16 14 17 22 13 40 38 22 35 27 12 37 27 3 29 17 23 11 27 14 39 34 19 19 31 14 38 24 17 21 22 22 24 12 24 25 34 30 28 41 21 29 9 8 9 11 16 28 21 | 34 46 22 22 16 22 26 27 33 21 44 8 12 18 13 19 28 19 25 16 0 30 21 26 20 18 26 14 10 27 32 14 24 30 30 23 26 22 10 17 18 20 8 7 35 30 19 19 21 20 36 29 6 19 13 37 19 23 25 30 43 26 20 34 35 19 15 25 34 19 25 19 45 12 25 13 31 21 30 28 32 18 38 4 20 28 34 25 27 26 19 46 11 20 20 24 25 27 24 20 22 | 37 48 13 29 20 30 32 35 34 10 56 30 11 7 12 18 34 19 24 24 44 0 15 23 29 30 35 29 22 24 38 36 31 23 33 26 31 29 19 24 33 21 24 28 27 45 34 26 24 9 26 21 18 9 22 23 8 35 43 30 45 11 32 39 32 8 30 36 27 31 30 18 34 40 14 8 36 16 33 23 24 17 27 26 19 17 29 27 39 25 33 46 23 29 14 13 33 16 21 26 23 | 38 71 36 58 38 45 43 48 45 34 61 56 41 50 42 42 42 38 49 36 56 60 0 44 32 46 38 49 43 49 23 61 48 53 57 50 27 53 43 44 58 35 49 58 38 49 42 51 50 47 64 59 39 50 46 43 49 65 40 41 71 56 44 63 56 39 51 36 52 46 56 47 32 27 55 29 50 37 43 56 36 51 58 52 44 41 44 24 42 43 57 64 44 33 39 44 45 47 45 40 24 | 40 58 42 46 42 48 43 42 45 21 61 40 32 37 33 39 54 29 45 35 39 49 23 0 36 24 42 40 36 34 46 46 42 47 48 37 31 39 30 35 44 25 40 46 38 48 45 36 45 3 41 62 32 39 33 38 38 29 29 24 39 43 26 57 43 19 45 30 39 25 42 28 55 47 44 33 40 30 54 42 35 35 38 36 40 28 40 47 50 32 44 53 36 45 24 24 40 27 32 42 25 | 37 55 16 37 6 29 31 34 43 26 32 36 27 23 28 22 22 9 27 24 40 35 11 33 0 27 6 33 19 20 12 42 27 39 29 23 16 25 35 28 40 19 36 42 43 17 26 22 34 25 42 43 34 25 21 27 24 49 24 39 52 46 29 43 41 24 30 34 43 28 28 24 43 11 30 24 34 32 23 39 40 23 43 32 22 33 21 31 53 27 46 36 20 13 10 29 33 32 37 30 26 | 16 49 27 28 19 24 19 19 24 18 45 16 20 23 11 27 30 22 29 24 27 35 23 22 13 0 19 16 18 32 25 22 18 24 24 31 8 30 18 11 26 32 16 27 17 30 21 27 29 25 38 38 14 24 21 35 24 31 37 12 25 34 2 33 32 16 21 7 28 1 33 4 41 24 30 9 33 17 32 34 14 11 24 12 24 25 25 31 35 21 39 41 19 24 22 21 33 24 29 18 27 | 41 49 17 42 38 23 25 28 49 31 26 30 34 32 35 36 29 39 44 38 50 44 28 35 32 25 0 30 17 30 42 36 32 36 38 30 33 35 32 25 40 13 30 51 42 11 20 32 36 27 48 37 28 34 35 47 33 43 18 37 50 42 27 39 46 33 35 32 38 26 38 18 59 5 39 33 28 40 40 46 39 17 47 26 39 27 15 45 49 21 42 56 18 30 28 33 40 36 42 42 28 | 37 41 22 20 23 8 12 13 39 22 49 28 23 19 24 29 14 24 29 29 39 31 20 35 17 24 23 0 20 19 27 13 10 16 16 33 24 24 24 3 38 29 28 40 32 16 5 21 26 12 30 22 26 21 27 32 20 22 41 30 48 42 26 37 24 20 13 31 20 25 27 16 46 28 26 20 17 27 38 31 29 15 32 24 24 29 20 23 26 13 34 34 17 28 19 18 27 21 33 37 29 | 24 48 27 36 27 32 27 27 32 25 52 24 26 22 19 19 38 30 32 30 35 32 11 30 21 8 27 24 0 19 33 30 26 29 32 13 16 24 26 19 34 38 24 35 25 38 29 21 22 17 31 46 22 24 27 42 23 39 45 20 33 42 10 24 40 23 29 15 33 9 27 12 43 32 29 17 41 25 40 32 22 19 32 20 32 32 33 28 43 29 47 49 1 30 16 28 39 31 33 26 30 | 20 44 8 25 16 21 25 26 30 6 33 28 7 3 8 14 27 15 20 20 20 15 11 19 25 16 31 13 18 0 34 26 21 19 27 22 24 5 15 14 29 19 20 22 23 29 18 2 27 5 22 35 14 5 18 23 4 31 39 26 41 26 18 39 28 4 24 23 23 17 8 18 30 32 10 4 30 12 29 19 20 17 23 24 15 13 25 23 35 21 29 30 19 25 10 9 29 12 17 22 31 | 45 48 25 38 15 22 26 27 36 35 41 36 36 32 37 31 28 18 36 33 46 44 20 21 9 29 15 26 26 29 0 39 28 34 34 32 4 30 38 21 35 12 29 51 36 26 19 31 35 24 48 36 34 34 30 20 33 42 17 31 54 41 21 40 42 33 31 26 37 30 33 24 52 4 39 33 27 41 32 36 33 31 46 32 31 26 21 40 52 20 41 45 24 22 19 32 39 35 46 20 32 | 39 59 30 44 30 44 46 40 50 28 56 38 19 27 20 16 36 31 32 23 32 39 29 27 24 33 30 38 40 33 36 0 40 40 46 35 19 29 17 33 39 16 33 36 43 41 43 26 37 29 43 57 36 26 20 45 28 9 41 17 58 45 30 47 37 26 37 35 41 34 32 26 54 35 34 28 31 36 37 40 40 25 45 34 27 30 27 25 13 33 48 35 37 27 32 31 32 34 32 24 33 | 27 31 27 10 25 24 14 29 35 22 49 30 25 21 25 32 41 28 38 36 41 32 27 31 19 14 25 30 32 25 31 28 0 35 38 24 14 30 31 25 40 28 30 41 31 36 35 27 22 15 40 38 28 23 34 39 22 37 31 26 39 43 16 30 14 20 3 21 17 15 33 18 48 30 28 22 33 30 42 32 28 25 38 26 33 29 31 13 32 3 24 54 7 32 26 25 17 28 33 29 34 | 34 54 17 33 24 38 37 18 41 16 50 26 15 20 16 22 38 26 28 21 37 23 8 29 35 31 41 30 31 17 31 32 38 0 30 32 35 22 26 31 36 15 28 32 34 46 35 19 35 13 30 17 27 13 18 40 12 39 48 27 49 34 33 45 38 21 34 38 4 32 25 24 38 35 18 21 30 25 37 27 31 23 40 32 23 23 35 31 45 29 39 47 32 30 7 26 30 23 27 30 35 | 39 55 30 38 38 34 31 39 40 17 62 26 28 34 29 35 30 26 41 13 50 35 15 30 36 23 42 38 32 31 38 32 40 33 0 33 31 36 26 33 36 46 16 45 33 28 43 33 27 27 14 48 28 27 28 34 26 33 50 35 48 39 25 50 39 15 42 30 35 24 39 26 47 42 30 31 43 26 48 15 30 33 33 34 36 24 32 38 45 42 40 53 33 38 21 20 22 23 28 38 36 | 21 47 44 43 34 57 45 56 60 43 60 41 44 46 45 50 47 32 50 39 57 58 34 22 28 46 34 54 42 43 40 47 50 47 52 0 44 48 45 49 51 47 32 60 53 45 54 45 53 25 59 64 52 42 36 53 47 51 51 42 61 59 48 63 31 41 36 52 51 47 51 42 65 39 53 46 62 52 51 39 50 41 45 50 45 50 39 46 60 43 64 59 43 41 33 39 48 42 20 23 37 | 42 60 21 36 11 34 36 34 39 31 37 41 32 28 33 27 27 14 32 29 42 40 16 17 5 32 11 38 24 25 17 47 32 40 34 28 0 30 36 33 31 24 25 47 32 22 31 27 39 20 47 48 34 30 26 32 29 46 29 27 56 51 17 36 46 29 29 22 44 33 33 29 48 16 35 29 39 37 28 32 29 28 48 37 27 38 17 36 58 32 51 41 25 18 15 34 38 37 42 16 38 | 15 47 25 26 28 22 26 27 36 35 54 31 35 32 36 31 28 26 43 35 23 30 11 28 22 30 28 14 30 33 34 27 16 22 22 19 20 0 33 9 41 37 26 30 29 30 19 35 37 26 36 36 29 34 36 46 33 36 46 24 55 41 14 43 30 33 19 19 26 31 3 22 43 33 25 33 31 41 32 33 26 21 46 27 38 33 33 29 40 19 40 40 23 22 27 32 33 31 39 17 39 | 27 42 13 32 14 27 31 23 33 11 40 21 2 10 3 9 24 14 15 6 35 22 12 17 10 16 16 21 23 17 22 27 23 23 29 27 24 12 0 16 22 29 21 19 26 27 26 9 20 12 26 40 19 9 3 28 11 36 24 28 41 33 18 30 26 9 26 23 27 17 15 9 37 21 17 11 37 19 24 23 23 8 28 17 10 18 30 18 40 16 31 37 20 15 15 14 15 17 15 17 40 | 34 38 27 17 28 13 17 18 40 26 54 25 27 23 28 34 19 25 34 26 44 35 21 38 22 21 28 5 25 24 32 18 7 13 13 30 21 29 25 0 35 28 25 44 33 21 10 26 28 17 27 27 23 25 28 37 24 27 38 33 46 43 23 34 21 24 10 28 17 22 32 13 50 33 30 24 22 32 35 28 30 12 37 21 29 33 25 20 31 10 31 31 14 25 20 23 24 22 37 36 41 | 22 50 5 36 23 26 21 29 34 25 44 26 21 22 21 11 11 8 9 23 37 26 10 32 23 10 29 18 2 19 33 31 26 31 28 15 18 24 28 21 0 38 26 37 27 34 23 21 16 19 33 24 24 24 20 42 23 40 47 22 35 37 12 26 32 23 29 17 35 11 27 14 42 34 29 19 35 27 12 26 24 20 34 22 4 32 29 20 44 26 35 35 3 2 9 28 26 31 35 19 42 | 37 61 25 32 33 38 35 29 47 23 50 29 24 20 25 31 44 32 37 37 37 32 28 36 41 33 47 30 31 17 51 35 38 36 41 23 41 22 31 31 39 0 29 39 40 46 35 19 42 22 39 52 27 22 34 40 21 30 53 43 55 29 35 55 34 21 25 40 25 34 25 35 47 49 27 21 15 29 46 36 37 34 40 25 32 14 26 35 48 38 46 47 32 41 27 26 46 29 34 39 43 | 49 61 14 45 36 46 48 51 50 26 71 32 27 23 28 26 46 35 40 40 55 35 26 36 39 42 45 38 34 40 49 38 48 39 49 42 41 45 34 41 42 47 0 44 43 54 43 42 44 25 42 32 30 25 37 43 24 47 58 40 45 31 44 58 45 24 46 49 43 43 46 38 50 50 30 24 52 32 47 39 40 37 43 28 35 33 37 35 51 41 49 62 35 37 30 29 49 32 34 34 44 | 32 44 32 15 31 16 19 21 51 27 37 43 30 26 31 32 38 34 41 36 47 38 32 19 25 38 31 24 41 40 37 16 26 32 32 34 35 45 33 19 50 32 23 0 44 40 29 42 44 22 45 22 37 28 33 44 27 25 24 32 46 49 39 44 28 25 8 44 36 38 48 31 53 36 33 27 38 35 48 22 41 31 40 39 36 34 43 18 29 27 12 50 31 38 31 30 39 33 17 34 45 | 30 42 18 34 12 30 5 29 7 15 29 27 8 12 9 15 30 15 21 12 38 24 17 17 16 14 22 27 6 23 28 33 29 28 35 19 22 18 6 22 28 35 25 25 0 33 30 15 26 14 31 44 2 14 9 32 13 40 30 26 39 35 16 30 32 13 32 21 29 15 21 15 39 27 19 13 31 21 30 24 9 14 32 23 16 22 34 24 44 22 37 42 7 21 16 18 21 21 21 23 46 | 30 54 6 42 33 38 14 33 38 20 58 30 25 21 25 25 44 31 38 36 41 33 17 33 27 14 33 30 6 25 39 36 32 35 38 19 22 30 31 25 40 44 30 41 31 0 35 27 28 23 37 52 28 23 33 41 22 45 51 26 39 42 16 30 42 22 35 21 38 15 33 18 48 38 28 22 37 29 46 37 28 25 38 26 33 27 4 34 49 35 43 55 7 36 22 27 45 28 31 32 47 | 37 44 17 23 18 3 7 8 34 17 44 31 18 14 19 25 9 19 24 24 42 26 15 30 12 23 18 11 15 24 22 24 13 19 19 28 26 29 19 6 40 29 31 35 27 11 0 26 21 7 33 17 24 16 22 27 15 33 36 27 43 37 25 39 27 15 16 30 23 24 32 19 41 23 21 15 28 22 35 30 24 18 27 27 19 24 15 26 37 16 33 37 16 25 14 13 24 16 28 33 48 | 18 42 6 23 14 25 26 30 28 4 31 26 5 1 6 12 28 13 18 18 26 13 9 17 23 24 29 17 16 18 32 30 19 17 25 20 23 3 13 12 27 25 18 20 21 33 22 0 25 3 20 34 12 3 16 21 2 29 37 24 39 24 17 37 26 2 22 22 21 25 6 16 28 34 8 2 30 10 27 17 18 15 21 22 13 11 23 21 33 19 27 28 17 23 8 7 27 10 15 20 49 | 38 55 23 30 30 32 26 15 44 20 66 40 21 17 22 28 38 24 25 26 52 10 25 33 35 32 41 24 32 34 47 37 26 30 27 22 33 39 29 19 40 31 11 38 37 40 29 36 0 19 36 31 28 19 23 33 18 45 53 37 55 21 27 49 40 18 29 32 34 26 40 28 44 46 24 18 41 26 43 10 34 27 28 36 20 27 39 37 49 29 43 50 33 35 24 23 35 26 31 36 50 | 48 56 40 43 39 48 40 39 42 18 64 40 29 35 30 36 51 26 42 32 36 47 20 31 33 32 39 41 33 32 43 45 43 49 46 34 28 37 27 36 41 22 40 43 35 50 46 34 42 0 43 62 29 36 30 35 36 26 51 21 36 40 34 57 40 16 46 27 36 33 40 36 52 44 42 36 37 27 51 44 32 35 35 36 37 25 37 44 47 43 41 50 34 42 22 21 37 24 29 44 51 | 32 46 16 24 25 32 17 34 40 22 61 24 22 24 23 28 16 28 29 17 43 36 1 35 29 27 35 24 22 28 24 30 26 32 32 35 24 33 26 19 33 36 2 34 33 40 29 30 31 26 0 34 22 20 14 39 25 19 41 28 47 33 18 41 40 20 29 23 36 17 36 12 33 28 31 25 41 31 36 1 30 19 19 20 24 29 39 25 43 29 40 50 23 26 26 25 26 28 33 34 52 | 45 67 43 47 37 47 30 40 32 40 54 33 33 37 34 40 53 40 32 37 25 49 42 42 34 39 40 39 31 48 31 39 49 53 29 42 29 43 31 42 43 43 33 32 25 51 44 40 46 33 43 0 27 39 34 51 38 48 48 10 64 51 23 55 32 38 40 28 54 40 46 40 64 35 44 38 56 46 55 44 34 39 57 29 41 47 46 38 52 47 44 39 32 45 41 43 46 46 46 45 53 | 28 40 17 34 10 31 31 27 27 15 44 25 6 12 7 13 28 13 19 10 39 24 15 21 14 12 20 25 4 21 26 31 27 27 33 17 20 16 4 20 26 33 23 23 29 31 28 13 24 14 30 44 0 13 7 31 13 40 28 24 37 35 14 28 30 13 30 19 31 13 19 13 39 25 19 13 41 21 28 22 26 12 32 21 14 22 34 22 44 20 35 40 5 19 14 18 19 21 19 21 54 | 28 44 4 28 28 32 30 32 46 30 47 35 2 28 3 9 25 14 15 29 45 32 12 38 22 22 28 24 31 25 34 35 32 14 34 28 30 30 31 27 45 29 15 19 39 39 29 27 22 27 17 31 27 0 26 47 26 36 43 34 41 35 24 43 30 29 21 29 18 23 21 23 44 33 32 29 41 37 24 14 36 26 32 31 10 20 28 18 48 16 31 41 20 20 15 34 38 37 36 17 55 | 29 46 10 30 11 24 28 20 30 8 47 18 8 17 9 15 21 14 21 3 34 27 13 21 26 13 32 18 20 14 36 24 20 20 26 24 21 19 17 13 19 33 18 25 23 34 23 16 17 17 23 37 16 6 0 25 16 33 41 25 38 30 15 27 30 6 23 20 24 14 22 6 42 37 22 18 34 17 22 20 20 5 25 14 16 15 27 24 37 22 31 41 21 12 12 11 12 14 19 23 56 | 25 39 28 18 28 14 18 19 16 27 54 25 20 24 20 27 20 26 33 27 33 36 8 31 22 9 28 6 17 25 31 19 8 14 14 29 17 10 26 1 35 29 21 36 26 22 11 27 29 18 28 28 23 26 29 0 25 28 39 21 34 43 11 35 22 25 11 16 18 10 13 13 40 33 31 18 23 26 36 20 23 13 33 21 28 34 26 21 32 11 32 32 15 26 21 24 25 23 38 27 57 | 29 42 5 21 12 33 25 33 29 4 48 26 3 18 4 10 26 14 16 19 37 11 13 17 23 23 29 25 19 25 35 31 32 15 25 20 25 26 14 28 36 23 16 20 22 40 30 23 23 1 18 32 15 1 17 33 0 27 38 22 37 22 25 43 26 17 22 28 19 24 22 23 26 34 6 19 38 13 25 15 19 22 33 22 11 11 23 19 44 17 27 41 20 21 15 22 28 11 15 18 58 | 53 54 36 52 43 47 55 52 57 33 72 53 34 30 35 41 57 42 47 47 57 42 38 18 50 37 56 49 45 47 61 51 55 46 56 49 45 52 42 48 56 43 47 51 50 65 54 49 54 21 49 61 41 32 45 50 31 0 47 42 57 53 39 53 55 31 53 44 50 38 53 41 57 61 37 31 58 39 56 46 47 48 50 49 42 40 52 50 62 26 47 69 30 52 37 36 56 39 44 49 59 | 30 31 25 31 27 24 30 29 38 31 49 19 23 28 24 30 32 30 36 27 41 37 25 17 27 14 33 18 21 25 39 25 21 18 27 34 22 30 21 14 29 33 19 40 31 19 23 27 27 20 41 35 17 27 24 48 29 34 0 26 39 37 16 30 35 29 24 21 22 15 33 7 55 38 35 23 35 31 37 37 28 14 38 15 31 38 23 34 38 3 24 45 7 27 25 34 22 36 36 31 60 | 35 61 37 37 30 37 33 30 35 36 56 23 27 33 28 34 43 33 22 31 15 45 35 33 24 33 30 29 25 42 36 29 39 45 42 32 19 37 25 32 33 35 23 22 28 41 34 34 36 23 51 44 21 34 28 51 34 38 40 0 58 41 13 49 22 34 30 18 45 34 40 34 60 27 40 28 46 36 45 43 25 33 53 19 35 43 36 28 42 41 34 29 26 35 34 39 40 42 39 35 61 | 25 39 9 18 16 32 22 34 33 8 47 30 7 22 8 2 22 18 20 23 41 15 17 21 15 22 21 29 17 29 27 35 8 19 27 24 22 29 17 32 17 27 19 24 26 32 34 26 27 5 22 36 13 5 20 37 4 31 39 26 0 26 17 38 22 21 11 22 23 23 26 26 30 26 10 23 41 11 23 19 23 25 37 26 15 15 27 11 40 11 31 45 15 13 19 26 25 15 19 10 62 | 30 45 8 24 15 19 28 24 28 7 51 19 6 21 7 7 27 17 19 22 40 14 16 20 20 21 26 18 21 28 32 25 20 18 26 23 28 22 17 13 29 26 19 23 25 34 23 26 13 4 21 33 17 4 20 12 3 30 41 25 40 0 23 28 28 20 23 28 22 22 25 7 29 31 9 22 35 16 28 18 22 6 36 15 14 14 26 16 37 20 30 44 22 18 18 25 31 14 18 15 63 | 40 57 27 30 17 40 20 17 22 30 43 33 23 27 24 30 33 20 32 27 25 39 22 20 11 24 17 36 16 31 23 39 38 43 29 29 6 33 21 31 37 30 31 32 15 28 37 30 38 23 43 54 17 29 24 38 28 48 35 10 49 50 0 40 32 28 23 5 32 25 36 28 54 22 34 28 45 31 34 38 12 29 42 29 31 37 23 33 52 37 44 39 17 24 21 28 36 31 36 22 64 | 21 55 35 37 26 23 27 28 40 29 52 32 34 30 35 41 29 16 8 31 47 42 18 32 20 38 26 17 34 27 11 30 27 33 33 30 15 32 34 20 42 23 32 49 33 31 20 29 41 27 47 37 30 32 28 31 31 39 24 36 63 50 32 0 41 31 30 31 33 39 35 20 27 15 37 31 34 38 42 39 38 19 47 28 29 36 32 40 43 27 48 43 31 32 17 33 40 36 40 23 65 | 31 57 41 44 37 42 41 40 43 19 65 29 30 36 31 37 48 27 43 33 37 48 21 32 34 22 40 35 31 33 44 35 39 43 45 10 29 38 28 32 39 23 29 44 36 50 39 35 42 1 44 56 27 37 31 36 37 27 52 22 37 41 24 38 0 17 42 28 37 23 41 25 53 45 43 31 38 28 51 45 33 32 36 25 38 26 38 45 48 42 42 51 15 41 23 22 38 25 30 33 66 | 33 40 24 27 23 32 24 34 26 2 48 24 13 19 14 20 35 11 26 16 36 31 7 15 21 25 27 25 17 16 30 29 27 33 31 18 23 21 11 20 25 31 24 30 19 38 30 18 30 14 37 46 13 20 14 19 20 38 35 35 50 24 27 41 24 0 30 32 20 26 24 20 39 32 26 20 28 11 35 34 16 19 19 20 21 9 21 29 31 27 25 38 18 26 6 5 25 8 13 28 67 | 24 57 24 7 31 43 11 48 43 19 63 41 22 18 23 29 45 28 35 33 52 30 24 32 31 32 37 42 33 32 43 46 38 34 44 35 40 37 28 37 42 42 35 39 36 47 47 34 36 20 37 51 29 20 31 36 19 45 28 41 56 41 34 36 41 17 0 39 37 33 40 35 45 42 25 19 30 27 44 34 33 36 36 37 30 26 38 10 48 31 42 55 34 40 23 22 31 25 30 26 68 | 35 52 22 37 12 35 15 12 17 25 38 28 18 22 19 25 28 15 27 22 20 34 17 15 6 19 12 34 11 26 18 34 33 38 24 24 1 28 16 30 32 25 26 27 10 23 32 25 33 18 38 49 12 24 19 33 23 43 30 5 44 45 18 35 27 23 30 0 27 20 31 23 49 17 29 23 40 26 29 33 7 24 37 24 26 32 18 33 47 32 39 34 12 19 16 23 31 26 31 17 69 | 48 72 36 43 44 49 46 40 58 34 49 40 35 31 36 42 55 43 48 48 48 43 39 47 52 44 58 41 42 28 55 46 49 47 52 34 52 33 42 42 50 11 40 50 51 57 46 30 53 33 50 63 38 33 45 51 32 41 64 54 66 40 46 66 45 32 36 51 0 45 36 46 58 59 38 32 26 40 57 47 48 45 51 36 43 25 37 46 59 49 57 58 43 52 38 37 57 40 45 50 70 | 15 50 28 31 18 41 18 18 23 25 44 34 24 22 25 31 34 21 33 28 26 34 23 21 12 25 18 37 17 32 24 40 39 38 30 30 7 34 22 32 38 31 26 33 16 29 38 31 39 24 41 55 18 24 25 39 23 49 36 11 50 45 1 41 33 23 24 6 33 0 37 29 43 23 29 23 44 31 35 33 13 30 23 30 32 32 24 34 53 37 45 40 18 25 22 28 37 31 36 17 71 | 30 62 22 32 40 37 36 42 51 44 69 36 40 43 41 28 28 41 43 44 38 45 26 43 37 40 43 29 34 48 49 42 31 37 37 34 35 15 38 24 46 52 36 45 44 45 34 47 48 41 51 51 34 44 41 61 44 51 53 39 65 54 29 45 45 42 25 34 41 41 0 24 58 48 40 36 46 44 29 48 41 23 61 32 38 48 46 35 55 34 52 38 35 19 42 47 43 46 53 32 72 | 38 45 23 24 20 20 24 25 37 25 54 12 16 22 17 23 26 23 29 20 49 34 25 31 24 22 30 12 14 31 36 18 14 20 20 27 28 26 14 7 22 34 12 33 39 28 17 23 25 24 34 34 10 20 17 41 23 27 38 34 47 30 24 29 28 23 17 29 24 23 29 0 49 35 29 17 29 25 30 32 36 7 42 8 24 32 32 27 31 17 38 38 15 20 24 28 29 29 29 24 73 | 28 40 24 34 16 36 11 16 13 2 29 24 14 18 15 21 32 6 24 18 24 30 8 15 10 20 16 30 12 17 22 29 24 34 26 18 5 22 12 28 34 29 24 31 6 27 35 19 31 18 37 50 8 20 15 36 19 38 34 9 45 24 22 36 24 19 27 4 20 21 25 21 0 21 25 19 37 11 33 30 11 20 38 20 19 9 21 30 42 24 25 33 13 23 7 24 27 27 13 21 74 | 43 44 32 38 33 18 22 23 45 31 58 32 32 28 33 39 24 34 39 37 45 40 24 30 27 27 33 26 30 25 37 38 28 31 34 31 35 30 34 21 42 8 32 47 42 26 15 27 31 22 47 32 30 30 34 42 29 38 13 39 52 37 29 43 42 29 31 34 33 28 33 20 55 0 35 29 23 37 50 41 39 27 42 28 34 22 30 41 51 16 37 52 20 40 23 28 35 31 42 44 75 | 42 53 18 34 25 35 37 40 39 15 61 35 16 12 17 23 39 24 29 29 49 5 20 28 34 35 40 34 27 29 43 41 36 28 19 31 36 34 24 29 38 26 29 27 32 47 39 31 29 14 31 26 23 14 27 28 13 40 48 35 50 16 37 44 37 13 35 41 32 36 35 23 39 45 0 13 41 21 38 28 29 22 32 31 24 22 34 32 44 30 38 51 28 34 19 18 38 21 26 31 76 | 33 50 27 44 20 37 41 37 37 25 54 35 12 22 13 19 38 19 20 20 49 34 21 28 24 22 30 29 14 30 36 41 37 37 39 27 30 26 14 30 36 43 33 29 39 41 34 23 27 24 40 51 10 23 17 41 23 50 38 34 47 45 24 38 37 23 37 29 41 23 29 23 49 35 29 0 39 8 34 32 36 22 42 31 15 32 44 28 54 26 41 46 15 29 20 28 29 31 26 27 77 | 22 46 10 17 18 23 21 28 32 8 35 30 9 5 10 16 29 17 22 22 22 17 13 21 27 18 33 15 20 2 36 28 23 21 29 24 26 7 17 16 31 21 22 24 25 31 20 4 29 7 24 37 16 7 20 25 6 15 38 28 43 28 20 41 30 6 10 25 25 19 10 20 32 34 12 6 0 14 31 21 22 19 25 26 17 15 27 20 37 23 31 32 21 27 12 11 31 14 19 24 78 | 30 42 19 36 12 33 33 29 29 17 46 27 8 14 9 15 30 15 21 12 41 26 17 20 16 14 22 27 6 23 28 33 29 29 35 19 22 18 6 22 28 35 25 25 31 33 30 15 26 16 32 46 2 15 9 33 15 42 30 26 39 37 16 30 29 15 32 21 33 15 21 15 41 27 21 15 43 0 30 24 28 14 34 23 16 24 36 24 46 22 37 42 7 21 16 20 21 23 18 23 79 | 31 60 33 42 11 35 33 30 24 31 56 41 28 28 29 35 40 14 18 29 38 35 16 33 24 25 30 27 24 25 36 40 32 43 34 28 19 30 34 30 45 43 36 45 28 41 32 27 25 30 47 49 30 30 26 32 29 49 48 23 50 46 13 48 45 29 35 18 45 26 33 29 48 35 35 29 44 37 0 35 25 29 48 37 13 38 36 40 53 32 53 41 25 37 15 34 38 37 42 33 80 | 31 45 15 26 24 37 16 33 39 21 60 31 21 23 22 27 34 27 33 16 42 35 26 34 28 26 34 31 33 27 40 37 33 33 39 37 23 32 30 26 32 46 1 33 32 45 36 29 30 25 36 33 29 19 13 38 24 46 52 27 46 32 17 40 43 19 36 22 37 16 35 19 38 39 30 24 42 30 35 0 29 18 18 27 28 28 38 36 50 35 44 54 34 25 25 24 25 27 32 33 81 | 33 45 21 37 15 33 8 32 10 18 32 30 11 15 12 18 33 18 24 15 29 27 20 8 19 17 25 30 9 26 31 36 32 31 38 22 25 21 9 25 31 31 28 27 3 36 33 18 29 11 34 47 5 17 12 35 16 37 33 29 42 38 19 33 35 16 35 24 20 18 24 18 42 30 22 16 34 24 33 27 0 17 35 26 19 25 37 27 47 25 39 45 10 24 19 21 24 24 24 26 82 | 39 46 16 25 21 21 25 26 38 26 55 13 17 23 18 22 22 24 30 21 50 35 26 32 25 23 31 13 15 32 33 19 15 21 21 28 29 27 15 8 23 35 13 34 34 29 18 24 26 25 35 35 11 21 18 42 24 28 39 35 48 31 25 22 29 24 18 30 25 24 30 1 49 36 30 18 30 26 23 33 31 0 43 9 25 33 33 28 32 18 39 39 16 13 25 29 30 30 30 25 83 | 47 27 25 8 32 31 12 36 33 22 49 37 23 19 24 30 46 26 36 36 44 30 27 34 30 40 36 39 32 36 42 31 41 35 44 38 25 41 31 34 45 43 36 15 26 47 40 38 43 21 38 37 28 21 34 39 20 40 39 29 57 41 42 54 43 20 23 24 39 41 42 40 20 41 25 20 38 28 45 35 31 39 0 40 31 29 41 33 44 35 27 53 33 41 26 25 45 28 32 38 84 | 30 42 18 30 12 18 22 23 29 17 46 4 8 14 9 15 24 15 21 12 41 26 17 23 16 14 22 10 6 23 28 10 20 26 26 19 22 18 6 13 14 26 4 25 31 26 15 15 17 16 32 32 2 15 9 33 15 19 30 26 39 22 16 30 32 15 23 21 30 15 21 15 41 27 21 9 27 17 26 24 28 14 34 0 16 24 30 24 23 22 37 42 7 16 16 20 21 23 21 16 85 | 18 50 23 32 27 22 26 27 36 21 48 28 17 18 18 24 27 4 5 19 35 22 6 34 25 12 31 14 30 15 29 27 22 30 24 18 20 20 30 17 35 34 23 34 29 30 19 17 12 20 37 36 26 20 16 38 19 36 46 24 37 33 14 35 36 19 25 19 34 13 23 16 38 33 25 19 31 27 38 22 26 16 36 24 0 28 34 30 40 22 43 31 26 28 5 24 28 27 32 20 86 | 30 53 23 39 23 29 21 34 40 22 57 15 19 25 20 22 35 26 32 23 42 29 28 31 27 25 33 21 17 34 39 21 31 33 37 9 33 19 17 24 25 22 15 36 40 37 26 26 28 19 36 43 13 19 20 27 18 30 41 37 41 15 27 41 20 26 34 32 11 26 22 22 44 38 24 20 37 28 37 33 37 21 45 11 27 0 12 31 34 33 45 53 18 27 27 31 32 29 29 27 87 | 53 54 24 57 37 52 44 54 48 16 64 38 33 39 34 40 55 40 46 37 65 51 36 29 41 39 47 44 31 48 53 43 54 54 60 32 37 42 31 47 48 45 38 50 41 58 49 40 51 32 57 66 27 40 34 50 40 52 51 51 64 38 41 55 38 40 52 46 34 40 45 40 66 52 46 40 60 25 55 49 38 39 59 34 41 23 0 49 56 47 39 67 32 46 41 45 46 48 27 48 88 | 14 64 37 36 27 50 40 55 63 42 53 34 43 39 44 43 43 25 43 40 56 51 27 54 21 47 27 49 40 36 33 40 43 37 45 39 37 41 48 49 44 40 25 39 56 38 47 38 50 41 40 54 49 41 37 48 40 49 45 57 70 52 49 63 57 40 29 54 41 48 44 43 59 32 46 39 55 47 44 32 53 42 50 51 38 49 32 0 53 36 51 52 40 34 26 42 49 45 53 16 89 | 26 46 17 31 17 31 33 27 37 15 43 25 6 14 7 3 23 18 19 10 19 26 16 19 11 20 17 25 27 21 23 31 27 27 33 22 6 16 4 20 26 30 20 23 30 28 30 13 24 16 30 44 23 13 7 32 15 40 28 4 45 37 17 34 24 13 24 22 31 21 19 13 41 22 21 15 41 23 24 27 27 12 32 21 14 22 14 12 0 20 35 22 24 14 19 18 19 21 19 11 90 | 27 28 30 39 30 21 30 26 35 28 46 27 29 25 22 34 41 33 35 35 38 37 26 33 24 11 30 27 29 22 36 25 29 32 35 42 19 27 29 22 37 41 27 38 28 41 32 24 40 20 44 35 25 27 32 45 26 34 33 23 36 45 13 27 43 26 32 18 36 12 30 15 52 35 32 20 44 28 43 41 25 22 35 23 35 35 36 42 38 0 21 52 4 35 32 31 44 34 39 29 91 | 42 43 34 18 24 36 22 41 50 32 25 31 23 29 24 20 40 27 36 27 36 41 29 29 18 26 24 30 33 37 30 4 33 30 39 39 23 33 21 26 41 20 31 40 43 31 35 30 39 18 47 47 29 30 24 45 30 13 12 21 34 49 28 42 41 30 36 33 34 27 36 19 56 29 36 30 35 38 41 44 40 26 49 27 31 34 31 29 17 15 0 39 19 31 28 35 34 38 36 28 92 | 6 54 20 28 19 41 32 44 47 30 45 5 22 31 23 26 26 17 24 30 43 37 19 38 13 25 19 33 17 28 25 11 23 32 37 30 29 33 24 34 15 27 17 39 42 30 38 30 31 27 25 39 20 27 27 35 26 20 37 28 46 23 27 41 37 32 21 32 36 26 36 29 51 24 32 10 42 18 27 24 39 29 42 37 19 37 24 31 24 26 47 0 18 17 18 37 39 37 36 8 93 | 23 47 26 35 26 31 26 26 31 24 51 23 25 21 18 32 37 29 31 31 34 33 22 29 20 7 26 23 25 18 32 29 25 28 31 38 15 23 25 18 33 37 23 34 24 37 28 20 36 16 40 45 21 23 28 41 22 38 44 19 32 41 9 23 39 22 28 14 32 8 26 11 48 31 28 16 40 24 39 37 21 18 31 19 31 31 32 38 42 28 46 48 0 31 28 27 40 30 35 25 94 | 32 63 3 37 21 36 19 40 34 29 54 37 29 26 30 9 9 23 24 37 48 38 15 42 22 21 28 33 15 34 34 37 35 41 43 28 29 39 31 32 28 41 26 46 38 39 38 36 29 28 45 50 27 28 34 42 27 46 45 33 46 47 23 34 30 27 30 28 45 22 42 25 47 33 33 17 45 25 10 33 35 32 45 33 19 36 27 18 50 37 33 50 16 0 24 32 24 35 40 17 95 | 27 54 18 35 22 31 35 31 40 16 43 29 17 13 18 24 32 25 30 14 30 25 1 29 33 24 39 23 28 10 24 35 31 29 37 32 28 15 25 24 30 29 29 32 33 39 28 12 28 15 32 45 24 15 11 33 14 41 41 36 49 36 26 38 38 14 34 31 33 25 18 17 33 28 20 14 40 22 33 29 30 16 33 25 25 23 35 25 43 31 39 40 29 23 0 19 23 22 27 29 96 | 28 41 19 22 20 27 19 29 21 16 43 27 8 14 9 15 30 6 21 11 31 26 2 19 16 21 22 20 20 11 25 33 22 28 26 20 29 16 6 15 27 30 27 25 14 33 25 13 25 9 32 41 16 15 9 14 15 35 30 30 45 33 23 36 32 14 25 28 31 22 19 15 34 27 21 15 23 23 30 29 11 14 14 23 16 20 32 24 44 22 37 33 21 21 1 0 20 3 21 23 97 | 17 50 28 27 20 12 20 17 25 19 46 17 21 22 12 28 31 23 30 25 28 15 22 23 14 1 20 17 19 31 26 23 19 25 25 27 9 31 19 12 27 33 16 28 18 31 22 28 5 24 39 26 15 24 22 34 23 32 38 13 26 26 3 28 33 17 20 8 29 2 34 5 42 25 29 10 34 18 33 15 15 12 25 13 25 26 26 16 36 22 40 42 20 25 21 20 0 23 30 19 98 | 30 45 16 31 17 29 16 26 18 13 40 24 5 13 6 12 27 3 18 8 32 25 5 16 13 18 19 24 17 14 25 30 21 26 23 17 26 15 3 19 25 28 24 22 11 30 29 12 22 6 29 43 13 12 6 30 14 32 27 27 42 30 20 33 29 11 24 25 28 19 18 12 37 24 20 14 39 22 27 26 8 11 30 20 13 20 32 21 42 19 34 30 18 18 4 16 17 0 18 20 99 | 38 27 26 32 27 40 36 36 40 23 62 34 24 33 25 31 37 25 37 19 41 43 21 2 35 26 41 34 36 30 44 40 36 36 42 17 33 35 25 29 35 27 34 41 33 50 39 32 33 5 39 53 32 22 16 33 32 31 31 26 41 45 28 43 11 21 25 32 40 27 38 22 53 46 38 28 42 32 38 36 30 21 33 30 32 30 42 35 52 34 46 52 26 28 20 19 28 22 0 39 100 | 37 48 21 20 11 34 24 39 48 31 37 41 32 28 33 27 27 14 32 29 45 40 16 38 5 31 11 38 24 25 17 45 32 24 34 28 21 30 40 33 45 24 9 47 48 22 31 27 39 30 47 41 39 30 26 32 29 54 29 43 54 40 33 47 46 29 13 38 28 32 33 29 48 16 35 29 39 37 28 16 45 28 34 37 27 38 26 23 58 20 41 41 24 18 15 34 38 37 42 0 101 | -------------------------------------------------------------------------------- /test/optim/dijkstra.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Edge { 5 | int from; 6 | int to; 7 | int weight; 8 | }; 9 | 10 | struct EdgeList { 11 | struct Edge **edges; 12 | int *next; 13 | int *first; 14 | int size; 15 | }; 16 | 17 | void EdgeList_init(struct EdgeList *g, int n, int m) { 18 | g->edges = malloc(sizeof(struct Edge *) * m); 19 | g->next = malloc(sizeof(int) * m); 20 | g->first = malloc(sizeof(int) * n); 21 | int i; 22 | for (i = 0; i < m; ++i) 23 | g->next[i] = -1; 24 | for (i = 0; i < n; ++i) 25 | g->first[i] = -1; 26 | g->size = 0; 27 | } 28 | 29 | void EdgeList_addEdge(struct EdgeList *g, int u, int v, int w) { 30 | struct Edge *e = malloc(sizeof(struct Edge)); 31 | e->from = u; 32 | e->to = v; 33 | e->weight = w; 34 | 35 | g->edges[g->size] = e; 36 | g->next[g->size] = g->first[u]; 37 | g->first[u] = g->size; 38 | ++g->size; 39 | } 40 | 41 | struct Node { 42 | 43 | int node; 44 | int dist; 45 | }; 46 | 47 | int Node_key_(struct Node *this) { return -this->dist; } 48 | 49 | struct Array_Node { 50 | struct Node **storage; 51 | int sz; 52 | int capacity; 53 | }; 54 | 55 | void Array_Node_Ctor(struct Array_Node *this); 56 | void Array_Node_push_back(struct Array_Node *this, struct Node *v); 57 | struct Node *Array_Node_pop_back(struct Array_Node *this); 58 | struct Node *Array_Node_back(struct Array_Node *this); 59 | struct Node *Array_Node_front(struct Array_Node *this); 60 | int Array_Node_size(struct Array_Node *this); 61 | void Array_Node_resize(struct Array_Node *this, int newSize); 62 | struct Node *Array_Node_get(struct Array_Node *this, int i); 63 | void Array_Node_set(struct Array_Node *this, int i, struct Node *v); 64 | void Array_Node_swap(struct Array_Node *this, int i, int j); 65 | void Array_Node_doubleStorage(struct Array_Node *this); 66 | 67 | struct Array_Node *heap; 68 | void init_heap(); 69 | void push(struct Node *v); 70 | struct Node *pop(); 71 | struct Node *top(); 72 | int size(); 73 | int lchild(int x); 74 | int rchild(int x); 75 | int pnt(int x); 76 | void maxHeapify(int x); 77 | 78 | int n; 79 | int m; 80 | struct EdgeList *g; 81 | int INF = 10000000; 82 | 83 | void init() { 84 | scanf("%d %d", &n, &m); 85 | g = malloc(sizeof(struct EdgeList)); 86 | EdgeList_init(g, n, m); 87 | 88 | init_heap(); 89 | 90 | int i; 91 | for (i = 0; i < m; ++i) { 92 | int u, v, w; 93 | scanf("%d %d %d", &u, &v, &w); 94 | EdgeList_addEdge(g, u, v, w); 95 | } 96 | } 97 | 98 | int *dijkstra(int s) { 99 | int *visited = malloc(sizeof(int) * n); 100 | int *d = malloc(sizeof(int) * n); 101 | int i; 102 | for (i = 0; i < n; ++i) { 103 | d[i] = INF; 104 | visited[i] = 0; 105 | } 106 | d[s] = 0; 107 | 108 | init_heap(); 109 | struct Node *src = malloc(sizeof(struct Node)); 110 | src->dist = 0; 111 | src->node = s; 112 | push(src); 113 | 114 | while (size() != 0) { 115 | struct Node *node = pop(); 116 | int u = node->node; 117 | if (visited[u] == 1) 118 | continue; 119 | visited[u] = 1; 120 | int k; 121 | for (k = g->first[u]; k != -1; k = g->next[k]) { 122 | int v = g->edges[k]->to; 123 | int w = g->edges[k]->weight; 124 | int alt = d[u] + w; 125 | if (alt >= d[v]) 126 | continue; 127 | d[v] = alt; 128 | node = malloc(sizeof(struct Node)); 129 | node->node = v; 130 | node->dist = d[v]; 131 | push(node); 132 | } 133 | } 134 | 135 | return d; 136 | } 137 | 138 | int main() { 139 | init(); 140 | int i; 141 | int j; 142 | for (i = 0; i < n; ++i) { 143 | int *d = dijkstra(i); 144 | for (j = 0; j < n; ++j) { 145 | if (d[j] == INF) { 146 | printf("-1"); 147 | } else { 148 | printf("%d", d[j]); 149 | } 150 | printf(" "); 151 | } 152 | puts(""); 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | void Array_Node_Ctor(struct Array_Node *this) { 159 | this->sz = 0; 160 | this->capacity = 16; 161 | this->storage = malloc(sizeof(struct Node *) * this->capacity); 162 | } 163 | 164 | void Array_Node_push_back(struct Array_Node *this, struct Node *v) { 165 | if (Array_Node_size(this) == this->capacity) { 166 | Array_Node_doubleStorage(this); 167 | } 168 | this->storage[this->sz] = v; 169 | ++this->sz; 170 | } 171 | 172 | struct Node *Array_Node_pop_back(struct Array_Node *this) { 173 | --this->sz; 174 | return this->storage[this->sz]; 175 | } 176 | 177 | struct Node *Array_Node_back(struct Array_Node *this) { 178 | return this->storage[this->sz - 1]; 179 | } 180 | 181 | struct Node *Array_Node_front(struct Array_Node *this) { 182 | return this->storage[0]; 183 | } 184 | 185 | int Array_Node_size(struct Array_Node *this) { return this->sz; } 186 | 187 | void Array_Node_resize(struct Array_Node *this, int newSize) { 188 | while (this->capacity < newSize) 189 | Array_Node_doubleStorage(this); 190 | this->sz = newSize; 191 | } 192 | 193 | struct Node *Array_Node_get(struct Array_Node *this, int i) { 194 | return this->storage[i]; 195 | } 196 | 197 | void Array_Node_set(struct Array_Node *this, int i, struct Node *v) { 198 | this->storage[i] = v; 199 | } 200 | 201 | void Array_Node_swap(struct Array_Node *this, int i, int j) { 202 | struct Node *t = this->storage[i]; 203 | this->storage[i] = this->storage[j]; 204 | this->storage[j] = t; 205 | } 206 | 207 | void Array_Node_doubleStorage(struct Array_Node *this) { 208 | this->capacity *= 2; 209 | 210 | struct Node **copy = this->storage; 211 | int szCopy = this->sz; 212 | 213 | this->storage = malloc(sizeof(struct Node *) * this->capacity); 214 | this->sz = 0; 215 | 216 | for (; this->sz != szCopy; ++this->sz) { 217 | this->storage[this->sz] = copy[this->sz]; 218 | } 219 | } 220 | 221 | void init_heap() { 222 | heap = malloc(sizeof(struct Array_Node)); 223 | Array_Node_Ctor(heap); 224 | } 225 | 226 | void push(struct Node *v) { 227 | Array_Node_push_back(heap, v); 228 | int x = Array_Node_size(heap) - 1; 229 | while (x > 0) { 230 | int p = pnt(x); 231 | if (Node_key_(Array_Node_get(heap, p)) >= 232 | Node_key_(Array_Node_get(heap, x))) 233 | break; 234 | Array_Node_swap(heap, p, x); 235 | x = p; 236 | } 237 | } 238 | 239 | struct Node *pop() { 240 | struct Node *res = Array_Node_front(heap); 241 | Array_Node_swap(heap, 0, Array_Node_size(heap) - 1); 242 | Array_Node_pop_back(heap); 243 | maxHeapify(0); 244 | return res; 245 | } 246 | 247 | struct Node *top() { 248 | return Array_Node_front(heap); 249 | } 250 | 251 | int size() { return Array_Node_size(heap); } 252 | 253 | // private: 254 | int lchild(int x) { return x * 2 + 1; } 255 | 256 | int rchild(int x) { return x * 2 + 2; } 257 | 258 | int pnt(int x) { return (x - 1) / 2; } 259 | 260 | void maxHeapify(int x) { 261 | int l = lchild(x); 262 | int r = rchild(x); 263 | int largest = x; 264 | 265 | if (l < size() && Node_key_(Array_Node_get(heap, l)) > 266 | Node_key_(Array_Node_get(heap, largest))) 267 | largest = l; 268 | if (r < size() && Node_key_(Array_Node_get(heap, r)) > 269 | Node_key_(Array_Node_get(heap, largest))) 270 | largest = r; 271 | 272 | if (largest == x) 273 | return; 274 | Array_Node_swap(heap, x, largest); 275 | maxHeapify(largest); 276 | } -------------------------------------------------------------------------------- /test/optim/humble.ans: -------------------------------------------------------------------------------- 1 | 284456 2 | -------------------------------------------------------------------------------- /test/optim/humble.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int MAXK = 105; 5 | int MAXN = 100005; 6 | 7 | int main() { 8 | int point = 0; 9 | int k; 10 | int MIN; 11 | int K; 12 | int N; 13 | int i; 14 | int *primes = malloc(sizeof(int) * MAXK); 15 | int *pindex = malloc(sizeof(int) * MAXK); 16 | int *ans = malloc(sizeof(int) * MAXN); 17 | scanf("%d %d", &K, &N); 18 | for (i = 0; i < K; ++i) { 19 | scanf("%d", &primes[i]); 20 | } 21 | ans[0] = 1; 22 | while (point <= N) { 23 | MIN = 2139062143; 24 | for (i = 0; i < K; ++i) { 25 | while (ans[point] >= primes[i] * ans[pindex[i]]) 26 | pindex[i]++; 27 | if (primes[i] * ans[pindex[i]] < MIN) { 28 | MIN = primes[i] * ans[pindex[i]]; 29 | k = i; 30 | } 31 | } 32 | ans[++point] = MIN; 33 | } 34 | printf("%d\n", ans[N]); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /test/optim/humble.in: -------------------------------------------------------------------------------- 1 | 100 100000 2 | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 3 | -------------------------------------------------------------------------------- /test/optim/kruskal.ans: -------------------------------------------------------------------------------- 1 | 79894 2 | -------------------------------------------------------------------------------- /test/optim/kruskal.c: -------------------------------------------------------------------------------- 1 | // By Yunwei Ren, ACM 2017 2 | 3 | #include 4 | #include 5 | 6 | struct Edge { 7 | int u, v, w; 8 | }; 9 | 10 | int n, m; 11 | struct Edge **edges; 12 | struct Edge **buffer; 13 | 14 | // disjoint set 15 | int *pnt; 16 | 17 | void init() { 18 | scanf("%d%d", &n, &m); 19 | edges = malloc(sizeof(struct Edge *) * m); 20 | buffer = malloc(sizeof(struct Edge *) * m); 21 | for (int i = 0; i < m; ++i) { 22 | edges[i] = malloc(sizeof(struct Edge)); 23 | scanf("%d%d%d", &edges[i]->u, &edges[i]->v, &edges[i]->w); 24 | } 25 | 26 | pnt = malloc(sizeof(int) * n); 27 | for (int i = 0; i < n; ++i) 28 | pnt[i] = -1; 29 | } 30 | 31 | void sort(int l, int r) { 32 | if (l + 1 == r) 33 | return; 34 | int mid = (l + r) / 2; 35 | sort(l, mid); 36 | sort(mid, r); 37 | 38 | int lpos = l; 39 | int rpos = mid; 40 | for (int i = 0; i < r - l; ++i) { 41 | if (lpos == mid) { 42 | buffer[i] = edges[rpos++]; 43 | continue; 44 | } 45 | if (rpos == r) { 46 | buffer[i] = edges[lpos++]; 47 | continue; 48 | } 49 | if (edges[lpos]->w < edges[rpos]->w) { 50 | buffer[i] = edges[lpos++]; 51 | continue; 52 | } 53 | buffer[i] = edges[rpos++]; 54 | } 55 | 56 | for (int i = 0; i < r - l; ++i) { 57 | edges[l + i] = buffer[i]; 58 | } 59 | } 60 | 61 | int findRoot(int x) { 62 | if (pnt[x] == -1) 63 | return x; 64 | int y = findRoot(pnt[x]); 65 | pnt[x] = y; 66 | return y; 67 | } 68 | 69 | void unionSets(int x, int y) { 70 | int px = findRoot(x); 71 | int py = findRoot(y); 72 | if (px == py) 73 | return; 74 | pnt[px] = py; 75 | } 76 | 77 | int main() { 78 | init(); 79 | sort(0, m); 80 | 81 | int cnt = 0; 82 | int ans = 0; 83 | for (int i = 0; i < m /* && cnt != n - 1 */; ++i) { 84 | if (findRoot(edges[i]->u) == findRoot(edges[i]->v)) 85 | continue; 86 | unionSets(edges[i]->u, edges[i]->v); 87 | ++cnt; 88 | ans += edges[i]->w; 89 | } 90 | printf("%d\n", ans); 91 | return 0; 92 | } -------------------------------------------------------------------------------- /test/optim/lca.c: -------------------------------------------------------------------------------- 1 | // by Yifan Xu, ACM2017 2 | 3 | #include 4 | #include 5 | 6 | struct Edge { 7 | int x; 8 | int y; 9 | int next; 10 | }; 11 | 12 | int n; 13 | int m; 14 | int root; 15 | int total = 0; 16 | int MAX = 20; 17 | 18 | int *first; 19 | int *depth; 20 | int *ans; 21 | int **f; 22 | int *pow2; 23 | struct Edge **edge; 24 | 25 | void init() { 26 | first = malloc(sizeof(int) * (n + 1)); 27 | depth = malloc(sizeof(int) * (n + 1)); 28 | int i; 29 | for (i = 0; i <= n; ++i) { 30 | first[i] = 0; 31 | depth[i] = 0; 32 | } 33 | ans = malloc(sizeof(int) * (m + 1)); 34 | f = malloc(sizeof(int *) * (n + 1)); 35 | for (i = 0; i <= n; ++i) { 36 | f[i] = malloc(sizeof(int) * (MAX + 1)); 37 | } 38 | int j; 39 | for (i = 0; i <= n; ++i) { 40 | for (j = 0; j <= MAX; ++j) { 41 | f[i][j] = 0; 42 | } 43 | } 44 | pow2 = malloc(sizeof(int) * (MAX + 1)); 45 | pow2[0] = 1; 46 | for (i = 1; i <= MAX; ++i) { 47 | pow2[i] = 2 * pow2[i - 1]; 48 | } 49 | edge = malloc(sizeof(struct Edge *) * (2 * n - 1)); 50 | } 51 | 52 | void addedge(int x, int y) { 53 | ++total; 54 | edge[total] = malloc(sizeof(struct Edge)); 55 | edge[total]->x = x; 56 | edge[total]->y = y; 57 | edge[total]->next = first[x]; 58 | first[x] = total; 59 | } 60 | 61 | void dfs(int x, int parent) { 62 | depth[x] = depth[parent] + 1; 63 | f[x][0] = parent; 64 | int i; 65 | for (i = 1; i <= MAX; ++i) { 66 | f[x][i] = f[f[x][i - 1]][i - 1]; 67 | } 68 | for (i = first[x]; i != 0; i = edge[i]->next) { 69 | int y = edge[i]->y; 70 | if (y != parent) { 71 | dfs(y, x); 72 | } 73 | } 74 | } 75 | 76 | int lca(int a, int b) { 77 | if (depth[a] < depth[b]) { 78 | int tmp = a; 79 | a = b; 80 | b = tmp; 81 | } 82 | int i; 83 | for (i = MAX; i >= 0; --i) { 84 | if (depth[a] - depth[b] >= pow2[i]) { 85 | a = f[a][i]; 86 | } 87 | } 88 | if (a == b) { 89 | return a; 90 | } 91 | for (i = MAX; i >= 0; --i) { 92 | if (f[a][i] != f[b][i]) { 93 | a = f[a][i]; 94 | b = f[b][i]; 95 | } 96 | } 97 | return f[a][0]; 98 | } 99 | 100 | int main() { 101 | scanf("%d", &n); 102 | scanf("%d", &m); 103 | scanf("%d", &root); 104 | init(); 105 | int i; 106 | for (i = 1; i <= n - 1; ++i) { 107 | int x; 108 | int y; 109 | scanf("%d", &x); 110 | scanf("%d", &y); 111 | addedge(x, y); 112 | addedge(y, x); 113 | } 114 | dfs(root, 0); 115 | for (i = 1; i <= m; ++i) { 116 | int a; 117 | int b; 118 | scanf("%d", &a); 119 | scanf("%d", &b); 120 | ans[i] = lca(a, b); 121 | } 122 | for (i = 1; i <= m; ++i) { 123 | printf("%d\n", ans[i]); 124 | } 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /test/optim/lunatic.ans: -------------------------------------------------------------------------------- 1 | 2 2 | 4 3 | 846 4 | -------------------------------------------------------------------------------- /test/optim/lunatic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int Mod; 5 | int **p; 6 | int *res; 7 | int **ksm; 8 | int *prime; 9 | int tot; 10 | int *v; 11 | int **q; 12 | int ***g; 13 | int ***Sum; 14 | int *m; 15 | int *b; 16 | int **Comb; 17 | 18 | int C; 19 | int M; 20 | int N; 21 | int *fn; 22 | int *fc; 23 | int **fm; 24 | 25 | void init() { 26 | tot = 0; 27 | C = 0; 28 | M = 0; 29 | N = 0; 30 | int i; 31 | int j; 32 | int k; 33 | g = malloc(sizeof(int **) * 6); 34 | for (i = 0; i < 6; i++) { 35 | g[i] = malloc(sizeof(int *) * 100001); 36 | for (j = 0; j < 100001; j++) { 37 | g[i][j] = malloc(sizeof(int) * 15); 38 | for (k = 0; k < 15; k++) 39 | g[i][j][k] = 0; 40 | } 41 | } 42 | Sum = malloc(sizeof(int **) * 6); 43 | for (i = 0; i < 6; i++) { 44 | Sum[i] = malloc(sizeof(int *) * 100001); 45 | for (j = 0; j < 100001; j++) { 46 | Sum[i][j] = malloc(sizeof(int) * 15); 47 | for (k = 0; k < 15; k++) 48 | Sum[i][j][k] = 0; 49 | } 50 | } 51 | fm = malloc(sizeof(int *) * 1001); 52 | for (i = 0; i < 1001; i++) { 53 | fm[i] = malloc(sizeof(int) * 13); 54 | for (j = 0; j < 13; j++) 55 | fm[i][j] = 0; 56 | } 57 | ksm = malloc(sizeof(int *) * 100001); 58 | for (i = 0; i < 100001; i++) { 59 | ksm[i] = malloc(sizeof(int) * 21); 60 | for (j = 0; j < 21; j++) 61 | ksm[i][j] = 0; 62 | } 63 | p = malloc(sizeof(int *) * 21); 64 | for (i = 0; i < 21; i++) { 65 | p[i] = malloc(sizeof(int) * 21); 66 | for (j = 0; j < 21; j++) 67 | p[i][j] = 0; 68 | } 69 | q = malloc(sizeof(int *) * 21); 70 | for (i = 0; i < 21; i++) { 71 | q[i] = malloc(sizeof(int) * 100001); 72 | for (j = 0; j < 100001; j++) 73 | q[i][j] = 0; 74 | } 75 | Comb = malloc(sizeof(int *) * 100001); 76 | for (i = 0; i < 100001; i++) { 77 | Comb[i] = malloc(sizeof(int) * 21); 78 | for (j = 0; j < 21; j++) 79 | Comb[i][j] = 0; 80 | } 81 | fn = malloc(sizeof(int) * 1001); 82 | for (i = 0; i < 1001; i++) 83 | fn[i] = 0; 84 | fc = malloc(sizeof(int) * 1001); 85 | for (i = 0; i < 1001; i++) 86 | fc[i] = 0; 87 | m = malloc(sizeof(int) * 1001); 88 | for (i = 0; i < 1001; i++) 89 | m[i] = 0; 90 | res = malloc(sizeof(int) * 1001); 91 | for (i = 0; i < 1001; i++) 92 | res[i] = 0; 93 | b = malloc(sizeof(int) * 1001); 94 | for (i = 0; i < 1001; i++) 95 | b[i] = 0; 96 | v = malloc(sizeof(int) * 100001); 97 | for (i = 0; i < 100001; i++) 98 | v[i] = 0; 99 | prime = malloc(sizeof(int) * 100001); 100 | for (i = 0; i < 100001; i++) 101 | prime[i] = 0; 102 | } 103 | int Ksm(int P, int x) { 104 | if (x == 0) 105 | return 1; 106 | if (x == 1) 107 | return P % Mod; 108 | int tmp; 109 | tmp = Ksm(P, x >> 1); 110 | if (x % 2 == 1) 111 | return tmp * tmp % Mod * P % Mod; 112 | else 113 | return tmp * tmp % Mod; 114 | } 115 | 116 | void Calculate_p() { 117 | int i; 118 | int j; 119 | p[0][0] = 1; 120 | p[1][1] = 1; 121 | p[1][0] = Mod - 1; 122 | for (i = 2; i <= C - 2; i++) { 123 | int tmp; 124 | tmp = Ksm(i, Mod - 2); 125 | for (j = 0; j < i; j++) 126 | p[i][j + 1] = p[i - 1][j]; 127 | for (j = 0; j <= i; j++) 128 | p[i][j] = (p[i][j] - p[i - 1][j] * i % Mod + Mod) * tmp % Mod; 129 | } 130 | } 131 | void Euler(int x) { 132 | 133 | tot = 0; 134 | q[x][1] = 1; 135 | int i; 136 | int j; 137 | for (i = 0; i < 100001; i++) 138 | v[i] = 0; 139 | for (i = 2; i <= M; i++) { 140 | if (v[i] == 0) { 141 | prime[++tot] = i; 142 | q[x][i] = (ksm[i][x] + Mod - 1) % Mod; 143 | } 144 | for (j = 1; j <= tot && prime[j] * i <= M; j++) { 145 | v[prime[j] * i] = 1; 146 | if (i % prime[j] == 0) { 147 | q[x][i * prime[j]] = q[x][i] * ksm[prime[j]][x] % Mod; 148 | break; 149 | } else 150 | q[x][i * prime[j]] = q[x][i] * q[x][prime[j]] % Mod; 151 | } 152 | } 153 | } 154 | void Calculate_q() { 155 | int i; 156 | for (i = 0; i <= C - 2; i++) 157 | Euler(i); 158 | } 159 | void Calculate_Ksm() { 160 | int i; 161 | int j; 162 | for (i = 1; i <= M; i++) { 163 | ksm[i][0] = 1; 164 | for (j = 1; j <= C - 2; j++) 165 | ksm[i][j] = ksm[i][j - 1] * i % Mod; 166 | } 167 | } 168 | void Calculate_G() { 169 | Calculate_Ksm(); 170 | Calculate_p(); 171 | Calculate_q(); 172 | int i; 173 | int j; 174 | int k; 175 | for (i = 1; i <= M; i++) 176 | for (j = 2; j <= C; j++) { 177 | for (k = 0; k <= j - 2; k++) 178 | g[0][i][j] = (g[0][i][j] + p[j - 2][k] * q[k][i]) % Mod; 179 | for (k = 1; k <= N; k++) 180 | g[k][i][j] = g[k - 1][i][j] * i % Mod; 181 | } 182 | for (k = 0; k <= N; k++) { 183 | for (i = 2; i <= C; i++) 184 | for (j = 1; j <= M; j++) { 185 | Sum[k][j][i] = Sum[k][j - 1][i] + g[k][j][i]; 186 | if (Sum[k][j][i] >= Mod) 187 | Sum[k][j][i] = Sum[k][j][i] - Mod; 188 | } 189 | } 190 | } 191 | void Calculate_Comb() { 192 | int i; 193 | int j; 194 | for (i = 0; i <= M; i++) 195 | Comb[i][0] = 1; 196 | for (i = 1; i <= M; i++) 197 | for (j = 1; j <= C; j++) { 198 | Comb[i][j] = Comb[i - 1][j] + Comb[i - 1][j - 1]; 199 | if (Comb[i][j] >= Mod) 200 | Comb[i][j] = Comb[i][j] - Mod; 201 | } 202 | } 203 | int main() { 204 | int T; 205 | int n; 206 | int c; 207 | 208 | scanf("%d", &T); 209 | init(); 210 | fn[1] = 2; 211 | fc[1] = 3; 212 | fm[1][1] = 3; 213 | fm[1][2] = 4; 214 | fn[2] = 3; 215 | fc[2] = 3; 216 | fm[2][1] = 3; 217 | fm[2][2] = 4; 218 | fm[2][3] = 4; 219 | fn[3] = 4; 220 | fc[3] = 4; 221 | fm[3][1] = 5; 222 | fm[3][2] = 7; 223 | fm[3][3] = 8; 224 | fm[3][4] = 9; 225 | C = 4; 226 | M = 9; 227 | N = 4; 228 | Mod = 10007; 229 | Calculate_G(); 230 | Calculate_Comb(); 231 | int rp; 232 | for (rp = 1; rp <= T; rp++) { 233 | n = fn[rp]; 234 | c = fc[rp]; 235 | int ii; 236 | for (ii = 1; ii <= n; ii++) 237 | m[ii] = fm[rp][ii]; 238 | if (n == 1) 239 | printf("%d\n", Comb[m[1]][c]); 240 | else { 241 | int ans; 242 | int l; 243 | int r; 244 | int temp; 245 | ans = 0; 246 | temp = 0; 247 | l = 0; 248 | r = 1; 249 | 250 | for (; r <= m[1]; r++) { 251 | int tmp; 252 | tmp = (m[1] / (m[1] / r)); 253 | int i; 254 | for (i = 2; i <= n; i++) { 255 | int get; 256 | get = m[i] / (m[i] / r); 257 | if (get < tmp) 258 | tmp = get; 259 | } 260 | if (m[1] < tmp) 261 | tmp = m[1]; 262 | r = tmp; 263 | b[0] = 1; 264 | for (i = 1; i <= n; i++) { 265 | int tmp1; 266 | int tmp2; 267 | int tmp3; 268 | tmp1 = (m[i] / r) % Mod; 269 | tmp2 = tmp1 * (tmp1 + 1) / 2 % Mod; 270 | tmp3 = m[i] * tmp1 % Mod; 271 | int j; 272 | for (j = 0; j < i; j++) 273 | res[j + 1] = b[j] * (Mod - tmp2) % Mod; 274 | res[0] = 0; 275 | for (j = 0; j < i; j++) 276 | res[j] = (res[j] + tmp3 * b[j]) % Mod; 277 | for (j = 0; j <= i; j++) 278 | b[j] = res[j]; 279 | } 280 | for (i = 0; i <= n; i++) 281 | ans = (ans + b[i] * (Sum[i][r][c] - Sum[i][l][c])) % Mod; 282 | l = r; 283 | } 284 | if (ans < 0) 285 | ans = ans + Mod; 286 | printf("%d\n", ans); 287 | } 288 | } 289 | return 0; 290 | } 291 | 292 | 293 | // lunatic-515030910648-yangzhuolin.txt -------------------------------------------------------------------------------- /test/optim/lunatic.in: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /test/optim/maxflow.ans: -------------------------------------------------------------------------------- 1 | 49 2 | -------------------------------------------------------------------------------- /test/optim/maxflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int **c; 5 | int ans = 0; 6 | int visit[110]; 7 | int pre[110]; 8 | int f[110]; 9 | int i; 10 | int j; 11 | int open; 12 | int closed; 13 | 14 | void origin(int N) { 15 | c = malloc(sizeof(int *) * N); 16 | for (i = 0; i < N; i++) { 17 | c[i] = malloc(sizeof(int) * N); 18 | for (j = 0; j < N; j++) 19 | c[i][j] = 0; 20 | } 21 | } 22 | 23 | int build(int start, int ending) { 24 | for (i = 1; i <= 49; i++) { 25 | for (j = 50; j <= 98 - i + 1; j++) { 26 | c[i][j] = 1; 27 | } 28 | } 29 | for (i = 1; i <= 49; i++) 30 | c[start][i] = 1; 31 | for (i = 50; i <= 98; i++) 32 | c[i][ending] = 1; 33 | return 0; 34 | } 35 | 36 | int find(int ending, int start, int flag) { 37 | open = 0; 38 | closed = 1; 39 | for (i = 1; i <= ending; i++) { 40 | visit[i] = 0; 41 | } 42 | f[1] = start; 43 | visit[start] = 1; 44 | pre[start] = 0; 45 | flag = 0; 46 | while (open < closed && flag == 0) { 47 | open++; 48 | i = f[open]; 49 | for (j = 1; j <= ending; j++) 50 | if (c[i][j] > 0 && visit[j] == 0) { 51 | visit[j] = 1; 52 | closed++; 53 | f[closed] = j; 54 | pre[j] = i; 55 | if (closed == ending) 56 | flag = 1; 57 | } 58 | } 59 | return flag; 60 | } 61 | 62 | int improve(int ending) { 63 | i = ending; 64 | ans++; 65 | while (pre[i] > 0) { 66 | j = pre[i]; 67 | c[j][i]--; 68 | c[i][j]++; 69 | i = j; 70 | } 71 | return 0; 72 | } 73 | 74 | int main() { 75 | origin(110); 76 | int k; 77 | int start; 78 | int ending; 79 | int flag; 80 | int i1; 81 | 82 | k = 0; 83 | start = 99; 84 | ending = 100; 85 | flag = 0; 86 | 87 | build(start, ending); 88 | while (find(ending, start, flag) > 0) { 89 | improve(ending); 90 | } 91 | printf("%d\n", ans); 92 | return 0; 93 | } 94 | 95 | /*!! metadata: 96 | === comment === 97 | // maxflow-5100379110-daibo.mx 98 | === input === 99 | 100 | === assert === 101 | output 102 | === timeout === 103 | 0.3 104 | === output === 105 | 49 106 | === phase === 107 | codegen pretest 108 | === is_public === 109 | True 110 | 111 | !!*/ 112 | -------------------------------------------------------------------------------- /test/optim/maxflow.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Engineev/ravel/5676d3ae1e1dcebee3b03252831eefa4ed5e01eb/test/optim/maxflow.in -------------------------------------------------------------------------------- /test/optim/pi.ans: -------------------------------------------------------------------------------- 1 | 3141592653589793238462643383279528841971693993751058209749445923078164062862089986280348253421170679821480865132823664709384469555822317253594081284811174502841270193852115559644622948954930381964428810975665933446128475648233786783165271201991456485669234634861045432664821339360726024914127372458706606315588174881520920962829254917153643678925903611330530548820466521384146951941511609433057273657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566438602139494639522473719070217986943702770539217176293176752384674818467669451320005681271452635608277857713427577896091736371787214684409012249534301465495853710579227968925892354201995611212902196864344181598136297747713099605187072113499999983729780499510597317328160963185 2 | -------------------------------------------------------------------------------- /test/optim/pi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | int a = 10000; 6 | int b = 0; 7 | int c = 2800; 8 | int d = 0; 9 | int e = 0; 10 | int *f = malloc(sizeof(int) * 2801); 11 | int g = 0; 12 | 13 | for (; b - c != 0;) 14 | f[b++] = a / 5; 15 | for (;; e = d % a) { 16 | d = 0; 17 | g = c * 2; 18 | if (g == 0) 19 | break; 20 | 21 | for (b = c;; d = d * b) { 22 | d = d + f[b] * a; 23 | f[b] = d % --g; 24 | d = d / g--; 25 | if (--b == 0) 26 | break; 27 | } 28 | 29 | c = c - 14; 30 | printf("%d", e + d / a); 31 | } 32 | printf("\n"); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/optim/pi.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Engineev/ravel/5676d3ae1e1dcebee3b03252831eefa4ed5e01eb/test/optim/pi.in -------------------------------------------------------------------------------- /test/optim/segtree.ans: -------------------------------------------------------------------------------- 1 | 25964 2 | -------------------------------------------------------------------------------- /test/optim/segtree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int* b; 5 | int* now; 6 | int* t; 7 | int* a; 8 | int n; 9 | int m; 10 | int p; 11 | int op; 12 | int L = 1; 13 | int* flag; 14 | int** s; 15 | int* sum; 16 | int ans = 0; 17 | 18 | //int b[500005]; 19 | //int now[500005]; 20 | //int t[500005]; 21 | //int a[200005]; 22 | //int n; 23 | //int m; 24 | //int p; 25 | //int op; 26 | //int L = 1; 27 | //int flag[500005]; 28 | //int s[500005][80]; 29 | //int sum[500005]; 30 | //int ans = 0; 31 | 32 | void init_global_array() { 33 | int sz = sizeof(int); 34 | b = malloc(sz * 500005); 35 | now = malloc(sz * 500005); 36 | t = malloc(sz * 500005); 37 | a = malloc(sz * 200005); 38 | flag = malloc(sz * 500005); 39 | s = malloc(sizeof(int*) * 500005); 40 | for (int i = 0; i < 500005; ++i) 41 | s[i] = malloc(sz * 80); 42 | sum = malloc(sz * 500005); 43 | } 44 | 45 | int square(int x) { return (x % p) * (x % p); } 46 | 47 | int gcd(int x, int y) { 48 | if (y == 0) 49 | return x; 50 | if (x < y) 51 | return gcd(y, x); 52 | else 53 | return gcd(y, x % y); 54 | } 55 | 56 | int lcm(int a, int b) { return a / gcd(a, b) * b; } 57 | 58 | int aa = 13131; 59 | int bb = 5353; 60 | int MOD = (2 << 14) - 7; 61 | int no = 1; 62 | 63 | int Rand() { 64 | int i = 1; 65 | for (i = 1; i < 3; i++) 66 | no = (no * aa + bb) % MOD; 67 | if (no < 0) { 68 | no = -no; 69 | } 70 | return no; 71 | } 72 | 73 | int RandRange(int low, int high) { return low + Rand() % (high - low + 1) + 1; } 74 | 75 | void init() { 76 | int* c; 77 | c = malloc(sizeof(int) * 140005); 78 | int i = 0; 79 | int j = 0; 80 | for (i = 2; i < p; ++i) 81 | c[i] = i; 82 | for (i = 2; i < p; ++i) 83 | for (j = 1; j <= 15; ++j) 84 | c[i] = square(c[i]) % p; 85 | for (i = 2; i < p; ++i) { 86 | int j; 87 | int x = c[i]; 88 | for (j = 1;; ++j) { 89 | x = square(x) % p; 90 | b[x] = 1; 91 | if (x == c[i]) 92 | break; 93 | } 94 | L = lcm(L, j); 95 | } 96 | b[0] = 1; 97 | b[1] = 1; 98 | } 99 | 100 | void build(int o, int l, int r) { 101 | int i = 0; 102 | if (l == r) { 103 | sum[o] = a[l]; 104 | if (a[l] < p && a[l] >= 0 && b[a[l] % p] > 0) { 105 | flag[o] = 1; 106 | s[o][0] = a[l]; 107 | for (i = 1; i < L; ++i) 108 | s[o][i] = square(s[o][i - 1]) % p; 109 | } 110 | now[o] = 0; 111 | } else { 112 | int lc = o * 2; 113 | int rc = o * 2 + 1; 114 | int mid = (l + r) / 2; 115 | build(lc, l, mid); 116 | build(rc, mid + 1, r); 117 | sum[o] = sum[lc] + sum[rc]; 118 | flag[o] = flag[lc] & flag[rc]; 119 | if (flag[o] > 0) { 120 | for (i = 0; i < L; ++i) 121 | s[o][i] = s[lc][i] + s[rc][i]; 122 | now[0] = 0; 123 | } 124 | } 125 | } 126 | 127 | void pushdown(int o) { 128 | if (t[o] > 0) { 129 | int lc = o * 2; 130 | int rc = o * 2 + 1; 131 | now[lc] = (now[lc] + t[o]) % L; 132 | sum[lc] = s[lc][now[lc]]; 133 | t[lc] = (t[lc] + t[o]) % L; 134 | now[rc] = (now[rc] + t[o]) % L; 135 | sum[rc] = s[rc][now[rc]]; 136 | t[rc] = (t[rc] + t[o]) % L; 137 | t[o] = 0; 138 | } 139 | } 140 | 141 | int pl = 0; 142 | int pr = 0; 143 | // 144 | void update(int o, int l, int r) { 145 | if (pl <= l && pr >= r && flag[o] > 0) { 146 | now[o] = (now[o] + 1) % L; 147 | sum[o] = s[o][now[o]]; 148 | t[o] = (t[o] + 1) % L; 149 | return; 150 | } 151 | if (l == r) { 152 | sum[o] = square(sum[o]) % p; 153 | if (b[sum[o]] > 0) { 154 | flag[o] = 1; 155 | s[o][0] = sum[o]; 156 | int i = 0; 157 | for (i = 1; i < L; ++i) 158 | s[o][i] = square(s[o][i - 1]) % p; 159 | } 160 | return; 161 | } 162 | if (t[o] > 0) 163 | pushdown(o); 164 | int lc = o * 2; 165 | int rc = o * 2 + 1; 166 | int mid = (l + r) / 2; 167 | if (pl <= mid) 168 | update(lc, l, mid); 169 | if (pr >= mid + 1) 170 | update(rc, mid + 1, r); 171 | sum[o] = sum[lc] + sum[rc]; 172 | flag[o] = flag[lc] & flag[rc]; 173 | if (flag[o] > 0) { 174 | int i = 0; 175 | for (i = 0; i < L; ++i) 176 | s[o][i] = s[lc][(i + now[lc]) % L] + s[rc][(i + now[rc]) % L]; 177 | now[o] = 0; 178 | } 179 | } 180 | 181 | int query(int o, int l, int r) { 182 | if (pl <= l && pr >= r) 183 | return sum[o]; 184 | int lc = o * 2; 185 | int rc = o * 2 + 1; 186 | int mid = (l + r) / 2; 187 | int ss = 0; 188 | if (t[o] > 0) 189 | pushdown(o); 190 | if (pl <= mid) 191 | ss = (ss + query(lc, l, mid)) % MOD; 192 | if (pr >= mid + 1) 193 | ss = (ss + query(rc, mid + 1, r)) % MOD; 194 | return ss; 195 | } 196 | 197 | int main() { 198 | init_global_array(); 199 | scanf("%d%d", &n, &m); 200 | scanf("%d", &p); 201 | int i = 1; 202 | for (i = 1; i <= n; ++i) 203 | a[i] = RandRange(0, p); 204 | init(); 205 | build(1, 1, n); 206 | while (m > 0) { 207 | op = Rand() % 2; 208 | pl = RandRange(1, n); 209 | pr = RandRange(1, n); 210 | while (pr <= pl) 211 | pr = RandRange(1, n); 212 | if (op == 0) 213 | update(1, 1, n); 214 | if (op == 1) 215 | ans = (ans + query(1, 1, n)) % MOD; 216 | m--; 217 | } 218 | printf("%d\n", ans); 219 | return 0; 220 | } 221 | 222 | 223 | // segtree-515030910592-lijinning.txt 224 | -------------------------------------------------------------------------------- /test/optim/segtree.in: -------------------------------------------------------------------------------- 1 | 40000 1000 9977 2 | -------------------------------------------------------------------------------- /test/optim/sha_1.ans: -------------------------------------------------------------------------------- 1 | 5B38674EB4BD02CEC1D41C8DE3CC14A9872A2656 2 | ACM 3 | -------------------------------------------------------------------------------- /test/optim/sha_1.c: -------------------------------------------------------------------------------- 1 | // Compute and Crack SHA-1 2 | // by zzk 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int hex2int(char *x) { 9 | int i; 10 | int result = 0; 11 | int len = strlen(x); 12 | for (i = 0; i < len; i++) { 13 | int digit = x[i]; 14 | if (digit >= 48 && digit <= 57) 15 | result = result * 16 + digit - 48; 16 | else if (digit >= 65 && digit <= 70) 17 | result = result * 16 + digit - 65 + 10; 18 | else if (digit >= 97 && digit <= 102) 19 | result = result * 16 + digit - 97 + 10; 20 | else 21 | return 0; 22 | } 23 | return result; 24 | } 25 | 26 | char asciiTable[] = " !\"#$%&'()*+,-./" 27 | "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" 28 | "abcdefghijklmnopqrstuvwxyz{|}~"; 29 | char int2chr(int x) { 30 | if (x >= 32 && x <= 126) 31 | return asciiTable[x - 32]; 32 | return 0; 33 | } 34 | char *toStringHex(int x) { 35 | char *ret = malloc(9); 36 | ret[8] = '\0'; 37 | int i; 38 | int pos = 0; 39 | for (i = 28; i >= 0; i = i - 4) { 40 | int digit = (x >> i) & 15; 41 | if (digit < 10) 42 | ret[pos++] = int2chr(48 + digit); 43 | else 44 | ret[pos++] = int2chr(65 + digit - 10); 45 | } 46 | return ret; 47 | } 48 | int rotate_left(int x, int shift) { 49 | if (shift == 1) 50 | return ((x & 2147483647) << 1) | ((x >> 31) & 1); 51 | if (shift == 31) 52 | return ((x & 1) << 31) | ((x >> 1) & 2147483647); 53 | return ((x & ((1 << (32 - shift)) - 1)) << shift) | 54 | ((x >> (32 - shift)) & ((1 << shift) - 1)); 55 | } 56 | // to avoid possible undefined behaviour when overflow 57 | int add(int x, int y) { 58 | int low = (x & 65535) + (y & 65535); 59 | int high = (((x >> 16) & 65535) + ((y >> 16) & 65535) + (low >> 16)) & 65535; 60 | return (high << 16) | (low & 65535); 61 | } 62 | int lohi(int lo, int hi) { return lo | (hi << 16); } 63 | 64 | int MAXCHUNK = 100; 65 | int MAXLENGTH; 66 | int **chunks; 67 | int *inputBuffer; 68 | int outputBuffer[5]; 69 | 70 | void initializeGlobalVariables() { 71 | MAXLENGTH = (MAXCHUNK - 1) * 64 - 16; 72 | chunks = malloc(sizeof(int *) * MAXCHUNK); 73 | for (int i = 0; i < MAXCHUNK; ++i) 74 | chunks[i] = malloc(sizeof(int) * 80); 75 | inputBuffer = malloc(sizeof(int) * MAXLENGTH); 76 | } 77 | 78 | int *sha1(int *input, int length) { 79 | int nChunk = (length + 64 - 56) / 64 + 1; 80 | if (nChunk > MAXCHUNK) { 81 | puts("nChunk > MAXCHUNK!"); 82 | return NULL; 83 | } 84 | int i; 85 | int j; 86 | for (i = 0; i < nChunk; i++) 87 | for (j = 0; j < 80; j++) 88 | chunks[i][j] = 0; 89 | for (i = 0; i < length; i++) 90 | chunks[i / 64][i % 64 / 4] = 91 | chunks[i / 64][i % 64 / 4] | (input[i] << ((3 - i % 4) * 8)); 92 | chunks[i / 64][i % 64 / 4] = 93 | chunks[i / 64][i % 64 / 4] | (128 << ((3 - i % 4) * 8)); 94 | chunks[nChunk - 1][15] = length << 3; 95 | chunks[nChunk - 1][14] = (length >> 29) & 7; 96 | 97 | int h0 = 1732584193; // 0x67452301 98 | int h1 = lohi(43913, 61389); // 0xEFCDAB89 99 | int h2 = lohi(56574, 39098); // 0x98BADCFE 100 | int h3 = 271733878; // 0x10325476 101 | int h4 = lohi(57840, 50130); // 0xC3D2E1F0 102 | for (i = 0; i < nChunk; i++) { 103 | for (j = 16; j < 80; j++) 104 | chunks[i][j] = rotate_left(chunks[i][j - 3] ^ chunks[i][j - 8] ^ 105 | chunks[i][j - 14] ^ chunks[i][j - 16], 106 | 1); 107 | 108 | int a = h0; 109 | int b = h1; 110 | int c = h2; 111 | int d = h3; 112 | int e = h4; 113 | for (j = 0; j < 80; j++) { 114 | int f; 115 | int k; 116 | if (j < 20) { 117 | f = (b & c) | ((~b) & d); 118 | k = 1518500249; // 0x5A827999 119 | } else if (j < 40) { 120 | f = b ^ c ^ d; 121 | k = 1859775393; // 0x6ED9EBA1 122 | } else if (j < 60) { 123 | f = (b & c) | (b & d) | (c & d); 124 | k = lohi(48348, 36635); // 0x8F1BBCDC 125 | } else { 126 | f = b ^ c ^ d; 127 | k = lohi(49622, 51810); // 0xCA62C1D6 128 | } 129 | int temp = add(add(add(rotate_left(a, 5), e), add(f, k)), chunks[i][j]); 130 | e = d; 131 | d = c; 132 | c = rotate_left(b, 30); 133 | b = a; 134 | a = temp; 135 | } 136 | h0 = add(h0, a); 137 | h1 = add(h1, b); 138 | h2 = add(h2, c); 139 | h3 = add(h3, d); 140 | h4 = add(h4, e); 141 | } 142 | outputBuffer[0] = h0; 143 | outputBuffer[1] = h1; 144 | outputBuffer[2] = h2; 145 | outputBuffer[3] = h3; 146 | outputBuffer[4] = h4; 147 | return outputBuffer; 148 | } 149 | 150 | void computeSHA1(char *input) { 151 | int i; 152 | int len = strlen(input); 153 | for (i = 0; i < len; i++) 154 | inputBuffer[i] = input[i]; 155 | int *result = sha1(inputBuffer, len); 156 | for (i = 0; i < 5; i++) 157 | printf("%s", toStringHex(result[i])); 158 | puts(""); 159 | } 160 | 161 | int nextLetter(int now) { 162 | if (now == 122) //'z' 163 | return -1; 164 | if (now == 90) //'Z' 165 | return 97; //'a' 166 | if (now == 57) //'9' 167 | return 65; 168 | return now + 1; 169 | } 170 | 171 | int nextText(int *now, int length) { 172 | int i; 173 | for (i = length - 1; i >= 0; i--) { 174 | now[i] = nextLetter(now[i]); 175 | if (now[i] == -1) 176 | now[i] = 48; //'0' 177 | else 178 | return 1; 179 | } 180 | return 0; 181 | } 182 | 183 | int array_equal(int *a, int *b, int len) { 184 | int i; 185 | for (i = 0; i < len; i++) 186 | if (a[i] != b[i]) 187 | return 0; 188 | return 1; 189 | } 190 | 191 | void crackSHA1(char *input) { 192 | int *target = malloc(sizeof(int) * 5); 193 | if (strlen(input) != 40) { 194 | puts("Invalid input"); 195 | return; 196 | } 197 | int i; 198 | for (i = 0; i < 5; i++) 199 | target[i] = 0; 200 | for (i = 0; i < 40; i = i + 4) { 201 | char buffer[5] = {0}; 202 | memcpy(buffer, input + i, 4); 203 | target[i / 8] = target[i / 8] | (hex2int(buffer) << (1 - (i / 4) % 2) * 16); 204 | } 205 | 206 | int MAXDIGIT = 4; 207 | int digit; 208 | for (digit = 1; digit <= MAXDIGIT; digit++) { 209 | for (i = 0; i < digit; i++) 210 | inputBuffer[i] = 48; 211 | while (1) { 212 | int *out = sha1(inputBuffer, digit); 213 | if (array_equal(out, target, 5)) { 214 | for (i = 0; i < digit; i++) 215 | printf("%c", int2chr(inputBuffer[i])); 216 | puts(""); 217 | return; 218 | } 219 | if (!nextText(inputBuffer, digit)) 220 | break; 221 | } 222 | } 223 | printf("Not Found!\n"); 224 | } 225 | 226 | int main() { 227 | initializeGlobalVariables(); 228 | int op; 229 | char input[256]; 230 | while (1) { 231 | scanf("%d", &op); 232 | if (op == 0) 233 | break; 234 | if (op == 1) { 235 | scanf("%s", input); 236 | computeSHA1(input); 237 | } else if (op == 2) { 238 | scanf("%s", input); 239 | crackSHA1(input); 240 | } 241 | } 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /test/optim/sha_1.in: -------------------------------------------------------------------------------- 1 | 1 acm2015 2 | 2 ABC64A57029F21F165A96BDB59F0351C7C7D1769 3 | 0 4 | -------------------------------------------------------------------------------- /test/run_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | import time 5 | 6 | compilers = { 7 | 'gcc': 'riscv32-unknown-linux-gnu-gcc -S -fno-section-anchors -O%d ' + 8 | '-o test.s test.c', 9 | # 'clang': 'clang-9 --target=riscv32 -march=rv32ima -S -O%d -o test.s test.c' 10 | } 11 | 12 | test_cases = [ 13 | 'optim/sha_1', 14 | 'optim/pi', 15 | 'optim/humble', 16 | 'optim/segtree', 17 | 'optim/lunatic', 18 | 'optim/maxflow', 19 | 'optim/dijkstra', 20 | 'optim/lca', 21 | 'optim/binary_tree', 22 | 'optim/kruskal' 23 | ] 24 | test_cases.sort() 25 | 26 | ravel_cmd = './ravel --oj-mode --enable-cache --timeout=30000000000 ' + \ 27 | '>ravel.out 2>/dev/null' 28 | diff_cmd = 'diff test.out test.ans -q >/dev/null 2>/dev/null' 29 | 30 | color_red = "\033[0;31m" 31 | color_green = "\033[0;32m" 32 | color_none = "\033[0m" 33 | 34 | 35 | def execute(cmd): 36 | # print("running: %s" % cmd) 37 | return subprocess.run(cmd, shell=True, executable="/bin/bash") 38 | 39 | 40 | # build 41 | directory = os.path.dirname(os.path.abspath(__file__)) 42 | os.chdir(os.path.join(directory, '..')) 43 | os.system('mkdir build; cd build') 44 | os.chdir(os.path.join(os.getcwd(), 'build')) 45 | if os.system('cmake .. && make'): 46 | print("Build failed") 47 | exit(1) 48 | os.chdir(directory) 49 | os.system('cp ../build/src/ravel ./') 50 | 51 | # test 52 | print("%d test cases." % len(test_cases)) 53 | total_time_used = 0 54 | failed_test_cases = [] 55 | for test_case in test_cases: 56 | print(test_case + ': ', end='\t', flush=True) 57 | execute('cp %s.c ./test.c' % test_case) 58 | execute('cp %s.in ./test.in' % test_case) 59 | execute('cp %s.ans ./test.ans' % test_case) 60 | execute('touch builtin.s') 61 | for compiler, compiler_cmd in compilers.items(): 62 | for opt_level in [0, 1, 2]: 63 | execute(compiler_cmd % opt_level) 64 | identifier = "%s-O%d" % (compiler, opt_level) 65 | start = time.time() 66 | ravel_res = execute(ravel_cmd) 67 | end = time.time() 68 | time_used = end - start 69 | total_time_used += time_used 70 | if ravel_res.returncode: 71 | print(color_red + identifier + '(RE)' + color_none, 72 | end='\t', flush=True) 73 | failed_test_cases.append(test_case + '(' + identifier + ')') 74 | continue 75 | diff_res = execute(diff_cmd) 76 | if diff_res.returncode: 77 | 78 | print(color_red + identifier + '(WA)' + color_none, 79 | end='\t', flush=True) 80 | failed_test_cases.append(test_case + '(' + identifier + ')') 81 | continue 82 | with open('ravel.out', 'r') as f: 83 | lines = f.readlines() 84 | for line in lines: 85 | if not line.startswith('time: '): 86 | continue 87 | cycles = int(line[6:]) 88 | break 89 | print(color_green + identifier + '(' + f'{cycles:,}' + ')' 90 | + color_none, end='\t', flush=True) 91 | print('') 92 | 93 | execute('rm ravel test.ans test.c test.in test.out test.s ravel.out') 94 | print('total time used = %d s' % total_time_used) 95 | if len(failed_test_cases) == 0: 96 | print('Passed all test cases') 97 | exit(0) 98 | print("Failed: ") 99 | for test_case in failed_test_cases: 100 | print(test_case) 101 | 102 | -------------------------------------------------------------------------------- /test/test-ravel-sim.cpp: -------------------------------------------------------------------------------- 1 | #include "ravel/ravel.h" 2 | 3 | int main() { 4 | std::size_t size = 32 * 1024 * 1024; 5 | std::uint32_t regs[32]; 6 | std::vector storage(size); 7 | 8 | // The function signature of ravel::simulate is 9 | // std::size_t simulate(const std::string &src, std::uint32_t *regs, 10 | // std::byte *storageBegin, std::byte *storageEnd); 11 | // The return value is the number of cycles. 12 | ravel::simulate(".text\n.globl main\nmain:\nnop\nret", regs, storage.data(), 13 | storage.data() + size); 14 | 15 | return 0; 16 | } --------------------------------------------------------------------------------