├── .clang-format ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── Doxyfile ├── Makefile ├── README.md ├── emu ├── emu-checkpoint.cpp ├── emu.cpp └── support │ ├── compress.cpp │ └── compress.h ├── include ├── ExpTree.h ├── Node.h ├── StmtTree.h ├── common.h ├── config.h ├── debug.h ├── graph.h ├── opFuncs.h ├── perf.h ├── splitNode.h ├── util.h └── valInfo.h ├── parser ├── PNode.cpp ├── include │ ├── PNode.h │ └── Parser.h ├── lexical.l ├── plib.cpp └── syntax.y ├── scripts ├── activeCount.sh ├── diff-graph.py ├── extract_perf_result.py ├── genSigDiff.py ├── init_resctrl.sh ├── perf_l3.py ├── regression.sh ├── run_until_exit.sh └── sigFilter.py └── src ├── AST2Graph.cpp ├── ENode.cpp ├── ExpTree.cpp ├── GraphDumper.cpp ├── MFFCPartition.cpp ├── Node.cpp ├── StmtTree.cpp ├── aliasAnalysis.cpp ├── clockOptimize.cpp ├── commonExpr.cpp ├── constantNode.cpp ├── cppEmitter.cpp ├── deadNodes.cpp ├── exprOpt.cpp ├── firParser.cpp ├── graph.cpp ├── graphPartition.cpp ├── inferWidth.cpp ├── instsGenerator.cpp ├── loopDetector.cpp ├── main.cpp ├── mergeNodes.cpp ├── mergeRegister.cpp ├── opFuncs.cpp ├── patternDetect.cpp ├── perfAnalysis.cpp ├── replication.cpp ├── resetAnalysis.cpp ├── splitArray.cpp ├── splitNodes.cpp ├── superNode.cpp ├── topoSort.cpp ├── traversal.cpp ├── usedBits.cpp └── util.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: Google 3 | # --- 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignTrailingComments: false # Should be off, causes many dummy problems!! 7 | AllowShortBlocksOnASingleLine: true 8 | AllowShortCaseLabelsOnASingleLine: true 9 | ColumnLimit: 120 10 | IndentCaseLabels: true 11 | IndentWidth: 2 12 | IndentWrappedFunctionNames: true 13 | MaxEmptyLinesToKeep: 1 14 | NamespaceIndentation: None 15 | DerivePointerAlignment: false 16 | ReflowComments: true # Should be true, otherwise clang-format doesn't touch comments 17 | SortIncludes: Never 18 | SpaceBeforeAssignmentOperators: true 19 | Standard: c++20 20 | TabWidth: 2 21 | UseTab: Never # Available options are Never, Always, ForIndentation 22 | AllowShortEnumsOnASingleLine: true 23 | BreakBeforeTernaryOperators: true 24 | AlignOperands: true 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ready-to-run/SimTop-xiangshan.hi.fir filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: [ v1-dev, master ] 5 | pull_request: 6 | branches: [ v1-dev, master ] 7 | jobs: 8 | build_rocket: 9 | runs-on: ubuntu-24.04 10 | steps: 11 | - name: Check out code 12 | uses: actions/checkout@v2 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: 3.x 16 | - name: Install dependencies 17 | run: | 18 | sudo apt install -y clang llvm doxygen flex bison libfl-dev ccache 19 | - name: Untar linux.bin 20 | run: | 21 | git submodule set-url ready-to-run https://github.com/jaypiper/gsim-ready-to-run.git 22 | make init 23 | - name: Compile 24 | run: | 25 | make compile dutName=rocket -j `nproc` 26 | - name: Build EMU 27 | run: | 28 | make difftest MODE=0 dutName=rocket -j `nproc` 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | obj/ 3 | .vscode/ 4 | out/ 5 | logs/ 6 | *log* 7 | obj_dir 8 | tests 9 | tmp* 10 | *bin/ 11 | .cache/ 12 | compile_commands.json 13 | data/ 14 | doc/html 15 | *.out 16 | *.data* 17 | *.txt 18 | emu/obj* 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ready-to-run"] 2 | path = ready-to-run 3 | url = git@github.com:jaypiper/gsim-ready-to-run.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GSIM: A Fast RTL Simulator for Large-Scale Designs 2 | 3 | GSIM accepts chirrtl, and compiles it to C++ 4 | 5 | ## Prerequisites 6 | 7 | + Install [GMP](https://gmplib.org/), [clang 16+](https://clang.llvm.org/). 8 | 9 | ## Quike Start 10 | 11 | + GSIM provides 4 RISC-V cores ready for simulation: [ysyx3](https://ysyx.oscc.cc/), [Rocket](https://github.com/chipsalliance/rocket-chip), [BOOM](https://github.com/riscv-boom/riscv-boom), [XiangShan](https://github.com/OpenXiangShan/XiangShan). 12 | 13 | + To try GSIM, using 14 | ``` 15 | $ make init 16 | $ make run dutName=core 17 | ``` 18 | + Set core to `ysyx3`, `rocket`, `small-boom`, `large-boom`, `minimal-xiangshan` or `default-xiangshan` 19 | 20 | ## Usage 21 | 22 | + Run `make build-gsim` to build GSIM 23 | + Run `build/gsim/gsim $(chirrtl-file)` to compile chirrtl to C++ 24 | + Refer to `build/gsim/gsim --help` for more information 25 | + See [C++ harness example](https://github.com/jaypiper/simulator/blob/master/emu/emu.cpp) to know how it interacts with the emitted C++ code. 26 | -------------------------------------------------------------------------------- /emu/emu-checkpoint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 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 | #include 16 | #include 17 | #include 18 | 19 | #include "support/compress.h" 20 | 21 | #define DUT_MEMORY memory$ram$rdata_mem$mem 22 | #define REF_MEMORY SimTop__DOT__memory__DOT__ram__DOT__rdata_mem__DOT__mem_ext__DOT__Memory 23 | 24 | #define MEM_SIZE (8 * 1024 * 1024 * 1024UL) 25 | #define MAX_INSTS 40000000 26 | size_t warmupInsts = 20000000; 27 | 28 | #if not defined(__DUT_minimal_xiangshan__) && not defined(__DUT_default_xiangshan__) 29 | #error checkpoint require Xiangshan 30 | #endif 31 | 32 | #if defined(GSIM) 33 | #include DUT_HEADER 34 | DUT_NAME* dut; 35 | uint64_t* g_mem; 36 | // unused blackbox 37 | void imsic_csr_top(uint8_t _0, uint8_t _1, uint16_t _2, uint8_t _3, uint8_t _4, uint16_t _5, uint8_t _6, uint8_t _7, uint8_t _8, uint8_t _9, uint8_t _10, uint8_t _11, uint64_t _12, uint8_t& _13, uint64_t& _14, uint8_t& _15, uint8_t& _16, uint32_t& _17, uint32_t& _18, uint32_t& _19) { 38 | _13 = 0; 39 | _15 = 0; 40 | _16 = 0; // o_irq 41 | _17 = 0; 42 | _18 = 0; 43 | _19 = 0; 44 | } 45 | 46 | // unused blackbox 47 | void SimJTAG(uint8_t _0, uint8_t& _1, uint8_t& _2, uint8_t& _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7, uint32_t& _8) { 48 | _1 = 1; // TRSTn 49 | _2 = 0; // TMS 50 | _3 = 0; // TDI 51 | _8 = 0; 52 | } 53 | 54 | // unused blackbox 55 | void FlashHelper(uint8_t en, uint32_t addr, uint64_t &data) { 56 | data = 0; 57 | } 58 | 59 | // unused blackbox 60 | void SDCardHelper(uint8_t setAddr, uint32_t addr, uint8_t ren, uint32_t& data) { 61 | data = 0; 62 | } 63 | 64 | void MemRWHelper(uint8_t r_enable, uint64_t r_index, uint64_t& r_data, uint8_t w_enable, uint64_t w_index, uint64_t w_data, uint64_t w_mask){ 65 | if(r_enable){ 66 | r_data = g_mem[r_index]; 67 | } 68 | if(w_enable){ 69 | g_mem[w_index] = (g_mem[w_index] & ~w_mask) | (w_data & w_mask); 70 | } 71 | } 72 | 73 | void dut_init(DUT_NAME *dut) { 74 | dut->set_difftest$$perfCtrl$$clean(0); 75 | dut->set_difftest$$perfCtrl$$dump(0); 76 | dut->set_difftest$$logCtrl$$begin(0); 77 | dut->set_difftest$$logCtrl$$end(0); 78 | dut->set_difftest$$logCtrl$$level(0); 79 | dut->set_difftest$$uart$$in$$ch(-1); 80 | } 81 | 82 | void dut_hook(DUT_NAME *dut) { 83 | if (dut->get_difftest$$uart$$out$$valid()) { 84 | printf("%c", dut->get_difftest$$uart$$out$$ch()); 85 | fflush(stdout); 86 | } 87 | } 88 | #endif 89 | 90 | #if defined(VERILATOR) 91 | #include "verilated.h" 92 | #include REF_HEADER 93 | #if defined (V_WAVE) 94 | #include "verilated_fst_c.h" 95 | VerilatedFstC *tfp; 96 | const std::unique_ptr contextp{new VerilatedContext}; 97 | #endif 98 | REF_NAME* ref; 99 | uint64_t* v_mem; 100 | void ref_init(REF_NAME *ref) { 101 | ref->difftest_perfCtrl_clean = ref->difftest_perfCtrl_dump = 0; 102 | ref->difftest_uart_in_ch = -1; 103 | ref->difftest_uart_in_valid = 0; 104 | 105 | #if defined(V_WAVE) 106 | Verilated::traceEverOn(true); 107 | tfp = new VerilatedFstC; 108 | ref->trace(tfp, 10); 109 | Verilated::mkdir("wave/"); 110 | tfp->open("wave/V_wave.fst"); 111 | if(tfp->isOpen() == false){ 112 | printf("Fail to open wave file!\n"); 113 | } 114 | #endif 115 | } 116 | 117 | void ref_hook(REF_NAME *ref) { 118 | if (ref->difftest_uart_out_valid) { 119 | printf("%c", ref->difftest_uart_out_ch); 120 | fflush(stdout); 121 | } 122 | } 123 | 124 | extern "C" void flash_read(unsigned int addr, unsigned long long* data){ 125 | printf("WARNING: Trying to invoke flash_read\n"); 126 | } 127 | 128 | extern "C" void sd_setaddr(int addr){ 129 | printf("WARNING: Trying to invoke sd_setaddr\n"); 130 | } 131 | 132 | extern "C" void sd_read(int* data){ 133 | printf("WARNING: Trying to invoke sd_read\n"); 134 | } 135 | 136 | extern "C" long long difftest_ram_read(long long rIdx){ 137 | return v_mem[rIdx]; 138 | } 139 | 140 | extern "C" void difftest_ram_write(long long index, long long data, long long mask){ 141 | v_mem[index] = (v_mem[index] & ~mask) | (data & mask); 142 | } 143 | #endif 144 | 145 | static size_t program_sz = 0; 146 | static bool dut_end = false; 147 | 148 | size_t readFromBin(void* dest, const char* filename, long max_bytes) { 149 | uint64_t file_size; 150 | std::ifstream file(filename, std::ios::binary | std::ios::in); 151 | if(!file.is_open()){ 152 | printf("Can't open %s\n", filename); 153 | return 0; 154 | } 155 | file.seekg(0, std::ios::end); 156 | file_size = file.tellg(); 157 | file.seekg(0, std::ios::beg); 158 | 159 | uint64_t read_size = (file_size > max_bytes) ? max_bytes : file_size; 160 | file.read(static_cast(dest), read_size); 161 | file.close(); 162 | return read_size; 163 | } 164 | 165 | void load_program(void* dest,const char* filename) { 166 | assert(filename != NULL); 167 | printf("The image is %s\n", filename); 168 | if (isGzFile(filename)) { 169 | printf("Gzip file detected and loading image from extracted gz file\n"); 170 | program_sz = readFromGz(dest, filename, MEM_SIZE, LOAD_RAM); 171 | } else if (isZstdFile(filename)) { 172 | printf("Zstd file detected and loading image from extracted zstd file\n"); 173 | program_sz = readFromZstd(dest, filename, MEM_SIZE, LOAD_RAM); 174 | } else { 175 | printf("Bin file detected and loading image from binary file\n"); 176 | program_sz = readFromBin(dest, filename, MEM_SIZE); 177 | } 178 | 179 | printf("load program size: 0x%lx\n", program_sz); 180 | assert(program_sz > 0 && program_sz <= MEM_SIZE); 181 | return; 182 | } 183 | 184 | // load gcpt 185 | void overwrite_ram(void* mem, const char* filename) { 186 | std::fstream fs(filename, std::ios::binary | std::ios::in); 187 | if (!fs.is_open()) { 188 | printf("Failed to open: %s\n", filename); 189 | exit(EXIT_FAILURE); 190 | } 191 | fs.seekg(0, std::ios::end); 192 | auto file_size = fs.tellg(); 193 | fs.seekg(0, std::ios::beg); 194 | if (!fs.read((char*)mem, file_size)) { 195 | printf("Failed to read: %s\n", filename); 196 | exit(EXIT_FAILURE); 197 | } 198 | std::cout<< "size of gcpt is " << file_size << std::endl; 199 | 200 | fs.close(); 201 | } 202 | 203 | void init_sim_mem(int &mem_fd, const char* filename, const char* gcptname){ 204 | mem_fd = memfd_create("sim_mem", 0); 205 | if(mem_fd == -1){ 206 | printf("Couldn't memfd_create\n"); 207 | exit(-1); 208 | } 209 | ftruncate(mem_fd, MEM_SIZE); 210 | 211 | auto mem = (uint64_t*)mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0); 212 | if(mem == MAP_FAILED){ 213 | printf("Couldn't mmap\n"); 214 | exit(-1); 215 | } 216 | // This way, we only need to load those two file once when diff-testing 217 | load_program(mem, filename); 218 | overwrite_ram(mem, gcptname); 219 | 220 | munmap(mem, MEM_SIZE); 221 | } 222 | 223 | uint64_t* new_mem(const char* filename, const char* gcptname){ 224 | static int mem_fd =0; 225 | if(mem_fd == 0){ 226 | init_sim_mem(mem_fd, filename, gcptname); 227 | } 228 | auto mem = (uint64_t*)mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, mem_fd, 0); 229 | if(mem == MAP_FAILED){ 230 | printf("Couldn't mmap\n"); 231 | exit(-1); 232 | } 233 | return mem; 234 | } 235 | 236 | 237 | static void del_mem(void* mem) { 238 | munmap(mem, MEM_SIZE); 239 | } 240 | 241 | #ifdef GSIM 242 | void dut_cycle(int n) { while (n --) dut->step(); } 243 | void dut_reset() { dut->set_reset(1); dut_cycle(10); dut->set_reset(0); } 244 | #endif 245 | #ifdef VERILATOR 246 | void ref_cycle(int n) { 247 | while (n --) { 248 | #ifdef V_WAVE 249 | contextp->timeInc(1); 250 | #endif 251 | ref->clock = 0; ref->eval(); 252 | #ifdef V_WAVE 253 | tfp->dump(contextp->time()); 254 | contextp->timeInc(1); 255 | #endif 256 | ref->clock = 1; ref->eval(); 257 | #ifdef V_WAVE 258 | tfp->dump(contextp->time()); 259 | #endif 260 | } 261 | } 262 | void ref_reset() { ref->reset = 1; ref_cycle(10); ref->reset = 0; } 263 | #endif 264 | 265 | #if defined(VERILATOR) && defined(GSIM) 266 | bool checkSig(bool display, REF_NAME* ref, DUT_NAME* dut); 267 | bool checkSignals(bool display) { 268 | return checkSig(display, ref, dut); 269 | } 270 | #endif 271 | 272 | int main(int argc, char** argv) { 273 | #ifdef GSIM 274 | dut = new DUT_NAME(); 275 | g_mem = new_mem(argv[2], argv[1]); 276 | 277 | dut_init(dut); 278 | dut_reset(); 279 | dut_cycle(1); 280 | #endif 281 | #ifdef VERILATOR 282 | ref = new REF_NAME(); 283 | v_mem = new_mem(argv[2], argv[1]); 284 | ref_init(ref); 285 | ref_reset(); 286 | #endif 287 | std::cout << "start testing.....\n"; 288 | std::signal(SIGINT, [](int){ dut_end = true; }); 289 | std::signal(SIGTERM, [](int){ dut_end = true; }); 290 | uint64_t cycles = 0; 291 | #ifdef PERF 292 | FILE* activeFp = fopen(ACTIVE_FILE, "w"); 293 | #endif 294 | std::size_t instrCnt = 0; 295 | auto start = std::chrono::system_clock::now(); 296 | while (!dut_end) { 297 | #ifdef VERILATOR 298 | ref_cycle(1); 299 | ref_hook(ref); 300 | instrCnt += ref->rootp->SimTop__DOT__l_soc__DOT__core_with_l2__DOT__core__DOT__backend__DOT__inner_ctrlBlock__DOT__io_robio_csr_perfinfo_retiredInstr_REG; 301 | if (instrCnt >= warmupInsts) { 302 | ref->difftest_perfCtrl_clean = 1; 303 | ref->difftest_perfCtrl_dump = 1; 304 | std::cout << "cycleCnt = " << cycles << std::endl; 305 | std::cout << "instrCnt = " << instrCnt << std::endl; 306 | } 307 | #endif 308 | #if defined(GSIM) 309 | dut_cycle(1); 310 | dut_hook(dut); 311 | #if not defined(VERILATOR) 312 | instrCnt += dut->l_soc$core_with_l2$core$backend$inner$ctrlBlock$io_robio_csr_perfinfo_retiredInstr_REG; 313 | #endif 314 | if (instrCnt >= warmupInsts) { 315 | printf("Warmup finished. The performance counters will be dumped and then reset.\n"); 316 | dut->set_difftest$$perfCtrl$$clean(true); 317 | dut->set_difftest$$perfCtrl$$dump(true); 318 | std::cout << "cycleCnt = " << cycles << std::endl; 319 | std::cout << "instrCnt = " << instrCnt << std::endl; 320 | } 321 | #endif 322 | if (instrCnt >= warmupInsts) warmupInsts = -1; 323 | cycles++; 324 | #if defined(VERILATOR) && defined(GSIM) 325 | bool isDiff = checkSignals(false); 326 | if(isDiff) { 327 | printf("all Sigs:\n -----------------\n"); 328 | checkSignals(true); 329 | printf("ALL diffs: dut -- ref\n"); 330 | printf("Failed after %ld cycles\n", cycles); 331 | checkSignals(false); 332 | return -1; 333 | } 334 | #endif 335 | if ((cycles % 100000) == 0 || dut_end || instrCnt >= MAX_INSTS) { 336 | if(instrCnt >= MAX_INSTS) dut_end = 1; 337 | auto dur = std::chrono::system_clock::now() - start; 338 | auto msec = std::chrono::duration_cast(dur); 339 | fprintf(stderr, "cycles %ld (%ld ms, %ld per sec) instructs %zu\n", 340 | cycles, msec.count(), cycles * 1000 / msec.count(), instrCnt); 341 | } 342 | 343 | } 344 | 345 | auto now = std::chrono::system_clock::now(); 346 | auto dur = now - start; 347 | 348 | std::cout << "Host time spent: " << std::chrono::duration_cast(dur).count() << "ms" << std::endl; 349 | #ifdef GSIM 350 | del_mem(g_mem); 351 | #endif 352 | #ifdef VERILATOR 353 | del_mem(v_mem); 354 | #endif 355 | #ifdef V_WAVE 356 | tfp->flush(); 357 | tfp->close(); 358 | #endif 359 | return 0; 360 | } 361 | -------------------------------------------------------------------------------- /emu/emu.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define CYCLE_STEP_PERCENT 1 16 | 17 | #if defined(__DUT_ysyx3__) 18 | #define DUT_MEMORY mem$ram 19 | #define REF_MEMORY newtop__DOT__mem__DOT__ram_ext__DOT__Memory 20 | #define CYCLE_MAX_PERF 5000000 21 | #define CYCLE_MAX_SIM 11000000 22 | #elif defined(__DUT_NutShell__) 23 | #define DUT_MEMORY mem$rdata_mem$mem 24 | #define REF_MEMORY SimTop__DOT__mem__DOT__rdata_mem__DOT__mem_ext__DOT__Memory 25 | #define CYCLE_MAX_PERF 50000000 26 | #define CYCLE_MAX_SIM 250000000 27 | #elif defined(__DUT_rocket__) 28 | #define DUT_MEMORY mem$srams$mem 29 | #define REF_MEMORY TestHarness__DOT__mem__DOT__srams__DOT__mem_ext__DOT__Memory 30 | #define CYCLE_MAX_PERF 2000000 31 | #define CYCLE_MAX_SIM 4200000 32 | #elif defined(__DUT_large_boom__) || defined(__DUT_small_boom__) 33 | #define DUT_MEMORY mem$srams$mem 34 | #define REF_MEMORY TestHarness__DOT__mem__DOT__srams__DOT__mem_ext__DOT__Memory 35 | #define CYCLE_MAX_PERF 1000000 36 | #ifdef __DUT_large_boom__ 37 | #define CYCLE_MAX_SIM 3900000 38 | #else 39 | #define CYCLE_MAX_SIM 5400000 40 | #endif 41 | #elif defined(__DUT_minimal_xiangshan__) || defined(__DUT_default_xiangshan__) 42 | #define DUT_MEMORY memory$ram$rdata_mem$mem 43 | #define REF_MEMORY SimTop__DOT__memory__DOT__ram__DOT__rdata_mem__DOT__mem_ext__DOT__Memory 44 | #define CYCLE_MAX_PERF 500000 45 | #ifdef __DUT_default_xiangshan__ 46 | #define CYCLE_MAX_SIM 1900000 47 | #else 48 | #define CYCLE_MAX_SIM 3400000 49 | #endif 50 | 51 | // unused blackbox 52 | void imsic_csr_top(uint8_t _0, uint8_t _1, uint16_t _2, uint8_t _3, uint8_t _4, uint16_t _5, uint8_t _6, uint8_t _7, uint8_t _8, uint8_t _9, uint8_t _10, uint8_t _11, uint64_t _12, uint8_t& _13, uint64_t& _14, uint8_t& _15, uint8_t& _16, uint32_t& _17, uint32_t& _18, uint32_t& _19) { 53 | _13 = 0; 54 | _15 = 0; 55 | _16 = 0; // o_irq 56 | _17 = 0; 57 | _18 = 0; 58 | _19 = 0; 59 | } 60 | 61 | // unused blackbox 62 | void SimJTAG(uint8_t _0, uint8_t& _1, uint8_t& _2, uint8_t& _3, uint8_t _4, uint8_t _5, uint8_t _6, uint8_t _7, uint32_t& _8) { 63 | _1 = 1; // TRSTn 64 | _2 = 0; // TMS 65 | _3 = 0; // TDI 66 | _8 = 0; 67 | } 68 | 69 | // unused blackbox 70 | void FlashHelper(uint8_t en, uint32_t addr, uint64_t &data) { 71 | data = 0; 72 | } 73 | 74 | // unused blackbox 75 | void SDCardHelper(uint8_t setAddr, uint32_t addr, uint8_t ren, uint32_t& data) { 76 | data = 0; 77 | } 78 | 79 | #else 80 | #error Unsupport DUT = DUT_NAME 81 | #endif 82 | 83 | #if defined(GSIM) 84 | #include DUT_HEADER 85 | static DUT_NAME* dut; 86 | 87 | void dut_init(DUT_NAME *dut) { 88 | #if defined(__DUT_NutShell__) 89 | dut->set_difftest$$logCtrl$$begin(0); 90 | dut->set_difftest$$logCtrl$$end(0); 91 | dut->set_difftest$$uart$$in$$ch(-1); 92 | #elif defined(__DUT_minimal_xiangshan__) || defined(__DUT_default_xiangshan__) 93 | // dut->set_difftest$$perfCtrl$$clean(0); 94 | // dut->set_difftest$$perfCtrl$$dump(0); 95 | // dut->set_difftest$$logCtrl$$begin(0); 96 | // dut->set_difftest$$logCtrl$$end(0); 97 | // dut->set_difftest$$logCtrl$$level(0); 98 | dut->set_difftest$$uart$$in$$ch(-1); 99 | #endif 100 | } 101 | 102 | void dut_hook(DUT_NAME *dut) { 103 | #if defined(__DUT_NutShell__) 104 | if (dut->get_difftest$$uart$$out$$valid()) { 105 | printf("%c", dut->get_difftest$$uart$$out$$ch()); 106 | fflush(stdout); 107 | } 108 | #elif defined(__DUT_minimal_xiangshan__) || defined(__DUT_default_xiangshan__) 109 | if (dut->get_difftest$$uart$$out$$valid()) { 110 | printf("%c", dut->get_difftest$$uart$$out$$ch()); 111 | fflush(stdout); 112 | } 113 | #endif 114 | } 115 | #endif 116 | 117 | #if defined(VERILATOR) 118 | #include "verilated.h" 119 | #include REF_HEADER 120 | static REF_NAME* ref; 121 | 122 | void ref_init(REF_NAME *ref) { 123 | #if defined(__DUT_NutShell__) 124 | ref->rootp->difftest_logCtrl_begin = ref->rootp->difftest_logCtrl_begin = 0; 125 | ref->rootp->difftest_uart_in_valid = -1; 126 | #elif defined(__DUT_minimal_xiangshan__) || defined(__DUT_default_xiangshan__) 127 | ref->difftest_perfCtrl_clean = ref->difftest_perfCtrl_dump = 0; 128 | ref->difftest_uart_in_ch = -1; 129 | ref->difftest_uart_in_valid = 0; 130 | #endif 131 | } 132 | 133 | void ref_hook(REF_NAME *ref) { 134 | #if defined(__DUT_NutShell__) 135 | if (ref->rootp->difftest_uart_out_valid) { 136 | printf("%c", ref->rootp->difftest_uart_out_ch); 137 | fflush(stdout); 138 | } 139 | #elif defined(__DUT_minimal_xiangshan__) || defined(__DUT_default_xiangshan__) 140 | if (ref->difftest_uart_out_valid) { 141 | printf("%c", ref->difftest_uart_out_ch); 142 | fflush(stdout); 143 | } 144 | #endif 145 | } 146 | #endif 147 | 148 | #if defined(GSIM_DIFF) 149 | #error not support now 150 | #include 151 | REF_NAME* ref; 152 | #endif 153 | 154 | static int program_sz = 0; 155 | static int program_fd = 0; 156 | static void *program = NULL; 157 | static bool dut_end = false; 158 | 159 | template 160 | std::vector sort_indexes(const std::vector &v) { 161 | 162 | // initialize original index locations 163 | std::vector idx(v.size()); 164 | iota(idx.begin(), idx.end(), 0); 165 | 166 | // when v contains elements of equal values 167 | stable_sort(idx.begin(), idx.end(), 168 | [&v](size_t i1, size_t i2) {return v[i1] < v[i2];}); 169 | 170 | return idx; 171 | } 172 | 173 | static void load_program(const char *filename) { 174 | assert(filename != NULL); 175 | program_fd = open(filename, O_RDONLY); 176 | assert(program_fd != -1); 177 | 178 | struct stat s; 179 | int ret = fstat(program_fd, &s); 180 | assert(ret == 0); 181 | program_sz = s.st_size; 182 | 183 | program = mmap(NULL, program_sz, PROT_READ, MAP_PRIVATE, program_fd, 0); 184 | assert(program != (void *)-1); 185 | 186 | printf("load program size: 0x%x\n", program_sz); 187 | } 188 | 189 | static void close_program() { 190 | munmap(program, program_sz); 191 | close(program_fd); 192 | } 193 | 194 | #ifdef GSIM 195 | void dut_cycle(int n) { while (n --) dut->step(); } 196 | void dut_reset() { dut->set_reset(1); dut_cycle(10); dut->set_reset(0); } 197 | #endif 198 | #ifdef VERILATOR 199 | void ref_cycle(int n) { 200 | while (n --) { 201 | ref->clock = 0; ref->eval(); 202 | ref->clock = 1; ref->eval(); 203 | } 204 | } 205 | void ref_reset() { ref->reset = 1; ref_cycle(10); ref->reset = 0; } 206 | #endif 207 | #ifdef GSIM_DIFF 208 | void ref_cycle(int n) { while (n --) ref->step(); } 209 | void ref_reset() { ref->set_reset(1); ref_cycle(10); ref->set_reset(0); } 210 | #endif 211 | 212 | #if (defined(VERILATOR) || defined(GSIM_DIFF)) && defined(GSIM) 213 | bool checkSig(bool display, REF_NAME* ref, DUT_NAME* dut); 214 | bool checkSignals(bool display) { 215 | return checkSig(display, ref, dut); 216 | } 217 | #endif 218 | 219 | int main(int argc, char** argv) { 220 | load_program(argv[1]); 221 | #ifdef GSIM 222 | dut = new DUT_NAME(); 223 | memcpy(&dut->DUT_MEMORY, program, program_sz); 224 | dut_init(dut); 225 | dut_reset(); 226 | #endif 227 | #ifdef VERILATOR 228 | ref = new REF_NAME(); 229 | memcpy(&ref->rootp->REF_MEMORY, program, program_sz); 230 | ref_init(ref); 231 | ref_reset(); 232 | #endif 233 | #ifdef GSIM_DIFF 234 | ref = new REF_NAME(); 235 | memcpy(&ref->DUT_MEMORY, program, program_sz); 236 | ref_reset(); 237 | #endif 238 | close_program(); 239 | 240 | std::cout << "start testing.....\n"; 241 | std::signal(SIGINT, [](int){ dut_end = true; }); 242 | std::signal(SIGTERM, [](int){ dut_end = true; }); 243 | uint64_t cycles = 0; 244 | #ifdef PERF 245 | FILE* activeFp = fopen(ACTIVE_FILE, "w"); 246 | #endif 247 | auto start = std::chrono::system_clock::now(); 248 | while (!dut_end) { 249 | #if defined(GSIM) 250 | dut_cycle(1); 251 | dut_hook(dut); 252 | #endif 253 | #ifdef VERILATOR 254 | ref_cycle(1); 255 | ref_hook(ref); 256 | #endif 257 | #ifdef GSIM_DIFF 258 | ref_cycle(1); 259 | #endif 260 | cycles ++; 261 | #if (defined(VERILATOR) || defined(GSIM_DIFF)) && defined(GSIM) 262 | bool isDiff = checkSignals(false); 263 | if(isDiff) { 264 | printf("all Sigs:\n -----------------\n"); 265 | checkSignals(true); 266 | printf("ALL diffs: dut -- ref\n"); 267 | printf("Failed after %ld cycles\n", cycles); 268 | checkSignals(false); 269 | return -1; 270 | } 271 | #endif 272 | if (cycles % (CYCLE_MAX_SIM / (CYCLE_STEP_PERCENT * 100)) == 0 && cycles <= CYCLE_MAX_SIM) { 273 | auto dur = std::chrono::system_clock::now() - start; 274 | auto msec = std::chrono::duration_cast(dur); 275 | fprintf(stderr, "cycles %ld (%ld ms, %ld per sec) simulation process %.2lf%% \n", 276 | cycles, msec.count(), cycles * 1000 / msec.count(), (double)cycles * 100 / CYCLE_MAX_SIM); 277 | #ifdef PERF 278 | size_t totalActives = 0; 279 | size_t validActives = 0; 280 | size_t nodeActives = 0; 281 | for (size_t i = 0; i < sizeof(dut->activeTimes) / sizeof(dut->activeTimes[0]); i ++) { 282 | totalActives += dut->activeTimes[i]; 283 | validActives += dut->validActive[i]; 284 | nodeActives += dut->nodeNum[i] * dut->activeTimes[i]; 285 | } 286 | printf("nodeNum %ld totalActives %ld activePerCycle %ld totalValid %ld validPerCycle %ld nodeActive %ld\n", 287 | nodeNum, totalActives, totalActives / cycles, validActives, validActives / cycles, nodeActives); 288 | fprintf(activeFp, "totalActives %ld activePerCycle %ld totalValid %ld validPerCycle %ld\n", 289 | totalActives, totalActives / cycles, validActives, validActives / cycles); 290 | for (size_t i = 1; i < sizeof(dut->activeTimes) / sizeof(dut->activeTimes[0]); i ++) { 291 | fprintf(activeFp, "%ld: activeTimes %ld validActive %ld\n", i, dut->activeTimes[i], dut->validActive[i]); 292 | } 293 | 294 | std::ofstream out("data/active/activeTimes" + std::to_string(cycles / 10000000) + ".txt"); 295 | std::vector activeTimes(dut->allActiveTimes); 296 | std::vector sorted = sort_indexes(activeTimes); 297 | out << "posActives " << dut->posActivate << " " << dut->posActivate / cycles << " actives " << dut->activeNum / cycles << std::endl; 298 | out << "funcTime " << dut->funcTime << " activeTime " << dut->activeTime << " regsTime " << dut->regsTime << " memoryTime " << dut->memoryTime << std::endl; 299 | for (int i = sorted.size()-1; i >= 0; i --) { 300 | if (dut->allNames[sorted[i]].length() == 0) continue; 301 | out << dut->allNames[sorted[i]] << " " << dut->nodeNum[sorted[i]] << " " << (double)activeTimes[sorted[i]] / cycles << " " << activeTimes[sorted[i]] << " " \ 302 | << dut->posActives[sorted[i]] << " " << (double)dut->posActives[sorted[i]] / activeTimes[sorted[i]] << std::endl; 303 | } 304 | #endif 305 | #if defined(PERF) || defined(PERF_CYCLE) 306 | if (cycles >= CYCLE_MAX_PERF) return 0; 307 | #endif 308 | if (cycles == CYCLE_MAX_SIM) return 0; 309 | } 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /emu/support/compress.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2020-2023 Institute of Computing Technology, Chinese Academy of Sciences 3 | * Copyright (c) 2020-2021 Peng Cheng Laboratory 4 | * 5 | * DiffTest is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | #include "compress.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | double calcTime(timeval s, timeval e) { 25 | double sec, usec; 26 | sec = e.tv_sec - s.tv_sec; 27 | usec = e.tv_usec - s.tv_usec; 28 | return 1000 * sec + usec / 1000.0; 29 | } 30 | 31 | // Return whether the file is a gz file 32 | bool isGzFile(const char* filename) { 33 | #ifdef NO_GZ_COMPRESSION 34 | return false; 35 | #endif 36 | int fd = -1; 37 | 38 | fd = open(filename, O_RDONLY); 39 | assert(fd); 40 | 41 | uint8_t buf[2]; 42 | 43 | size_t sz = read(fd, buf, 2); 44 | if (sz != 2) { 45 | close(fd); 46 | return false; 47 | } 48 | 49 | close(fd); 50 | 51 | const uint8_t gz_magic[2] = {0x1f, 0x8B}; 52 | return memcmp(buf, gz_magic, 2) == 0; 53 | } 54 | 55 | // Return whether the file is a zstd file 56 | bool isZstdFile(const char* filename) { 57 | #ifdef NO_ZSTD_COMPRESSION 58 | return false; 59 | #endif 60 | int fd = -1; 61 | 62 | fd = open(filename, O_RDONLY); 63 | assert(fd); 64 | 65 | uint8_t buf[4]; 66 | 67 | size_t sz = read(fd, buf, 4); 68 | if (sz != 4) { 69 | close(fd); 70 | return false; 71 | } 72 | 73 | close(fd); 74 | 75 | const uint8_t zstd_magic[4] = {0x28, 0xB5, 0x2F, 0xFD}; 76 | return memcmp(buf, zstd_magic, 4) == 0; 77 | } 78 | 79 | long snapshot_compressToFile(uint8_t* ptr, const char* filename, long buf_size) { 80 | #ifndef NO_GZ_COMPRESSION 81 | gzFile compressed_mem = gzopen(filename, "wb"); 82 | 83 | if (compressed_mem == NULL) { 84 | printf("Can't open compressed binary file '%s'", filename); 85 | return -1; 86 | } 87 | 88 | long curr_size = 0; 89 | const uint32_t chunk_size = 16384; 90 | long* temp_page = new long[chunk_size]; 91 | long* pmem_current = (long*)ptr; 92 | 93 | while (curr_size < buf_size) { 94 | memset(temp_page, 0, chunk_size * sizeof(long)); 95 | for (uint32_t x = 0; x < chunk_size / sizeof(long); x++) { 96 | pmem_current = (long*)((uint8_t*)ptr + curr_size + x * sizeof(long)); 97 | if (*pmem_current != 0) { *(temp_page + x) = *pmem_current; } 98 | } 99 | uint32_t bytes_write = gzwrite(compressed_mem, temp_page, chunk_size); 100 | if (bytes_write <= 0) { 101 | printf("Compress failed\n"); 102 | break; 103 | } 104 | curr_size += bytes_write; 105 | // assert(bytes_write % sizeof(long) == 0); 106 | } 107 | // printf("Write %lu bytes from gz stream in total\n", curr_size); 108 | 109 | delete[] temp_page; 110 | 111 | if (gzclose(compressed_mem)) { 112 | printf("Error closing '%s'\n", filename); 113 | return -1; 114 | } 115 | return curr_size; 116 | #else 117 | return 0; 118 | #endif 119 | } 120 | 121 | long readFromGz(void* ptr, const char* file_name, long buf_size, uint8_t load_type) { 122 | #ifndef NO_GZ_COMPRESSION 123 | assert(buf_size > 0); 124 | gzFile compressed_mem = gzopen(file_name, "rb"); 125 | 126 | if (compressed_mem == NULL) { 127 | printf("Can't open compressed binary file '%s'", file_name); 128 | return -1; 129 | } 130 | 131 | uint64_t curr_size = 0; 132 | const uint32_t chunk_size = 16384; 133 | 134 | // Only load from RAM need check 135 | if (load_type == LOAD_RAM && (buf_size % chunk_size) != 0) { 136 | printf("buf_size must be divisible by chunk_size\n"); 137 | assert(0); 138 | } 139 | 140 | long* temp_page = new long[chunk_size]; 141 | 142 | while (curr_size < buf_size) { 143 | uint32_t bytes_read = gzread(compressed_mem, temp_page, chunk_size * sizeof(long)); 144 | if (bytes_read == 0) { break; } 145 | for (uint32_t x = 0; x < bytes_read / sizeof(long) + 1; x++) { 146 | if (*(temp_page + x) != 0) { 147 | long* pmem_current = (long*)((uint8_t*)ptr + curr_size + x * sizeof(long)); 148 | *pmem_current = *(temp_page + x); 149 | } 150 | } 151 | curr_size += bytes_read; 152 | } 153 | 154 | if (gzread(compressed_mem, temp_page, chunk_size) > 0) { 155 | printf("File size is larger than buf_size!\n"); 156 | assert(0); 157 | } 158 | // printf("Read %lu bytes from gz stream in total\n", curr_size); 159 | 160 | delete[] temp_page; 161 | 162 | if (gzclose(compressed_mem)) { 163 | printf("Error closing '%s'\n", file_name); 164 | return -1; 165 | } 166 | return curr_size; 167 | #else 168 | return 0; 169 | #endif 170 | } 171 | 172 | long readFromZstd(void* ptr, const char* file_name, long buf_size, uint8_t load_type) { 173 | #ifndef NO_ZSTD_COMPRESSION 174 | assert(buf_size > 0); 175 | 176 | int fd = -1; 177 | int file_size = 0; 178 | uint8_t* compress_file_buffer = NULL; 179 | size_t compress_file_buffer_size = 0; 180 | 181 | uint64_t curr_size = 0; 182 | const uint32_t chunk_size = 16384; 183 | 184 | // Only load from RAM need check 185 | if (load_type == LOAD_RAM && (buf_size % chunk_size) != 0) { 186 | printf("buf_size must be divisible by chunk_size\n"); 187 | return -1; 188 | } 189 | 190 | fd = open(file_name, O_RDONLY); 191 | if (fd < 0) { 192 | printf("Can't open compress binary file '%s'", file_name); 193 | return -1; 194 | } 195 | 196 | file_size = lseek(fd, 0, SEEK_END); 197 | if (file_size == 0) { 198 | printf("File size must not be zero"); 199 | return -1; 200 | } 201 | 202 | lseek(fd, 0, SEEK_SET); 203 | 204 | compress_file_buffer = new uint8_t[file_size]; 205 | assert(compress_file_buffer); 206 | 207 | compress_file_buffer_size = read(fd, compress_file_buffer, file_size); 208 | if (compress_file_buffer_size != file_size) { 209 | close(fd); 210 | free(compress_file_buffer); 211 | printf("Zstd compressed file read failed, file size: %d, read size: %ld\n", file_size, compress_file_buffer_size); 212 | return -1; 213 | } 214 | 215 | close(fd); 216 | 217 | ZSTD_inBuffer input_buffer = {compress_file_buffer, compress_file_buffer_size, 0}; 218 | 219 | long* temp_page = new long[chunk_size]; 220 | 221 | ZSTD_DStream* dstream = ZSTD_createDStream(); 222 | if (!dstream) { 223 | printf("Can't create zstd dstream object\n"); 224 | delete[] compress_file_buffer; 225 | delete[] temp_page; 226 | return -1; 227 | } 228 | 229 | size_t init_result = ZSTD_initDStream(dstream); 230 | if (ZSTD_isError(init_result)) { 231 | printf("Can't init zstd dstream object: %s\n", ZSTD_getErrorName(init_result)); 232 | ZSTD_freeDStream(dstream); 233 | delete[] compress_file_buffer; 234 | delete[] temp_page; 235 | return -1; 236 | } 237 | 238 | while (curr_size < buf_size) { 239 | ZSTD_outBuffer output_buffer = {temp_page, chunk_size * sizeof(long), 0}; 240 | 241 | size_t decompress_result = ZSTD_decompressStream(dstream, &output_buffer, &input_buffer); 242 | 243 | if (ZSTD_isError(decompress_result)) { 244 | printf("Decompress failed: %s\n", ZSTD_getErrorName(decompress_result)); 245 | ZSTD_freeDStream(dstream); 246 | delete[] compress_file_buffer; 247 | delete[] temp_page; 248 | return -1; 249 | } 250 | 251 | if (output_buffer.pos == 0) { break; } 252 | 253 | for (uint32_t x = 0; x < output_buffer.pos / sizeof(long) + 1; x++) { 254 | if (*(temp_page + x) != 0) { 255 | long* pmem_current = (long*)((uint8_t*)ptr + curr_size + x * sizeof(long)); 256 | *pmem_current = *(temp_page + x); 257 | } 258 | } 259 | curr_size += output_buffer.pos; 260 | } 261 | 262 | ZSTD_outBuffer output_buffer = {temp_page, chunk_size * sizeof(long), 0}; 263 | size_t decompress_result = ZSTD_decompressStream(dstream, &output_buffer, &input_buffer); 264 | if (ZSTD_isError(decompress_result) || output_buffer.pos != 0) { 265 | printf("Decompress failed: %s\n", ZSTD_getErrorName(decompress_result)); 266 | printf("Binary size larger than memory\n"); 267 | ZSTD_freeDStream(dstream); 268 | delete[] compress_file_buffer; 269 | delete[] temp_page; 270 | return -1; 271 | } 272 | 273 | ZSTD_freeDStream(dstream); 274 | delete[] compress_file_buffer; 275 | delete[] temp_page; 276 | 277 | return curr_size; 278 | #else 279 | return 0; 280 | #endif 281 | } 282 | 283 | void nonzero_large_memcpy(const void* __restrict dest, const void* __restrict src, size_t n) { 284 | uint64_t* _dest = (uint64_t*)dest; 285 | uint64_t* _src = (uint64_t*)src; 286 | while (n >= sizeof(uint64_t)) { 287 | if (*_src != 0) { *_dest = *_src; } 288 | _dest++; 289 | _src++; 290 | n -= sizeof(uint64_t); 291 | } 292 | if (n > 0) { 293 | uint8_t* dest8 = (uint8_t*)_dest; 294 | uint8_t* src8 = (uint8_t*)_src; 295 | while (n > 0) { 296 | *dest8 = *src8; 297 | dest8++; 298 | src8++; 299 | n--; 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /emu/support/compress.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2020-2023 Institute of Computing Technology, Chinese Academy of Sciences 3 | * Copyright (c) 2020-2021 Peng Cheng Laboratory 4 | * 5 | * DiffTest is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | #ifndef COMPRESS_H 18 | #define COMPRESS_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #define LOAD_SNAPSHOT 0 28 | #define LOAD_RAM 1 29 | 30 | double calcTime(timeval s, timeval e); 31 | 32 | bool isGzFile(const char* filename); 33 | long snapshot_compressToFile(uint8_t* ptr, const char* filename, long buf_size); 34 | long readFromGz(void* ptr, const char* file_name, long buf_size, uint8_t load_type); 35 | 36 | void nonzero_large_memcpy(const void* __restrict dest, const void* __restrict src, size_t n); 37 | 38 | bool isZstdFile(const char* filename); 39 | long readFromZstd(void* ptr, const char* file_name, long buf_size, uint8_t load_type); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/StmtTree.h: -------------------------------------------------------------------------------- 1 | #ifndef STMTTREE_H 2 | #define STMTTREE_H 3 | /* stmt trees indicate how to generate statements in a supernode */ 4 | #include "common.h" 5 | class ENode; 6 | class ExpTree; 7 | 8 | class StmtNode { 9 | public: 10 | bool isENode = false; 11 | ENode* enode = nullptr; 12 | ExpTree* tree = nullptr; 13 | Node* belong = nullptr; 14 | std::vector child; 15 | OPType type = OP_EMPTY; 16 | valInfo* computeInfo = nullptr; 17 | StmtNode(OPType _type) : type(_type) {} 18 | StmtNode(ENode* _enode, Node* _belong) : isENode(true), enode(_enode), belong(_belong), type(OP_STMT_NODE) {} 19 | StmtNode(ExpTree* _tree, Node* _belong) : isENode(false), tree(_tree), belong(_belong), type(OP_STMT_NODE) {} 20 | size_t getChildNum() { return child.size(); } 21 | size_t checkChildIdx(size_t idx) { 22 | Assert(getChildNum() > idx, "idx %ld is out of bound [0, %ld)", idx, getChildNum()); 23 | return idx; 24 | } 25 | StmtNode* getChild(size_t idx) { return child[checkChildIdx(idx)]; } 26 | void setChild(size_t idx, StmtNode* node) { child[checkChildIdx(idx)] = node; } 27 | void eraseChild(size_t idx) { child.erase(child.begin() + checkChildIdx(idx)); } 28 | void addChild(StmtNode* node) { child.push_back(node); } 29 | void generateWhenTree(ENode* lvalue, ENode* enode, std::vector& subPath, Node* belong); 30 | void compute(std::vector& insts); 31 | }; 32 | 33 | class StmtTree { 34 | public: 35 | StmtNode* root; 36 | void mergeExpTree(ExpTree* tree, std::vector& prevPath, std::vector& nodePath, Node* belong); 37 | void display(); 38 | void addSeq(ExpTree* tree, Node* belong); 39 | void mergeStmtTree(StmtTree* tree); 40 | void compute(std::vector& insts); 41 | }; 42 | 43 | #endif -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file common.h 3 | * @brief common headers and macros 4 | */ 5 | 6 | #ifndef COMMON_H 7 | #define COMMON_H 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define NR_THREAD 10 25 | #define ORDERED_TOPO_SORT 26 | // #define PERF 27 | 28 | #define LENGTH(a) (sizeof(a) / sizeof(a[0])) 29 | 30 | #define _STR(a) # a 31 | #define STR(a) _STR(a) 32 | #define _CONCAT(a, b) a ## b 33 | #define CONCAT(a, b) _CONCAT(a, b) 34 | 35 | #define MAX(a, b) ((a >= b) ? a : b) 36 | #define MIN(a, b) ((a >= b) ? b : a) 37 | #define ABS(a) (a >= 0 ? a : -a) 38 | #define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1)) 39 | 40 | #define nodeType(node) widthUType(node->width) 41 | 42 | #define Cast(width, sign) \ 43 | ("(" + (sign ? widthSType(width) : widthUType(width)) + ")") 44 | 45 | #define widthType(width, sign) \ 46 | (sign ? widthSType(width) : widthUType(width)) 47 | 48 | #define widthUType(width) \ 49 | std::string(width <= 8 ? "uint8_t" : \ 50 | (width <= 16 ? "uint16_t" : \ 51 | (width <= 32 ? "uint32_t" : \ 52 | (width <= 64 ? "uint64_t" : format("unsigned _BitInt(%d)", ROUNDUP(width, 64)))))) 53 | 54 | #define widthSType(width) \ 55 | std::string(width <= 8 ? "int8_t" : \ 56 | (width <= 16 ? "int16_t" : \ 57 | (width <= 32 ? "int32_t" : \ 58 | (width <= 64 ? "int64_t" : format("_BitInt(%d)", ROUNDUP(width, 64)))))) 59 | 60 | #define widthBits(width) \ 61 | (width <= 8 ? 8 : \ 62 | (width <= 16 ? 16 : \ 63 | (width <= 32 ? 32 : \ 64 | (width <= 64 ? 64 : ROUNDUP(width, 64))))) 65 | 66 | #define BASIC_WIDTH 256 67 | #define MAX_UINT_WIDTH 2048 68 | #define BASIC_TYPE __uint128_t 69 | #define uint128_t __uint128_t 70 | #define MAX_U8 0xff 71 | #define MAX_U16 0xffff 72 | #define MAX_U32 0xffffffff 73 | #define MAX_U64 0xffffffffffffffff 74 | 75 | #define UCast(width) (std::string("(") + widthUType(width) + ")") 76 | 77 | #define MAP(c, f) c(f) 78 | 79 | // #define TIME_COUNT 80 | 81 | #ifdef TIME_COUNT 82 | #define MUX_COUNT(...) __VA_ARGS__ 83 | #else 84 | #define MUX_COUNT(...) 85 | #endif 86 | 87 | #define MUX_DEF(macro, ...) \ 88 | do { \ 89 | if (macro) { \ 90 | __VA_ARGS__ \ 91 | } \ 92 | } while(0) 93 | 94 | #define MUX_NDEF(macro, ...) \ 95 | do { \ 96 | if (!macro) { \ 97 | __VA_ARGS__ \ 98 | } \ 99 | } while(0) 100 | 101 | 102 | #define ACTIVATE_ALL 0xff 103 | 104 | #ifndef CLOCK_GATE_NAME 105 | #define CLOCK_GATE_NAME "ClockGate" 106 | #endif 107 | 108 | class TypeInfo; 109 | class PNode; 110 | class Node; 111 | class AggrParentNode; 112 | class ENode; 113 | class ExpTree; 114 | class SuperNode; 115 | class valInfo; 116 | class clockVal; 117 | class ArrayMemberList; 118 | 119 | enum ResetType { UNCERTAIN, ASYRESET, UINTRESET, ZERO_RESET }; 120 | 121 | std::string arrayMemberName(Node* node, std::string suffix); 122 | #define newBasic(node) (node->isArrayMember ? arrayMemberName(node, "new") : (node->name + "$new")) 123 | #define newName(node) newBasic(node) 124 | #define oldName(node) (node->name + "$old$" + std::to_string(node->id)) 125 | #define ASSIGN_LABLE std::string("ASSIGN$$$LABEL") 126 | #define ASSIGN_INDI(node) (node->name + "$$UPDATE") 127 | #define ASSIGN_BEG(node) (node ? (node->name + std::to_string(node->id) + "$$BEG ") : "") 128 | #define ASSIGN_END(node) (node ? (node->name + std::to_string(node->id) + "$$END ") : "") 129 | 130 | #include "opFuncs.h" 131 | #include "debug.h" 132 | #include "Node.h" 133 | #include "PNode.h" 134 | #include "ExpTree.h" 135 | #include "StmtTree.h" 136 | #include "graph.h" 137 | #include "util.h" 138 | #include "valInfo.h" 139 | #include "perf.h" 140 | #include "config.h" 141 | 142 | #define TIMER_START(name) struct timeval CONCAT(__timer_, name) = getTime(); 143 | #define TIMER_END(name) do { \ 144 | struct timeval t = getTime(); \ 145 | char buf[256]; \ 146 | snprintf(buf, sizeof(buf) - 1, "Timer.%s()." STR(name), __func__); \ 147 | showTime(buf, CONCAT(__timer_, name), t); \ 148 | } while (0) 149 | 150 | struct ordercmp { 151 | bool operator()(Node* n1, Node* n2) { 152 | return n1->order > n2->order; 153 | } 154 | }; 155 | 156 | void getENodeRelyNodes(ENode* enode, std::set& allNodes); 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | struct Config { 5 | bool EnableDumpGraph; 6 | std::string OutputDir; 7 | int SuperNodeMaxSize; 8 | uint32_t cppMaxSizeKB; 9 | std::string sep_module; 10 | std::string sep_aggr; 11 | Config(); 12 | }; 13 | 14 | extern Config globalConfig; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | macros for debugging 3 | */ 4 | 5 | #ifndef DEBUG_H 6 | #define DEBUG_H 7 | 8 | #include 9 | #include 10 | void print_stacktrace(); 11 | 12 | #define ANSI_FG_BLACK "\33[1;30m" 13 | #define ANSI_FG_RED "\33[1;31m" 14 | #define ANSI_FG_GREEN "\33[1;32m" 15 | #define ANSI_FG_YELLOW "\33[1;33m" 16 | #define ANSI_FG_BLUE "\33[1;34m" 17 | #define ANSI_FG_MAGENTA "\33[1;35m" 18 | #define ANSI_FG_CYAN "\33[1;36m" 19 | #define ANSI_FG_WHITE "\33[1;37m" 20 | #define ANSI_BG_BLACK "\33[1;40m" 21 | #define ANSI_BG_RED "\33[1;41m" 22 | #define ANSI_BG_GREEN "\33[1;42m" 23 | #define ANSI_BG_YELLOW "\33[1;43m" 24 | #define ANSI_BG_BLUE "\33[1;44m" 25 | #define ANSI_BG_MAGENTA "\33[1;45m" 26 | #define ANSI_BG_CYAN "\33[1;46m" 27 | #define ANSI_BG_WHITE "\33[1;47m" 28 | #define ANSI_NONE "\33[0m" 29 | 30 | #define ANSI_FMT(str, fmt) fmt str ANSI_NONE 31 | 32 | #define Log(format, ...) do { \ 33 | printf(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \ 34 | __FILE__, __LINE__, __func__, ## __VA_ARGS__); \ 35 | fflush(stdout); \ 36 | } while (0) 37 | 38 | #define Assert(cond, ...) \ 39 | do { \ 40 | if (!(cond)) { \ 41 | print_stacktrace(); \ 42 | fprintf(stderr, "\33[1;31m"); \ 43 | fprintf(stderr, __VA_ARGS__); \ 44 | fprintf(stderr, "\33[0m\n"); \ 45 | fflush(stdout); \ 46 | assert(cond); \ 47 | } \ 48 | } while (0) 49 | 50 | #define TODO() Assert(0, "Implement ME!") 51 | #define Panic() Assert(0, "Should Not Reach Here!") 52 | #ifdef DEBUG 53 | #define MUX_DEBUG(...) __VA_ARGS__ 54 | #else 55 | #define MUX_DEBUG(...) 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/graph.h: -------------------------------------------------------------------------------- 1 | /* 2 | graph class which describe the whole design graph 3 | */ 4 | 5 | #ifndef GRAPH_H 6 | #define GRAPH_H 7 | 8 | class graph { 9 | FILE *srcFp; 10 | int srcFileIdx; 11 | int srcFileBytes; 12 | 13 | bool __emitSrc(int indent, bool canNewFile, bool alreadyEndFunc, const char *nextFuncDef, const char *fmt, ...); 14 | void emitPrintf(); 15 | void activateNext(Node* node, std::set& nextNodeId, std::string oldName, bool inStep, std::string flagName, int indent); 16 | void activateUncondNext(Node* node, std::setactivateId, bool inStep, std::string flagName, int indent); 17 | 18 | FILE* genHeaderStart(); 19 | void genNodeDef(FILE* fp, Node* node); 20 | void genNodeInsts(Node* node, std::string flagName, int indent); 21 | void genInterfaceInput(Node* input); 22 | void genInterfaceOutput(Node* output); 23 | void genStep(int subStepIdxMax); 24 | void genHeaderEnd(FILE* fp); 25 | int genNodeStepStart(SuperNode* node, uint64_t mask, int idx, std::string flagName, int indent); 26 | int genNodeStepEnd(SuperNode* node, int indent); 27 | void genNodeInit(Node* node, int mode); 28 | void genMemInit(Node* node); 29 | void nodeDisplay(Node* member, int indent); 30 | void genMemRead(FILE* fp); 31 | int genActivate(); 32 | void genUpdateRegister(FILE* fp); 33 | void genMemWrite(FILE* fp); 34 | void saveDiffRegs(); 35 | void genResetAll(); 36 | void genResetDef(SuperNode* super, bool isUIntReset, int indent); 37 | void genResetActivation(SuperNode* super, bool isUIntReset, int indent, int resetId); 38 | void genResetDecl(FILE* fp); 39 | void genSuperEval(SuperNode* super, std::string flagName, int indent); 40 | std::string saveOldVal(Node* node); 41 | void removeNodesNoConnect(NodeStatus status); 42 | void reconnectSuper(); 43 | void reconnectAll(); 44 | void resetAnalysis(); 45 | /* defined in mergeNodes */ 46 | void mergeWhenNodes(); 47 | void mergeAsyncReset(); 48 | void mergeResetAll(); 49 | void mergeOut1(); 50 | void mergeIn1(); 51 | void mergeSublings(); 52 | void mergeNear(); 53 | void splitArrayNode(Node* node); 54 | void checkNodeSplit(Node* node); 55 | void splitOptionalArray(); 56 | void constantMemory(); 57 | void orderAllNodes(); 58 | void genDiffSig(FILE* fp, Node* node); 59 | void removeDeadReg(); 60 | void graphCoarsen(); 61 | void graphInitPartition(); 62 | void graphRefine(); 63 | void resort(); 64 | void detectSortedSuperLoop(); 65 | public: 66 | std::vector allNodes; 67 | std::vector input; 68 | std::vector output; 69 | std::vector regsrc; 70 | std::vector sorted; 71 | std::vector memory; 72 | std::vector external; 73 | std::set halfConstantArray; 74 | std::vector specialNodes; 75 | /* used before toposort */ 76 | std::vector supersrc; 77 | /* used after toposort */ 78 | std::vector sortedSuper; 79 | std::vector uintReset; 80 | std::set splittedArray; 81 | std::vector extDecl; 82 | std::string name; 83 | int nodeNum = 0; 84 | void addReg(Node* reg) { 85 | regsrc.push_back(reg); 86 | } 87 | void detectLoop(); 88 | void topoSort(); 89 | void instsGenerator(); 90 | void cppEmitter(); 91 | void usedBits(); 92 | void traversal(); 93 | void traversalNoTree(); 94 | void splitArray(); 95 | void removeDeadNodes(); 96 | void aliasAnalysis(); 97 | void mergeNodes(); 98 | size_t countNodes(); 99 | void removeEmptySuper(); 100 | void removeNodes(NodeStatus status); 101 | void mergeRegister(); 102 | void clockOptimize(std::map& allSignals); 103 | void constantAnalysis(); 104 | void constructRegs(); 105 | void commonExpr(); 106 | void splitNodes(); 107 | void replicationOpt(); 108 | void perfAnalysis(); 109 | void exprOpt(); 110 | void patternDetect(); 111 | void graphPartition(); 112 | void MFFCPartition(); 113 | void mergeEssentSmallSubling(size_t maxSize, double sim); 114 | void essentPartition(); 115 | void inferAllWidth(); 116 | void dump(std::string FileName); 117 | void depthPerf(); 118 | void generateStmtTree(); 119 | void connectDep(); 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /include/opFuncs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file opFuncs.h 3 | * @brief operation functions 4 | */ 5 | 6 | #ifndef OPFUNCS_H 7 | #define OPFUNCS_H 8 | 9 | #include 10 | 11 | void invalidExpr1Int1(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n); 12 | void u_pad(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n); 13 | void s_pad(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n); 14 | void u_shl(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n); 15 | void u_shr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n); 16 | void s_shr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n); 17 | void u_head(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n); 18 | void u_tail(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n); 19 | 20 | void invalidExpr1(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 21 | void u_asUInt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 22 | void s_asSInt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 23 | void u_asClock(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 24 | void u_asAsyncReset(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 25 | void u_cvt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 26 | void s_cvt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 27 | void s_neg(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 28 | void u_not(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 29 | void u_orr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 30 | void u_andr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 31 | void u_xorr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt); 32 | 33 | void invalidExpr2(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 34 | void us_add(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 35 | void us_sub(mpz_t& dst, mpz_t& src1, mpz_t& src2, mp_bitcnt_t dst_bitcnt); 36 | void us_mul(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 37 | void us_div(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 38 | void us_rem(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 39 | void us_lt(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 40 | void us_leq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 41 | void us_gt(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 42 | void us_geq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 43 | void us_eq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 44 | void us_neq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2); 45 | void u_dshr(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 46 | void u_dshl(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 47 | void s_dshr(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 48 | void u_and(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 49 | void u_ior(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 50 | void u_xor(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 51 | void u_cat(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2); 52 | 53 | void invalidExpr1Int2(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l); 54 | void u_bits(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l); 55 | void u_bits_noshift(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l); 56 | 57 | void us_mux(mpz_t& dst, mpz_t& cond, mpz_t& src1, mpz_t& src2); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/perf.h: -------------------------------------------------------------------------------- 1 | void countNodes(graph* g); 2 | void countOps(graph* g); -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | #include 6 | 7 | enum class ShiftDir{ 8 | Left, 9 | Right, 10 | }; 11 | 12 | OPType str2op_expr2(std::string name); 13 | OPType str2op_expr1(std::string name); 14 | OPType str2op_expr1int1(std::string name); 15 | 16 | int upperPower2(int x); 17 | int upperLog2(int x); 18 | 19 | std::string to_hex_string(BASIC_TYPE x); 20 | std::pair firStrBase(std::string s); 21 | std::string format(const char *fmt, ...); 22 | std::string bitMask(int width); 23 | std::string shiftBits(unsigned int bits, ShiftDir dir); 24 | std::string shiftBits(std::string bits, ShiftDir dir); 25 | void print_stacktrace(); 26 | 27 | static inline struct timeval getTime() { 28 | struct timeval now; 29 | gettimeofday(&now, NULL); 30 | return now; 31 | } 32 | 33 | static inline uint64_t diffTime(struct timeval &t0, struct timeval &t1) { 34 | uint64_t t0_us = t0.tv_sec * 1000000 + t0.tv_usec; 35 | uint64_t t1_us = t1.tv_sec * 1000000 + t1.tv_usec; 36 | return t1_us - t0_us; 37 | } 38 | 39 | static inline void showTime(const char *msg, struct timeval &t0, struct timeval &t1) { 40 | uint64_t diff_ms = diffTime(t0, t1) / 1000; 41 | printf(ANSI_FMT("%s = %ld ms\n", ANSI_FG_MAGENTA), msg, diff_ms); 42 | fflush(stdout); 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/valInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef VALINFO_H 2 | #define VALINFO_H 3 | 4 | std::string legalCppCons(std::string str); 5 | int upperPower2(int x); 6 | 7 | enum valStatus { 8 | VAL_EMPTY = 0, 9 | VAL_VALID, 10 | VAL_CONSTANT, 11 | VAL_FINISH /* for printf/assert*/ , 12 | VAL_INVALID 13 | }; 14 | enum valType {TYPE_NORMAL = 0, TYPE_ARRAY, TYPE_STMT}; 15 | class valInfo { 16 | private: 17 | mpz_t mask; 18 | public: 19 | std::string valStr; 20 | int opNum = 0; 21 | valStatus status = VAL_VALID; 22 | valType type = TYPE_NORMAL; 23 | std::vector insts; 24 | mpz_t consVal; 25 | int width = 0; 26 | bool sign = 0; 27 | int typeWidth = 0; 28 | int consLength = 0; 29 | int beg = -1; 30 | int end = -1; 31 | std::vector memberInfo; 32 | bool sameConstant = false; 33 | mpz_t assignmentCons; 34 | bool fullyUpdated = true; 35 | bool directUpdate = true; 36 | 37 | valInfo(int _width = 0, bool _sign = 0) { 38 | mpz_init(consVal); 39 | mpz_init(mask); 40 | mpz_init(assignmentCons); 41 | width = _width; 42 | sign = _sign; 43 | typeWidth = upperPower2(_width); 44 | } 45 | void mergeInsts(valInfo* newInfo) { 46 | insts.insert(insts.end(), newInfo->insts.begin(), newInfo->insts.end()); 47 | newInfo->insts.clear(); 48 | } 49 | void setConsStr() { 50 | if (mpz_sgn(consVal) >= 0) { 51 | valStr = mpz_get_str(NULL, 16, consVal); 52 | } else { 53 | mpz_t sintVal; 54 | mpz_init(sintVal); 55 | u_asUInt(sintVal, consVal, widthBits(width)); 56 | valStr = mpz_get_str(NULL, 16, sintVal); 57 | } 58 | consLength = valStr.length(); 59 | if (valStr.length() <= 16) valStr = (sign ? Cast(width, sign) : "") + "0x" + valStr; 60 | else valStr = legalCppCons(valStr); 61 | status = VAL_CONSTANT; 62 | mpz_set(assignmentCons, consVal); 63 | sameConstant = true; 64 | opNum = 0; 65 | } 66 | void updateConsVal() { 67 | mpz_set_ui(mask, 1); 68 | mpz_mul_2exp(mask, mask, width); 69 | mpz_sub_ui(mask, mask, 1); 70 | mpz_and(consVal, consVal, mask); 71 | if (sign) { 72 | s_asSInt(consVal, consVal, width); 73 | } 74 | setConsStr(); 75 | } 76 | void setConstantByStr(std::string str, int base = 16) { 77 | mpz_set_str(consVal, str.c_str(), base); 78 | updateConsVal(); 79 | } 80 | valInfo* dup(int beg = 0, int end = -1) { 81 | valInfo* ret = new valInfo(); 82 | ret->opNum = opNum; 83 | ret->type = type; 84 | ret->valStr = valStr; 85 | ret->status = status; 86 | mpz_set(ret->consVal, consVal); 87 | ret->width = width; 88 | ret->typeWidth = typeWidth; 89 | ret->sign = sign; 90 | ret->consLength = consLength; 91 | ret->fullyUpdated = fullyUpdated; 92 | mpz_set(ret->assignmentCons, assignmentCons); 93 | ret->sameConstant = sameConstant; 94 | 95 | for (int i = beg; i <= end; i ++) { 96 | if (getMemberInfo(i)) ret->memberInfo.push_back(getMemberInfo(i)->dup()); 97 | else ret->memberInfo.push_back(nullptr); 98 | } 99 | return ret; 100 | } 101 | void setFullyUpdated() { 102 | fullyUpdated = true; 103 | for (valInfo* info : memberInfo) { 104 | if (info) info->setFullyUpdated(); 105 | } 106 | } 107 | valInfo* dupWithCons() { 108 | valInfo* ret = dup(); 109 | mpz_set(ret->assignmentCons, assignmentCons); 110 | ret->sameConstant = sameConstant; 111 | return ret; 112 | } 113 | valInfo* getMemberInfo(size_t idx) { 114 | if (idx >= memberInfo.size()) return nullptr; 115 | return memberInfo[idx]; 116 | } 117 | }; 118 | 119 | #endif -------------------------------------------------------------------------------- /parser/PNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file PNode.cpp 3 | * @brief PNode class functions implementions 4 | */ 5 | 6 | #include 7 | #include "common.h" 8 | 9 | void PNode::appendChild(PNode* p) { 10 | if (p) child.push_back(p); 11 | } 12 | void PNode::appendExtraInfo(const char* info) { extraInfo.push_back(std::string(info)); } 13 | void PNode::appendChildList(PList* plist) { 14 | if (plist) child.insert(child.end(), plist->siblings.begin(), plist->siblings.end()); 15 | } 16 | void PNode::setWidth(int _width) { width = _width; } 17 | 18 | int PNode::getChildNum() { return child.size(); } 19 | 20 | PNode* PNode::getChild(int idx) { 21 | Assert(idx < (int)child.size(), "idx %d is outof bound(%ld)", idx, child.size()); return child[idx]; 22 | } 23 | 24 | void pnewNode(PNode* parent, int num, va_list valist) { 25 | for (int i = 0; i < num; i++) { 26 | PNode* next = va_arg(valist, PNode*); 27 | parent->child.push_back(next); 28 | } 29 | } 30 | 31 | PNode* newNode(PNodeType type, int lineno, const char* info, const char* name, int num, ...) { 32 | PNode* parent = new PNode(type, lineno); 33 | if (info) parent->info = std::string(info); 34 | if (name) parent->name = std::string(name); 35 | va_list valist; 36 | va_start(valist, num); 37 | pnewNode(parent, num, valist); 38 | va_end(valist); 39 | return parent; 40 | } 41 | 42 | PNode* newNode(PNodeType type, int lineno, const char* name, int num, ...) { 43 | PNode* parent = new PNode(type, lineno); 44 | if (name) parent->name = std::string(name); 45 | va_list valist; 46 | va_start(valist, num); 47 | pnewNode(parent, num, valist); 48 | va_end(valist); 49 | return parent; 50 | } 51 | 52 | PNode* newNode(PNodeType type, int lineno, const char* info, const char* name) { 53 | PNode* parent = new PNode(type, lineno); 54 | if (info) parent->info = std::string(info); 55 | if (name) parent->name = std::string(name); 56 | return parent; 57 | } 58 | 59 | void PList::append(PNode* pnode) { 60 | if (pnode) siblings.push_back(pnode); 61 | } 62 | 63 | void PList::append(int num, ...) { 64 | va_list valist; 65 | va_start(valist, num); 66 | for (int i = 0; i < num; i++) { 67 | PNode* pnode = va_arg(valist, PNode*); 68 | if (pnode) siblings.push_back(pnode); 69 | } 70 | va_end(valist); 71 | } 72 | 73 | void PList::concat(PList* plist) { 74 | if (!plist) return; 75 | siblings.insert(siblings.end(), plist->siblings.begin(), plist->siblings.end()); 76 | } 77 | -------------------------------------------------------------------------------- /parser/include/PNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file PNode.h 3 | * @brief Declaration of PNode and PList classes. 4 | */ 5 | 6 | #ifndef PNODE_H 7 | #define PNODE_H 8 | 9 | /** 10 | * @class PList 11 | * @brief A class representing a list of PNodes. 12 | * 13 | */ 14 | class PList; 15 | class Node; 16 | 17 | /* AST Node */ 18 | enum PNodeType{ 19 | P_EMPTY, 20 | P_CIRCUIT, 21 | P_MOD, 22 | P_EXTMOD, 23 | P_INTMOD, 24 | P_PORTS, 25 | P_INPUT, 26 | P_OUTPUT, 27 | P_WIRE_DEF, 28 | P_REG_DEF, 29 | P_REG_RESET_DEF, 30 | P_INST, 31 | P_NODE, 32 | P_CONNECT, 33 | P_PAR_CONNECT, 34 | P_WHEN, 35 | P_MEMORY, 36 | P_SEQ_MEMORY, 37 | P_COMB_MEMORY, 38 | P_WRITE, 39 | P_READ, 40 | P_INFER, 41 | P_MPORT, 42 | P_READER, 43 | P_WRITER, 44 | P_READWRITER, 45 | P_RUW, 46 | P_RLATENCT, 47 | P_WLATENCT, 48 | P_DATATYPE, 49 | P_DEPTH, 50 | P_REF, 51 | P_REF_DOT, 52 | P_REF_IDX_INT, 53 | P_REF_IDX_EXPR, 54 | P_2EXPR, 55 | P_1EXPR, 56 | P_1EXPR1INT, 57 | P_1EXPR2INT, 58 | P_FIELD, 59 | P_FLIP_FIELD, 60 | P_AG_ARRAY, 61 | P_AG_FIELDS, 62 | P_Clock, 63 | P_ASYRESET, 64 | P_RESET, 65 | P_INT_TYPE, 66 | P_PROBE, 67 | P_EXPR_INT_NOINIT, 68 | P_EXPR_INT_INIT, 69 | P_EXPR_MUX, 70 | P_STATEMENTS, 71 | P_PRINTF, 72 | P_EXPRS, 73 | P_ASSERT, 74 | P_STOP, // exit 75 | P_INDEX, 76 | P_CONS_INDEX, 77 | P_L_CONS_INDEX, 78 | P_L_INDEX, 79 | P_INVALID, 80 | }; 81 | 82 | enum PNodeState { VALID_PNODE, CONSTANT_PNODE }; 83 | 84 | class AggrType; 85 | 86 | /** 87 | * @class PNode 88 | * @brief A class representing a node in a parse tree. 89 | * 90 | */ 91 | class PNode { 92 | public: 93 | /** 94 | * @brief Default constructor. 95 | */ 96 | PNode() {} 97 | 98 | /** 99 | * @brief Constructor with a type parameter. 100 | * 101 | * @param _type The type of the node. 102 | */ 103 | PNode(PNodeType _type, int _lineno = -1) { type = _type; lineno = _lineno; } 104 | 105 | /** 106 | * @brief Constructor with a string parameter. 107 | * 108 | * @param str The string value of the node. 109 | */ 110 | PNode(const char* str, int _lineno = -1) { name = std::string(str); lineno = _lineno; } 111 | 112 | /** 113 | * @brief A vector of child nodes. 114 | */ 115 | std::vector child; 116 | std::string info; 117 | std::string name; 118 | std::vector extraInfo; 119 | PNodeType type; 120 | int width = 0; 121 | int lineno; 122 | bool sign = 0; 123 | // AggrType* aggrType = NULL; 124 | int id = -1; 125 | /** 126 | * @brief set valid_node to CONSTANT_PNODE 127 | */ 128 | PNodeState status = VALID_PNODE; 129 | /** 130 | * @brief used for CONSTANT_PNODE 131 | */ 132 | std::string consVal; 133 | 134 | void appendChild(PNode* p); 135 | void appendExtraInfo(const char* info); 136 | void appendChildList(PList* plist); 137 | void setWidth(int _width); 138 | int getChildNum(); 139 | PNode* getChild(int idx); 140 | int getExtraNum() { return extraInfo.size(); } 141 | std::string getExtra(int idx) { return extraInfo[idx]; } 142 | void setSign(bool s) { sign = s; } 143 | }; 144 | 145 | /** 146 | * @class PList 147 | * @brief A class representing pnode list in a parse tree. 148 | * 149 | */ 150 | class PList { 151 | public: 152 | /** 153 | * @brief Constructor with a initial node parameter. 154 | * 155 | * @param pnode 156 | */ 157 | PList(PNode* pnode) { siblings.push_back(pnode); } 158 | PList() {} 159 | 160 | std::vector siblings; 161 | 162 | void append(PNode* pnode); 163 | void append(int num, ...); 164 | void concat(PList* plist); 165 | }; 166 | 167 | PNode* newNode(PNodeType type, int lineno, const char* info, const char* name, int num, ...); 168 | PNode* newNode(PNodeType type, int lineno, const char* name, int num, ...); 169 | PNode* newNode(PNodeType type, int lineno, const char* info, const char* name); 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /parser/include/Parser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file opFuncs.h 3 | * @brief operation functions 4 | */ 5 | 6 | #ifndef PARSER_H 7 | #define PARSER_H 8 | 9 | #if !defined(yyFlexLexerOnce) 10 | #include 11 | #endif 12 | 13 | #include 14 | #include "PNode.h" 15 | 16 | namespace Parser { 17 | 18 | class Lexical : public yyFlexLexer { 19 | public: 20 | PNode* root = NULL; 21 | PList* list = NULL; 22 | Lexical(std::istream& arg_yyin, std::ostream& arg_yyout) : Lexical(&arg_yyin, &arg_yyout) {} 23 | Lexical(std::istream* arg_yyin = nullptr, std::ostream* arg_yyout = nullptr) : 24 | yyFlexLexer(arg_yyin, arg_yyout) { 25 | indentLevels.push(0); 26 | } 27 | int lex(Syntax::semantic_type* yylval); 28 | int lex_debug(Syntax::semantic_type* yylval); 29 | void set_lineno(int n) { yylineno = n; } 30 | protected: 31 | int curr_indent = 0; 32 | int angle_num = 0; 33 | int square_num = 0; 34 | int bracket_num = 0; 35 | int parenthesis_num = 0; 36 | std::stackindentLevels; 37 | }; 38 | 39 | } // namespace Parser 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /parser/lexical.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "common.h" 4 | #include "syntax.hh" 5 | #include "Parser.h" 6 | static const int TAB_WIDTH = 2; 7 | #define YY_USER_INIT { \ 8 | BEGIN(indent); \ 9 | } 10 | typedef Parser::Syntax::token token; 11 | #define YY_DECL int Parser::Lexical::lex(Parser::Syntax::semantic_type* yylval) 12 | int Parser::Lexical::lex_debug(Parser::Syntax::semantic_type* yylval) { 13 | int ret = lex(yylval); 14 | std::cout << "(" << lineno() << ", " << ret << ") " << yytext << std::endl; 15 | return ret; 16 | } 17 | %} 18 | 19 | %option c++ noyywrap yylineno nodefault 20 | 21 | /* Integer literal definitions */ 22 | digit_bin 0|1 23 | digit_oct [0-7] 24 | digit_dec [0-9] 25 | digit_hex [0-9A-Fa-f] 26 | /* Integer */ 27 | int -?{digit_dec}+ 28 | /* Radix-specified Integer Literals */ 29 | rint -?0b{digit_bin}+|-?0o{digit_oct}+|-?0d{digit_dec}+|-?0h{digit_hex}+ 30 | int_dec -?{digit_dec}+ 31 | /* Identifiers define legal FIRRTL or Verilog names */ 32 | letter [A-Za-z] 33 | id (_|{letter})(_|{letter}|{digit_dec})* 34 | string \"((\\\")|[!|0-9A-Za-z %\\,:=_^.&~\t()-{}$'#])*\" 35 | info [0-9A-Za-z.{}:,/ _-]+ 36 | /* Fileinfo communicates Chisel source file and line/column info */ 37 | 38 | /* %x initial */ 39 | %x indent 40 | %x info 41 | %x anno 42 | %x dotId 43 | %x intid 44 | %s normal 45 | 46 | %% 47 | 48 | 49 | " " { curr_indent ++; } 50 | \t { curr_indent = (curr_indent + TAB_WIDTH) & ~ (TAB_WIDTH - 1); } 51 | \n { curr_indent = 0; } 52 | . { yyless(0); 53 | if(curr_indent > indentLevels.top()) { 54 | BEGIN(normal); 55 | indentLevels.push(curr_indent); 56 | return token::INDENT; 57 | } else if(curr_indent < indentLevels.top()) { 58 | /* may need to return multiple DEDENT */ 59 | indentLevels.pop(); 60 | return token::DEDENT; 61 | } else { 62 | BEGIN(normal); 63 | } 64 | } 65 | <> { if(indentLevels.top() != 0) { 66 | indentLevels.pop(); 67 | return token::DEDENT; 68 | } else { 69 | yyterminate(); 70 | } 71 | } 72 | 73 | {int} { yylval->strVal = strdup(yytext); return token::ID; } 74 | "`" { BEGIN(normal); } 75 | 76 | "[" { } 77 | {info}* { yylval->strVal = strdup(yytext); return token::Info; } 78 | "]" { BEGIN(normal); } 79 | 80 | {int_dec}|{id} { yylval->name = strdup(yytext); BEGIN(normal); return token::ID; } 81 | "`" { BEGIN(intid); } 82 | 83 | "]]" { BEGIN(normal); } 84 | "\n"|. { } 85 | 86 | "@" { BEGIN(info); } 87 | "`" { BEGIN(intid); } 88 | "%[[" { BEGIN(anno); } 89 | "<<" { return token::DoubleLeft; } 90 | ">>" { return token::DoubleRight; } 91 | Clock { yylval->typeGround = "Clock"; return token::Clock; } 92 | Reset { yylval->typeGround = "Reset"; return token::Reset; } 93 | AsyncReset { yylval->typeGround = "AsyncReset"; return token::AsyReset; } 94 | UInt { yylval->typeGround = "UInt"; return token::IntType; } 95 | SInt { yylval->typeGround = "SInt"; return token::IntType; } 96 | Probe { yylval->typeGround = "Probe"; return token::ProbeType; } 97 | probe { yylval->typeGround = "probe"; return token::Probe; } 98 | Analog { yylval->typeGround = "Analog"; return token::anaType; } 99 | Fixed { yylval->typeGround = "Fixed"; return token::FixedType; } 100 | flip { return token::Flip;} 101 | (add|sub|mul|div|rem|lt|leq|gt|geq|eq|neq|dshl|dshr|and|or|xor|cat)[(] { parenthesis_num++; yylval->typeOP = strndup(yytext, strlen(yytext)-1); return token::E2OP; } 102 | (asUInt|asSInt|asClock|asAsyncReset|cvt|neg|not|andr|orr|xorr)[(] { parenthesis_num ++; yylval->typeOP = strndup(yytext, strlen(yytext)-1); return token::E1OP; } 103 | (pad|shl|shr|head|tail)[(] { parenthesis_num ++; yylval->typeOP = strndup(yytext, strlen(yytext)-1); return token::E1I1OP; } 104 | bits[(] { parenthesis_num ++; yylval->typeOP = "bits"; return token::E1I2OP; } 105 | mux { return token::Mux; } 106 | validif { return token::Validif; } 107 | old { yylval->typeRUW = "old"; return token::Ruw; } 108 | new { yylval->typeRUW = "new"; return token::Ruw; } 109 | undefined { yylval->typeRUW = "undefined"; return token::Ruw; } 110 | mem { return token::Mem; } 111 | smem { return token::SMem; } 112 | cmem { return token::CMem; } 113 | write { return token::Write; } 114 | read { return token::Read; } 115 | infer { return token::Infer; } 116 | mport { return token::Mport; } 117 | rdwr { return token::Rdwr; } 118 | {int} { yylval->strVal = strdup(yytext); return token::INT; } 119 | {rint} { yylval->strVal = strdup(yytext); return token::RINT; } 120 | {int_dec} { if (angle_num == 0 && square_num == 0 && parenthesis_num == 0 && bracket_num != 0) { \ 121 | yylval->name = strdup(yytext); return token::ID; \ 122 | } \ 123 | yylval->strVal = strdup(yytext); return token::INT; } 124 | data-type { return token::DataType; } 125 | depth { return token::Depth; } 126 | read-latency { return token::ReadLatency; } 127 | write-latency { return token::WriteLatency; } 128 | read-under-write { return token::ReadUnderwrite; } 129 | reader { return token::Reader; } 130 | writer { return token::Writer; } 131 | readwriter { return token::Readwriter; } 132 | wire { return token::Wire; } 133 | reg { return token::Reg; } 134 | regreset { return token::RegReset; } 135 | inst { return token::Inst; } 136 | of { return token::Of; } 137 | node { return token::Node; } 138 | invalidate { return token::Invalidate; } 139 | attach { return token::Attach; } 140 | when { return token::When; } 141 | else { return token::Else; } 142 | stop { return token::Stop; } 143 | printf { return token::Printf; } 144 | assert { return token::Assert; } 145 | skip { return token::Skip; } 146 | input { return token::Input; } 147 | output { return token::Output; } 148 | module { return token::Module; } 149 | extmodule { return token::Extmodule; } 150 | defname { return token::Defname; } 151 | parameter { return token::Parameter; } 152 | intmodule { return token::Intmodule; } 153 | intrinsic { return token::Intrinsic; } 154 | FIRRTL { return token::Firrtl; } 155 | version { return token::Version; } 156 | circuit { return token::Circuit; } 157 | connect { return token::Connect; } 158 | public { return token::Public; } 159 | define { return token::Define; } 160 | const { return token::Const; } 161 | {id} { yylval->name = strdup(yytext); return token::ID; } 162 | {string} { yylval->strVal = strdup(yytext); return token::String; } 163 | "=>" { return token::RightArrow; } 164 | "<-" { return token::Leftarrow; } 165 | "<" { angle_num ++; return yytext[0];} 166 | ">" { angle_num --; return yytext[0];} 167 | "[" { square_num ++; return yytext[0];} 168 | "]" { square_num --; return yytext[0];} 169 | "{" { bracket_num ++; return yytext[0];} 170 | "}" { bracket_num --; return yytext[0];} 171 | "(" { parenthesis_num ++; return yytext[0];} 172 | ")" { parenthesis_num --; return yytext[0];} 173 | "." { if (lineno() != 1) BEGIN(dotId); return yytext[0]; } 174 | [.,:=@%<>()\[\]{}""] { return yytext[0]; } 175 | [ \t] { } 176 | \n { curr_indent = 0; BEGIN(indent); } 177 | . { std::cout << "Mysterious character: " << yytext << std::endl; } 178 | 179 | %% 180 | 181 | int yyFlexLexer::yylex() { 182 | throw std::runtime_error("Invalid call to yyFlexLexer::yylex()"); 183 | } -------------------------------------------------------------------------------- /parser/plib.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file plib.cpp 3 | * @brief PNode utils 4 | */ 5 | 6 | #include "common.h" 7 | 8 | static inline int bit(char c, int base) { 9 | switch (base) { 10 | case 2: 11 | case 8: 12 | case 10: return c - '0'; 13 | case 16: return (c >= '0' && c <= '9') ? c - '0' : ((c >= 'A' && c <= 'Z') ? c - 'A' : c - 'a') + 10; 14 | default: Assert("Invalid char %c with base %d\n", &c, base); 15 | } 16 | return -1; 17 | } 18 | 19 | int p_stoi(const char* str) { // oct/dec/hex string to int 20 | int len = strlen(str); 21 | if (len == 0) return 0; 22 | 23 | int val = 0; 24 | int idx = 0; 25 | int neg = 0; 26 | int base = 10; 27 | 28 | if (str[idx] == '-') { 29 | idx++; 30 | neg = 1; 31 | } 32 | 33 | for (int i = idx; i < len; i++) { val = val * base + bit(str[i], base); } 34 | if (neg) return -val; 35 | 36 | return val; 37 | } 38 | -------------------------------------------------------------------------------- /scripts/activeCount.sh: -------------------------------------------------------------------------------- 1 | tests=( 2 | "ysyx3" 3 | "NutShell" 4 | "rocket" 5 | "boom" 6 | "small-boom" 7 | "xiangshan" 8 | "xiangshan-default" 9 | ) 10 | tests_num=${#tests[*]} 11 | 12 | for ((i=0; i < ${tests_num}; i ++)) 13 | do 14 | testName=${tests[i]} 15 | make compile -j dutName=${testName} PERF=1 > logs/log-${testName} 16 | make difftest -j dutName=${testName} PERF=1 > logs/emu-${testName} 17 | done -------------------------------------------------------------------------------- /scripts/diff-graph.py: -------------------------------------------------------------------------------- 1 | import pygraphviz as pgv 2 | import argparse 3 | import os 4 | 5 | # Define the specific order of passes 6 | passes = [ 7 | "00Init", 8 | "01TopoSort", 9 | "02ClockOptimize", 10 | "03RemoveDeadNodes", 11 | "04ExprOpt", 12 | "05ConstantAnalysis", 13 | "06RemoveDeadNodes", 14 | "07AliasAnalysis", 15 | "08CommonExpr", 16 | "09RemoveDeadNodes", 17 | "10MergeNodes", 18 | "11MergeRegister", 19 | "12ConstructRegs", 20 | "13Final" 21 | ] 22 | 23 | 24 | def load_dot_file(file_path): 25 | """Load a DOT file and return the graph.""" 26 | return pgv.AGraph(file_path) 27 | 28 | 29 | def compare_graphs(graph1, graph2): 30 | """Compare two graphs and return the differences in nodes and edges.""" 31 | nodes_diff = { 32 | 'added': set(graph2.nodes()) - set(graph1.nodes()), 33 | 'removed': set(graph1.nodes()) - set(graph2.nodes()) 34 | } 35 | edges_diff = { 36 | 'added': set(graph2.edges()) - set(graph1.edges()), 37 | 'removed': set(graph1.edges()) - set(graph2.edges()) 38 | } 39 | return nodes_diff, edges_diff 40 | 41 | 42 | def highlight_differences(graph, nodes_diff, edges_diff): 43 | """Highlight differences in the graph.""" 44 | for node in nodes_diff['added']: 45 | graph.get_node(node).attr['color'] = 'green' 46 | graph.get_node(node).attr['style'] = 'filled' 47 | graph.get_node(node).attr['fillcolor'] = 'lightgreen' 48 | for node in nodes_diff['removed']: 49 | graph.add_node(node, color='red', style='filled', 50 | fillcolor='lightcoral') 51 | for edge in edges_diff['added']: 52 | u, v = edge 53 | graph.get_edge(u, v).attr['color'] = 'green' 54 | for edge in edges_diff['removed']: 55 | u, v = edge 56 | graph.add_edge(u, v, color='red', style='dashed') 57 | return graph 58 | 59 | 60 | def save_graph(graph, file_path): 61 | """Save the graph to a DOT file.""" 62 | graph.write(file_path) 63 | 64 | 65 | def find_dot_files_by_pass(obj_dir, topname, passes): 66 | """Find dot files matching the specific pass order and topname.""" 67 | files_by_pass = {} 68 | for p in passes: 69 | pattern = f"{topname}_{p}.dot" 70 | for file in os.listdir(obj_dir): 71 | if file == pattern: 72 | files_by_pass[p] = os.path.join(obj_dir, file) 73 | break 74 | return [files_by_pass[p] for p in passes if p in files_by_pass] 75 | 76 | 77 | def main(obj_dir, topname): 78 | 79 | files = find_dot_files_by_pass(obj_dir, topname, passes) 80 | for i in range(len(files) - 1): 81 | file1 = files[i] 82 | file2 = files[i + 1] 83 | output_file = os.path.join(obj_dir, f"{topname}_{passes[i]}_{ 84 | passes[i+1]}_diff.dot") 85 | 86 | graph1 = load_dot_file(file1) 87 | graph2 = load_dot_file(file2) 88 | 89 | print(f'@{i} {files[i]} {files[i + 1]} -> {output_file}') 90 | 91 | nodes_diff, edges_diff = compare_graphs(graph1, graph2) 92 | highlighted_graph = highlight_differences( 93 | graph2, nodes_diff, edges_diff) 94 | 95 | save_graph(highlighted_graph, output_file) 96 | 97 | 98 | if __name__ == "__main__": 99 | parser = argparse.ArgumentParser( 100 | description="Automatically compare DOT files according to specific pass order.") 101 | parser.add_argument("obj_dir", help="Directory containing DOT files.") 102 | parser.add_argument("topname", help="Top-level name for DOT files.") 103 | 104 | args = parser.parse_args() 105 | 106 | main(args.obj_dir, args.topname) 107 | -------------------------------------------------------------------------------- /scripts/extract_perf_result.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | 5 | llc_slice_size = 96*1024*1024/16 # Configured for Zen4-X3D 6 | 7 | def extract_perf_result(folder: Path, suffix = ""): 8 | with open(folder / f"err{suffix}.log", "r") as file: 9 | lines = file.readlines() 10 | # extract perf stat 11 | perf_start_line = -1 12 | perf_stop_line = -1 13 | for idx in range(len(lines)): 14 | if lines[idx].startswith(" Performance counter stats"): 15 | perf_start_line = idx 16 | if lines[idx].strip().endswith(" seconds sys"): 17 | perf_stop_line = idx 18 | assert(perf_start_line != -1 and perf_stop_line != -1) 19 | perf_stat = lines[perf_start_line+2:perf_stop_line] 20 | stat = dict() 21 | for x in perf_stat: 22 | line = x.strip() 23 | if line.find("(") != -1: 24 | line = line[:line.index("(")].strip() 25 | if line.find("#") != -1: 26 | line = line[:line.index("#")].strip() 27 | if len(line) == 0: 28 | continue 29 | line = line.split() 30 | value = line[0].replace(',','') 31 | if '.' in value: 32 | number = float(value) 33 | else: 34 | number = int(value) 35 | key = " ".join(line[1:]) 36 | stat[key] = number 37 | return stat 38 | 39 | def extract_l3_result(folder: Path, suffix = ""): 40 | with open(folder / f"l3{suffix}.log", "r") as file: 41 | l3 = [] 42 | for line in file.readlines(): 43 | l3.append(int(line.strip())) 44 | return l3 45 | 46 | def extract_result(folder: Path, suffix = ""): 47 | stat = extract_perf_result(folder, suffix) 48 | l3 = extract_l3_result(folder, suffix) 49 | stat['name'] = "-".join(folder.name.split("-")[:-1]) 50 | stat['llc-size'] = int(folder.name.split("-")[-1]) * llc_slice_size 51 | stat['l3_0-90p'] = sorted(l3)[int(len(l3)*0.90)] 52 | return stat 53 | 54 | def extract_result_to_csv(result_dir: Path): 55 | result = [] 56 | for x in sorted(result_dir.iterdir()): 57 | if x.is_dir(): 58 | stat = extract_result(x) 59 | result.append(stat) 60 | keys = ['name', 'llc-size'] + [key for key in sorted(result[0].keys()) if key != 'name' and key != 'llc-size'] 61 | buf = "" 62 | buf += ",".join(keys) + "\n" 63 | for stat in result: 64 | buf += ",".join(str(stat[key]) for key in keys) + "\n" 65 | return buf 66 | 67 | def extract_result_multicopy_to_csv(result_dir: Path): 68 | result = [] 69 | data = dict() 70 | for x in sorted(result_dir.iterdir()): 71 | if x.is_dir(): 72 | name, xs_copy, l3_0_cache_unit = x.name.split("-") 73 | xs_copy = int(xs_copy) 74 | total_cycles = 0 75 | for i in range(xs_copy): 76 | stat = extract_result(x, f"-{i}") 77 | total_cycles += stat['cycles'] 78 | data_key = (name, xs_copy) 79 | if data_key not in data: 80 | data[data_key] = dict() 81 | data[data_key][int(l3_0_cache_unit)] = total_cycles / xs_copy 82 | res = dict() 83 | for key in data: 84 | best_cycles = min(data[key].values()) 85 | best_l3_0_cache_unit = min(data[key], key=data[key].get) 86 | for l3_0_cache_unit in data[key]: 87 | best_l3_0_cache_unit = l3_0_cache_unit if data[key][l3_0_cache_unit] * 0.99 < best_cycles and l3_0_cache_unit < best_l3_0_cache_unit else best_l3_0_cache_unit 88 | res[key] = f"{best_l3_0_cache_unit * llc_slice_size / 1024 / 1024} MB" 89 | return "\n".join(f"{key[0]}-{key[1]}copy,{res[key]}" for key in res) 90 | 91 | if __name__ == "__main__": 92 | with open(Path("result-multicopy").resolve() / "result-multicopy.csv", "w") as file: 93 | file.write(extract_result_multicopy_to_csv(Path("result-multicopy").resolve())) 94 | with open(Path("result").resolve() / "result.csv", "w") as file: 95 | file.write(extract_result_to_csv(Path("result").resolve())) 96 | -------------------------------------------------------------------------------- /scripts/genSigDiff.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import re 4 | class SigFilter(): 5 | def __init__(self, name): 6 | self.srcfp = None 7 | self.reffp = None 8 | self.dstfp = None 9 | self.name = name 10 | self.numPerFile = 10000 11 | self.fileIdx = 0 12 | self.varNum = 0 13 | self.dstFileName = "obj/" + name + "/" + name + "_checkSig" 14 | 15 | def closeDstFile(self): 16 | if self.dstfp is not None: 17 | self.dstfp.writelines("return ret;\n}\n") 18 | self.dstfp.close() 19 | 20 | def newDstFile(self): 21 | self.closeDstFile() 22 | self.dstfp = open(self.dstFileName + str(self.fileIdx) + ".cpp", "w") 23 | self.dstfp.writelines("#include \n#include \n#include <" + self.name + ".h>\n#include \"top_ref.h\"\n") 24 | self.dstfp.writelines("bool checkSig" + str(self.fileIdx) + "(bool display, Diff" + self.name + "* ref, S" + self.name + "* mod) {\n") 25 | self.dstfp.writelines("bool ret = false;\n") 26 | self.dstfp.writelines("mpz_t tmp1;\nmpz_init(tmp1);\n \ 27 | mpz_t tmp2;\nmpz_init(tmp2);\n \ 28 | mpz_t tmp3;\nmpz_init(tmp3);\n") 29 | self.fileIdx += 1 30 | self.varNum = 0 31 | 32 | def potentialName(self, oldName): 33 | last_sep_index = oldName.rfind('$') 34 | ret = oldName 35 | if last_sep_index != -1: 36 | ret = oldName[:last_sep_index + 1] + oldName[last_sep_index + 1:].replace('_', '$') 37 | return ret 38 | 39 | def filter(self, srcFile, refFile): 40 | self.srcfp = open(srcFile, "r") 41 | self.reffp = open(refFile, "r") 42 | all_sigs = {} 43 | for line in self.reffp.readlines(): 44 | match = re.search(r'((uint[0-9]*_t)|mpz_t)(.*)width =', line) 45 | if match: 46 | line = line.strip(" ;\n") 47 | line = re.split(' |\[|;', line) 48 | width = line[-1] 49 | all_sigs[line[1]] = int(width) 50 | self.newDstFile() 51 | 52 | for line in self.srcfp.readlines(): 53 | line = line.strip("\n") 54 | line = line.split(" ") 55 | sign = int(line[0]) 56 | mod_width = int(line[1]) 57 | index = line[3].find('[') 58 | if index == -1: 59 | matchName = line[3] 60 | else: 61 | matchName = line[3][:index] 62 | if matchName in all_sigs: 63 | if mod_width != all_sigs[matchName]: 64 | continue 65 | if self.varNum == self.numPerFile: 66 | self.newDstFile() 67 | self.varNum += 1 68 | refName = "ref->" + line[3] 69 | modName = "mod->" + line[2] 70 | 71 | if mod_width <= 64: 72 | mask = hex((1 << mod_width) - 1) if mod_width <= 64 else "((uint256_t)" + hex((1 << (mod_width - 64))-1) + "<< 64 | " + hex((1 << 64)-1) + ")" 73 | 74 | self.dstfp.writelines( \ 75 | "if(display || (" + modName + " & " + mask + ") != (" + refName + " & " + mask + ")){\n" + \ 76 | " ret = true;\n" + \ 77 | " std::cout << std::hex <<\"" + line[2] + ": \" << +" + \ 78 | (modName if mod_width <= 64 else "(uint64_t)(" + modName + " >> 64) << " + "(uint64_t)" + modName) + " << \" \" << +" + \ 79 | (refName if mod_width <= 64 else "(uint64_t)(" + refName + " >> 64) << " + "(uint64_t)" + refName) + "<< std::endl;\n" + \ 80 | "} \n") 81 | elif mod_width <= 256 and not sign: 82 | mask = hex((1 << mod_width) - 1) if mod_width <= 64 else "((uint256_t)" + hex((1 << (mod_width - 64))-1) + "<< 64 | " + hex((1 << 64)-1) + ")" 83 | if mod_width <= 64: 84 | outMod = modName 85 | mask = hex((1 << mod_width) - 1) 86 | elif mod_width <= 128: 87 | outMod = "(uint64_t)(" + modName + " >> 64) << " + "(uint64_t)" + modName 88 | mask = "((uint256_t)" + hex((1 << (mod_width - 64))-1) + "<< 64 | " + hex((1 << 64)-1) + ")" 89 | else: 90 | outMod = "(uint64_t)(" + modName + " >> 192) <<" + "(uint64_t)(" + modName + " >> 128) <<" + "(uint64_t)(" + modName + " >> 64) << " + "(uint64_t)" + modName 91 | mask = "((uint256_t)" + hex((1 << max(0, mod_width - 192))-1) + "<< 192 | " + "(uint256_t)" + hex((1 << min(64, mod_width - 128))-1) + "<< 128 | " + "(uint256_t)" + hex((1 << 64)-1) + "<< 64 | " + hex((1 << 64)-1) + ")" 92 | if mod_width <= 64: 93 | outRef = refName 94 | elif mod_width <= 128: 95 | outRef = "(uint64_t)(" + refName + " >> 64) << " + "(uint64_t)" + refName 96 | else: 97 | outRef = "(uint64_t)(" + refName + " >> 192) <<" + "(uint64_t)(" + refName + " >> 128) <<" + "(uint64_t)(" + refName + " >> 64) << " + "(uint64_t)" + refName 98 | self.dstfp.writelines( \ 99 | "if(display || (" + modName + " & " + mask + ") != (" + refName + " & " + mask + ")){\n" + \ 100 | " ret = true;\n" + \ 101 | " std::cout << std::hex <<\"" + line[2] + ": \" << +" + outMod + " << \" \" << +" + outRef + "<< std::endl;\n" + \ 102 | "} \n") 103 | elif mod_width > 256: 104 | self.dstfp.writelines( \ 105 | "if(display || (" + modName + " != " + refName + ")){\n" + \ 106 | " ret = true;\n" + \ 107 | " std::cout << std::hex <<\"" + line[2] + ": \\n\"; \n" + \ 108 | modName + ".displayn();\n" + \ 109 | refName + ".displayn();\n" + \ 110 | "} \n") 111 | 112 | self.srcfp.close() 113 | self.reffp.close() 114 | self.closeDstFile() 115 | self.dstfp = open(self.dstFileName + ".cpp", "w") 116 | self.dstfp.writelines("#include \n#include \n#include <" + self.name + ".h>\n#include \"top_ref.h\"\n") 117 | for i in range (self.fileIdx): 118 | self.dstfp.writelines("bool checkSig" + str(i) + "(bool display, Diff" + self.name + "* ref, S" + self.name + "* mod);\n") 119 | self.dstfp.writelines("bool checkSig" + "(bool display, Diff" + self.name + "* ref, S" + self.name + "* mod){\nbool ret = false;\n") 120 | for i in range (self.fileIdx): 121 | self.dstfp.writelines("ret |= checkSig" + str(i) + "(display, ref, mod);\n") 122 | self.dstfp.writelines("return ret;\n}\n") 123 | self.dstfp.close() 124 | 125 | if __name__ == "__main__": 126 | sigFilter = SigFilter(sys.argv[1]) 127 | sigFilter.filter("obj/" + sys.argv[1] + "_sigs.txt", "emu/obj_" + sys.argv[2] + "/top_ref.h") -------------------------------------------------------------------------------- /scripts/init_resctrl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mount -t resctrl resctrl /sys/fs/resctrl 4 | mkdir -p /sys/fs/resctrl/group0 5 | chmod 777 -R /sys/fs/resctrl/group0 6 | -------------------------------------------------------------------------------- /scripts/perf_l3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Assume we have setup the resctrl group0 using scripts/init_resctrl.sh . 4 | # And also have the amd_uncore kernel module loaded. 5 | 6 | from pathlib import Path 7 | import os 8 | import asyncio 9 | import signal 10 | import psutil 11 | 12 | def set_cache_size(l3_id: int, size: int): 13 | # size is how many unit 14 | size = min(16, size) 15 | os.system("echo \"L3:{:d}={:04x}\" > /sys/fs/resctrl/group0/schemata".format(l3_id, (1< /dev/null 15 | if [ $? != 0 ] ; then exit; fi 16 | } 17 | 18 | cd .. 19 | 20 | rebuild_gsim MODE=2 21 | log "Functional regression start" 22 | (for t in $TASKS; do 23 | (make diff dutName=$t -j `nproc` > /dev/null; 24 | result="fail"; 25 | if grep "simulation process 100.00%" build/$t/$t.log > /dev/null; then result="pass"; fi; 26 | log "$t: ${result}" 27 | ) & 28 | done; wait) & all1=$! 29 | wait $all1 30 | log "Functional regression finish" 31 | 32 | 33 | rebuild_gsim MODE=0 34 | log "Performance regression start" 35 | for t in $TASKS; do 36 | make run dutName=$t -j `nproc` > /dev/null 37 | result=`grep "simulation process 100.00%" build/$t/$t.log | grep -o "[0-9]* per sec" | awk '{print $1}'` 38 | make pgo dutName=$t -j `nproc` > /dev/null 39 | result_pgo=`grep "simulation process 100.00%" build/$t/$t.log | grep -o "[0-9]* per sec" | awk '{print $1}'` 40 | make bolt dutName=$t -j `nproc` > /dev/null 41 | result_bolt=`grep "simulation process 100.00%" build/$t/$t.log | grep -o "[0-9]* per sec" | awk '{print $1}'` 42 | log "$t(plain / pgo / bolt ): ${result}Hz / ${result_pgo}Hz / ${result_bolt}Hz" 43 | done 44 | log "Performance regression finish" 45 | -------------------------------------------------------------------------------- /scripts/run_until_exit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CMD=("${@:1}") 4 | 5 | echo "Running "${CMD[@]}"" 6 | coproc ("${CMD[@]}") 7 | pid=${COPROC_PID} 8 | while read -r o <&"${COPROC[0]}" 9 | do 10 | echo "${o}" 11 | if [[ "$o" =~ "Exit with code" ]]; then 12 | kill $pid 13 | wait $pid 14 | if [[ "$o" =~ "0" ]]; then 15 | exit 0 16 | else 17 | exit 1 18 | fi 19 | fi 20 | if [[ "$o" =~ "MicroBench PASS" ]]; then 21 | kill $pid 22 | wait $pid 23 | exit 0 24 | fi 25 | done 26 | exit 1 27 | -------------------------------------------------------------------------------- /scripts/sigFilter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import re 4 | 5 | class SigFilter(): 6 | def __init__(self, name): 7 | self.srcfp = None 8 | self.reffp = None 9 | self.dstfp = None 10 | self.name = name 11 | self.numPerFile = 10000 12 | self.fileIdx = 0 13 | self.varNum = 0 14 | self.dstFileName = sys.argv[1] + "/model/" + name + "_checkSig" 15 | 16 | def closeDstFile(self): 17 | if self.dstfp is not None: 18 | self.dstfp.writelines("return ret;\n}\n") 19 | self.dstfp.close() 20 | 21 | def newDstFile(self): 22 | self.closeDstFile() 23 | self.dstfp = open(self.dstFileName + str(self.fileIdx) + ".cpp", "w") 24 | self.dstfp.writelines("#include \n#include <" + self.name + ".h>\n#include \"V" + self.name + "__Syms.h\"\n") 25 | self.dstfp.writelines("bool checkSig" + str(self.fileIdx) + "(bool display, V" + self.name + "* ref, S" + self.name + "* mod) {\n") 26 | self.dstfp.writelines("bool ret = false;\n") 27 | self.fileIdx += 1 28 | self.varNum = 0 29 | 30 | def width(self, data): 31 | endIdx = len(data) - 1 32 | while data[endIdx] != ':': 33 | endIdx -= 1 34 | startIdx = endIdx 35 | while data[startIdx-1] != '*': 36 | startIdx -= 1 37 | return int(data[startIdx : endIdx]) + 1 38 | 39 | def genDiffCode(self, modName, refName, line, mod_width, ref_width): 40 | refUName = line[3] + "_u" 41 | if mod_width > 128: 42 | num = int((ref_width + 31) / 32) 43 | self.dstfp.writelines("unsigned _BitInt(" + str(num*32) + ") " + refUName + " = " + refName + "[" + str(num-1) +"U];\n") 44 | for i in range(num - 1, 0, -1): 45 | self.dstfp.writelines(refUName + " = (" + refUName + " << 32) + " + refName + "[" + str(i-1) + "U];\n") 46 | 47 | refName128 = "" 48 | if ref_width > 64: 49 | num = int((ref_width + 31) / 32) 50 | bits = num * 32 51 | utype = "unsigned _BitInt(" + str(bits) + ")" 52 | for i in range(num): 53 | refName128 = refName128 + (" | " if i != 0 else "") + "((" + utype + ")" + refName + "[" + str(i) + "] << " + str(i * 32) + ")" 54 | refName = refName.lstrip("ref->rootp->") + "_" + str(bits) 55 | self.dstfp.writelines(utype + " " + refName + " = " + refName128 + ";\n") 56 | mask = (hex((1 << mod_width) - 1) + "u" if mod_width <= 64 else 57 | "((unsigned _BitInt(" + str(mod_width) + "))0 - 1)") 58 | self.dstfp.writelines("if( display || (((" + modName + " ^ " + refName + ") & " + mask + ") != 0)) {\n" + \ 59 | " ret = true;\n" + \ 60 | " std::cout << std::hex << \"" + line[2] + ": \" ") 61 | num = int((mod_width + 63) / 64) 62 | for i in range(num - 1, -1, -1): 63 | self.dstfp.writelines(" << (uint64_t)(" + modName + " >> " + str(i * 64) + ") << '_'") 64 | self.dstfp.writelines(" << \" \" ") 65 | num = int((ref_width + 63) / 64) 66 | for i in range(num - 1, -1, -1): 67 | self.dstfp.writelines(" << (uint64_t)(" + refName + " >> " + str(i * 64) + ") << '_'") 68 | self.dstfp.writelines(" << std::endl;\n" + "} \n") 69 | 70 | def genDiffCode2(self, modName, refName, line, width): 71 | # This code is simpler, but it does not work with clang 16. 72 | # clang 16 can not correctly handle pointer of _BitInt like: 73 | # *(_BitInt(28) *)a 74 | # It should work with clang 19. 75 | utype = "unsigned _BitInt(" + str(width) + ")" 76 | modNameLocal = line[3] + "_dut" 77 | refNameLocal = line[3] + "_ref" 78 | self.dstfp.writelines(utype + " " + modNameLocal + " = " + "*(" + utype + "*)(&(" + modName + "));\n") 79 | self.dstfp.writelines(utype + " " + refNameLocal + " = " + "*(" + utype + "*)(&(" + refName + "));\n") 80 | self.dstfp.writelines("if (display || (" + modNameLocal + " != " + refNameLocal + ")) {\n" + \ 81 | " ret = true;\n" + \ 82 | " std::cout << std::hex <<\"" + line[2] + ": \" ") 83 | num = int((width + 63) / 64) 84 | for i in range(num - 1, -1, -1): 85 | self.dstfp.writelines(" << (uint64_t)(" + modNameLocal + " >> " + str(i * 64) + ")") 86 | self.dstfp.writelines(" << \" \" ") 87 | for i in range(num - 1, -1, -1): 88 | self.dstfp.writelines(" << (uint64_t)(" + refNameLocal + " >> " + str(i * 64) + ")") 89 | self.dstfp.writelines(" << std::endl;\n" + "} \n") 90 | 91 | def filter(self, srcFile, refFile): 92 | self.srcfp = open(srcFile, "r") 93 | self.reffp = open(refFile, "r") 94 | # self.dstfp = open(dstFile, "w") 95 | all_sigs = {} 96 | for line in self.reffp.readlines(): 97 | match = re.search(r'/\*[0-9]*:[0-9]*\*/ ', line) 98 | if match: 99 | line = line.strip(" ;\n") 100 | line = line.split(" ") 101 | all_sigs[line[len(line) - 1]] = self.width(line[0]) 102 | 103 | self.newDstFile() 104 | 105 | for line in self.srcfp.readlines(): 106 | line = line.strip("\n") 107 | line = line.split(" ") 108 | sign = int(line[0]) 109 | mod_width = int(line[1]) 110 | if line[3] in all_sigs: 111 | if self.varNum == self.numPerFile: 112 | self.newDstFile() 113 | self.varNum += 1 114 | ref_width = all_sigs[line[3]] 115 | refName = "ref->rootp->" + line[3] 116 | modName = "mod->" + line[2] 117 | if mod_width > ref_width: 118 | continue 119 | assert(mod_width <= ref_width), "width(" + line[2] + ") = " + str(mod_width) + ", width(" + line[3] + ") = " + str(ref_width) 120 | width = mod_width 121 | 122 | self.genDiffCode(modName, refName, line, mod_width, ref_width) 123 | #self.genDiffCode2(modName, refName, line, width) 124 | 125 | # self.dstfp.writelines("return ret;\n") 126 | self.srcfp.close() 127 | self.reffp.close() 128 | # self.dstfp.close() 129 | self.closeDstFile() 130 | self.dstfp = open(self.dstFileName + ".cpp", "w") 131 | self.dstfp.writelines("#include \n#include <" + self.name + ".h>\n#include \"V" + self.name + "__Syms.h\"\n") 132 | for i in range (self.fileIdx): 133 | self.dstfp.writelines("bool checkSig" + str(i) + "(bool display, V" + self.name + "* ref, S" + self.name + "* mod);\n") 134 | self.dstfp.writelines("bool checkSig" + "(bool display, V" + self.name + "* ref, S" + self.name + "* mod){\nbool ret = false;\n") 135 | for i in range (self.fileIdx): 136 | self.dstfp.writelines("ret |= checkSig" + str(i) + "(display, ref, mod);\n") 137 | self.dstfp.writelines("return ret;\n}\n") 138 | self.dstfp.close() 139 | 140 | 141 | if __name__ == "__main__": 142 | sigFilter = SigFilter(sys.argv[2]) 143 | sigFilter.filter(sys.argv[1] + "/model/" + sys.argv[2] + "_sigs.txt", 144 | sys.argv[1] + "/verilator/V" + sys.argv[2] + "___024root.h") 145 | -------------------------------------------------------------------------------- /src/ExpTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common.h" 4 | 5 | void ExpTree::when2mux(int width) { 6 | if (getRoot()->opType != OP_WHEN || width >= BASIC_WIDTH) return; 7 | std::stacks; 8 | s.push(getRoot()); 9 | std::set whenNodes; 10 | bool update = true; 11 | while (!s.empty()) { 12 | ENode* top = s.top(); 13 | s.pop(); 14 | if (top->opType != OP_WHEN) continue; 15 | /* TODO: optimize invalid */ 16 | if (top->getChild(1) && (top->getChild(1)->opType != OP_STMT && top->getChild(1)->opType != OP_WHEN && top->getChild(1)->opType != OP_INVALID) 17 | && top->getChild(2) && (top->getChild(2)->opType != OP_STMT && top->getChild(2)->opType != OP_WHEN && top->getChild(2)->opType != OP_INVALID)) { 18 | whenNodes.insert(top); 19 | for (ENode* child : top->child) s.push(child); 20 | } else { 21 | update = false; 22 | break; 23 | } 24 | } 25 | if (update) { 26 | for (ENode* when : whenNodes) when->opType = OP_MUX; 27 | } 28 | } 29 | 30 | /* add OP_CAT or OP_BITS to match expWidth with nodeWidth */ 31 | void ExpTree::matchWidth(int width) { 32 | std::vector> allNodes; 33 | std::stacks; 34 | /* generate all nodes that need to be updated, passing down to when children */ 35 | if (getRoot()->opType != OP_WHEN && getRoot()->opType != OP_RESET) { 36 | allNodes.push_back(std::make_pair(nullptr, -1)); 37 | } else { 38 | s.push(getRoot()); 39 | getRoot()->width = width; 40 | } 41 | while (!s.empty()) { 42 | ENode* top = s.top(); 43 | s.pop(); 44 | for (size_t i = top->opType == OP_STMT ? 0 : 1; i < top->getChildNum(); i ++) { 45 | ENode* child = top->getChild(i); 46 | if (child) { 47 | if (child->opType == OP_WHEN || child->opType == OP_STMT || child->opType == OP_RESET) { 48 | s.push(child); 49 | child->width = width; 50 | } 51 | else allNodes.push_back(std::make_pair(top, i)); 52 | } 53 | } 54 | } 55 | /* update node width */ 56 | for (auto iter : allNodes) { 57 | ENode* oldNode = iter.first ? iter.first->getChild(iter.second) : getRoot(); 58 | if (width > oldNode->width) { // add OP_CAT 59 | if (oldNode->opType == OP_INT || oldNode->opType == OP_INVALID) { 60 | oldNode->width = width; 61 | } else if (oldNode->sign) { 62 | ENode* sext = new ENode(OP_SEXT); 63 | sext->width = width; 64 | sext->sign = true; 65 | sext->addVal(width); 66 | sext->addChild(oldNode); 67 | if (iter.first) iter.first->setChild(iter.second, sext); 68 | else setRoot(sext); 69 | } else { 70 | ENode* pad = new ENode(OP_PAD); 71 | pad->addVal(width); 72 | pad->width = width; 73 | pad->addChild(oldNode); 74 | if (iter.first) iter.first->setChild(iter.second, pad); 75 | else setRoot(pad); 76 | } 77 | } else if (width < oldNode->width) { 78 | if (oldNode->opType == OP_INVALID) { 79 | oldNode->width = width; 80 | } else { 81 | ENode* bits = new ENode(OP_BITS); 82 | bits->width = width; 83 | bits->sign = oldNode->sign; 84 | bits->addVal(width - 1); 85 | bits->addVal(0); 86 | bits->addChild(oldNode); 87 | if (iter.first) iter.first->setChild(iter.second, bits); 88 | else setRoot(bits); 89 | } 90 | } 91 | } 92 | } 93 | 94 | ENode* allocIntEnode(int width, std::string val) { 95 | ENode* ret = new ENode(OP_INT); 96 | ret->width = width; 97 | ret->strVal = val; 98 | return ret; 99 | } 100 | 101 | ExpTree* ExpTree::dup() { 102 | ExpTree* ret = new ExpTree(getRoot()->dup(), getlval()->dup()); 103 | return ret; 104 | } 105 | -------------------------------------------------------------------------------- /src/GraphDumper.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | class GraphDumper { 4 | public: 5 | GraphDumper(std::ostream& os) : os(os) {} 6 | 7 | void dump(const graph* g); 8 | 9 | private: 10 | template 11 | void dumpSuperNode(const T& Super); 12 | 13 | void dump(const SuperNode* N); 14 | 15 | std::string& fixName(std::string& Name); 16 | 17 | private: 18 | const graph* Root; 19 | 20 | std::ostream& os; 21 | }; 22 | 23 | std::string& GraphDumper::fixName(std::string& Name) { 24 | std::replace(Name.begin(), Name.end(), '$', '_'); 25 | return Name; 26 | } 27 | 28 | void GraphDumper::dump(const graph* g) { 29 | Root = g; 30 | 31 | os << "digraph GSimGraph {\n"; 32 | 33 | if (!g->sortedSuper.empty()) 34 | dumpSuperNode(g->sortedSuper); // Used after toposort 35 | else 36 | dumpSuperNode(g->supersrc); // Used before toposort 37 | 38 | os << "}\n"; 39 | } 40 | 41 | template 42 | void GraphDumper::dumpSuperNode(const T& Super) { 43 | for (auto* N : Super) dump(N); 44 | 45 | for (auto* Super : Super) 46 | for (auto* Member : Super->member) 47 | for (auto* Next : Member->next) os << "\t\t\"" << Member->name << "\" -> \"" << Next->name << "\";\n"; 48 | } 49 | 50 | void GraphDumper::dump(const SuperNode* N) { 51 | os << "\tsubgraph cluster_" << N->id << "{\n"; 52 | 53 | for (auto* node : N->member) { 54 | auto& Name = node->name; 55 | 56 | os << "\t\t\"" << Name << "\"\n"; 57 | } 58 | 59 | os << "\t}\n"; 60 | } 61 | 62 | void graph::dump(std::string FileName) { 63 | std::ofstream ofs{globalConfig.OutputDir + "/" + this->name + "_" + FileName + ".dot"}; 64 | GraphDumper(ofs).dump(this); 65 | } 66 | -------------------------------------------------------------------------------- /src/MFFCPartition.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX_SIB_SIZE 25 12 | 13 | std::map> MFFC; 14 | std::map MFFCRoot; 15 | 16 | void graph::MFFCPartition() { 17 | /* computr MFFC */ 18 | for (size_t i = 0; i < sortedSuper.size(); i ++) { 19 | SuperNode* super = sortedSuper[i]; 20 | if (super->superType != SUPER_VALID) { 21 | MFFC[super] = std::set(); 22 | MFFC[super].insert(super); 23 | MFFCRoot[super] = super; 24 | continue; 25 | } 26 | std::set SuperMFFC; 27 | SuperMFFC.insert(super); 28 | std::queue q; 29 | for (SuperNode* prev : super->prev) q.push(prev); 30 | while (!q.empty()) { 31 | SuperNode* top = q.front(); 32 | q.pop(); 33 | if (top->superType != SUPER_VALID) continue; 34 | bool allInMFFC = true; 35 | for (SuperNode* next : top->next) { 36 | if (SuperMFFC.find(next) == SuperMFFC.end()) { 37 | allInMFFC = false; 38 | break; 39 | } 40 | } 41 | if (allInMFFC) { 42 | SuperMFFC.insert(top); 43 | for (SuperNode* prev : top->prev) q.push(prev); 44 | } 45 | } 46 | MFFC[super] = SuperMFFC; 47 | SuperNode* root = super; 48 | for (SuperNode* node : SuperMFFC) { 49 | if (node->order < root->order) root = node; 50 | } 51 | for (SuperNode* node : SuperMFFC) MFFCRoot[node] = root; 52 | } 53 | 54 | /* merge */ 55 | for (SuperNode* super : sortedSuper) { 56 | SuperNode* root = MFFCRoot[super]; 57 | if (root == super) continue; 58 | for (Node* node : super->member) { 59 | node->super = root; 60 | root->member.push_back(node); 61 | } 62 | super->member.clear(); 63 | } 64 | size_t totalSuper = sortedSuper.size(); 65 | removeEmptySuper(); 66 | reconnectSuper(); 67 | printf("[MFFCPartition] remove %ld superNodes (%ld -> %ld)\n", totalSuper - sortedSuper.size(), totalSuper, sortedSuper.size()); 68 | } 69 | 70 | bool anyPath(SuperNode* super1, SuperNode* super2, graph* g) { 71 | std::stack s; 72 | s.push(super1); 73 | clock_t start = clock(); 74 | while(!s.empty()) { 75 | clock_t end = clock(); 76 | if((end - start) / CLOCKS_PER_SEC > 600) { 77 | Assert(0, "time error"); 78 | } 79 | SuperNode* top = s.top(); 80 | s.pop(); 81 | if (top == super2) return true; 82 | for (SuperNode* next : top->next) s.push(next); 83 | } 84 | return false; 85 | } 86 | 87 | void findAllNext(std::set&next, SuperNode* super) { 88 | std::stack s; 89 | std::set visited; 90 | s.push(super); 91 | clock_t start = clock(); 92 | while(!s.empty()) { 93 | clock_t end = clock(); 94 | if((end - start) / CLOCKS_PER_SEC > 60) { 95 | Assert(0, "time error"); 96 | } 97 | SuperNode* top = s.top(); 98 | s.pop(); 99 | if (visited.find(top) != visited.end()) continue; 100 | next.insert(top); 101 | visited.insert(top); 102 | for (SuperNode* nextNode : top->next) s.push(nextNode); 103 | } 104 | } 105 | void findAllPrev(std::set&prev, SuperNode* super) { 106 | std::stack s; 107 | s.push(super); 108 | std::set visited; 109 | clock_t start = clock(); 110 | while(!s.empty()) { 111 | clock_t end = clock(); 112 | if((end - start) / CLOCKS_PER_SEC > 60) { 113 | Assert(0, "time error"); 114 | } 115 | SuperNode* top = s.top(); 116 | s.pop(); 117 | if (visited.find(top) != visited.end()) continue; 118 | prev.insert(top); 119 | visited.insert(top); 120 | for (SuperNode* prevNode : top->prev) s.push(prevNode); 121 | } 122 | } 123 | 124 | void graph::mergeEssentSmallSubling(size_t maxSize, double sim) { 125 | int idx = 0; 126 | int seg = sortedSuper.size() / 10; 127 | int percent = 0; 128 | for (SuperNode* super : sortedSuper) { 129 | idx ++; 130 | if (idx >= seg) { 131 | printf("%d0%%\n", percent ++); 132 | idx = 0; 133 | } 134 | if (super->prev.size() == 0 || super->member.size() > MAX_SIB_SIZE) continue; 135 | if (super->superType != SUPER_VALID) continue; 136 | std::set siblings; 137 | SuperNode* select = nullptr; 138 | double similarity = 0; 139 | for (SuperNode* prev : super->prev) { 140 | for (SuperNode* next : prev->next) { 141 | if (next->superType != SUPER_VALID) continue; 142 | if (next->member.size() <= maxSize && next->member.size() > 0 && next->order < super->order) { 143 | siblings.insert(next); 144 | } 145 | } 146 | } 147 | std::set next; 148 | findAllNext(next, super); 149 | std::set prev; 150 | findAllPrev(prev, super); 151 | for (SuperNode* sib : siblings) { 152 | if (next.find(sib) != next.end() || prev.find(sib) != prev.end()) continue; 153 | int num = 0; 154 | for (SuperNode* prev : super->prev) { 155 | if (sib->prev.find(prev) != sib->prev.end()) num ++; 156 | } 157 | double new_sim = (double)num / super->prev.size(); 158 | if (new_sim > sim) { 159 | if (!select || new_sim > similarity) { 160 | select = sib; 161 | similarity = new_sim; 162 | } 163 | } 164 | } 165 | if (select) { 166 | for (Node* node : super->member) { 167 | node->super = select; 168 | select->member.push_back(node); 169 | } 170 | super->member.clear(); 171 | /* update connect */ 172 | for (SuperNode* prev : super->prev) { 173 | prev->eraseNext(super); 174 | prev->addNext(select); 175 | select->addPrev(prev); 176 | } 177 | for (SuperNode* next : super->next) { 178 | next->erasePrev(super); 179 | next->addPrev(select); 180 | select->addNext(next); 181 | } 182 | super->clear_relation(); 183 | } 184 | 185 | } 186 | removeEmptySuper(); 187 | reconnectSuper(); 188 | } 189 | 190 | bool sortOrderCmp(Node* n1, Node* n2) { 191 | return n1->order < n2->order; 192 | } 193 | 194 | 195 | void graph::essentPartition(){ 196 | size_t totalSuper = sortedSuper.size(); 197 | size_t phaseSuper = sortedSuper.size(); 198 | mergeAsyncReset(); 199 | mergeResetAll(); 200 | printf("[mergeNodes-reset] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 201 | 202 | phaseSuper = sortedSuper.size(); 203 | orderAllNodes(); 204 | MFFCPartition(); 205 | for (SuperNode* super : sortedSuper) { 206 | std::sort(super->member.begin(), super->member.end(), sortOrderCmp); 207 | } 208 | resort(); 209 | printf("[mergeNodes-MFFC] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 210 | 211 | phaseSuper = sortedSuper.size(); 212 | mergeIn1(); 213 | printf("[mergeNodes-In] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 214 | 215 | phaseSuper = sortedSuper.size(); 216 | mergeSublings(); 217 | printf("[mergeNodes-Sibling] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 218 | 219 | phaseSuper = sortedSuper.size(); 220 | orderAllNodes(); 221 | mergeEssentSmallSubling(MAX_SIB_SIZE, 0.5); 222 | 223 | for (SuperNode* super : sortedSuper) { 224 | std::sort(super->member.begin(), super->member.end(), sortOrderCmp); 225 | } 226 | resort(); 227 | 228 | printf("[mergeNodes-smallSib1] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 229 | phaseSuper = sortedSuper.size(); 230 | mergeEssentSmallSubling(4 * MAX_SIB_SIZE, 0.25); 231 | for (SuperNode* super : sortedSuper) { 232 | std::sort(super->member.begin(), super->member.end(), sortOrderCmp); 233 | } 234 | resort(); 235 | 236 | printf("[mergeNodes-smallSib2] remove %ld superNodes (%ld -> %ld)\n", phaseSuper - sortedSuper.size(), phaseSuper, sortedSuper.size()); 237 | phaseSuper = sortedSuper.size(); 238 | printf("[mergeNodes] remove %ld superNodes (%ld -> %ld)\n", totalSuper - phaseSuper, totalSuper, phaseSuper); 239 | } 240 | -------------------------------------------------------------------------------- /src/aliasAnalysis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | determine whether two nodes refer to the same value, keep only one copy of it 3 | */ 4 | 5 | #include "common.h" 6 | #include 7 | #include 8 | 9 | /* TODO: array alias */ 10 | /* TODO: A = B[idx] */ 11 | ENode* Node::isAlias() { 12 | if (type != NODE_OTHERS) return nullptr; 13 | if (isArray()) { 14 | /* alias array A to array B iff 15 | A <= B (if idx = dim[0], A.arrayval[idx] = B, otherwise A.arrayval[idx] = null ) (Done) 16 | A[i] <= B[i] for every i (WIP) 17 | */ 18 | if (prev.size() == 1 && assignTree.size() == 1 && assignTree[0]->getlval()->getChildNum() == 0 && assignTree[0]->getRoot()->getNode() 19 | && assignTree[0]->getRoot()->getNode()->type == NODE_OTHERS) { 20 | return assignTree[0]->getRoot(); 21 | } 22 | return nullptr; 23 | } 24 | if (assignTree.size() != 1) return nullptr; 25 | if (!assignTree[0]->getRoot()->getNode()) return nullptr; 26 | if (prev.size() != 1) return nullptr; 27 | return assignTree[0]->getRoot(); 28 | } 29 | 30 | ENode* ENode::mergeSubTree(ENode* newSubTree) { 31 | ENode* ret = newSubTree->dup(); 32 | for (ENode* childENode : child) ret->addChild(childENode->dup()); 33 | return ret; 34 | } 35 | 36 | Node* getLeafNode(bool isArray, ENode* enode) { 37 | if (!enode->getNode()) return nullptr; 38 | Node* node = enode->getNode(); 39 | if (node->isArray() && node->arraySplitted()) { 40 | int beg, end; 41 | std::tie(beg, end) = enode->getIdx(node); 42 | if (beg < 0 || (isArray && enode->getChildNum() != node->dimension.size())) return node; 43 | else return node->getArrayMember(beg); 44 | } 45 | return node; 46 | } 47 | 48 | void ExpTree::replace(std::map& aliasMap, bool isArray) { 49 | std::stack s; 50 | Node* leafNode = getLeafNode(isArray, getRoot()); 51 | if(aliasMap.find(leafNode) != aliasMap.end()) { 52 | int width = getRoot()->width; 53 | if (leafNode == getRoot()->getNode()) 54 | setRoot(getRoot()->mergeSubTree(aliasMap[leafNode])); 55 | else 56 | setRoot(aliasMap[leafNode]->dup()); 57 | getRoot()->width = width; 58 | } 59 | s.push(getRoot()); 60 | 61 | if (getlval()) s.push(getlval()); 62 | 63 | while (!s.empty()) { 64 | ENode* top = s.top(); 65 | s.pop(); 66 | for (size_t i = 0; i < top->getChildNum(); i ++) { 67 | if (!top->getChild(i)) continue; 68 | s.push(top->getChild(i)); 69 | if (!top->getChild(i)->getNode()) continue; 70 | Node* replaceNode = getLeafNode(isArray, top->getChild(i)); 71 | if (aliasMap.find(replaceNode) != aliasMap.end()) { 72 | ENode* newChild; 73 | if (replaceNode != top->getChild(i)->getNode()) { // splitted array member 74 | newChild = aliasMap[replaceNode]->dup(); 75 | } else { 76 | newChild = top->getChild(i)->mergeSubTree(aliasMap[replaceNode]); 77 | } 78 | newChild->width = top->getChild(i)->width; 79 | top->setChild(i, newChild); 80 | } 81 | } 82 | } 83 | } 84 | /* 85 | A -> | | -> E 86 | | C -> D | 87 | B -> | | -> F 88 | remove 89 | */ 90 | void graph::aliasAnalysis() { 91 | /* counters */ 92 | size_t totalNodes = 0; 93 | size_t aliasNum = 0; 94 | size_t totalSuper = sortedSuper.size(); 95 | std::map aliasMap; 96 | for (SuperNode* super : sortedSuper) { 97 | totalNodes += super->member.size(); 98 | for (Node* member : super->member) { 99 | if (member->status != VALID_NODE) continue; 100 | ENode* enode = member->isAlias(); 101 | if (!enode) continue; 102 | aliasNum ++; 103 | Node* interNode = getLeafNode(member->isArray(), enode);//->getNode(); 104 | ENode* aliasENode = enode; 105 | if (aliasMap.find(interNode) != aliasMap.end()) { 106 | if (interNode == enode->getNode()) aliasENode = enode->mergeSubTree(aliasMap[interNode]); 107 | else aliasENode = aliasMap[interNode]->dup(); 108 | } 109 | if (member->isArrayMember && aliasENode->getNode()->isArray() && !aliasENode->getNode()->arraySplitted()) { 110 | /* do not alias array member to */ 111 | } else if (member->isArray() && (member->arraySplitted() ^ aliasENode->getNode()->arraySplitted())) { 112 | 113 | } else { 114 | member->status = DEAD_NODE; 115 | aliasMap[member] = aliasENode; 116 | } 117 | } 118 | } 119 | /* update valTree */ 120 | for (SuperNode* super : sortedSuper) { 121 | for (Node* member : super->member) { 122 | if (member->status == DEAD_NODE) continue; 123 | for (ExpTree* tree : member->assignTree) tree->replace(aliasMap, member->isArray()); 124 | } 125 | } 126 | 127 | for (Node* reg : regsrc) { 128 | if (reg->resetTree) reg->resetTree->replace(aliasMap, reg->isArray()); 129 | } 130 | for (auto iter : aliasMap) { 131 | if(iter.first->isArrayMember) { 132 | Node* parent = iter.first->arrayParent; 133 | parent->arrayMember[iter.first->arrayIdx] = getLeafNode(false, iter.second); 134 | } 135 | if (iter.first->type == NODE_MEM_MEMBER) { 136 | Node* parent = iter.first->parent; 137 | for (size_t i = 0; i < parent->member.size(); i ++) { 138 | if (parent->member[i] == iter.first) { 139 | parent->member[i] = getLeafNode(false, iter.second); 140 | break; 141 | } 142 | } 143 | } 144 | } 145 | removeNodesNoConnect(DEAD_NODE); 146 | reconnectAll(); 147 | printf("[aliasAnalysis] remove %ld alias (%ld -> %ld)\n", aliasNum, totalNodes, totalNodes - aliasNum); 148 | printf("[aliasAnalysis] remove %ld superNodes (%ld -> %ld)\n", totalSuper - sortedSuper.size(), totalSuper, sortedSuper.size()); 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/clockOptimize.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | 5 | class clockVal { 6 | public: 7 | Node* node = nullptr; 8 | bool isConstant = false; 9 | bool isInvalid = false; 10 | ENode* gateENode = nullptr; // ClockGate 11 | clockVal(Node* n) { node = n; } 12 | clockVal(int v) { isConstant = true; } 13 | clockVal(bool invalid) { isInvalid = invalid; } 14 | }; 15 | 16 | std::map clockMap; 17 | 18 | clockVal* ENode::clockCompute() { 19 | if (width == 0) return new clockVal(0); 20 | if (nodePtr) { 21 | if (clockMap.find(nodePtr) != clockMap.end()) return clockMap[nodePtr]; 22 | else return nodePtr->clockCompute(); 23 | } 24 | 25 | clockVal* childVal = nullptr; 26 | clockVal* ret = nullptr; 27 | switch (opType) { 28 | case OP_WHEN: 29 | childVal = getChild(1)->clockCompute(); 30 | ret = getChild(2)->clockCompute(); 31 | Assert(childVal->isInvalid || ret->isInvalid, "invalid clock"); 32 | if (ret->isInvalid) ret = childVal; 33 | break; 34 | case OP_ASUINT: 35 | case OP_ASSINT: 36 | case OP_ASCLOCK: 37 | case OP_ASASYNCRESET: 38 | ret = getChild(0)->clockCompute(); 39 | break; 40 | case OP_BITS: 41 | Assert(values[0] == 0 && values[1] == 0, "bits %d %d", values[0], values[1]); 42 | ret = getChild(0)->clockCompute(); 43 | break; 44 | case OP_INVALID: 45 | ret = new clockVal(true); 46 | ret->isInvalid = true; 47 | break; 48 | case OP_INT: 49 | ret = new clockVal(0); 50 | break; 51 | case OP_EQ: 52 | ret = new clockVal(0); 53 | printf("Warning: A clock signal driven by the == operator is detected. " 54 | "It is not supported now and treated as a constant clock signal. " 55 | "This may cause wrong result during simulation.\n"); 56 | display(); 57 | break; 58 | case OP_OR: 59 | ret = new clockVal(false); 60 | ret->gateENode = this; 61 | break; 62 | case OP_AND: 63 | childVal = getChild(0)->clockCompute(); // first child 64 | ret = getChild(1)->clockCompute(); // second child 65 | if (childVal->node && ret->gateENode) { 66 | ret->node = childVal->node; 67 | } else if (childVal->gateENode && ret->node) { 68 | ret->gateENode = ret->gateENode; 69 | } else Panic(); 70 | break; 71 | case OP_MUX: { 72 | ENode* cond = getChild(0); 73 | ENode* neg = new ENode(OP_NOT); 74 | neg->addChild(cond); 75 | childVal = getChild(1)->clockCompute(); 76 | Assert(childVal->isConstant || childVal->isInvalid || (childVal->node && childVal->node->type == NODE_INP), "invalid mux"); 77 | ret = getChild(2)->clockCompute(); 78 | Assert(ret->isConstant || ret->isInvalid || (ret->node && ret->node->type == NODE_INP), "invalid mux"); 79 | ENode* first = nullptr, *second = nullptr; 80 | if (ret->isInvalid) { 81 | ret = childVal; 82 | } else if (!childVal->isInvalid) { // if childVal is invalid, ret is the clock 83 | if (!childVal->isConstant) { // null first 84 | if (childVal->gateENode) { 85 | first = new ENode(OP_AND); 86 | first->addChild(cond); 87 | first->addChild(childVal->gateENode); 88 | } else first = cond; 89 | } 90 | if (!ret->isConstant) { // null second 91 | if (ret->gateENode) { 92 | second = new ENode(OP_AND); 93 | second->addChild(neg); 94 | second->addChild(ret->gateENode); 95 | } else second = neg; 96 | } 97 | if (!first && !second) ret = new clockVal(0); 98 | else if (!first) ret->gateENode = second; 99 | else if (!second) ret->gateENode = first; 100 | else { 101 | ENode* andEnode = new ENode(OP_OR); 102 | andEnode->addChild(first); 103 | andEnode->addChild(second); 104 | ret->gateENode = andEnode; 105 | } 106 | } 107 | break; 108 | } 109 | default: 110 | Assert(0, "invalid op %d", opType); 111 | } 112 | return ret; 113 | } 114 | 115 | clockVal* Node::clockCompute() { 116 | if (clockMap.find(this) != clockMap.end()) return clockMap[this]; 117 | if (type == NODE_INP || type == NODE_REG_SRC) { 118 | clockMap[this] = new clockVal(this); 119 | return clockMap[this]; 120 | } 121 | Assert(assignTree.size() <= 1, "multiple clock assignment in %s", name.c_str()); 122 | if (assignTree.size() != 0) { 123 | clockMap[this] = assignTree[0]->getRoot()->clockCompute(); 124 | } else { 125 | clockMap[this] = new clockVal(0); 126 | printf("Warning: An external clock signal is detected. " 127 | "It is not supported now and treated as a constant clock signal. " 128 | "This may cause wrong result during simulation.\n"); 129 | display(); 130 | } 131 | return clockMap[this]; 132 | } 133 | 134 | Node* Node::clockAlias() { 135 | if (assignTree.size() != 1) return nullptr; 136 | /* check if is when with invalid side */ 137 | if (!assignTree[0]->getRoot()->getNode()) return nullptr; 138 | Assert(assignTree[0]->getRoot()->getChildNum() == 0, "alias clock %s to array %s\n", name.c_str(), assignTree[0]->getRoot()->getNode()->name.c_str()); 139 | if (prev.size() != 1) return nullptr; 140 | return assignTree[0]->getRoot()->getNode(); 141 | } 142 | 143 | void Node::setConstantZero(int w) { 144 | ENode* enode = allocIntEnode(w, "0"); 145 | assignTree.clear(); 146 | assignTree.push_back(new ExpTree(enode, this)); 147 | } 148 | void Node::setConstantInfoZero(int w) { 149 | computeInfo = new valInfo(); 150 | if (w > 0) computeInfo->width = w; 151 | else computeInfo->width = width; 152 | computeInfo->setConstantByStr("0"); 153 | status = CONSTANT_NODE; 154 | } 155 | 156 | bool ExpTree::isReadTree() { 157 | std::stack s; 158 | s.push(getRoot()); 159 | bool isRead = false; 160 | while (!s.empty()) { 161 | ENode* top = s.top(); 162 | s.pop(); 163 | if (top->opType == OP_READ_MEM) { 164 | isRead = true; 165 | break; 166 | } else { 167 | for (size_t i = 0; i < top->getChildNum(); i ++) { 168 | if (top->getChild(i)) s.push(top->getChild(i)); 169 | } 170 | } 171 | } 172 | return isRead; 173 | } 174 | 175 | /* clock alias & clock constant analysis */ 176 | void graph::clockOptimize(std::map& allSignals) { 177 | for (auto iter : allSignals) { 178 | Node* node = iter.second; 179 | if (!node->isClock) continue; 180 | Assert(!node->isArray(), "clock %s is array", node->name.c_str()); 181 | if (node->type == NODE_INP) clockMap[node] = new clockVal(node); 182 | else node->clockCompute(); 183 | } 184 | 185 | for (auto iter : allSignals) { 186 | Node* node = iter.second; 187 | if (node->type == NODE_REG_DST) { 188 | Assert(clockMap.find(node->clock) != clockMap.end(), "%s: clock %s(%p) not found", node->name.c_str(), node->clock->name.c_str(), node->clock); 189 | clockVal* val = clockMap[node->clock]; 190 | Assert(!val->gateENode || val->node, "invalid clock %s %d", node->clock->name.c_str(), node->clock->lineno); 191 | if (val->gateENode) { 192 | ENode* gate = new ENode(OP_WHEN); 193 | gate->width = node->width; 194 | gate->sign = node->sign; 195 | ENode* cond = val->gateENode->dup(); 196 | gate->addChild(cond); 197 | gate->addChild(nullptr); 198 | gate->addChild(nullptr); 199 | for (ExpTree* tree : node->assignTree) { 200 | ENode* gateDup = gate->dup(); 201 | gateDup->setChild(1, tree->getRoot()); 202 | tree->setRoot(gateDup); 203 | } 204 | } else if (val->node) { 205 | if (node->clock->type != NODE_INP) { 206 | ENode* clockENode = new ENode(val->node); 207 | clockENode->width = val->node->width; 208 | node->clock->assignTree[0]->setRoot(clockENode); 209 | } 210 | } else { 211 | node->setConstantZero(0); 212 | node->regNext->setConstantZero(0); 213 | node->getSrc()->resetTree = nullptr; 214 | node->getSrc()->reset = ZERO_RESET; 215 | } 216 | } else if (node->type == NODE_EXT && node->clock) { 217 | clockVal* val = clockMap[node->clock]; 218 | if (val->node) { 219 | ENode* clockENode = new ENode(val->node); 220 | clockENode->width = val->node->width; 221 | node->clock->assignTree[0]->setRoot(clockENode); 222 | } else { 223 | for (Node* member : node->member) 224 | member->setConstantZero(0); 225 | } 226 | } else if (node->type == NODE_READER || node->type == NODE_WRITER || node->type == NODE_READWRITER) { 227 | clockVal* val = nullptr; 228 | Node* clockMember = nullptr; 229 | if (node->type == NODE_READER || node->type == NODE_WRITER || node->type == NODE_READWRITER) { 230 | Assert(clockMap.find(node->clock) != clockMap.end(), "%s: clock %s not found", node->name.c_str(), node->clock->name.c_str()); 231 | val = clockMap[node->clock]; 232 | clockMember = node->clock; 233 | } 234 | if (val) { 235 | Assert(!val->gateENode || val->node, "invalid clock %s %d", node->clock->name.c_str(), node->clock->lineno); 236 | if (val->gateENode) { 237 | if (node->type == NODE_WRITER || node->type == NODE_READWRITER) { 238 | ENode* gate = new ENode(OP_WHEN); 239 | gate->width = node->width; 240 | gate->sign = node->sign; 241 | ENode* cond = val->gateENode->dup(); 242 | gate->addChild(cond); 243 | gate->addChild(nullptr); 244 | gate->addChild(nullptr); 245 | for (ExpTree* tree : node->assignTree) { 246 | if (tree->isReadTree()) continue; 247 | ENode* gateDup = gate->dup(); 248 | gateDup->setChild(1, tree->getRoot()); 249 | tree->setRoot(gateDup); 250 | } 251 | } 252 | } else if (val->node) { 253 | ENode* clockENode = new ENode(val->node); 254 | clockENode->width = val->node->width; 255 | clockMember->assignTree[0]->setRoot(clockENode); 256 | } else { 257 | for (Node* member : node->member) 258 | member->setConstantZero(0); 259 | } 260 | } 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/commonExpr.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | 5 | #define MAX_COMMON_NEXT 5 6 | 7 | static std::map> exprId; 8 | static std::map> exprVisitedNodes; 9 | static std::map nodeId; 10 | static std::map realValueMap; 11 | static std::map aliasMap; 12 | 13 | Node* getLeafNode(bool isArray, ENode* enode); 14 | 15 | uint64_t ENode::keyHash() { 16 | if (nodePtr) { 17 | Node* node = getLeafNode(true, this); 18 | if (node) { 19 | Assert(nodeId.find(node) != nodeId.end(), "node %s not found status %d type %d", node->name.c_str(), node->status, node->type); 20 | return nodeId[node]; 21 | } else { 22 | return nodePtr->id; 23 | } 24 | } 25 | else return opType * width; 26 | } 27 | 28 | uint64_t ExpTree::keyHash() { 29 | std::stack s; 30 | s.push(getRoot()); 31 | uint64_t ret = 0; 32 | while (!s.empty()) { 33 | ENode* top = s.top(); 34 | s.pop(); 35 | ret = ret * 123 + top->keyHash(); 36 | for (ENode* childENode : top->child) { 37 | if (childENode) s.push(childENode); 38 | } 39 | } 40 | return ret; 41 | } 42 | 43 | uint64_t Node::keyHash() { 44 | uint64_t ret = 0; 45 | for (ExpTree* tree : assignTree) ret += tree->keyHash(); 46 | return ret; 47 | } 48 | 49 | bool checkENodeEq(ENode* enode1, ENode* enode2) { 50 | if (!enode1 && !enode2) return true; 51 | if (!enode1 || !enode2) return false; 52 | if (enode1->opType != enode2->opType) return false; 53 | if (enode1->width != enode2->width || enode1->sign != enode2->sign) return false; 54 | if (enode1->child.size() != enode2->child.size()) return false; 55 | if (enode1->opType == OP_INT && enode1->strVal != enode2->strVal) return false; 56 | if (enode1->values.size() != enode2->values.size()) return false; 57 | if ((!enode1->getNode() && enode2->getNode()) || (enode1->getNode() && !enode2->getNode())) return false; 58 | bool realEq = realValueMap.find(enode1->getNode()) != realValueMap.end() && realValueMap.find(enode2->getNode()) != realValueMap.end() && realValueMap[enode1->getNode()] == realValueMap[enode2->getNode()]; 59 | if (enode1->getNode() && enode2->getNode() && enode1->getNode() != enode2->getNode() && !realEq) return false; 60 | for (size_t i = 0; i < enode1->values.size(); i ++) { 61 | if (enode1->values[i] != enode2->values[i]) return false; 62 | } 63 | // if (enode1->opType == OP_INDEX_INT && enode1->values[0] != enode2->values[0]) return false; 64 | return true; 65 | } 66 | 67 | static bool checkTreeEq(ExpTree* tree1, ExpTree* tree2) { 68 | std::stack> s; 69 | s.push(std::make_pair(tree1->getRoot(), tree2->getRoot())); 70 | while (!s.empty()) { 71 | ENode *top1, *top2; 72 | std::tie(top1, top2) = s.top(); 73 | s.pop(); 74 | bool enodeEq = checkENodeEq(top1, top2); 75 | if (!enodeEq) return false; 76 | if (!top1) continue; 77 | for (size_t i = 0; i < top1->child.size(); i ++) { 78 | s.push(std::make_pair(top1->child[i], top2->child[i])); 79 | } 80 | } 81 | return true; 82 | } 83 | 84 | static bool checkNodeEq (Node* node1, Node* node2) { 85 | if (node1->assignTree.size() != node2->assignTree.size()) return false; 86 | for (size_t i = 0; i < node1->assignTree.size(); i ++) { 87 | if (!checkTreeEq(node1->assignTree[i], node2->assignTree[i])) return false; 88 | } 89 | return true; 90 | } 91 | 92 | void ExpTree::replace(std::map& aliasMap) { 93 | std::stack s; 94 | s.push(getRoot()); 95 | if (getlval()) s.push(getlval()); 96 | while (!s.empty()) { 97 | ENode* top = s.top(); 98 | s.pop(); 99 | if (top->getNode() && aliasMap.find(top->getNode()) != aliasMap.end()) { 100 | top->nodePtr = aliasMap[top->getNode()]; 101 | } 102 | for (ENode* childENode : top->child) { 103 | if (childENode) s.push(childENode); 104 | } 105 | } 106 | } 107 | 108 | /* TODO: check common regs */ 109 | void graph::commonExpr() { 110 | for (SuperNode* super : sortedSuper) { 111 | if (super->superType != SUPER_VALID) { 112 | for (Node* node : super->member) nodeId[node] = node->id; 113 | continue; 114 | } 115 | for (Node* node : super->member) { 116 | if(node->status != VALID_NODE) continue; 117 | nodeId[node] = node->id; 118 | if (node->type != NODE_OTHERS || node->isArray()) continue; 119 | if (node->prev.size() == 0) continue; 120 | // if (node->next.size() == 1) continue; 121 | uint64_t key = node->keyHash(); 122 | if (exprId.find(key) == exprId.end()) { 123 | exprId[key] = std::set(); 124 | } 125 | exprId[key].insert(node); 126 | nodeId[node] = key; 127 | } 128 | } 129 | 130 | std::map> uniqueNodes; 131 | for (SuperNode* super : sortedSuper) { 132 | for (Node* node : super->member) { 133 | uint64_t key = nodeId[node]; 134 | if (exprId[key].size() <= 1) { // hash slot with only one member 135 | realValueMap[node] = node; 136 | uniqueNodes[node] = std::vector(1, node); 137 | continue; 138 | } 139 | for (Node* elseNode : exprVisitedNodes[key]) { 140 | if (elseNode == node) continue; 141 | if (uniqueNodes.find(elseNode) != uniqueNodes.end() && checkNodeEq(node, elseNode)) { 142 | uniqueNodes[elseNode].push_back(node); 143 | realValueMap[node] = elseNode; 144 | } 145 | } 146 | if (realValueMap.find(node) == realValueMap.end()) { 147 | realValueMap[node] = node; 148 | uniqueNodes[node] = std::vector(1, node); 149 | exprVisitedNodes[key].insert(node); 150 | } 151 | } 152 | } 153 | 154 | for (auto iter : uniqueNodes) { 155 | bool mergeCond = iter.second.size() >= MAX_COMMON_NEXT || iter.second[0]->width > BASIC_WIDTH; 156 | if (!mergeCond) { 157 | for (auto iter1 : iter.second) { 158 | if (iter1->next.size() > 1) mergeCond = true; 159 | } 160 | } 161 | if (mergeCond) { 162 | Node* aliasNode = iter.second[0]; 163 | for (size_t i = 1; i < iter.second.size(); i ++) { 164 | Node* node = iter.second[i]; 165 | aliasMap[node] = aliasNode; 166 | node->status = DEAD_NODE; 167 | } 168 | } 169 | } 170 | 171 | /* update assignTrees */ 172 | for (SuperNode* super : sortedSuper) { 173 | for (Node* member : super->member) { 174 | if (member->status == DEAD_NODE) continue; 175 | for (ExpTree* tree : member->assignTree) tree->replace(aliasMap); 176 | if (member->resetTree) member->resetTree->replace(aliasMap); 177 | } 178 | } 179 | /* apdate arrayMember */ 180 | for (Node* array: splittedArray) { 181 | for (size_t i = 0; i < array->arrayMember.size(); i ++) { 182 | if (array->arrayMember[i] && aliasMap.find(array->arrayMember[i]) != aliasMap.end()) { 183 | array->arrayMember[i] = aliasMap[array->arrayMember[i]]; 184 | } 185 | } 186 | } 187 | 188 | /* update connection */ 189 | removeNodesNoConnect(DEAD_NODE); 190 | reconnectAll(); 191 | 192 | printf("[commonExpr] remove %ld nodes (-> %ld)\n", aliasMap.size(), countNodes()); 193 | 194 | } 195 | 196 | -------------------------------------------------------------------------------- /src/deadNodes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Remove deadNodes. A node is a deadNode if it has no successor or all successors are also deadNodes. 3 | must be called after topo-sort 4 | */ 5 | #include "common.h" 6 | #include 7 | 8 | static std::set nodesInUpdateTree; 9 | 10 | static inline bool potentialDead(Node* node) { 11 | return (node->type == NODE_OTHERS || node->type == NODE_REG_SRC || node->type == NODE_READER) && nodesInUpdateTree.find(node) == nodesInUpdateTree.end(); 12 | } 13 | 14 | static inline bool isSink(Node* node) { 15 | return node->type == NODE_REG_DST || node->type == NODE_SPECIAL || node->type == NODE_OUT || 16 | node->type == NODE_READER || node->type == NODE_WRITER || node->type == NODE_READWRITER || 17 | node->type == NODE_EXT_IN; 18 | } 19 | 20 | void getENodeRelyNodes(ENode* enode, std::set& allNodes) { 21 | std::stack s; 22 | s.push(enode); 23 | while (!s.empty()) { 24 | ENode* top = s.top(); 25 | s.pop(); 26 | Node* prevNode = top->getNode(); 27 | if (prevNode) { 28 | if (prevNode->isArray() && prevNode->arraySplitted()) { 29 | ArrayMemberList* list = top->getArrayMember(prevNode); 30 | for (Node* arrayMember : list->member) { 31 | allNodes.insert(arrayMember); 32 | } 33 | } else { 34 | allNodes.insert(prevNode); 35 | } 36 | } 37 | for (size_t i = 0; i < top->getChildNum(); i ++) { 38 | if (top->getChild(i)) s.push(top->getChild(i)); 39 | } 40 | } 41 | } 42 | 43 | void ExpTree::getRelyNodes(std::set& allNodes) { 44 | getENodeRelyNodes(getRoot(), allNodes); 45 | for (ENode* child : getlval()->child) { 46 | getENodeRelyNodes(child, allNodes); 47 | } 48 | } 49 | 50 | bool anyOuterEdge(Node* node) { 51 | bool ret = false; 52 | for (Node* next : node->next) { 53 | if (next == node || (node->type == NODE_REG_SRC && next == node->getDst()) 54 | || next->status == DEAD_NODE /* point to dead registers */) continue; 55 | ret = true; 56 | } 57 | return ret; 58 | } 59 | 60 | void graph::removeDeadNodes() { 61 | std::set visited; 62 | std::stack s; 63 | auto add = [&visited, &s](Node* node) { 64 | if (visited.find(node) == visited.end()) { 65 | s.push(node); 66 | visited.insert(node); 67 | } 68 | }; 69 | for (Node* outNode : output) add(outNode); 70 | for (Node* special : specialNodes) add(special); 71 | for (SuperNode* super : sortedSuper) { 72 | for (Node* member : super->member) { 73 | if (member->type == NODE_EXT) add(member); 74 | } 75 | } 76 | while (!s.empty()) { 77 | Node* top = s.top(); 78 | s.pop(); 79 | for (Node* prev : top->prev) { 80 | add(prev); 81 | } 82 | if (top->type == NODE_REG_SRC) { 83 | add(top->getDst()); 84 | std::set resetNodes; 85 | if (top->resetTree) top->resetTree->getRelyNodes(resetNodes); 86 | for (Node* node : resetNodes) add(node); 87 | } else if (top->type == NODE_READER) { 88 | Node* memory = top->parent; 89 | for (Node* port : memory->member) { 90 | if (port->type == NODE_WRITER) add(port); 91 | if (port->type == NODE_READWRITER) add(port); 92 | } 93 | } else if (top->type == NODE_EXT_OUT) { 94 | Node* ext = top->parent; 95 | for (Node* member : ext->member) add(member); 96 | } 97 | } 98 | 99 | for (SuperNode* super : sortedSuper) { 100 | for (Node* node : super->member) { 101 | if (visited.find(node) == visited.end()) { 102 | node->status = DEAD_NODE; 103 | } 104 | } 105 | } 106 | 107 | /* counters */ 108 | size_t totalNodes = countNodes(); 109 | size_t totalSuper = sortedSuper.size(); 110 | 111 | removeNodes(DEAD_NODE); 112 | regsrc.erase( 113 | std::remove_if(regsrc.begin(), regsrc.end(), [](const Node* n){ return n->status == DEAD_NODE; }), 114 | regsrc.end() 115 | ); 116 | input.erase( 117 | std::remove_if(input.begin(), input.end(), [](const Node* n){ return n->status == DEAD_NODE; }), 118 | input.end() 119 | ); 120 | for (size_t i = 0; i < memory.size(); i ++) { 121 | Node* mem = memory[i]; 122 | mem->member.erase( 123 | std::remove_if(mem->member.begin(), mem->member.end(), [](const Node* n) {return n->status == DEAD_NODE; }), 124 | mem->member.end() 125 | ); 126 | if (mem->member.size() == 0) { 127 | mem->status = DEAD_NODE; 128 | memory.erase(memory.begin() + i); 129 | i --; 130 | } 131 | } 132 | reconnectAll(); 133 | 134 | size_t optimizedNodes = countNodes(); 135 | size_t optimizedSuper = sortedSuper.size(); 136 | 137 | printf("[removeDeadNodes] remove %ld deadNodes (%ld -> %ld)\n", totalNodes - optimizedNodes, totalNodes, optimizedNodes); 138 | printf("[removeDeadNodes] remove %ld superNodes (%ld -> %ld)\n", totalSuper - optimizedSuper, totalSuper, optimizedSuper); 139 | 140 | } 141 | 142 | void graph::removeDeadReg() { 143 | std::map> dstMap; /* regieters that first point to */ 144 | for (int i = sortedSuper.size() - 1; i >= 0; i --) { 145 | for (int j = sortedSuper[i]->member.size() - 1; j >= 0; j--) { 146 | Node* node = sortedSuper[i]->member[j]; 147 | if (isSink(node)) dstMap[node] = std::make_pair(1, node); 148 | else { 149 | dstMap[node] = std::make_pair(0, nullptr); 150 | for (Node* next : node->next) { 151 | if (dstMap[next].first >= 2) { 152 | dstMap[node].first = 2; 153 | break; 154 | } else if (dstMap[next].first == 1) { 155 | if (dstMap[node].first == 1 && dstMap[node].second == dstMap[next].second) continue; 156 | else if (dstMap[node].first == 1) { 157 | dstMap[node].first = 2; 158 | break; 159 | } else { 160 | dstMap[node] = dstMap[next]; 161 | } 162 | } 163 | 164 | } 165 | } 166 | } 167 | } 168 | std::stack checkNodes; 169 | std::set visited; 170 | for (SuperNode* super : sortedSuper) { 171 | for (Node* node : super->member) { 172 | if (node->type == NODE_REG_SRC && dstMap[node].first == 1 && dstMap[node].second == node->getDst()) { 173 | checkNodes.push(node); 174 | checkNodes.push(node->getDst()); 175 | } 176 | } 177 | } 178 | while (!checkNodes.empty()) { 179 | Node* top = checkNodes.top(); 180 | checkNodes.pop(); 181 | top->status = DEAD_NODE; 182 | if (visited.find(top) != visited.end()) continue; 183 | visited.insert(top); 184 | if (top->type == NODE_REG_SRC) checkNodes.push(top->getDst()); 185 | for (Node* prev : top->prev) { 186 | prev->next.erase(top); 187 | if (!prev->anyExtEdge() && potentialDead(prev)) checkNodes.push(prev); 188 | } 189 | top->prev.clear(); 190 | } 191 | removeNodes(DEAD_NODE); 192 | reconnectAll(); 193 | } 194 | -------------------------------------------------------------------------------- /src/exprOpt.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | 5 | void fillEmptyWhen(ExpTree* newTree, ENode* oldNode); 6 | 7 | void Node::fillArrayInvalid(ExpTree* tree) { 8 | int beg, end; 9 | std::tie(beg, end) = tree->getlval()->getIdx(this); 10 | bool canBeInvalid = true; 11 | for (int i = beg; i <= end; i ++) { 12 | if (invalidIdx.find(i) == invalidIdx.end()) canBeInvalid = false; 13 | } 14 | if (canBeInvalid) fillEmptyWhen(tree, new ENode(OP_INVALID)); 15 | } 16 | 17 | void Node::invalidArrayOptimize() { 18 | if (invalidIdx.size() == 0) return; 19 | if (!isArray()) return; 20 | if (type != NODE_OTHERS) return; 21 | /* can compute in AST2Graph and pass using member variable */ 22 | std::set allIdx; 23 | int beg, end; 24 | for (ExpTree* tree : assignTree) { 25 | std::tie(beg, end) = tree->getlval()->getIdx(this); 26 | if (beg < 0) return; // varialble index 27 | for (int i = beg; i <= end; i ++) { 28 | if (allIdx.find(i) != allIdx.end()) return; // multiple assignment 29 | allIdx.insert(i); 30 | } 31 | } 32 | for (ExpTree* tree : assignTree) fillArrayInvalid(tree); 33 | } 34 | 35 | bool checkENodeEq(ENode* enode1, ENode* enode2); 36 | bool subTreeEq(ENode* enode1, ENode* enode2) { 37 | if (!checkENodeEq(enode1, enode2)) return false; 38 | for (size_t i = 0; i < enode1->getChildNum(); i ++) { 39 | if (!subTreeEq(enode1->getChild(i), enode2->getChild(i))) return false; 40 | } 41 | return true; 42 | } 43 | 44 | void ExpTree::treeOpt() { 45 | std::stack> s; 46 | s.push(std::make_tuple(getRoot(), nullptr, -1)); 47 | 48 | while(!s.empty()) { 49 | ENode* top, *parent; 50 | int idx; 51 | std::tie(top, parent, idx) = s.top(); 52 | s.pop(); 53 | if (top->opType == OP_WHEN || top->opType == OP_MUX) { 54 | if (subTreeEq(top->getChild(1), top->getChild(2))) { 55 | if (parent) { 56 | parent->setChild(idx, top->getChild(1)); 57 | } else { 58 | setRoot(top->getChild(1)); 59 | } 60 | s.push(std::make_tuple(top->getChild(1), parent, idx)); 61 | continue; 62 | } 63 | } 64 | if (top->opType == OP_ASASYNCRESET) { 65 | if (parent) { 66 | parent->setChild(idx, top->getChild(0)); 67 | } else { 68 | setRoot(top->getChild(0)); 69 | } 70 | s.push(std::make_tuple(top->getChild(0), parent, idx)); 71 | continue; 72 | } 73 | if (top->opType == OP_ASSINT || top->opType == OP_ASUINT) { 74 | if (top->getChild(0)->sign == top->sign && top->getChild(0)->width == top->width) { 75 | if (parent) { 76 | parent->setChild(idx, top->getChild(0)); 77 | } else { 78 | setRoot(top->getChild(0)); 79 | } 80 | s.push(std::make_tuple(top->getChild(0), parent, idx)); 81 | } 82 | continue; 83 | } 84 | /* width = 1 xor 0*/ 85 | for (size_t i = 0; i < top->child.size(); i ++) { 86 | if (top->child[i]) s.push(std::make_tuple(top->child[i], top, i)); 87 | } 88 | } 89 | } 90 | 91 | void graph::exprOpt() { 92 | for (SuperNode* super : sortedSuper) { 93 | if (super->superType != SUPER_VALID) continue; 94 | for (Node* node : super->member) { 95 | if (node->width == 0) { 96 | node->assignTree.clear(); 97 | ENode* enodeInt = allocIntEnode(0, "0"); 98 | node->assignTree.push_back(new ExpTree(enodeInt, node)); 99 | continue; 100 | } 101 | for (ExpTree* tree : node->assignTree) tree->treeOpt(); 102 | if (node->resetTree) node->resetTree->treeOpt(); 103 | } 104 | } 105 | 106 | reconnectAll(); 107 | } 108 | -------------------------------------------------------------------------------- /src/firParser.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "syntax.hh" 3 | #include "Parser.h" 4 | #include 5 | #include 6 | #include 7 | 8 | #define MODULES_PER_TASK 5 9 | 10 | typedef struct TaskRecord { 11 | off_t offset; 12 | size_t len; 13 | int lineno; 14 | int id; 15 | } TaskRecord; 16 | 17 | static std::vector *taskQueue; 18 | static std::mutex m; 19 | static std::condition_variable cv; 20 | static PList **lists; 21 | static PNode *globalRoot; 22 | 23 | void parseFunc(char *strbuf, int tid) { 24 | while (true) { 25 | std::unique_lock lk(m); 26 | cv.wait(lk, []{ return !taskQueue->empty(); }); 27 | auto e = taskQueue->back(); 28 | taskQueue->pop_back(); 29 | lk.unlock(); 30 | cv.notify_one(); 31 | 32 | if (e.id == -1) { return; } 33 | //Log("e.offset = %ld, e.lineno = %d", e.offset, e.lineno); 34 | //for (int i = 0; i < 100; i ++) { putchar(strbuf[e.offset + i]); } putchar('\n'); 35 | 36 | std::istringstream *streamBuf = new std::istringstream(strbuf + e.offset); 37 | Parser::Lexical *lexical = new Parser::Lexical(*streamBuf, std::cout); 38 | Parser::Syntax *syntax = new Parser::Syntax(lexical); 39 | lexical->set_lineno(e.lineno); 40 | syntax->parse(); 41 | 42 | lists[e.id] = lexical->list; 43 | if (e.id == 0) { 44 | assert(lexical->root != NULL); 45 | globalRoot = lexical->root; 46 | } 47 | 48 | delete syntax; 49 | delete lexical; 50 | delete streamBuf; 51 | } 52 | } 53 | 54 | PNode* parseFIR(char *strbuf) { 55 | taskQueue = new std::vector; 56 | std::future *threads = new std::future [NR_THREAD]; 57 | 58 | // create tasks 59 | char *prev = strbuf; 60 | char *next = strstr(prev, "\n module "); 61 | int next_lineno = 1; 62 | int id = 0; 63 | int modules = 0; 64 | while (true) { 65 | int prev_lineno = next_lineno; 66 | bool isEnd = false; 67 | for (int i = 0; i < MODULES_PER_TASK; i ++) { 68 | next ++; 69 | next = strstr(next, "\n module "); 70 | modules ++; 71 | isEnd = (next == NULL); 72 | if (isEnd) break; 73 | } 74 | if (!isEnd) { 75 | assert(next[0] == '\n'); 76 | next[0] = '\0'; 77 | for (char *q = prev; (q = strchr(q, '\n')) != NULL; next_lineno ++, q ++); 78 | next_lineno ++; // '\0' is overwritten originally from '\n', so count it 79 | } 80 | taskQueue->push_back(TaskRecord{prev - strbuf, strlen(prev) + 1, prev_lineno, id}); 81 | id ++; 82 | if (isEnd) break; 83 | prev = next + 1; 84 | } 85 | printf("[Parser] using %d threads to parse %d modules with %d tasks\n", 86 | NR_THREAD, modules, id); 87 | lists = new PList* [id]; 88 | for (int i = 0; i < NR_THREAD; i ++) { 89 | taskQueue->push_back(TaskRecord{0, 0, -1, -1}); // exit flags 90 | } 91 | 92 | // sort to handle the largest module first 93 | std::sort(taskQueue->begin(), taskQueue->end(), 94 | [](TaskRecord &a, TaskRecord &b){ return a.len < b.len; }); 95 | 96 | // create threads 97 | for (int i = 0; i < NR_THREAD; i ++) { 98 | threads[i] = async(std::launch::async, parseFunc, strbuf, i); 99 | } 100 | 101 | for (int i = 0; i < NR_THREAD; i ++) { 102 | printf("[Parser] waiting for thread %d/%d...\n", i, NR_THREAD - 1); 103 | threads[i].get(); 104 | } 105 | assert(taskQueue->empty()); 106 | 107 | printf("[Parser] merging lists...\n"); 108 | TIMER_START(MergeList); 109 | for (int i = 1; i < id; i ++) { 110 | lists[0]->concat(lists[i]); 111 | } 112 | globalRoot->child.assign(lists[0]->siblings.begin(), lists[0]->siblings.end()); 113 | TIMER_END(MergeList); 114 | 115 | delete [] lists; 116 | delete [] threads; 117 | delete taskQueue; 118 | return globalRoot; 119 | } 120 | -------------------------------------------------------------------------------- /src/graph.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | void graph::reconnectAll() { 4 | for (SuperNode* super : sortedSuper) { 5 | for (Node* member : super->member) { 6 | member->clear_relation(); 7 | } 8 | } 9 | 10 | for (SuperNode* super : sortedSuper) { 11 | for (Node* member : super->member) { 12 | member->updateConnect(); 13 | } 14 | } 15 | connectDep(); 16 | reconnectSuper(); 17 | } 18 | 19 | void graph::connectDep() { 20 | for (SuperNode* super : sortedSuper) { 21 | for (Node* member : super->member) { 22 | if (member->type == NODE_REG_SRC) member->updateDep(); 23 | } 24 | } 25 | } 26 | 27 | void graph::reconnectSuper() { 28 | for (SuperNode* super : sortedSuper) { 29 | super->clear_relation(); 30 | } 31 | for (SuperNode* super : sortedSuper) { 32 | for (Node* member : super->member) member->constructSuperConnect(); 33 | } 34 | } 35 | 36 | void graph::removeNodesNoConnect(NodeStatus status) { 37 | for (SuperNode* super : sortedSuper) { 38 | super->member.erase( 39 | std::remove_if(super->member.begin(), super->member.end(), [status](const Node* n){ return n->status == status; }), 40 | super->member.end() 41 | ); 42 | } 43 | removeEmptySuper(); 44 | } 45 | 46 | size_t graph::countNodes() { 47 | size_t ret = 0; 48 | for (SuperNode* super : sortedSuper) ret += super->member.size(); 49 | return ret; 50 | } 51 | 52 | void graph::removeNodes(NodeStatus status) { 53 | removeNodesNoConnect(status); 54 | removeEmptySuper(); 55 | reconnectSuper(); 56 | } 57 | 58 | void graph::removeEmptySuper() { 59 | sortedSuper.erase( 60 | std::remove_if(sortedSuper.begin(), sortedSuper.end(), [](const SuperNode* super) {return (super->superType == SUPER_VALID || super->superType == SUPER_UPDATE_REG) && super->member.size() == 0; }), 61 | sortedSuper.end() 62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /src/loopDetector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | using dfs to detect if there is any loop 3 | */ 4 | 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | #define NOT_VISIT 0 10 | #define EXPANDED 1 11 | #define VISITED 2 12 | 13 | void graph::detectLoop() { 14 | std::stack s; 15 | std::map states; 16 | 17 | for (SuperNode* node : supersrc) { 18 | s.push(node); 19 | states[node] = NOT_VISIT; 20 | } 21 | 22 | while (!s.empty()) { 23 | SuperNode* top = s.top(); 24 | if (states[top] == NOT_VISIT) { 25 | states[top] = EXPANDED; 26 | 27 | for (SuperNode* next : top->next) { 28 | /* enable self-loop for memory reader port with latency = 0 */ 29 | if (next == top) continue; 30 | if (states.find(next) == states.end()) { 31 | s.push(next); 32 | states[next] = NOT_VISIT; 33 | } else if (states[next] == EXPANDED) { // find an expanded loop 34 | printf("Detect Loop:\n"); 35 | next->display(); 36 | while (!s.empty()) { 37 | SuperNode* n = s.top(); 38 | s.pop(); 39 | // display all expanded nodes until n 40 | if (states[n] == EXPANDED) n->display(); 41 | if (n == next) Assert(0, "-------"); 42 | } 43 | } 44 | 45 | } 46 | } else if (states[top] == EXPANDED) { 47 | states[top] = VISITED; 48 | s.pop(); 49 | } 50 | } 51 | std::cout << "NO Loop!\n"; 52 | } 53 | 54 | void graph::detectSortedSuperLoop() { 55 | std::stack s; 56 | std::map states; 57 | 58 | for (SuperNode* node : sortedSuper) { 59 | s.push(node); 60 | states[node] = NOT_VISIT; 61 | } 62 | 63 | while (!s.empty()) { 64 | SuperNode* top = s.top(); 65 | if (states[top] == NOT_VISIT) { 66 | states[top] = EXPANDED; 67 | 68 | for (SuperNode* next : top->depNext) { 69 | /* enable self-loop for memory reader port with latency = 0 */ 70 | if (next == top) continue; 71 | if (states.find(next) == states.end()) { 72 | s.push(next); 73 | states[next] = NOT_VISIT; 74 | } else if (states[next] == EXPANDED) { // find an expanded loop 75 | printf("Detect Loop:\n"); 76 | next->display(); 77 | while (!s.empty()) { 78 | SuperNode* n = s.top(); 79 | s.pop(); 80 | // display all expanded nodes until n 81 | if (states[n] == EXPANDED) n->display(); 82 | if (n == next) Assert(0, "-------"); 83 | } 84 | } 85 | } 86 | } else if (states[top] == EXPANDED) { 87 | states[top] = VISITED; 88 | s.pop(); 89 | } else if (states[top] == VISITED) { 90 | s.pop(); 91 | } 92 | } 93 | std::cout << "NO Loop!\n"; 94 | } 95 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.cpp 3 | * @brief start entry 4 | */ 5 | 6 | #include 7 | 8 | #include "common.h" 9 | #include "graph.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | PNode* parseFIR(char *strbuf); 18 | void preorder_traversal(PNode* root); 19 | graph* AST2Graph(PNode* root); 20 | void inferAllWidth(); 21 | 22 | Config::Config() { 23 | EnableDumpGraph = false; 24 | OutputDir = "."; 25 | SuperNodeMaxSize = 35; 26 | cppMaxSizeKB = -1; 27 | sep_module = "$"; 28 | sep_aggr = "$$"; 29 | } 30 | Config globalConfig; 31 | 32 | 33 | #define FUNC_WRAPPER_INTERNAL(func, name, dumpCond) \ 34 | do { \ 35 | struct timeval start = getTime(); \ 36 | func; \ 37 | struct timeval end = getTime(); \ 38 | showTime("{" #func "}", start, end); \ 39 | if (dumpCond && globalConfig.EnableDumpGraph) g->dump(std::to_string(dumpIdx ++) + name); \ 40 | } while(0) 41 | 42 | #define FUNC_TIMER(func) FUNC_WRAPPER_INTERNAL(func, "", false) 43 | #define FUNC_WRAPPER(func, name) FUNC_WRAPPER_INTERNAL(func, name, true) 44 | 45 | static void printUsage(const char* ProgName) { 46 | std::cout << "Usage: " << ProgName << " [options] \n" 47 | << "Options:\n" 48 | << " -h, --help Display this help message and exit.\n" 49 | << " --dump Enable dumping of the graph.\n" 50 | << " --dir=[dir] Specify the output directory.\n" 51 | << " --supernode-max-size=[num] Specify the maximum size of a superNode.\n" 52 | << " --cpp-max-size-KB=[num] Specify the maximum size (approximate) of a generated C++ file.\n" 53 | << " --sep-mod=[str] Specify the seperator for submodule (default: $).\n" 54 | << " --sep-aggr=[str] Specify the seperator for aggregate member (default: $$).\n" 55 | ; 56 | } 57 | 58 | static char* parseCommandLine(int argc, char** argv) { 59 | if (argc <= 1) { 60 | printUsage(argv[0]); 61 | exit(EXIT_SUCCESS); 62 | } 63 | 64 | const struct option Table[] = { 65 | {"help", no_argument, nullptr, 'h'}, 66 | {"dump", no_argument, nullptr, 'd'}, 67 | {"dir", required_argument, nullptr, 0}, 68 | {"supernode-max-size", required_argument, nullptr, 0}, 69 | {"cpp-max-size-KB", required_argument, nullptr, 0}, 70 | {"sep-mod", required_argument, nullptr, 0}, 71 | {"sep-aggr", required_argument, nullptr, 0}, 72 | {nullptr, no_argument, nullptr, 0}, 73 | }; 74 | 75 | int Option{0}; 76 | int option_index; 77 | while ((Option = getopt_long(argc, argv, "-h", Table, &option_index)) != -1) { 78 | switch (Option) { 79 | case 0: switch (option_index) { 80 | case 1: globalConfig.EnableDumpGraph = true; break; 81 | case 2: globalConfig.OutputDir = optarg; break; 82 | case 3: sscanf(optarg, "%d", &globalConfig.SuperNodeMaxSize); break; 83 | case 4: sscanf(optarg, "%d", &globalConfig.cppMaxSizeKB); break; 84 | case 5: globalConfig.sep_module = optarg; break; 85 | case 6: globalConfig.sep_aggr = optarg; break; 86 | case 0: 87 | default: printUsage(argv[0]); exit(EXIT_SUCCESS); 88 | } 89 | break; 90 | case 1: return optarg; // InputFileName 91 | case 'd': globalConfig.EnableDumpGraph = true; break; 92 | default: { 93 | printUsage(argv[0]); 94 | exit(EXIT_SUCCESS); 95 | } 96 | } 97 | } 98 | assert(0); 99 | } 100 | 101 | static char* readFile(const char *InputFileName, size_t &size, size_t &mapSize) { 102 | int fd = open(InputFileName, O_RDONLY); 103 | assert(fd != -1); 104 | struct stat sb; 105 | int ret = fstat(fd, &sb); 106 | assert(ret != -1); 107 | size = sb.st_size + 1; 108 | mapSize = (size + 4095) & ~4095L; 109 | char *buf = (char *)mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 110 | assert(buf != (void *)-1); 111 | buf[size - 1] = '\0'; 112 | close(fd); 113 | return buf; 114 | } 115 | 116 | /** 117 | * @brief main function. 118 | * 119 | * @param argc arg count. 120 | * @param argv arg value string. 121 | * @return exit state. 122 | */ 123 | int main(int argc, char** argv) { 124 | TIMER_START(total); 125 | graph* g = NULL; 126 | static int dumpIdx = 0; 127 | const char *InputFileName = parseCommandLine(argc, argv); 128 | 129 | size_t size = 0, mapSize = 0; 130 | char *strbuf; 131 | FUNC_TIMER(strbuf = readFile(InputFileName, size, mapSize)); 132 | 133 | PNode* globalRoot; 134 | FUNC_TIMER(globalRoot= parseFIR(strbuf)); 135 | munmap(strbuf, mapSize); 136 | 137 | FUNC_WRAPPER(g = AST2Graph(globalRoot), "Init"); 138 | 139 | FUNC_TIMER(g->splitArray()); 140 | 141 | FUNC_TIMER(g->detectLoop()); 142 | 143 | FUNC_WRAPPER(g->topoSort(), "TopoSort"); 144 | 145 | FUNC_TIMER(g->inferAllWidth()); 146 | 147 | FUNC_WRAPPER(g->removeDeadNodes(), "RemoveDeadNodes"); 148 | 149 | FUNC_WRAPPER(g->exprOpt(), "ExprOpt"); 150 | 151 | FUNC_TIMER(g->usedBits()); 152 | 153 | FUNC_TIMER(g->splitNodes()); 154 | 155 | FUNC_TIMER(g->removeDeadNodes()); 156 | 157 | FUNC_WRAPPER(g->constantAnalysis(), "ConstantAnalysis"); 158 | 159 | FUNC_WRAPPER(g->removeDeadNodes(), "RemoveDeadNodes"); 160 | 161 | FUNC_WRAPPER(g->aliasAnalysis(), "AliasAnalysis"); 162 | 163 | FUNC_WRAPPER(g->patternDetect(), "PatternDetect"); 164 | 165 | FUNC_WRAPPER(g->commonExpr(), "CommonExpr"); 166 | 167 | FUNC_WRAPPER(g->removeDeadNodes(), "RemoveDeadNodes"); 168 | 169 | // FUNC_WRAPPER(g->mergeNodes(), "MergeNodes"); 170 | FUNC_WRAPPER(g->graphPartition(), "graphPartition"); 171 | 172 | FUNC_WRAPPER(g->replicationOpt(), "Replication"); 173 | 174 | // FUNC_WRAPPER(g->mergeRegister(), "MergeRegister"); 175 | 176 | // FUNC_WRAPPER(g->constructRegs(), "ConstructRegs"); 177 | FUNC_TIMER(g->generateStmtTree()); 178 | 179 | FUNC_TIMER(g->instsGenerator()); 180 | 181 | FUNC_WRAPPER(g->cppEmitter(), "Final"); 182 | 183 | TIMER_END(total); 184 | 185 | return 0; 186 | } 187 | -------------------------------------------------------------------------------- /src/mergeRegister.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | merge regsrc into regdst if possible 3 | */ 4 | 5 | #include "common.h" 6 | #include 7 | #include 8 | Node* getLeafNode(bool isArray, ENode* enode); 9 | 10 | void ExpTree::replace(Node* oldNode, ENode* newENode) { 11 | std::stack> s; 12 | s.push(std::make_tuple(getRoot(), nullptr, -1)); 13 | if (getlval()) { 14 | for (size_t i = 0; i < getlval()->getChildNum(); i ++) s.push(std::make_tuple(getlval()->getChild(i), getlval(), i)); 15 | } 16 | 17 | while(!s.empty()) { 18 | ENode* top, *parent; 19 | int idx; 20 | std::tie(top, parent, idx) = s.top(); 21 | s.pop(); 22 | if (top->getNode() && getLeafNode(true, top) == oldNode) { 23 | if (parent) parent->setChild(idx, newENode); 24 | else setRoot(newENode); 25 | } 26 | 27 | for (size_t i = 0; i < top->getChildNum(); i ++) { 28 | ENode* enode = top->getChild(i); 29 | if (!enode) continue; 30 | s.push(std::make_tuple(enode, top, i)); 31 | } 32 | } 33 | } 34 | 35 | void ExpTree::removeSelfAssignMent(Node* node) { 36 | std::stack s; 37 | s.push(getRoot()); 38 | while (!s.empty()) { 39 | ENode* top = s.top(); 40 | s.pop(); 41 | if (top->opType == OP_WHEN) { 42 | for (size_t i = 1; i < top->getChildNum(); i ++) { 43 | if (top->child[i] && node == getLeafNode(true, top->child[i])) top->child[i] = nullptr; 44 | } 45 | } 46 | for (ENode* child : top->child) { 47 | if (child) s.push(child); 48 | } 49 | } 50 | } 51 | 52 | bool isNext(Node* node, Node* checkNode) { 53 | bool outSuperNext = checkNode->super->order > node->super->order; 54 | bool inSuperNext = (checkNode->super == node->super) && (checkNode->orderInSuper > node->orderInSuper); 55 | return outSuperNext || inSuperNext; 56 | } 57 | 58 | Node* laterNode(Node* node1, Node* node2) { 59 | if (!node1) return node2; 60 | if (!node2) return node1; 61 | if (isNext(node1, node2)) return node2; 62 | return node1; 63 | } 64 | 65 | void graph::orderAllNodes() { 66 | int order = 1; 67 | for (size_t i = 0; i < sortedSuper.size(); i ++) { 68 | sortedSuper[i]->order = i; 69 | for (size_t j = 0; j < sortedSuper[i]->member.size(); j ++) { 70 | sortedSuper[i]->member[j]->orderInSuper = j; 71 | sortedSuper[i]->member[j]->order = order ++; 72 | } 73 | } 74 | } 75 | 76 | // void graph::mergeRegister() { 77 | // orderAllNodes(); 78 | // int num = 0; 79 | // int totalNum = 0; 80 | // std::map maxNode; 81 | // std::map anyNextNodes; 82 | 83 | // for (int i = sortedSuper.size() - 1; i >= 0; i --) { 84 | // for (int j = (int)sortedSuper[i]->member.size() - 1; j >= 0; j --) { 85 | // Node* node = sortedSuper[i]->member[j]; 86 | // Node* latestNode = nullptr; 87 | // for (Node* next : node->next) { 88 | // latestNode = laterNode(latestNode, next); 89 | // } 90 | // maxNode[node] = latestNode; 91 | // } 92 | // } 93 | // for (Node* reg : regsrc) { 94 | // if (reg->status != VALID_NODE) continue; 95 | // totalNum ++; 96 | // if (reg->isArray() || reg->getDst()->assignTree.size() != 1) continue; 97 | // bool split = false; 98 | // if (maxNode[reg] && isNext(reg->getDst(), maxNode[reg])) split = true; 99 | // /* checking updateTree */ 100 | // std::stack s; 101 | // s.push(reg->updateTree->getRoot()); 102 | // while (!s.empty() && !split) { 103 | // ENode* top = s.top(); 104 | // s.pop(); 105 | // if (top->getNode()) { 106 | // Node* topNode = top->getNode(); 107 | // if (topNode->isArray() && topNode->arraySplitted()) { 108 | // ArrayMemberList* list = top->getArrayMember(topNode); 109 | // for (Node* member : list->member) { 110 | // if (isNext(reg->getDst(), member)) { 111 | // split = true; 112 | // break; 113 | // } 114 | // } 115 | // } else { 116 | // if (isNext(reg->getDst(), topNode)) split = true; 117 | // } 118 | // for (ENode* child : top->child) { 119 | // if (child) s.push(child); 120 | // } 121 | // } 122 | // } 123 | // if (!split) { // treat dst as NODE_OTHER 124 | // num ++; 125 | // reg->regSplit = reg->getDst()->regSplit = false; 126 | // reg->getDst()->name = reg->name; 127 | // } 128 | // } 129 | 130 | // printf("[mergeRegister] merge %d registers (total %d)\n", num, totalNum); 131 | // } 132 | 133 | // void graph::constructRegs() { 134 | // std::map dstSuper2updateSuper; 135 | // for (Node* node : regsrc) { 136 | // if (node->status != VALID_NODE) continue; 137 | // if (node->regSplit) { 138 | // Node* nodeUpdate = node->dup(NODE_REG_UPDATE); 139 | // node->regUpdate = nodeUpdate; 140 | // nodeUpdate->regNext = node; 141 | // nodeUpdate->assignTree.push_back(node->updateTree); 142 | // SuperNode* dstSuper = node->getDst()->super; 143 | // if (dstSuper2updateSuper.find(dstSuper) != dstSuper2updateSuper.end()) { 144 | // nodeUpdate->super = dstSuper2updateSuper[dstSuper]; 145 | // dstSuper2updateSuper[dstSuper]->member.push_back(nodeUpdate); 146 | // } else { 147 | // nodeUpdate->super = new SuperNode(nodeUpdate); 148 | // nodeUpdate->super->superType = SUPER_UPDATE_REG; 149 | // sortedSuper.push_back(nodeUpdate->super); 150 | // dstSuper2updateSuper[dstSuper] = nodeUpdate->super; 151 | // } 152 | // nodeUpdate->isArrayMember = node->isArrayMember; 153 | // } else { 154 | // Assert(node->getDst()->assignTree.size() == 1, "invalid assignTree for node %s", node->name.c_str()); 155 | // node->updateTree->replace(node->getDst(), node->getDst()->assignTree.back()->getRoot()); 156 | // /* remove self-assignments */ 157 | // if (getLeafNode(true, node->updateTree->getRoot()) == node->getSrc()) node->getDst()->assignTree.clear(); 158 | // else { 159 | // node->getDst()->assignTree[0] = node->updateTree; 160 | // node->getDst()->assignTree[0]->removeSelfAssignMent(node); 161 | // } 162 | // node->eraseNext(node->getDst()); 163 | // node->getDst()->status = VALID_NODE; 164 | // node->getDst()->computeInfo = nullptr; 165 | // } 166 | // } 167 | // reconnectAll(); 168 | // } 169 | -------------------------------------------------------------------------------- /src/opFuncs.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file opFuncs.cpp 3 | * @brief operation functions 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "common.h" 11 | 12 | static mpz_t t1; 13 | static mpz_t t2; 14 | // expr1int1 15 | void invalidExpr1Int1(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n) { 16 | Assert(0, "Invalid Expr1Int1 function\n"); 17 | } 18 | void u_pad(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n) { mpz_set(dst, src); } 19 | void s_pad(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t n) { 20 | if (bitcnt >= n || (mpz_cmp_ui(src, 0) >= 0)) { 21 | mpz_set(dst, src); 22 | return; 23 | } 24 | mpz_set_ui(t1, 1); 25 | mpz_mul_2exp(t1, t1, n - bitcnt); 26 | mpz_sub_ui(t1, t1, 1); 27 | mpz_mul_2exp(t1, t1, bitcnt); 28 | mpz_ior(dst, t1, src); 29 | } 30 | 31 | void u_shl(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n) { mpz_mul_2exp(dst, src, n); } 32 | 33 | void u_shr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n) { mpz_tdiv_q_2exp(dst, src, n); } 34 | void s_shr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n) { 35 | if (mpz_cmp_ui(src, 0) < 0) { 36 | mpz_fdiv_q_2exp(dst, dst, n); 37 | } else { 38 | mpz_tdiv_q_2exp(dst, src, n); 39 | } 40 | } 41 | // u_head: remove the last n bits 42 | void u_head(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n) { mpz_tdiv_q_2exp(dst, src, n); } 43 | // u_tail: remain the last n bits 44 | void u_tail(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, unsigned long n) { 45 | if (mpz_sgn(src) == 0) { 46 | mpz_set(dst, src); 47 | return; 48 | } 49 | mpz_set_ui(t1, 1); 50 | mpz_mul_2exp(t1, t1, n); 51 | mpz_sub_ui(t1, t1, 1); 52 | if (mpz_sgn(src) < 0) { 53 | mpz_set_ui(t2, 1); 54 | mpz_mul_2exp(t2, t2, bitcnt); 55 | mpz_add(t2, t2, src); 56 | mpz_and(dst, t1, t2); 57 | } else { 58 | mpz_and(dst, t1, src); 59 | } 60 | } 61 | // expr1 62 | void invalidExpr1(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { Assert(0, "Invalid Expr1 function\n"); } 63 | void u_asUInt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 64 | if (mpz_cmp_ui(src, 0) < 0) { 65 | mpz_set_ui(t1, 1); 66 | mpz_mul_2exp(t1, t1, bitcnt); 67 | mpz_add(dst, t1, src); 68 | } else { 69 | mpz_set(dst, src); 70 | } 71 | } 72 | 73 | void s_asSInt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 74 | if (mpz_sgn(src) > 0 && mpz_tstbit(src, bitcnt - 1)) { 75 | mpz_set_ui(t1, 1); 76 | mpz_mul_2exp(t1, t1, bitcnt); 77 | mpz_sub(t1, t1, src); 78 | mpz_neg(dst, t1); 79 | } else { 80 | mpz_set(dst, src); 81 | } 82 | } 83 | 84 | void u_asClock(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { mpz_set(dst, src); } 85 | void u_asAsyncReset(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { mpz_set(dst, src); } 86 | 87 | void u_cvt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { mpz_set(dst, src); } 88 | void s_cvt(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { mpz_set(dst, src); } 89 | void s_neg(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 90 | mpz_set_ui(t1, 0); 91 | mpz_sub(dst, t1, src); 92 | } 93 | void u_not(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 94 | mpz_set_ui(t1, 1); 95 | mpz_mul_2exp(t1, t1, bitcnt); 96 | mpz_sub_ui(t1, t1, 1); 97 | mpz_xor(dst, t1, src); 98 | } 99 | void u_orr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { mpz_set_ui(dst, mpz_cmp_ui(src, 0) == 0 ? 0 : 1); } 100 | void u_andr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 101 | mpz_set_ui(t1, 1); 102 | mpz_mul_2exp(t1, t1, bitcnt); 103 | mpz_sub_ui(t1, t1, 1); 104 | mpz_set_ui(dst, mpz_cmp(t1, src) == 0); 105 | } 106 | void u_xorr(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt) { 107 | mpz_set_ui(dst, mpz_popcount(src) & 1); // not work for negtive src 108 | } 109 | 110 | void invalidExpr2(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 111 | Assert(0, "Invalid Expr2 function\n"); 112 | } 113 | 114 | void us_add(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 115 | mpz_add(dst, src1, src2); 116 | } 117 | void us_sub(mpz_t& dst, mpz_t& src1, mpz_t& src2, mp_bitcnt_t dst_bitcnt) { 118 | if (mpz_sgn(src2) == 0) { 119 | mpz_set(dst, src1); 120 | return; 121 | } 122 | mpz_set_ui(t1, 1); 123 | mpz_mul_2exp(t1, t1, dst_bitcnt); 124 | mpz_sub(t1, t1, src2); 125 | mpz_add(dst, t1, src1); 126 | } 127 | void us_mul(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 128 | mpz_mul(dst, src1, src2); 129 | } 130 | void us_div(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 131 | if (mpz_cmp_ui(src2, 0) == 0) return; 132 | mpz_tdiv_q(dst, src1, src2); 133 | } 134 | void us_rem(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 135 | if (mpz_cmp_ui(src2, 0) == 0) return; 136 | mpz_tdiv_r(dst, src1, src2); 137 | } 138 | void us_lt(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 139 | mpz_set_ui(dst, mpz_cmp(op1, op2) < 0); 140 | } 141 | void us_leq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 142 | mpz_set_ui(dst, mpz_cmp(op1, op2) <= 0); 143 | } 144 | void us_gt(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 145 | mpz_set_ui(dst, mpz_cmp(op1, op2) > 0); 146 | } 147 | void us_geq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 148 | mpz_set_ui(dst, mpz_cmp(op1, op2) >= 0); 149 | } 150 | void us_eq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 151 | mpz_set_ui(dst, mpz_cmp(op1, op2) == 0); 152 | } 153 | void us_neq(mpz_t& dst, mpz_t& op1, mp_bitcnt_t bitcnt1, mpz_t& op2, mp_bitcnt_t bitcnt2) { 154 | mpz_set_ui(dst, mpz_cmp(op1, op2) != 0); 155 | } 156 | void u_dshl(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 157 | mpz_mul_2exp(dst, src1, mpz_get_ui(src2)); 158 | } 159 | void u_dshr(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 160 | mpz_tdiv_q_2exp(dst, src1, mpz_get_ui(src2)); 161 | } 162 | void s_dshr(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 163 | int n = mpz_get_ui(src2); 164 | if (mpz_cmp_ui(src1, 0) < 0) { 165 | mpz_fdiv_q_2exp(dst, src1, n); 166 | } else { 167 | mpz_tdiv_q_2exp(dst, src1, n); 168 | } 169 | } 170 | void u_and(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { mpz_and(dst, src1, src2); } 171 | void u_ior(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { mpz_ior(dst, src1, src2); } 172 | void u_xor(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { mpz_xor(dst, src1, src2); } 173 | void u_cat(mpz_t& dst, mpz_t& src1, mp_bitcnt_t bitcnt1, mpz_t& src2, mp_bitcnt_t bitcnt2) { 174 | Assert(mpz_sgn(src1) >= 0 && mpz_sgn(src2) >= 0, "src1 / src2 < 0\n"); 175 | mpz_mul_2exp(t1, src1, bitcnt2); 176 | mpz_ior(dst, t1, src2); 177 | } 178 | 179 | void invalidExpr1Int2(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l) { 180 | Assert(0, "Invalid Expr1Int2 function\n"); 181 | } 182 | 183 | void u_bits(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l) { 184 | if (mpz_sgn(src) < 0) { 185 | mpz_set_ui(t1, 1); 186 | mpz_mul_2exp(t1, t1, bitcnt); 187 | mpz_add(t1, t1, src); 188 | mpz_tdiv_q_2exp(t1, t1, l); 189 | } else { 190 | mpz_tdiv_q_2exp(t1, src, l); 191 | } 192 | mpz_set_ui(t2, 1); 193 | mpz_mul_2exp(t2, t2, h - l + 1); 194 | mpz_sub_ui(t2, t2, 1); 195 | mpz_and(dst, t1, t2); 196 | } 197 | 198 | void u_bits_noshift(mpz_t& dst, mpz_t& src, mp_bitcnt_t bitcnt, mp_bitcnt_t h, mp_bitcnt_t l) { 199 | if (mpz_sgn(src) < 0) { 200 | mpz_set_ui(t1, 1); 201 | mpz_mul_2exp(t1, t1, bitcnt); 202 | mpz_add(t1, t1, src); 203 | } else { 204 | mpz_set(t1, src); 205 | } 206 | mpz_set_ui(t2, 1); 207 | mpz_mul_2exp(t2, t2, h - l + 1); 208 | mpz_sub_ui(t2, t2, 1); 209 | mpz_mul_2exp(t2, t2, l); 210 | mpz_and(dst, t1, t2); 211 | } 212 | 213 | void us_mux(mpz_t& dst, mpz_t& cond, mpz_t& src1, mpz_t& src2) { 214 | if (mpz_sgn(cond) != 0) 215 | mpz_set(dst, src1); 216 | else 217 | mpz_set(dst, src2); 218 | } 219 | -------------------------------------------------------------------------------- /src/patternDetect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common.h" 4 | /* detect and optimize some specific patterns */ 5 | /* behind constantAnalysis */ 6 | Node* getLeafNode(bool isArray, ENode* enode); 7 | /* pattern 1: 8 | oneHot = dshl(1, shift) 9 | _T_0 = bits(oneHot, 0, 0) 10 | _T_1 = bits(oneHot, 1, 1) 11 | .... 12 | optimize: 13 | _T_i = shift == i 14 | */ 15 | static ENode* isDshlOne(ENode* enode) { 16 | if(enode->opType != OP_DSHL || enode->getChild(0)->opType != OP_INT) return nullptr; 17 | auto value = firStrBase(enode->getChild(0)->strVal); 18 | if (value.second != "1") return nullptr; 19 | if (enode->getChild(1)->nodePtr) return enode->getChild(1); 20 | return nullptr; 21 | } 22 | static bool isBitsOne(ENode* enode) { 23 | return (enode->opType == OP_BITS && enode->values[0] == enode->values[1]); 24 | } 25 | bool checkPatern1(Node* node) { 26 | if (node->isArray() || node->type != NODE_OTHERS || node->assignTree.size() != 1) return false; 27 | ENode* root = node->assignTree[0]->getRoot(); 28 | ENode* shiftENode = isDshlOne(root); 29 | if (!shiftENode) return false; 30 | bool ret = true; 31 | for (Node* next : node->next) { 32 | if (next->isArray() || next->assignTree.size() != 1 || !isBitsOne(next->assignTree[0]->getRoot())) { 33 | ret = false; 34 | continue; 35 | } 36 | ENode* intENode = allocIntEnode(shiftENode->width, std::to_string(next->assignTree[0]->getRoot()->values[0])); 37 | ENode* eq = new ENode(OP_EQ); 38 | eq->width = 1; 39 | eq->addChild(shiftENode->dup()); 40 | eq->addChild(intENode); 41 | ExpTree* newTree = new ExpTree(eq, new ENode(next)); 42 | next->assignTree.clear(); 43 | next->assignTree.push_back(newTree); 44 | } 45 | if (ret) node->status = DEAD_NODE; 46 | return ret; 47 | } 48 | 49 | void graph::patternDetect() { 50 | int num1 = 0; 51 | for (SuperNode* super : sortedSuper) { 52 | for (Node* member : super->member) { 53 | num1 += checkPatern1(member); 54 | } 55 | } 56 | removeNodesNoConnect(DEAD_NODE); 57 | reconnectAll(); 58 | printf("[patternDetect] find %d pattern1\n", num1); 59 | } -------------------------------------------------------------------------------- /src/perfAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | 5 | static size_t arithOp = 0; 6 | static size_t arith128 = 0; 7 | static size_t bitOp = 0; 8 | static size_t bit128 = 0; 9 | static size_t muxOp = 0; 10 | static size_t mux128 = 0; 11 | static size_t logiOp = 0; 12 | static size_t logi128 = 0; 13 | static size_t convertOp = 0; 14 | static size_t convert128 = 0; 15 | static size_t cmpOp = 0; 16 | static size_t cmp128 = 0; 17 | static size_t shiftOp = 0; 18 | static size_t shift128 = 0; 19 | static size_t readmemOp = 0; 20 | static size_t resetOp = 0; 21 | 22 | size_t countBits(Node* node) { 23 | Assert(node->width >= 0, "%s width = %d\n", node->name.c_str(), node->width); 24 | size_t ret = node->width; 25 | for (int dim : node->dimension) ret *= dim; 26 | return ret; 27 | } 28 | size_t countNodeNum(Node* node) { 29 | size_t ret = 1; 30 | for (int dim : node->dimension) ret *= dim; 31 | return ret; 32 | } 33 | 34 | void countAllNodeNum(graph* g) { 35 | size_t totalBits = 0; 36 | size_t regBits = 0; 37 | size_t midNum = 0; 38 | size_t regNum = 0; 39 | size_t simpleRegNum = 0; 40 | for (SuperNode* super : g->sortedSuper) { 41 | for (Node* node : super->member) { 42 | if (node->type == NODE_REG_DST) continue; // avoid duplicated counting 43 | if (node->type == NODE_REG_SRC) { 44 | regNum += countNodeNum(node); 45 | regBits += countBits(node); 46 | simpleRegNum += 1; 47 | } else { 48 | midNum += countNodeNum(node); 49 | } 50 | totalBits += countBits(node); 51 | } 52 | } 53 | printf("totalBits %ld midNum %ld regNum %ld regBits %ld total %ld simpleRegNum %ld\n", totalBits, midNum, regNum, regBits, midNum + regNum, simpleRegNum); 54 | } 55 | 56 | size_t countOpsInTree(ExpTree* tree) { 57 | size_t ret = 0; 58 | std::stack s; 59 | s.push(tree->getRoot()); 60 | if (tree->getlval()) s.push(tree->getlval()); 61 | while(!s.empty()) { 62 | ENode* top = s.top(); 63 | s.pop(); 64 | if (top->nodePtr || top->opType == OP_INT || top->opType == OP_INVALID || top->opType == OP_EMPTY || top->opType == OP_INDEX_INT || top->opType == OP_INDEX) { 65 | // do nothing 66 | } else { 67 | ret ++; 68 | switch (top->opType) { 69 | case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_REM: case OP_NEG: 70 | arithOp ++; 71 | if (top->width > 128) arith128 ++; 72 | break; 73 | case OP_LT: case OP_LEQ: case OP_GT: case OP_GEQ: case OP_EQ: case OP_NEQ: 74 | if (top->getChild(0)->width > 128) cmp128 ++; 75 | cmpOp ++; 76 | break; 77 | case OP_DSHL: case OP_DSHR: 78 | if (top->getChild(0)->width > 128 || top->width > 128) shift128 ++; 79 | shiftOp ++; 80 | break; 81 | case OP_AND: case OP_OR: case OP_XOR: case OP_NOT: 82 | if (top->width > 128) logi128 ++; 83 | logiOp ++; 84 | break; 85 | case OP_ASUINT: case OP_ASSINT: case OP_CVT: 86 | case OP_ASASYNCRESET: case OP_ASCLOCK: 87 | case OP_SEXT: 88 | if (top->getChild(0)->width > 128) convert128 ++; 89 | convertOp ++; 90 | break; 91 | case OP_PAD: case OP_SHL: case OP_SHR: case OP_HEAD: 92 | case OP_TAIL: case OP_BITS: case OP_BITS_NOSHIFT: case OP_CAT: 93 | if (top->getChild(0)->width > 128 || top->width > 128) bit128 ++; 94 | bitOp ++; 95 | break; 96 | case OP_MUX: case OP_WHEN: 97 | if (top->width > 128) mux128 ++; 98 | muxOp ++; 99 | break; 100 | case OP_READ_MEM: 101 | readmemOp ++; 102 | break; 103 | case OP_RESET: 104 | resetOp ++; 105 | break; 106 | case OP_ANDR: case OP_ORR: case OP_XORR: 107 | case OP_STMT: 108 | case OP_EXIT: 109 | case OP_PRINTF: 110 | case OP_ASSERT: 111 | break; 112 | default: 113 | fprintf(stderr, "invalid op %d\n", top->opType); 114 | Panic(); 115 | break; 116 | } 117 | } 118 | for (ENode* childENode : top->child) { 119 | if (childENode) s.push(childENode); 120 | } 121 | } 122 | return ret; 123 | } 124 | 125 | size_t countOpsInNode(Node* node) { 126 | size_t ret = 0; 127 | for (ExpTree* tree : node->assignTree) ret += countOpsInTree(tree); 128 | return ret; 129 | } 130 | 131 | /* count midNodes in trees */ 132 | void countOps(graph* g) { 133 | size_t totalOps = 0; 134 | for (SuperNode* super : g->sortedSuper) { 135 | for (Node* node : super->member) { 136 | totalOps += countOpsInNode(node); 137 | } 138 | } 139 | printf("totalOps %ld (total128 %ld) arithOp %ld (arith128 %ld) bitOp %ld (bit128 %ld) muxOp %ld (mux128 %ld) logiOp %ld (logi128 %ld) convertOp %ld (convert128 %ld) cmpOp %ld (cmp128 %ld) shiftOp %ld (shift128 %ld) readMem %ld reset %ld \n", 140 | totalOps, arith128 + bit128 + mux128 + logi128 + convert128 + cmp128 + shift128, arithOp, arith128, bitOp, bit128, muxOp, mux128, logiOp, logi128, convertOp, convert128, cmpOp, cmp128, shiftOp, shift128, readmemOp, resetOp); 141 | } 142 | 143 | void graph::perfAnalysis() { 144 | countAllNodeNum(this); 145 | countOps(this); 146 | } 147 | 148 | void graph::depthPerf() { 149 | orderAllNodes(); 150 | /* count depth & nodeNum of superNode*/ 151 | std::map superDepth; 152 | std::map> superNum; 153 | for (SuperNode* super : sortedSuper) { 154 | int depth = 0; 155 | for (SuperNode* prev : super->prev) { 156 | if (prev->order < super->order) { 157 | depth = MAX(superDepth[prev] + 1, depth); 158 | } 159 | } 160 | superDepth[super] = depth; 161 | if (superNum.find(depth) == superNum.end()) superNum[depth] = std::make_pair(0, 0); 162 | superNum[depth].first ++; 163 | superNum[depth].second += super->member.size(); 164 | } 165 | 166 | /* count depth of node */ 167 | std::map nodeDepth; 168 | std::map nodeNum; 169 | for (SuperNode* super : sortedSuper) { 170 | for (Node* node : super->member) { 171 | int depth = 0; 172 | for (Node* prev : node->prev) { 173 | if (prev->order < node->order) { 174 | depth = MAX(nodeDepth[prev] + 1, depth); 175 | } 176 | } 177 | nodeDepth[node] = depth; 178 | if (nodeNum.find(depth) == nodeNum.end()) nodeNum[depth] = 0; 179 | nodeNum[depth] ++; 180 | } 181 | } 182 | printf("SuperNode info:\n"); 183 | for (auto iter : superNum) { 184 | printf("depth %d superNum %d nodeNum %d\n", iter.first, iter.second.first, iter.second.second); 185 | } 186 | printf("Node info:\n"); 187 | for (auto iter : nodeNum) { 188 | printf("depth %d nodeNum %d\n", iter.first, iter.second); 189 | } 190 | } -------------------------------------------------------------------------------- /src/replication.cpp: -------------------------------------------------------------------------------- 1 | /* remove nodes by replication */ 2 | #include "common.h" 3 | #include 4 | #include 5 | 6 | /* non-negative if node is replicated and -1 if node is not */ 7 | static std::map opNum; 8 | Node* getLeafNode(bool isArray, ENode* enode); 9 | void getENodeRelyNodes(ENode* enode, std::set& allNodes); 10 | 11 | void ExpTree::replace(Node* oldNode, Node* newNode) { 12 | std::stack s; 13 | if (getRoot()) s.push(getRoot()); 14 | if (getlval()) s.push(getlval()); 15 | 16 | while(!s.empty()) { 17 | ENode* top = s.top(); 18 | s.pop(); 19 | if (top->getNode() && getLeafNode(true, top) == oldNode) { 20 | top->nodePtr = newNode; 21 | top->child.clear(); 22 | } 23 | for (ENode* childENode : top->child) { 24 | if (childENode) s.push(childENode); 25 | } 26 | } 27 | } 28 | 29 | int Node::repOpCount() { 30 | if (isArray() || type != NODE_OTHERS || assignTree.size() > 1) return -1; 31 | if (status == CONSTANT_NODE) return 0; 32 | int ret = 0; 33 | std::stack s; 34 | for (ExpTree* tree : assignTree) s.push(tree->getRoot()); 35 | while (!s.empty()) { 36 | ENode* top = s.top(); 37 | s.pop(); 38 | if (top->nodePtr) { 39 | Node* leafNode = getLeafNode(true, top); 40 | if (leafNode->isArray()) { 41 | for (ENode* child : top->child) { 42 | if (child->width > BASIC_WIDTH) return -1; 43 | else ret ++; 44 | } 45 | } 46 | if (opNum[leafNode] >= 0) ret += opNum[leafNode]; 47 | continue; 48 | } 49 | else if (top->opType == OP_INT) continue; 50 | else if (top->opType == OP_WHEN) return -1; 51 | if (top->width > BASIC_WIDTH) return -1; 52 | ret ++; 53 | for (ENode* child : top->child) { 54 | if (child) s.push(child); 55 | } 56 | } 57 | return ret; 58 | } 59 | 60 | void graph::replicationOpt() { 61 | size_t optimizeNum = 0; 62 | size_t oldNum = countNodes(); 63 | size_t oldSuper = sortedSuper.size(); 64 | std::set mustNodes; 65 | for (SuperNode* super : sortedSuper) { // TODO: support op in index 66 | for (Node* member : super->member) { 67 | if (!member->isArray()) continue; 68 | std::set rely; 69 | for (ExpTree* tree : member->assignTree) { 70 | getENodeRelyNodes(tree->getlval(), rely); 71 | } 72 | rely.erase(member); 73 | mustNodes.insert(rely.begin(), rely.end()); 74 | for (Node* next : member->next) { 75 | if (next->isArray()) mustNodes.insert(member); 76 | } 77 | } 78 | } 79 | std::vector repNodes; 80 | for (SuperNode* super : sortedSuper) { 81 | for (Node* member : super->member) { 82 | int op = member->repOpCount(); 83 | int threadHold = super->member.size() == 1 ? 3 : 0; 84 | if (mustNodes.find(member) != mustNodes.end() || op < 0 || op * (int)member->next.size() >= threadHold || !member->anyExtEdge()) { 85 | opNum[member] = -1; // mark node is valid 86 | } else { 87 | opNum[member] = op; // mark node is replicated 88 | repNodes.push_back(member); 89 | optimizeNum ++; 90 | } 91 | } 92 | } 93 | /* remove replication nodes and update connections */ 94 | for (int i = repNodes.size() - 1; i >= 0; i --) { 95 | Node* node = repNodes[i]; 96 | std::map> nextSuper; 97 | bool remainNode = false; 98 | for (Node* next : node->next) { 99 | if (nextSuper.find(next->super) == nextSuper.end()) nextSuper[next->super] = std::vector(); 100 | nextSuper[next->super].push_back(next); 101 | if (next->super == node->super) remainNode = true; 102 | } 103 | if (!remainNode) node->status = REPLICATION_NODE; 104 | int repIdx = 1; 105 | for (auto iter : nextSuper) { 106 | SuperNode* super = iter.first; 107 | if (super == node->super) continue; 108 | std::string dupName = format("%s$DUP_%d", node->name.c_str(), repIdx ++); 109 | Node* repNode = node->dup(node->type, dupName); 110 | for (Node* prev : node->prev) prev->addNext(repNode); 111 | repNode->assignTree.push_back(new ExpTree(node->assignTree[0]->getRoot()->dup(), new ENode(repNode))); 112 | super->member.insert(super->member.begin(), repNode); 113 | repNode->super = super; 114 | for (Node* next : iter.second) { 115 | for (ExpTree* tree : next->assignTree) tree->replace(node, repNode); 116 | } 117 | } 118 | } 119 | removeNodesNoConnect(REPLICATION_NODE); 120 | reconnectAll(); 121 | printf("[replication] remove %ld nodes (%ld -> %ld)\n", optimizeNum, oldNum, countNodes()); 122 | printf("[replication] remove %ld superNodes (%ld -> %ld)\n", oldSuper - sortedSuper.size(), oldSuper, sortedSuper.size()); 123 | } 124 | -------------------------------------------------------------------------------- /src/resetAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | /* before splitted array */ 4 | 5 | void fillEmptyWhen(ExpTree* newTree, ENode* oldNode); 6 | 7 | std::map resetMap; 8 | 9 | ResetType Node::inferReset() { 10 | if (reset != UNCERTAIN) return reset; 11 | Assert(assignTree.size() > 0, "empty assignTree"); 12 | for (ExpTree* tree : assignTree) { 13 | ResetType newReset = tree->getRoot()->inferReset(); 14 | if (reset == UNCERTAIN) reset = newReset; 15 | else if (reset != tree->getRoot()->reset) { 16 | printf("reset %d %d\n", reset, tree->getRoot()->reset); 17 | Panic(); 18 | } 19 | } 20 | return reset; 21 | } 22 | 23 | ResetType ENode::inferReset() { 24 | if (reset != UNCERTAIN) return reset; 25 | if (nodePtr) { 26 | reset = nodePtr->inferReset(); 27 | return reset; 28 | } 29 | int base; 30 | std::string str; 31 | switch (opType) { 32 | case OP_ASUINT: 33 | case OP_ASSINT: 34 | reset = UINTRESET; 35 | break; 36 | case OP_INT: 37 | std::tie(base, str) = firStrBase(strVal); 38 | if (str == "h0" || str == "0") 39 | reset = ZERO_RESET; 40 | else { 41 | std::cout << "Unknown :" << str << std::endl; 42 | TODO(); 43 | } 44 | break; 45 | case OP_ASASYNCRESET: 46 | reset = ASYRESET; 47 | break; 48 | case OP_BITS: 49 | case OP_OR: 50 | reset = UINTRESET; 51 | break; 52 | case OP_ASCLOCK: 53 | default: 54 | printf("opType %d\n", opType); 55 | Panic(); 56 | } 57 | return reset; 58 | } 59 | 60 | void fillOuterWhen(ExpTree* newTree, ENode* enode) { 61 | ENode* whenNode = newTree->getRoot(); 62 | while (whenNode->opType == OP_WHEN) { 63 | if (!whenNode->getChild(1)) whenNode->setChild(1, enode); 64 | if (!whenNode->getChild(2)) whenNode->setChild(2, enode); 65 | if (whenNode->getChild(1) && whenNode->getChild(2)) break; 66 | else if (whenNode->getChild(1)) whenNode = whenNode->getChild(1); 67 | else if (whenNode->getChild(2)) whenNode = whenNode->getChild(2); 68 | else Assert(0, "emptyWhen"); 69 | } 70 | } 71 | 72 | void Node::addReset() { // remove 73 | Assert(type == NODE_REG_SRC, "%s(%d) is not regsrc", name.c_str(), type); 74 | 75 | ResetType resetType = resetCond->getRoot()->inferReset(); 76 | reset = resetType; 77 | Assert(resetType != UNCERTAIN, "reset %s is uncertain", name.c_str()); 78 | } -------------------------------------------------------------------------------- /src/superNode.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | int SuperNode::counter = 1; 4 | 5 | void SuperNode::clear_relation() { 6 | prev.clear(); 7 | next.clear(); 8 | depPrev.clear(); 9 | depNext.clear(); 10 | } 11 | 12 | void SuperNode::addPrev(SuperNode* node) { 13 | prev.insert(node); 14 | depPrev.insert(node); 15 | } 16 | 17 | void SuperNode::addPrev(std::set& super) { 18 | prev.insert(super.begin(), super.end()); 19 | depPrev.insert(super.begin(), super.end()); 20 | } 21 | 22 | void SuperNode::erasePrev(SuperNode* node) { 23 | prev.erase(node); 24 | depPrev.erase(node); 25 | } 26 | 27 | void SuperNode::addDepPrev(SuperNode* node) { 28 | depPrev.insert(node); 29 | } 30 | 31 | void SuperNode::eraseDepPrev(SuperNode* node) { 32 | depPrev.erase(node); 33 | } 34 | 35 | void SuperNode::addNext(SuperNode* node) { 36 | next.insert(node); 37 | depNext.insert(node); 38 | } 39 | 40 | void SuperNode::addNext(std::set& super) { 41 | next.insert(super.begin(), super.end()); 42 | depNext.insert(super.begin(), super.end()); 43 | } 44 | 45 | void SuperNode::eraseDepNext(SuperNode* node) { 46 | depNext.erase(node); 47 | } 48 | 49 | void SuperNode::addDepNext(SuperNode* node) { 50 | depNext.insert(node); 51 | } 52 | 53 | void SuperNode::eraseNext(SuperNode* node) { 54 | next.erase(node); 55 | depNext.erase(node); 56 | } 57 | -------------------------------------------------------------------------------- /src/topoSort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | sort superNodes in topological order 3 | */ 4 | 5 | #include "common.h" 6 | #include 7 | #include 8 | 9 | void graph::topoSort() { 10 | std::maptimes; 11 | std::stack s; 12 | for (SuperNode* node : supersrc) { 13 | if (node->depPrev.size() == 0) s.push(node); 14 | } 15 | /* next.size() == 0, place the registers at the end to benefit mergeRegisters */ 16 | std::vector potentialRegs; 17 | std::set visited; 18 | while(!s.empty()) { 19 | SuperNode* top = s.top(); 20 | s.pop(); 21 | Assert(visited.find(top) == visited.end(), "superNode %d is already visited\n", top->id); 22 | visited.insert(top); 23 | sortedSuper.push_back(top); 24 | #ifdef ORDERED_TOPO_SORT 25 | std::vector sortedNext; 26 | sortedNext.insert(sortedNext.end(), top->depNext.begin(), top->depNext.end()); 27 | std::sort(sortedNext.begin(), sortedNext.end(), [](SuperNode* a, SuperNode* b) {return a->id < b->id;}); 28 | for (SuperNode* next : sortedNext) { 29 | #else 30 | for (SuperNode* next : top->depNext) { 31 | #endif 32 | if (times.find(next) == times.end()) times[next] = 0; 33 | times[next] ++; 34 | if (times[next] == (int)next->depPrev.size()) { 35 | s.push(next); 36 | } 37 | } 38 | } 39 | /* insert registers */ 40 | sortedSuper.insert(sortedSuper.end(), potentialRegs.begin(), potentialRegs.end()); 41 | /* order sortedSuper */ 42 | for (size_t i = 0; i < sortedSuper.size(); i ++) sortedSuper[i]->order = i + 1; 43 | int nodeOrder = 0; 44 | for (SuperNode* super : sortedSuper) { 45 | for (Node* node : super->member) { 46 | node->order = nodeOrder ++; 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/traversal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | traverse AST / graph 3 | */ 4 | 5 | #include "common.h" 6 | #include 7 | #include 8 | #include 9 | #include "PNode.h" 10 | 11 | static std::map pname = { 12 | {P_EMPTY, "P_EMPTY"}, {P_CIRCUIT, "P_CIRCUIT"}, {P_MOD, "P_MOD"}, {P_EXTMOD, "P_EXTMOD"}, 13 | {P_INTMOD, "P_INTMOD"}, {P_PORTS, "P_PORTS"}, {P_INPUT, "P_INPUT"}, {P_OUTPUT, "P_OUTPUT"}, 14 | {P_WIRE_DEF, "P_WIRE_DEF"}, {P_REG_DEF, "P_REG_DEF"}, {P_REG_RESET_DEF, "P_REG_RESET_DEF"}, {P_INST, "P_INST"}, 15 | {P_NODE, "P_NODE"}, {P_CONNECT, "P_CONNECT"}, {P_PAR_CONNECT, "P_PAR_CONNECT"}, {P_WHEN, "P_WHEN"}, 16 | {P_MEMORY, "P_MEMORY"}, {P_SEQ_MEMORY, "P_SEQ_MEMORY"}, {P_COMB_MEMORY, "P_COMB_MEMORY"}, {P_WRITE, "P_WRITE"}, 17 | {P_READ, "P_READ"}, {P_INFER, "P_INFER"}, {P_MPORT, "P_MPORT"}, {P_READER, "P_READER"}, 18 | {P_WRITER, "P_WRITER"}, {P_READWRITER, "P_READWRITER"}, {P_RUW, "P_RUW"}, {P_RLATENCT, "P_RLATENCT"}, 19 | {P_WLATENCT, "P_WLATENCT"}, {P_DATATYPE, "P_DATATYPE"}, {P_DEPTH, "P_DEPTH"}, {P_REF, "P_REF"}, 20 | {P_REF_DOT, "P_REF_DOT"}, {P_REF_IDX_INT, "P_REF_IDX_INT"}, {P_REF_IDX_EXPR, "P_REF_IDX_EXPR"}, {P_2EXPR, "P_2EXPR"}, 21 | {P_1EXPR, "P_1EXPR"}, {P_1EXPR1INT, "P_1EXPR1INT"}, {P_1EXPR2INT, "P_1EXPR2INT"}, {P_FIELD, "P_FIELD"}, 22 | {P_AG_ARRAY, "P_AG_ARRAY"}, {P_FLIP_FIELD, "P_FLIP_FIELD"}, {P_AG_FIELDS, "P_AG_FIELDS"}, {P_Clock, "P_Clock"}, 23 | {P_ASYRESET, "P_ASYRESET"}, {P_INT_TYPE, "P_INT_TYPE"}, {P_EXPR_INT_NOINIT, "P_EXPR_INT_NOINIT"}, {P_EXPR_INT_INIT, "P_EXPR_INT_INIT"}, 24 | {P_EXPR_MUX, "P_EXPR_MUX"}, {P_STATEMENTS, "P_STATEMENTS"}, {P_PRINTF, "P_PRINTF"}, {P_EXPRS, "P_EXPRS"}, 25 | {P_ASSERT, "P_ASSERT"}, {P_INDEX, "P_INDEX"}, {P_CONS_INDEX, "P_CONS_INDEX"}, {P_L_CONS_INDEX, "P_L_CONS_INDEX"}, 26 | {P_L_INDEX, "P_L_INDEX"}, {P_INVALID, "P_INVALID"} 27 | }; 28 | /* Preorder traversal of AST */ 29 | void preorder_traversal(PNode* root) { 30 | std::stack> s; 31 | s.push(std::make_pair(root, 0)); 32 | PNode* node; 33 | int depth; 34 | while (!s.empty()) { 35 | std::tie(node, depth) = s.top(); 36 | s.pop(); 37 | printf("%s", std::string(depth * 2, ' ').c_str()); 38 | if(!node) { 39 | std::cout << "NULL\n"; 40 | continue; 41 | } 42 | printf("%s [%s] (lineno %d, width %d): %s\n", node->name.c_str(), pname[node->type], node->lineno, node->width, node->name.c_str()); 43 | for (int i = node->getChildNum() - 1; i >= 0; i--) { 44 | s.push(std::make_pair(node->getChild(i), depth + 1)); 45 | } 46 | } 47 | fflush(stdout); 48 | } 49 | 50 | static std::map OP2Name = { 51 | {OP_INVALID, "invalid"}, {OP_MUX, "mux"}, {OP_ADD, "add"}, {OP_SUB, "sub"}, {OP_MUL, "mul"}, 52 | {OP_DIV, "div"}, {OP_REM, "rem"}, {OP_LT, "lt"}, {OP_LEQ, "leq"}, {OP_GT, "gt"}, {OP_GEQ, "geq"}, 53 | {OP_EQ, "eq"}, {OP_NEQ, "neq"}, {OP_DSHL, "dshl"}, {OP_DSHR, "dshr"}, {OP_AND, "and"}, 54 | {OP_OR, "or"}, {OP_XOR, "xor"}, {OP_CAT, "cat"}, {OP_ASUINT, "asuint"}, {OP_ASSINT, "assint"}, 55 | {OP_ASCLOCK, "asclock"}, {OP_ASASYNCRESET, "asasyncreset"}, {OP_CVT, "cvt"}, {OP_NEG, "neg"}, 56 | {OP_NOT, "not"}, {OP_ANDR, "andr"}, {OP_ORR, "orr"}, {OP_XORR, "xorr"}, {OP_PAD, "pad"}, {OP_SHL, "shl"}, 57 | {OP_SHR, "shr"}, {OP_HEAD, "head"}, {OP_TAIL, "tail"}, {OP_BITS, "bits"}, {OP_INDEX_INT, "index_int"}, 58 | {OP_INDEX, "index"}, {OP_WHEN, "when"}, {OP_PRINTF, "printf"}, {OP_ASSERT, "assert"}, {OP_INT, "int"}, 59 | {OP_READ_MEM, "readMem"}, {OP_WRITE_MEM, "writeMem"}, {OP_INFER_MEM, "inferMem"}, 60 | {OP_RESET, "reset"}, {OP_STMT, "stmts"}, {OP_SEXT, "sext"}, {OP_BITS_NOSHIFT, "bits_noshift"}, 61 | {OP_GROUP, "group"}, {OP_EXIT, "exit"}, {OP_EXT_FUNC, "ext_func"}, 62 | {OP_STMT_SEQ, "stmt_seq"}, {OP_STMT_WHEN, "stmt_when"}, {OP_STMT_NODE, "stmt_node"} 63 | }; 64 | 65 | static std::map NodeType2Name = { 66 | {NODE_INVALID, "invalid"}, {NODE_REG_SRC, "reg_src"}, {NODE_REG_DST, "reg_dst"}, {NODE_SPECIAL, "special"}, 67 | {NODE_INP, "inp"}, {NODE_OUT, "out"}, {NODE_MEMORY, "memory"}, {NODE_READER, "reader"}, 68 | {NODE_WRITER, "writer"}, {NODE_READWRITER, "readwriter"}, {NODE_MEM_MEMBER, "mem_member"}, 69 | {NODE_OTHERS, "others"}, {NODE_REG_RESET, "reg_reset"}, {NODE_EXT, "ext"}, {NODE_EXT_IN, "ext_in"}, 70 | {NODE_EXT_OUT, "ext_out"} 71 | }; 72 | 73 | static std::map NodeStatus2Name = { 74 | {VALID_NODE, "valid"}, {DEAD_NODE, "dead"}, {CONSTANT_NODE, "constant"}, {MERGED_NODE, "merged"}, 75 | {REPLICATION_NODE, "replication"}, {SPLITTED_NODE, "splitted"} 76 | }; 77 | 78 | void ExpTree::display(int depth) { 79 | if (getlval()) getlval()->display(depth); 80 | if (getRoot()) getRoot()->display(depth); 81 | } 82 | 83 | void StmtTree::display() { 84 | if (!root) return; 85 | std::stack> s; 86 | s.push(std::make_pair(root, 1)); 87 | while (!s.empty()) { 88 | StmtNode* top; 89 | int depth; 90 | std::tie(top, depth) = s.top(); 91 | s.pop(); 92 | if (!top) { 93 | printf("%s(EMPTY)\n",std::string(depth * 2, ' ').c_str()); 94 | continue; 95 | } 96 | printf("%s(%d %s) childNum %ld\n", std::string(depth * 2, ' ').c_str(), top->type, 97 | OP2Name[top->type], top->child.size() 98 | ); 99 | if (top->type == OP_STMT_NODE) { 100 | if (top->isENode) top->enode->display(depth + 1); 101 | else top->tree->display(depth + 1); 102 | } 103 | for (int i = top->child.size() - 1; i >= 0; i --) { 104 | StmtNode* child = top->child[i]; 105 | s.push(std::make_pair(child, depth + 1)); 106 | } 107 | } 108 | } 109 | 110 | /* traverse graph */ 111 | void graph::traversal() { 112 | for (SuperNode* super : sortedSuper) { 113 | super->display(); 114 | } 115 | } 116 | 117 | void SuperNode::display() { 118 | printf("----super %d(type=%d)----:\n", id, superType); 119 | for (Node* node : member) { 120 | node->display(); 121 | } 122 | printf("[stmtTree]\n"); 123 | if (stmtTree) stmtTree->display(); 124 | } 125 | 126 | 127 | void Node::display() { 128 | printf("node %s[width %d sign %d status=%s type=%s lineno=%d][", name.c_str(), width, sign, NodeStatus2Name[status], NodeType2Name[type], lineno); 129 | for (int dim : dimension) printf(" %d", dim); 130 | printf(" ]\n"); 131 | for (size_t i = 0; i < assignTree.size(); i ++) { 132 | printf("[assign] %ld\n", i); 133 | assignTree[i]->display(); 134 | } 135 | if (resetTree) { 136 | printf("[resetTree]:\n"); 137 | resetTree->display(); 138 | } 139 | #if 0 140 | for (Node* nextNode : next) { 141 | printf(" next %p %s\n", nextNode, nextNode->name.c_str()); 142 | } 143 | for (Node* prevNode : prev) { 144 | printf(" prev %p %s\n", prevNode, prevNode->name.c_str()); 145 | } 146 | #endif 147 | } 148 | 149 | void ENode::display(int depth) { 150 | std::stack> enodes; 151 | enodes.push(std::make_pair(this, depth)); 152 | while (!enodes.empty()) { 153 | ENode* top; 154 | int depth; 155 | std::tie(top, depth) = enodes.top(); 156 | enodes.pop(); 157 | if (!top) { 158 | printf("%s(EMPTY)\n",std::string(depth * 2, ' ').c_str()); 159 | continue; 160 | } 161 | printf("%s(%d %s %p) %s %s [width=%d, sign=%d, type=%s, lineno=%d]", std::string(depth * 2, ' ').c_str(), top->opType, 162 | OP2Name[top->opType], top, (top->nodePtr) ? top->nodePtr->name.c_str() : (top->opType == OP_READ_MEM || top->opType == OP_WRITE_MEM ? top->memoryNode->name.c_str() : ""), 163 | top->strVal.c_str(), top->width, 164 | top->sign, (top->nodePtr) ? NodeType2Name[top->nodePtr->type] : NodeType2Name[NODE_INVALID], top->nodePtr ? top->nodePtr->lineno : -1); 165 | for (int val : top->values) printf(" %d", val); 166 | printf("\n"); 167 | for (int i = top->child.size() - 1; i >= 0; i --) { 168 | ENode* childENode = top->child[i]; 169 | enodes.push(std::make_pair(childENode, depth + 1)); 170 | } 171 | } 172 | } 173 | 174 | void graph::traversalNoTree() { 175 | int nodeIdx = 0; 176 | for (size_t idx = 0; idx < sortedSuper.size(); idx ++) { 177 | SuperNode* super = sortedSuper[idx]; 178 | printf("---%ld super id = %d---\n", idx, super->id); 179 | for (Node* node : super->member) { 180 | printf("%d: %s (super %d)\n", nodeIdx ++, node->name.c_str(), super->id); 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/usedBits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Compute the usedBits for every nodes and enodes 3 | can merged into inferWidth 4 | */ 5 | 6 | #include "common.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #define Child(id, name) getChild(id)->name 12 | 13 | /* all nodes that may affect their previous ndoes*/ 14 | static std::vector checkNodes; 15 | 16 | void ENode::passWidthToChild() { 17 | std::vectorchildBits; 18 | if (nodePtr) { 19 | Node* node = nodePtr; 20 | if (node->isArray() && node->arraySplitted()) { 21 | auto range = this->getIdx(nodePtr); 22 | if (range.first < 0) { 23 | range.first = 0; 24 | range.second = node->arrayMember.size() - 1; 25 | } 26 | for (int i = range.first; i <= range.second; i ++) { 27 | Node* member = node->getArrayMember(i); 28 | if (usedBit > member->usedBit) { 29 | member->update_usedBit(usedBit); 30 | if (member->type == NODE_REG_SRC) { 31 | if (member->usedBit != member->getDst()->usedBit) { 32 | checkNodes.push_back(member->getDst()); 33 | member->getDst()->usedBit = member->usedBit; 34 | } 35 | } 36 | checkNodes.push_back(member); 37 | } 38 | } 39 | } else { 40 | if (usedBit > node->usedBit) checkNodes.push_back(node); 41 | } 42 | node->update_usedBit(usedBit); 43 | if (node->type == NODE_REG_SRC) { 44 | if (node->usedBit != node->getDst()->usedBit) { 45 | checkNodes.push_back(node->getDst()); 46 | node->getDst()->usedBit = node->usedBit; 47 | } 48 | } 49 | for (ENode* childENode : child) { 50 | if (!childENode) continue; 51 | childENode->usedBit = childENode->width; 52 | childENode->passWidthToChild(); 53 | } 54 | return; 55 | } 56 | if (child.size() == 0) return; 57 | switch (opType) { 58 | case OP_ADD: case OP_SUB: case OP_OR: case OP_XOR: case OP_AND: 59 | childBits.push_back(usedBit); 60 | childBits.push_back(usedBit); 61 | break; 62 | case OP_MUL: 63 | childBits.push_back(MIN(usedBit, Child(0, width))); 64 | childBits.push_back(MIN(usedBit, Child(1, width))); 65 | break; 66 | case OP_DIV: case OP_REM: case OP_DSHL: case OP_DSHR: 67 | case OP_LT: case OP_LEQ: case OP_GT: case OP_GEQ: case OP_EQ: case OP_NEQ: 68 | childBits.push_back(Child(0, width)); 69 | childBits.push_back(Child(1, width)); 70 | break; 71 | case OP_CAT: 72 | childBits.push_back(MAX(usedBit - Child(1, width), 0)); 73 | childBits.push_back(MIN(Child(1, width), usedBit)); 74 | break; 75 | case OP_CVT: 76 | childBits.push_back(usedBit); 77 | break; 78 | case OP_ASCLOCK: case OP_ASASYNCRESET: case OP_ANDR: 79 | case OP_ORR: case OP_XORR: case OP_INDEX_INT: case OP_INDEX: 80 | childBits.push_back(Child(0, width)); 81 | break; 82 | case OP_ASUINT: case OP_ASSINT: case OP_NOT: case OP_NEG: case OP_PAD: case OP_TAIL: 83 | childBits.push_back(usedBit); 84 | break; 85 | case OP_SHL: 86 | childBits.push_back(MAX(0, usedBit - values[0])); 87 | break; 88 | case OP_SHR: 89 | childBits.push_back(usedBit + values[0]); 90 | break; 91 | case OP_HEAD: 92 | // childBits.push_back(Child(0, width) - (values[0] - usedBit)); 93 | childBits.push_back(usedBit + values[0]); 94 | break; 95 | case OP_BITS: 96 | childBits.push_back(MIN(usedBit + values[1], values[0] + 1)); 97 | break; 98 | case OP_BITS_NOSHIFT: 99 | childBits.push_back(usedBit); 100 | break; 101 | case OP_SEXT: 102 | childBits.push_back(usedBit); 103 | break; 104 | case OP_MUX: 105 | case OP_WHEN: 106 | childBits.push_back(1); 107 | childBits.push_back(usedBit); 108 | childBits.push_back(usedBit); 109 | break; 110 | case OP_STMT: 111 | for (size_t i = 0; i < getChildNum(); i ++) childBits.push_back(usedBit); 112 | break; 113 | case OP_READ_MEM: 114 | childBits.push_back(Child(0, width)); 115 | break; 116 | case OP_WRITE_MEM: 117 | childBits.push_back(Child(0, width)); 118 | childBits.push_back(memoryNode->width); 119 | break; 120 | case OP_RESET: 121 | childBits.push_back(1); 122 | childBits.push_back(usedBit); 123 | break; 124 | case OP_GROUP: 125 | case OP_EXIT: 126 | case OP_PRINTF: 127 | case OP_ASSERT: 128 | case OP_EXT_FUNC: 129 | for (size_t i = 0; i < getChildNum(); i ++) { 130 | childBits.push_back(getChild(i)->width); 131 | } 132 | break; 133 | default: 134 | printf("invalid op %d\n", opType); 135 | Panic(); 136 | } 137 | 138 | Assert(child.size() == childBits.size(), "child.size %ld childBits.size %ld in op %d", child.size(), childBits.size(), opType); 139 | for (size_t i = 0; i < child.size(); i ++) { 140 | if (!child[i]) continue; 141 | 142 | int realBits = MIN(child[i]->width, childBits[i]); 143 | 144 | if (child[i]->usedBit != realBits) { 145 | child[i]->usedBit = realBits; 146 | child[i]->passWidthToChild(); 147 | } 148 | } 149 | 150 | } 151 | 152 | /* the with of node->next may be updated, thus node should also re-compute */ 153 | void Node::passWidthToPrev() { 154 | if (resetTree) { 155 | resetTree->getRoot()->usedBit = usedBit; 156 | resetTree->getRoot()->passWidthToChild(); 157 | } 158 | if (assignTree.size() == 0) return; 159 | Assert(usedBit >= 0, "invalid usedBit %d in node %s", usedBit, name.c_str()); 160 | for (ExpTree* tree : assignTree) { 161 | if (usedBit != tree->getRoot()->usedBit) { 162 | tree->getRoot()->usedBit = usedBit; 163 | tree->getRoot()->passWidthToChild(); 164 | } 165 | if (tree->getlval() && tree->getlval()->usedBit != usedBit) { 166 | tree->getlval()->usedBit = usedBit; 167 | tree->getlval()->passWidthToChild(); 168 | } 169 | } 170 | return; 171 | } 172 | 173 | void graph::usedBits() { 174 | std::set visitedNodes; 175 | /* add all sink nodes in topological order */ 176 | for (Node* special : specialNodes) checkNodes.push_back(special); 177 | for (Node* reg : regsrc) checkNodes.push_back(reg->getDst()); 178 | for (Node* out : output) checkNodes.push_back(out); 179 | for (Node* mem : memory) { // all memory input 180 | for (Node* port : mem->member) { 181 | if (port->type == NODE_READER) checkNodes.push_back(port); 182 | } 183 | } 184 | 185 | for (Node* node: checkNodes) { 186 | node->usedBit = node->width; 187 | } 188 | 189 | while (!checkNodes.empty()) { 190 | Node* top = checkNodes.back(); 191 | visitedNodes.insert(top); 192 | checkNodes.pop_back(); 193 | top->passWidthToPrev(); 194 | if (checkNodes.empty()) { 195 | for (Node* mem : memory) { 196 | int usedBit = 0; 197 | for (Node* port : mem->member) { 198 | if (port->type == NODE_READER || port->type == NODE_READWRITER) { 199 | usedBit = MAX(port->usedBit, usedBit); 200 | } 201 | } 202 | if (mem->usedBit != usedBit) { 203 | mem->usedBit = usedBit; 204 | for (Node* port : mem->member) { 205 | if (port->type == NODE_WRITER) { 206 | port->usedBit = usedBit; 207 | checkNodes.push_back(port); 208 | } 209 | } 210 | } 211 | } 212 | } 213 | } 214 | 215 | /* NOTE: reset cond & reset val tree*/ 216 | 217 | for (Node* node : visitedNodes) { 218 | node->width = node->usedBit; 219 | for (ExpTree* tree : node->assignTree) tree->getRoot()->updateWidth(); 220 | if (node->resetTree) node->resetTree->getRoot()->updateWidth(); 221 | } 222 | 223 | for (Node* node : splittedArray) { 224 | int width = 0; 225 | for (Node* member : node->arrayMember) width = MAX(width, member->width); 226 | node->width = width; 227 | } 228 | 229 | for (Node* mem : memory) mem->width = mem->usedBit; 230 | for (SuperNode* super : sortedSuper) { 231 | for (Node* node : super->member) node->updateTreeWithNewWIdth(); 232 | } 233 | } 234 | 235 | void Node::updateTreeWithNewWIdth() { 236 | /* add ops to match tree width */ 237 | for (ExpTree* tree : assignTree) tree->updateWithNewWidth(); 238 | if (resetTree) resetTree->updateWithNewWidth(); 239 | 240 | for (ExpTree* tree : assignTree) { 241 | tree->when2mux(width); 242 | tree->matchWidth(width); 243 | } 244 | if (resetTree) resetTree->matchWidth(width); 245 | } 246 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util.cpp 3 | * @brief utils 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "common.h" 10 | #include 11 | #include "util.h" 12 | 13 | /* convert firrtl constant to C++ constant 14 | In the new FIRRTL spec, there are 'int' and 'rint'.*/ 15 | std::pair firStrBase(std::string s) { 16 | if (s.length() <= 1) { return std::make_pair(10, s); } 17 | std::string ret; 18 | 19 | int idx = 0; 20 | int base = -1; 21 | 22 | // Check if the constant is negative. 23 | if (s[0] == '-') { 24 | ret += '-'; 25 | idx = 1; 26 | } 27 | if (s[idx] != '0') return std::make_pair(10, s); 28 | 29 | idx ++; 30 | 31 | // If there is no "0b", "0o", "0d", or "0h" prefix, treat it as a base-10 integer. 32 | if ((s[idx] != 'b') && (s[idx] != 'o') && (s[idx] != 'd') && (s[idx] != 'h')) { 33 | ret += s.substr(idx - 1); 34 | return std::make_pair(10, ret); 35 | } 36 | 37 | // Determine the base from the prefix. 38 | switch (s[idx]) { 39 | case 'b': base = 2; break; 40 | case 'o': base = 8; break; 41 | case 'h': base = 16; break; 42 | default: base = 10; break; 43 | } 44 | 45 | idx ++; 46 | ret += s.substr(idx); 47 | 48 | return std::make_pair(base, ret); 49 | } 50 | 51 | std::string to_hex_string(BASIC_TYPE x) { 52 | if (x == 0) { return "0"; } 53 | 54 | std::string ret; 55 | 56 | while (x != 0) { 57 | int rem = x % 16; 58 | ret = (char)(rem < 10 ? (rem + '0') : (rem - 10 + 'a')) + ret; 59 | x /= 16; 60 | } 61 | 62 | return ret; 63 | } 64 | 65 | static std::map expr2Map = { 66 | {"add", OP_ADD}, {"sub", OP_SUB}, {"mul", OP_MUL}, {"div", OP_DIV}, 67 | {"rem", OP_REM}, {"lt", OP_LT}, {"leq", OP_LEQ}, {"gt", OP_GT}, 68 | {"geq", OP_GEQ}, {"eq", OP_EQ}, {"neq", OP_NEQ}, {"dshl", OP_DSHL}, 69 | {"dshr", OP_DSHR}, {"and", OP_AND}, {"or", OP_OR}, {"xor", OP_XOR}, 70 | {"cat", OP_CAT}, 71 | }; 72 | 73 | OPType str2op_expr2(std::string name) { 74 | Assert(expr2Map.find(name) != expr2Map.end(), "invalid 2expr op %s\n", name.c_str()); 75 | return expr2Map[name]; 76 | } 77 | 78 | static std::map expr1Map = { 79 | {"asUInt", OP_ASUINT}, {"asSInt", OP_ASSINT}, {"asClock", OP_ASCLOCK}, {"asAsyncReset", OP_ASASYNCRESET}, 80 | {"cvt", OP_CVT}, {"neg", OP_NEG}, {"not", OP_NOT}, {"andr", OP_ANDR}, 81 | {"orr", OP_ORR}, {"xorr", OP_XORR}, 82 | }; 83 | 84 | OPType str2op_expr1(std::string name) { 85 | Assert(expr1Map.find(name) != expr1Map.end(), "invalid 1expr op %s\n", name.c_str()); 86 | return expr1Map[name]; 87 | } 88 | 89 | static std::map expr1int1Map = { 90 | {"pad", OP_PAD}, {"shl", OP_SHL}, {"shr", OP_SHR}, {"head", OP_HEAD}, {"tail", OP_TAIL}, 91 | }; 92 | 93 | OPType str2op_expr1int1(std::string name) { 94 | Assert(expr1int1Map.find(name) != expr1int1Map.end(), "invalid 1expr op %s\n", name.c_str()); 95 | return expr1int1Map[name]; 96 | } 97 | 98 | int upperPower2(int x) { 99 | return x <= 1 ? x : (1 << (32 - __builtin_clz(x - 1))); 100 | } 101 | 102 | int upperLog2(int x) { 103 | if (x <= 1) return x; 104 | return (32 - __builtin_clz(x - 1)); 105 | } 106 | 107 | static char buf[0x4000000]; 108 | 109 | std::string format(const char *fmt, ...) { 110 | va_list args; 111 | va_start(args, fmt); 112 | std::vsnprintf(buf, sizeof(buf), fmt, args); 113 | va_end(args); 114 | std::string ret = buf; 115 | Assert(ret.length() < sizeof(buf) - 1, "require larger buf"); 116 | return ret; 117 | } 118 | 119 | std::string bitMask(int width) { 120 | Assert(width > 0, "invalid width %d", width); 121 | if (width <= 64) { 122 | std::string ret = std::string(width/4, 'f'); 123 | const char* headTable[] = {"", "1", "3", "7"}; 124 | ret = headTable[width % 4] + ret; 125 | return "0x" + ret; 126 | } else { 127 | std::string type = widthUType(width); 128 | if (width % 64 == 0) { // in such case, (type)1 << width is undefined 129 | return format("((%s)0 - 1)", type.c_str()); 130 | } else { 131 | return format("(((%s)1 << %d) - 1)", type.c_str(), width); 132 | } 133 | } 134 | } 135 | 136 | std::string shiftBits(unsigned int bits, ShiftDir dir){ 137 | if(bits == 0) 138 | return ""; 139 | return (dir == ShiftDir::Left? " << " : " >> ") + std::to_string(bits); 140 | } 141 | std::string shiftBits(std:: string bits, ShiftDir dir){ 142 | if(bits == std::to_string(0) || bits == "0x0") 143 | return ""; 144 | return (dir == ShiftDir::Left? " << " : " >> ") + bits; 145 | } 146 | 147 | void print_stacktrace() { 148 | int size = 16; 149 | void * array[16]; 150 | int stack_num = backtrace(array, size); 151 | char ** stacktrace = backtrace_symbols(array, stack_num); 152 | for (int i = 0; i < stack_num; ++i) { 153 | fprintf(stderr, "%s\n", stacktrace[i]); 154 | } 155 | free(stacktrace); 156 | } 157 | --------------------------------------------------------------------------------