├── .gitignore
├── README.md
├── assets
└── structure.svg
└── src
├── Compiler.java
├── arg
└── Arg.java
├── backend
├── CodeGen.java
├── FPRegAllocator.java
├── GPRegAllocator.java
├── MergeBlock.java
├── NaiveRegAllocator.java
├── Parallel.java
├── PeepHole.java
└── RegAllocator.java
├── descriptor
├── Descriptor.java
└── MIDescriptor.java
├── exception
├── SemanticException.java
└── SyntaxException.java
├── frontend
├── Visitor.java
├── lexer
│ ├── Lexer.java
│ ├── Token.java
│ ├── TokenList.java
│ └── TokenType.java
├── semantic
│ ├── Evaluate.java
│ ├── Initial.java
│ └── symbol
│ │ ├── SymTable.java
│ │ └── Symbol.java
└── syntax
│ ├── Ast.java
│ └── Parser.java
├── lir
├── Arm.java
├── BJ.java
├── I.java
├── MC.java
├── MICall.java
├── MIComment.java
├── MachineInst.java
├── StackCtl.java
└── V.java
├── manage
└── Manager.java
├── midend
├── AggressiveFuncGCM.java
├── AggressiveFuncGVN.java
├── AggressiveMarkParallel.java
├── ArrayGVNGCM.java
├── ArrayLift.java
├── ArraySSA.java
├── BranchLift.java
├── BranchOptimize.java
├── CloneInfoMap.java
├── ConstFold.java
├── ConstTransFold.java
├── DeadCodeDelete.java
├── FuncInfo.java
├── FuncInline.java
├── GVNAndGCM.java
├── GepFuse.java
├── GepSplit.java
├── GlobalArrayGVN.java
├── GlobalValueLocalize.java
├── IfComb.java
├── InstrComb.java
├── LCSSA.java
├── LocalArrayGVN.java
├── LoopFold.java
├── LoopFuse.java
├── LoopIdcVarInfo.java
├── LoopInVarCodeLift.java
├── LoopInfo.java
├── LoopNest.java
├── LoopStrengthReduction.java
├── LoopUnRoll.java
├── MakeDFG.java
├── MarkParallel.java
├── MarkParallelForNormalLoop.java
├── MathOptimize.java
├── Mem2Reg.java
├── MemSetOptimize.java
├── MergeBB.java
├── MergeSimpleBB.java
├── MidEndRunner.java
├── MidPeepHole.java
├── OutParam.java
├── Rem2DivMulSub.java
├── RemovePhi.java
├── RemoveUselessStore.java
├── SimpleCalc.java
└── TestMain.java
├── mir
├── BasicBlock.java
├── Constant.java
├── Function.java
├── GlobalVal.java
├── Instr.java
├── Loop.java
├── Use.java
├── Value.java
└── type
│ ├── DataType.java
│ └── Type.java
└── util
├── CenterControl.java
├── FileDealer.java
├── ILinkNode.java
└── Ilist.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | out
3 | target
4 | *.iml
5 | *.MF
6 | *.c
7 | *.cpp
8 | *.h
9 | *.hpp
10 | *.sy
11 | *.ll
12 | *.txt
13 | *.s
14 | *.S
15 | *.elf
16 | *.in
17 | *.out
18 | *.err
19 | *.sh
20 | *.py
21 | *.ipynb
22 | /src/test
23 | /src/timeTest
24 | *.zip
25 | *.tar.*
26 | *.rar
27 | *.7z
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Meow-Compiler
2 |
3 | 2022 [全国大学生计算机系统能力大赛编译系统设计赛(华为毕昇杯)](https://compiler.educg.net) 参赛作品。
4 |
5 | ## Build
6 |
7 | Requirements: Java (JDK >= 15)
8 |
9 | ```bash
10 | mkdir target
11 | javac -d target -encoding 'utf-8' \
12 | $(find src -type f -name '*.java')
13 | cd target; mkdir -p META-INF; echo -e 'Manifest-Version: 1.0\r\nMain-Class: Compiler\r\n\r\n' > META-INF/MANIFEST.MF
14 | jar cfm compiler.jar META-INF/MANIFEST.MF *
15 | ```
16 |
17 | Artifact will be stored at target/compiler.jar .
18 |
19 | ## Usage
20 |
21 | ```
22 | java -jar compiler.jar {(-S|-emit-llvm) -o filename} filename [-On]
23 |
24 | Options:
25 | -S -o filename: generate armv7-a assembly to file.
26 | -emit-llvm -o filename: generate LLVM IR (.ll) to file.
27 | filename: source code file.
28 | -On: optimize level, possible value: -O0, -O1, -O2
29 | ```
30 |
31 | Examples:
32 |
33 | - (Contest Official Functional Test) Generate assembly test.S from source test.sy without optimization
34 | ```bash
35 | java -jar compiler.jar -S test.S test.sy
36 | ```
37 | - (Contest Official Performance Test) Generate assembly test.S from source test.sy with optimization
38 | ```bash
39 | java -jar compiler.jar -S test.S test.sy -O2
40 | ```
41 | - Generate LLVM IR test.ll from source test.sy with optimization
42 | ```bash
43 | java -jar compiler.jar -emit-llvm -o test.ll test.sy -O2
44 | ```
45 | - Generate both LLVM IR and assembly, without optimization and enable assertion
46 | ```bash
47 | java -ea -jar compiler.jar -emit-llvm -o test.ll -S -o test.S test.sy
48 | ```
49 |
50 | ## Run target code
51 |
52 | Before running target code, [SysY Runtime Library](https://gitlab.eduxiji.net/nscscc/compiler2022/-/blob/master/SysY2022%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BA%93-V1.pdf) is required first.
53 |
54 | - If target code (arm assembly) runs on raspberry pi, you should compile the runtime library on pi first;
55 | - If target code (llvm ir or arm assembly) runs on PC, you can use our [Docker Image](https://github.com/Meow-Twice/sysy-docker) as the environment.
56 |
57 | [Testcases](https://gitlab.eduxiji.net/nscscc/compiler2022/-/tree/master/%E5%85%AC%E5%BC%80%E6%A0%B7%E4%BE%8B%E4%B8%8E%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BA%93) can be accessed from educg gitlab.
58 |
59 | ## Structure
60 |
61 | 
62 |
63 | ## Optimization and Passes
64 |
65 | Mid-end optimization passed is managed at midend/MidEndRunner.java, and global control is managed at util/CenterControl.java .
--------------------------------------------------------------------------------
/src/Compiler.java:
--------------------------------------------------------------------------------
1 | import arg.Arg;
2 | import backend.*;
3 | import frontend.Visitor;
4 | import frontend.lexer.Lexer;
5 | import frontend.lexer.Token;
6 | import frontend.lexer.TokenList;
7 | import frontend.syntax.Ast;
8 | import frontend.syntax.Parser;
9 | import lir.MC;
10 | import manage.Manager;
11 | import midend.MergeBB;
12 | import midend.MidEndRunner;
13 | import midend.RemovePhi;
14 | import util.CenterControl;
15 | import util.FileDealer;
16 |
17 | import java.io.*;
18 |
19 | import static midend.MidEndRunner.O2;
20 | import static util.CenterControl._ONLY_FRONTEND;
21 |
22 | public class Compiler {
23 |
24 | public static boolean OUTPUT_LEX = false;
25 | // public static boolean ONLY_FRONTEND = false;
26 |
27 | private static String input(InputStream in) throws IOException {
28 | BufferedReader reader = new BufferedReader(new InputStreamReader(in));
29 | StringBuilder builder = new StringBuilder();
30 | String line;
31 | while ((line = reader.readLine()) != null) {
32 | builder.append(line).append("\n");
33 | }
34 | reader.close();
35 | return builder.toString();
36 | }
37 |
38 | public static void main(String[] args) {
39 | Arg arg = Arg.parse(args);
40 | CenterControl._HEURISTIC_BASE = arg.heuristicBase;
41 | try {
42 | BufferedInputStream source = new BufferedInputStream(arg.srcStream);
43 | // System.err.println(source); // output source code via stderr;
44 | TokenList tokenList = new TokenList();
45 | Lexer.getInstance().lex(source, tokenList);
46 | // OUTPUT_LEX = true;
47 | if (OUTPUT_LEX) {
48 | while (tokenList.hasNext()) {
49 | Token token = tokenList.consume();
50 | System.err.println(token.getType() + " " + token.getContent());
51 | }
52 | }
53 | System.err.println("AST out");
54 | Ast ast = new Parser(tokenList).parseAst();
55 | Visitor visitor = Visitor.VISITOR;
56 | // visitor.__ONLY_PARSE_OUTSIDE_DIM = false;
57 | visitor.visitAst(ast);
58 | System.err.println("visit end");
59 | // Manager manager = visitor.getIr();
60 | // GlobalValueLocalize globalValueLocalize = new GlobalValueLocalize(funcManager.globals);
61 | // globalValueLocalize.Run();
62 | Manager.MANAGER.outputLLVM();
63 |
64 | _ONLY_FRONTEND = !arg.outputAsm();
65 |
66 |
67 | O2 = arg.optLevel == 2;
68 | MidEndRunner.O0 = arg.optLevel == 0;
69 | System.err.println("opt level = " + arg.optLevel);
70 | System.err.println("mid optimization begin");
71 | long start = System.currentTimeMillis();
72 | MidEndRunner midEndRunner = new MidEndRunner(Manager.MANAGER.getFunctionList());
73 | midEndRunner.Run();
74 | System.err.println("mid optimization end, Use Time: " + ((double) System.currentTimeMillis() - start) / 1000 + "s");
75 |
76 | // DeadCodeDelete deadCodeDelete = new DeadCodeDelete(Manager.MANAGER.getFunctionList());
77 | // deadCodeDelete.Run();
78 | if (arg.outputLLVM()) {
79 | Manager.MANAGER.outputLLVM(arg.llvmStream);
80 | }
81 | if (_ONLY_FRONTEND) {
82 | return;
83 | }
84 |
85 | RemovePhi removePhi = new RemovePhi(midEndRunner.functions);
86 | removePhi.Run();
87 |
88 | Manager.MANAGER.outputLLVM();
89 |
90 | MergeBB mergeBB = new MergeBB(midEndRunner.functions);
91 | mergeBB.Run();
92 |
93 | CenterControl.AlreadyBackend = true;
94 | System.err.println("code gen begin");
95 | start = System.currentTimeMillis();
96 | //Manager.MANAGER.outputLLVM();
97 | CodeGen.CODEGEN.gen();
98 | System.err.println("code gen end, Use Time: " + ((double) System.currentTimeMillis() - start) / 1000 + "s");
99 | MC.Program p = MC.Program.PROGRAM;
100 | // 为 MI Descriptor 设置输入输出流
101 | // MIDescriptor.MI_DESCRIPTOR.setInput(arg.interpretInputStream);
102 | // MIDescriptor.MI_DESCRIPTOR.setOutput(arg.interpretOutputStream);
103 | // 用参数给定的输入输出流后,分配寄存器前和分配寄存器后只运行一遍解释器,否则后者的输出会覆盖前者
104 | // MIDescriptor.MI_DESCRIPTOR.run(); // 分配寄存器前
105 | // System.err.println("before");
106 | // Manager.MANAGER.outputMI();
107 | // System.err.println("before end");
108 | // Manager.outputMI(true);
109 | System.err.println("Reg Alloc begin");
110 | start = System.currentTimeMillis();
111 | if (CenterControl._FAST_REG_ALLOCATE) {
112 | NaiveRegAllocator regAllocator = new NaiveRegAllocator();
113 | regAllocator.AllocateRegister(p);
114 | } else {
115 | if (CodeGen.needFPU) {
116 | FPRegAllocator fpRegAllocator = new FPRegAllocator();
117 | fpRegAllocator.AllocateRegister(p);
118 | }
119 | // System.err.println("middle");
120 | // Manager.MANAGER.outputMI();
121 | // System.err.println("middle end");
122 | GPRegAllocator GPRegAllocator = new GPRegAllocator();
123 | GPRegAllocator.AllocateRegister(p);
124 | }
125 | System.err.println("Reg Alloc end, Use Time: " + ((double) System.currentTimeMillis() - start) / 1000 + "s");
126 | // Manager.outputMI(true);
127 | // System.err.println("after");
128 | // Manager.MANAGER.outputMI();
129 | // System.err.println("after end");
130 | // System.err.println("BEGIN rerun");
131 | // MIDescriptor.MI_DESCRIPTOR.setRegMode();
132 | // MIDescriptor.MI_DESCRIPTOR.run(); // 分配寄存器后
133 | // File output_file = new File("output.S");
134 | // PrintStream os = new PrintStream(output_file);
135 | // p.output(os);
136 |
137 | // System.err.println(p.getSTB());
138 | //
139 | if (CenterControl._GLOBAL_BSS)
140 | MC.Program.PROGRAM.bssInit();
141 |
142 | if (O2) {
143 | CenterControl._TAG = "O2_2";
144 | if (CenterControl._FUNC_PARALLEL) {
145 | CenterControl._TAG = "O2_func";
146 | }
147 | PeepHole peepHole = new PeepHole(p);
148 | peepHole.run();
149 | // Manager.MANAGER.outputMI();
150 | MergeBlock mergeBlock = new MergeBlock();
151 | int i = 0;
152 | while (i++ < 2) {
153 | mergeBlock.run(true);
154 | }
155 | // Manager.MANAGER.outputMI();
156 | if (CenterControl._OPEN_PARALLEL_BACKEND) {
157 | Parallel.PARALLEL.gen();
158 | }
159 | } else {
160 | PeepHole peepHole = new PeepHole(p);
161 | peepHole.runOneStage();
162 | }
163 | if (arg.outputAsm()) {
164 | FileDealer.outputToStream(p.getSTB(), arg.asmStream);
165 | // p.output(new PrintStream(arg.asmStream));
166 | }
167 | } catch (Exception e) {
168 | e.printStackTrace();
169 | System.exit(e.getClass().getSimpleName().length());
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/arg/Arg.java:
--------------------------------------------------------------------------------
1 | package arg;
2 |
3 | import java.io.*;
4 |
5 | public class Arg {
6 | public final String srcFilename; // 源代码文件名 e.g. "testcase.sy"
7 | public final int optLevel; // 优化等级,缺省值为 1
8 |
9 | public final String asmFilename; // 目标汇编代码文件名 e.g. "testcase.s"
10 | public final String llvmFilename; // LLVM IR 文件名 e.g. "testcase.ll"
11 |
12 | public final FileInputStream srcStream; // 源代码输入流
13 | public final OutputStream asmStream; // 汇编代码输出流
14 | public final OutputStream llvmStream; // LLVM IR 中间代码输出流
15 |
16 | public final boolean interpretMI; // 是否解释执行
17 | public final InputStream interpretInputStream; // 解释执行 stdin
18 | public final OutputStream interpretOutputStream; // 解释执行 stdout
19 |
20 | // options
21 | public double heuristicBase = 1.45;
22 |
23 | private Arg(String src, String asm, String llvm,
24 | boolean interpret, String interpretIn, String interpretOut, int optimize) throws FileNotFoundException {
25 | this.srcFilename = src;
26 | this.asmFilename = asm;
27 | this.llvmFilename = llvm;
28 |
29 | this.srcStream = new FileInputStream(srcFilename);
30 | this.asmStream = asm.isEmpty() ? null : new FileOutputStream(asmFilename);
31 | this.llvmStream = llvm.isEmpty() ? null : new FileOutputStream(llvmFilename);
32 |
33 | this.interpretMI = interpret;
34 | this.interpretInputStream = interpretIn.isEmpty() ? System.in : new FileInputStream(interpretIn);
35 | this.interpretOutputStream = interpretOut.isEmpty() ? System.out : new FileOutputStream(interpretOut);
36 |
37 | this.optLevel = optimize;
38 | }
39 |
40 | public boolean outputAsm() {
41 | return !asmFilename.isEmpty();
42 | }
43 |
44 | public boolean outputLLVM() { return !llvmFilename.isEmpty(); }
45 |
46 | public static Arg parse(String[] args) {
47 | String src = "", asm = "", llvm = "";
48 | int optLevel = 1;
49 | boolean interpret = false;
50 | String interpretIn = "", interpretOut = "";
51 | // options
52 | double heuristicBase = 1.45;
53 | for (int i = 0; i < args.length; i++) {
54 | // detect "-Ox"
55 | if (args[i].startsWith("-O")) {
56 | if (optLevel != 1) {
57 | throw new RuntimeException("Optimize level should only have one.");
58 | }
59 | optLevel = Integer.parseInt(args[i].substring(2));
60 | if (optLevel < 0 || optLevel > 2) {
61 | throw new RuntimeException("Optimize level should only be 0, 1, 2");
62 | }
63 | continue;
64 | }
65 | // detect optimize options
66 | if (args[i].startsWith("--heuristic-base=")) {
67 | heuristicBase = Double.parseDouble(args[i].substring(17));
68 | if (heuristicBase < 1 || heuristicBase > 2) {
69 | throw new RuntimeException("heuristic base should in range [1, 2]");
70 | }
71 | continue;
72 | }
73 | // detect "-S"
74 | if ("-S".equals(args[i])) {
75 | if (i + 2 < args.length && "-o".equals(args[i + 1])) {
76 | if (!asm.isEmpty()) {
77 | throw new RuntimeException("We got more than one assemble file when we expected only one.");
78 | }
79 | asm = args[i + 2];
80 | i += 2;
81 | continue;
82 | } else {
83 | throw new RuntimeException("-S expected -o filename");
84 | }
85 | }
86 | // detect "-emit-llvm"
87 | if ("-emit-llvm".equals(args[i])) {
88 | if (i + 2 < args.length && "-o".equals(args[i + 1])) {
89 | if (!llvm.isEmpty()) {
90 | throw new RuntimeException("We got more than one llvm-ir file when we expected only one.");
91 | }
92 | llvm = args[i + 2];
93 | i += 2;
94 | continue;
95 | } else {
96 | throw new RuntimeException("-emit-llvm expected -o filename");
97 | }
98 | }
99 | // detect "-i"
100 | if ("-I".equals(args[i])) {
101 | if (interpret) {
102 | throw new RuntimeException("We got more than one interpret option.");
103 | }
104 | interpret = true;
105 | while (i + 1 < args.length && ("-i".equals(args[i + 1]) || "-o".equals(args[i + 1]))) {
106 | if (i + 2 < args.length && "-i".equals(args[i + 1])) {
107 | if (!interpretIn.isEmpty()) {
108 | throw new RuntimeException("We got more than one interpreter input.");
109 | }
110 | interpretIn = args[i + 2];
111 | i += 2;
112 | }
113 | if (i + 2 < args.length && "-o".equals(args[i + 1])) {
114 | if (!interpretOut.isEmpty()) {
115 | throw new RuntimeException("We got more than one interpreter output.");
116 | }
117 | interpretOut = args[i + 2];
118 | i += 2;
119 | }
120 | }
121 | continue;
122 | }
123 | // detect illegal flags
124 | if (args[i].startsWith("-")) {
125 | throw new RuntimeException("invalid flag: " + args[i]);
126 | }
127 | // source file
128 | if (!src.isEmpty()) {
129 | throw new RuntimeException("We got more than one source file when we expected only one.");
130 | }
131 | src = args[i];
132 | }
133 | if (src.isEmpty()) {
134 | printHelp();
135 | throw new RuntimeException("source file should be specified.");
136 | }
137 | try {
138 | Arg arg = new Arg(src, asm, llvm, interpret, interpretIn, interpretOut, optLevel);
139 | arg.heuristicBase = heuristicBase;
140 | return arg;
141 | } catch (FileNotFoundException e) {
142 | printHelp();
143 | throw new RuntimeException(e);
144 | }
145 | }
146 |
147 | public static void printHelp() {
148 | System.err.println("Usage: compiler {(-S|-emit-llvm) -o filename} filename -On [options...]");
149 | System.err.println("optimize level: 0, 1 (default), 2");
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/backend/NaiveRegAllocator.java:
--------------------------------------------------------------------------------
1 | package backend;
2 |
3 | import lir.*;
4 | import mir.type.DataType;
5 |
6 | import java.util.ArrayList;
7 |
8 | import static mir.type.DataType.F32;
9 | import static mir.type.DataType.I32;
10 |
11 | public class NaiveRegAllocator extends RegAllocator {
12 | public NaiveRegAllocator() {
13 | initPool();
14 | }
15 |
16 | final int rRegNum = 8;
17 | final int sRegNum = 8;
18 |
19 | void initPool() {
20 | rRegPool[0] = Arm.Reg.getR(4);
21 | rRegPool[1] = Arm.Reg.getR(5);
22 | rRegPool[2] = Arm.Reg.getR(6);
23 | rRegPool[3] = Arm.Reg.getR(7);
24 | rRegPool[4] = Arm.Reg.getR(8);
25 | rRegPool[5] = Arm.Reg.getR(9);
26 | rRegPool[6] = Arm.Reg.getR(10);
27 | rRegPool[7] = Arm.Reg.getR(11);
28 | for (int i = 24; i < 32; i++) {
29 | sRegPool[i - 24] = Arm.Reg.getS(i);
30 | }
31 | }
32 |
33 | Arm.Reg[] rRegPool = new Arm.Reg[rRegNum];
34 | Arm.Reg[] sRegPool = new Arm.Reg[sRegNum];
35 | int rStackTop = rRegNum;
36 | int sStackTop = sRegNum;
37 |
38 | Arm.Reg rRegPop() {
39 | if (rStackTop <= 0) {
40 | throw new AssertionError("");
41 | }
42 | return rRegPool[--rStackTop];
43 | }
44 |
45 | Arm.Reg sRegPop() {
46 | return sRegPool[--sStackTop];
47 | }
48 |
49 | void reset() {
50 | rStackTop = rRegNum;
51 | sStackTop = sRegNum;
52 | }
53 |
54 | public void AllocateRegister(MC.Program program) {
55 |
56 | for (MC.McFunction mf : program.funcList) {
57 | mf.setAllocStack();
58 | mf.addVarStack(4 * mf.getVRSize());
59 | // if (needFPU)
60 | mf.addVarStack(4 * mf.getSVRSize());
61 | for (MC.Block mb : mf.mbList) {
62 | for (MachineInst mi : mb.miList) {
63 | if (mi.isCall()) {
64 | // TODO 可以放到CodeGen里
65 | mf.setUseLr();
66 | }
67 | }
68 | }
69 | mf.alignTotalStackSize();
70 | }
71 |
72 | fixStack(program.needFixList);
73 | /*
74 | Machine.McFunction mf = mi.getMb().mcFunc;
75 | I.Mov mv = (I.Mov) mi;
76 | Machine.Operand off = mv.getSrc();
77 | assert off.is_I_Imm();
78 | int newOff = switch (mv.getFixType()) {
79 | case INT_TOTAL_STACK, FLOAT_TOTAL_STACK -> off.getValue() + mf.getTotalStackSize();
80 | case VAR_STACK -> mf.getVarStack();
81 | case ONLY_PARAM -> mv.getCallee().getParamStack();
82 | default -> throw new AssertionError("needFixType Wrong");
83 | };
84 | boolean flag = false;
85 | if (mv.hasNext()) {
86 | if ((mv.getNext() instanceof I.Binary)) {
87 | // TODO 可以启发式做一些优化
88 | if (((I.Binary) mv.getNext()).getLOpd().equals(rSP) && ((I.Binary) mv.getNext()).getDst().equals(rSP)) {
89 | flag = true;
90 | if (CodeGen.immCanCode(newOff)) {
91 | ((I.Binary) mv.getNext()).setROpd(new Machine.Operand(I32, newOff));
92 | mv.remove();
93 | } else {
94 | Arm.Reg reg = rRegPop();
95 | mv.setSrc(new Machine.Operand(I32, newOff));
96 | mv.setDst(reg);
97 | ((I.Binary) mv.getNext()).setROpd(reg);
98 | mv.clearNeedFix();
99 | reset();
100 | }
101 | }
102 | }
103 | }
104 | if (!flag) {
105 | mv.setSrc(new Machine.Operand(I32, newOff));
106 | mv.clearNeedFix();
107 | }*/
108 |
109 | for (MC.McFunction mf : program.funcList) {
110 | int iVrBase = mf.getAllocStack();
111 | int sVrBase = mf.getVRSize() * 4 + iVrBase;
112 | for (MC.Block mb : mf.mbList) {
113 | for (MachineInst mi : mb.miList) {
114 | ArrayList defs = mi.defOpds;
115 | ArrayList uses = mi.useOpds;
116 | if (mi.isComment() || mi.isCall()) continue;
117 | assert uses.size() < 4;
118 | int useIdx = 0;
119 | for (MC.Operand use : uses) {
120 | if (use.isVirtual(I32)) {
121 | int offset = iVrBase + 4 * use.getValue();
122 | if (Math.abs(offset) < 4096) {
123 | Arm.Reg useReg = rRegPop();
124 | new I.Ldr(useReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), new MC.Operand(DataType.I32, offset), mi);
125 | mi.setUse(useIdx, useReg);
126 | } else {
127 | Arm.Reg offReg = rRegPop();
128 | new I.Mov(offReg, new MC.Operand(DataType.I32, offset), mi);
129 | Arm.Reg useReg = rRegPop();
130 | new I.Ldr(useReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), offReg, mi);
131 | mi.setUse(useIdx, useReg);
132 | }
133 | } else if (use.isVirtual(F32)) {
134 | int offset = sVrBase + 4 * use.getValue();
135 | if (Math.abs(offset) <= 1020) {
136 | Arm.Reg useReg = sRegPop();
137 | new V.Ldr(useReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), new MC.Operand(DataType.I32, offset), mi);
138 | mi.setUse(useIdx, useReg);
139 | } else {
140 | Arm.Reg offReg = rRegPop();
141 | new I.Mov(offReg, new MC.Operand(DataType.I32, offset), mi);
142 | new I.Binary(MachineInst.Tag.Add, offReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), offReg, mi);
143 | Arm.Reg useReg = sRegPop();
144 | new V.Ldr(useReg, offReg, mi);
145 | mi.setUse(useIdx, useReg);
146 | }
147 | }
148 | useIdx++;
149 | }
150 | // reset();
151 | if (defs.size() > 0) {
152 | assert defs.size() == 1;
153 | MC.Operand def = defs.get(0);
154 | if (def.isVirtual(I32)) {
155 | int offset = iVrBase + 4 * def.getValue();
156 | if (Math.abs(offset) < 4096) {
157 | Arm.Reg useReg = rRegPop();
158 | new I.Str(mi, useReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), new MC.Operand(DataType.I32, offset));
159 | mi.setDef(useReg);
160 | } else {
161 | Arm.Reg offReg = rRegPop();
162 | I.Mov mv = new I.Mov(mi, offReg, new MC.Operand(DataType.I32, offset));
163 | Arm.Reg defReg = rRegPop();
164 | new I.Str(mv, defReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), offReg);
165 | mi.setDef(defReg);
166 | }
167 | } else if (def.isVirtual(F32)) {
168 | int offset = sVrBase + 4 * def.getValue();
169 | if (Math.abs(offset) <= 1020) {
170 | Arm.Reg defReg = sRegPop();
171 | new V.Str(mi, defReg, rSP, new MC.Operand(DataType.I32, offset));
172 | mi.setDef(defReg);
173 | } else {
174 | Arm.Reg offReg = rRegPop();
175 | I.Mov mv = new I.Mov(mi, offReg, new MC.Operand(DataType.I32, offset));
176 | I.Binary bino = new I.Binary(mv, MachineInst.Tag.Add, offReg, Arm.Reg.getR(Arm.Regs.GPRs.sp), offReg);
177 | Arm.Reg defReg = sRegPop();
178 | new V.Str(bino, defReg, offReg);
179 | mi.setDef(defReg);
180 | }
181 | }
182 | }
183 | reset();
184 | }
185 | }
186 | }
187 |
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/backend/Parallel.java:
--------------------------------------------------------------------------------
1 | package backend;
2 |
3 | import lir.*;
4 |
5 | import java.util.HashMap;
6 |
7 | import static lir.Arm.Reg.getRSReg;
8 | import static lir.Arm.Regs.GPRs.*;
9 | import static lir.BJ.*;
10 | import static lir.MC.Operand.I_ONE;
11 | import static lir.MC.Operand.I_ZERO;
12 | import static lir.MachineInst.Tag.Add;
13 | import static lir.MachineInst.Tag.Sub;
14 | import static mir.type.DataType.I32;
15 |
16 | public class Parallel {
17 | public static final Parallel PARALLEL = new Parallel(MC.Program.PROGRAM);
18 | MC.Program p;
19 | // TODO parallel的function都需要def r2
20 | MC.McFunction mf_parallel_start = new MC.McFunction("parallel_start");
21 | MC.McFunction mf_parallel_end = new MC.McFunction("parallel_end");
22 | private static MC.McFunction curMF;
23 | public final HashMap tmpGlob = new HashMap<>();
24 | private String start_r5 = "$start_r5";
25 | private String start_r7 = "$start_r7";
26 | private String start_lr = "$start_lr";
27 | private String end_r7 = "$end_r7";
28 | private String end_lr = "$end_lr";
29 |
30 | MC.Block mb_parallel_start;
31 | MC.Block mb_parallel_start1;
32 | MC.Block mb_parallel_start2;
33 | MC.Block mb_parallel_end;
34 | MC.Block mb_parallel_end1;
35 | MC.Block mb_parallel_end2;
36 | MC.Block mb_parallel_end3;
37 | MC.Block mb_parallel_end4;
38 | private Parallel(MC.Program p) {
39 | this.p = p;
40 | }
41 |
42 | public void gen() {
43 | p.funcList.insertAtEnd(mf_parallel_start);
44 | p.funcList.insertAtEnd(mf_parallel_end);
45 | Arm.Glob g = new Arm.Glob(start_r5);
46 | MC.Program.PROGRAM.globList.add(g);
47 | tmpGlob.put(start_r5, g);
48 | g = new Arm.Glob(start_r7);
49 | MC.Program.PROGRAM.globList.add(g);
50 | tmpGlob.put(start_r7, g);
51 | g = new Arm.Glob(start_lr);
52 | MC.Program.PROGRAM.globList.add(g);
53 | tmpGlob.put(start_lr, g);
54 | g = new Arm.Glob(end_r7);
55 | MC.Program.PROGRAM.globList.add(g);
56 | tmpGlob.put(end_r7, g);
57 | g = new Arm.Glob(end_lr);
58 | MC.Program.PROGRAM.globList.add(g);
59 | tmpGlob.put(end_lr, g);
60 |
61 | curMF = mf_parallel_start;
62 | mb_parallel_start = new MC.Block(".parallel_start", curMF);
63 | mb_parallel_start1 = new MC.Block(".parallel_start1", curMF);
64 | mb_parallel_start2 = new MC.Block(".parallel_start2", curMF);
65 | curMF = mf_parallel_end;
66 | mb_parallel_end = new MC.Block(".parallel_end", curMF);
67 | mb_parallel_end1 = new MC.Block(".parallel_end1", curMF);
68 | mb_parallel_end2 = new MC.Block(".parallel_end2", curMF);
69 | mb_parallel_end3 = new MC.Block(".parallel_end3", curMF);
70 | mb_parallel_end4 = new MC.Block(".parallel_end4", curMF);
71 | genStart();
72 | genEnd();
73 | }
74 |
75 | private static MC.Block curMB;
76 | private Arm.Glob getGlob(String name){
77 | return tmpGlob.get(name);
78 | }
79 |
80 | /**
81 | *
82 | parallel_start:
83 | movw r2, :lower16:$start_r7
84 | movt r2, :upper16:$start_r7
85 | str r7, [r2]
86 | movw r2, :lower16:$start_r5
87 | movt r2, :upper16:$start_r5
88 | str r5, [r2]
89 | movw r2, :lower16:$start_lr
90 | movt r2, :upper16:$start_lr
91 | str lr, [r2]
92 | mov r5, #4 @4代表总共4个进程,因为处理器有4个核心
93 | .parallel_start1:
94 | sub r5, r5, #1
95 | cmp r5, #0
96 | beq .parallel_start2+0 @r2每次减一,到0的时候就跳到.__mtstart2
97 | mov r7, #120 @系统调用号
98 | mov r0, #273 @系统调用的第一个参数值
99 | mov r1, sp
100 | swi #0 @根据寄存器r7的值进行系统调用,r7中为120,所以进行120号系统调用,为clone
101 | cmp r0, #0 @clone调用者进程返回创建的子进程号,在创建的子进程里返回0
102 | bne .parallel_start1+0 @如果是clone出来的进程就继续执行.parallel_start2,主进程跳到.parallel_start1,继续开启下一个进程
103 | .parallel_start2:
104 | mov r0, r5
105 | movw r2, :lower16:$start_r7
106 | movt r2, :upper16:$start_r7
107 | ldr r7, [r2]
108 | movw r2, :lower16:$start_r5
109 | movt r2, :upper16:$start_r5
110 | ldr r5, [r2]
111 | movw r2, :lower16:$start_lr
112 | movt r2, :upper16:$start_lr
113 | ldr lr, [r2]
114 | bx lr
115 | */
116 | private void genStart() {
117 | curMF = mf_parallel_start;
118 | curMB = mb_parallel_start;
119 | new I.Mov(getRSReg(r2), getGlob(start_r7), curMB);
120 | new I.Str(getRSReg(r7), getRSReg(r2), I_ZERO, curMB);
121 |
122 | new I.Mov(getRSReg(r2), getGlob(start_r5), curMB);
123 | new I.Str(getRSReg(r5), getRSReg(r2), I_ZERO, curMB);
124 |
125 | new I.Mov(getRSReg(r2), getGlob(start_lr), curMB);
126 | new I.Str(getRSReg(lr), getRSReg(r2), I_ZERO, curMB);
127 |
128 | new I.Mov(getRSReg(r5), new MC.Operand(I32, 4), curMB);
129 | curMB = mb_parallel_start1;
130 | new I.Binary(Sub, getRSReg(r5), getRSReg(r5), new MC.Operand(I32, 1), curMB);
131 | new I.Cmp(Arm.Cond.Eq, getRSReg(r5), I_ZERO, curMB);
132 | new GDBranch(Arm.Cond.Eq, mb_parallel_start2, curMB);
133 | new I.Mov(getRSReg(r7), new MC.Operand(I32, 120), curMB);
134 | new I.Mov(getRSReg(r0), new MC.Operand(I32, 273), curMB);
135 | new I.Mov(getRSReg(r1), getRSReg(sp), curMB);
136 | new I.Swi(curMB);
137 | new I.Cmp(Arm.Cond.Ne, getRSReg(r0), new MC.Operand(I32, 0), curMB);
138 | new GDBranch(Arm.Cond.Ne, mb_parallel_start1, curMB);
139 | curMB = mb_parallel_start2;
140 | new I.Mov(getRSReg(r0), getRSReg(r5), curMB);
141 | new I.Mov(getRSReg(r2), getGlob(start_r7), curMB);
142 | new I.Ldr(getRSReg(r7), getRSReg(r2), I_ZERO, curMB);
143 |
144 | new I.Mov(getRSReg(r2), getGlob(start_r5), curMB);
145 | new I.Ldr(getRSReg(r5), getRSReg(r2), I_ZERO, curMB);
146 |
147 | new I.Mov(getRSReg(r2), getGlob(start_lr), curMB);
148 | new I.Ldr(getRSReg(lr), getRSReg(r2), I_ZERO, curMB);
149 | new I.Ret(curMB);
150 | }
151 |
152 | private void genEnd() {
153 | curMF = mf_parallel_end;
154 | curMB = mb_parallel_end;
155 | new I.Cmp(Arm.Cond.Eq, getRSReg(r0), I_ZERO, curMB);
156 | new GDBranch(Arm.Cond.Eq, mb_parallel_end2, curMB);
157 | curMB = mb_parallel_end1;
158 | new I.Mov(getRSReg(r7), I_ONE, curMB);
159 | new I.Swi(curMB);
160 | curMB = mb_parallel_end2;
161 | new I.Mov(getRSReg(r2), getGlob(end_r7), curMB);
162 | new I.Str(getRSReg(r7), getRSReg(r2), I_ZERO, curMB);
163 |
164 | new I.Mov(getRSReg(r2), getGlob(end_lr), curMB);
165 | new I.Str(getRSReg(lr), getRSReg(r2), I_ZERO, curMB);
166 |
167 | new I.Mov(getRSReg(r7), new MC.Operand(I32, 4), curMB);
168 |
169 | curMB = mb_parallel_end3;
170 | new I.Binary(Sub, getRSReg(r7), getRSReg(r7), I_ONE, curMB);
171 | new I.Cmp(Arm.Cond.Eq, getRSReg(r7), I_ZERO, curMB);
172 | new GDBranch(Arm.Cond.Eq, mb_parallel_end4, curMB);
173 | new I.Binary(Sub, getRSReg(r0), getRSReg(sp), new MC.Operand(I32, 4), curMB);
174 | new I.Binary(Sub, getRSReg(sp), getRSReg(sp), new MC.Operand(I32, 4), curMB);
175 | new I.Wait(curMB);
176 | new I.Binary(Add, getRSReg(sp), getRSReg(sp), new MC.Operand(I32, 4), curMB);
177 | new GDJump(mb_parallel_end3, curMB);
178 | curMB = mb_parallel_end4;
179 | new I.Mov(getRSReg(r2), getGlob(end_r7), curMB);
180 | new I.Ldr(getRSReg(r7), getRSReg(r2), I_ZERO, curMB);
181 |
182 | new I.Mov(getRSReg(r2), getGlob(end_lr), curMB);
183 | new I.Ldr(getRSReg(lr), getRSReg(r2), I_ZERO, curMB);
184 |
185 | new I.Ret(curMB);
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/descriptor/Descriptor.java:
--------------------------------------------------------------------------------
1 | package descriptor;
2 |
3 | public interface Descriptor {
4 | StringBuilder getOutput();
5 | void clear();
6 | }
7 |
--------------------------------------------------------------------------------
/src/exception/SemanticException.java:
--------------------------------------------------------------------------------
1 | package exception;
2 |
3 | /**
4 | * 中端异常
5 | */
6 | public class SemanticException extends Exception {
7 | public SemanticException() { super(); }
8 |
9 | public SemanticException(String message) { super(message); }
10 | }
11 |
--------------------------------------------------------------------------------
/src/exception/SyntaxException.java:
--------------------------------------------------------------------------------
1 | package exception;
2 |
3 | /**
4 | * 编译器前端发生的异常(词法分析和语法分析阶段)
5 | */
6 | public class SyntaxException extends Exception {
7 | public SyntaxException() { super(); }
8 |
9 | public SyntaxException(String message) { super(message); }
10 | }
11 |
--------------------------------------------------------------------------------
/src/frontend/lexer/Token.java:
--------------------------------------------------------------------------------
1 | package frontend.lexer;
2 |
3 | public class Token {
4 | private final TokenType type;
5 | public final String content;
6 |
7 | public int lineNum = 0;
8 |
9 | private static final boolean[] IS_ALU_TYPE = new boolean[100];
10 | private static final boolean[] IS_CMP_TYPE = new boolean[100];
11 |
12 | static {
13 | for (int i = TokenType.ADD.ordinal(); i <= TokenType.MOD.ordinal(); i++) {
14 | IS_ALU_TYPE[i] = true;
15 | }
16 | for (int i = TokenType.LE.ordinal(); i <= TokenType.GT.ordinal(); i++) {
17 | IS_CMP_TYPE[i] = true;
18 | }
19 | }
20 |
21 | public Token(final TokenType type, final String content) {
22 | this.type = type;
23 | this.content = content;
24 | System.err.print(" " + content);
25 | }
26 |
27 | public TokenType getType() {
28 | return this.type;
29 | }
30 |
31 | public String getContent() {
32 | return this.content;
33 | }
34 |
35 | public boolean isOf(TokenType type) {
36 | return this.type.equals(type);
37 | }
38 |
39 | public boolean isOf(TokenType... types) {
40 | for (TokenType type : types) {
41 | if (this.type.equals(type)) {
42 | return true;
43 | }
44 | }
45 | return false;
46 | }
47 |
48 | public boolean isNumber() {
49 | return type.ordinal() <= TokenType.DEC_INT.ordinal()
50 | && type.ordinal() >= TokenType.HEX_FLOAT.ordinal();
51 | }
52 |
53 | public boolean isIntConst() {
54 | return type.ordinal() <= TokenType.DEC_INT.ordinal()
55 | && type.ordinal() >= TokenType.HEX_INT.ordinal();
56 | }
57 |
58 | public boolean isFloatConst() {
59 | return type.ordinal() <= TokenType.DEC_FLOAT.ordinal()
60 | && type.ordinal() >= TokenType.HEX_FLOAT.ordinal();
61 | }
62 |
63 | @Override
64 | public String toString() {
65 | return "<" + type + " " + content + ">";
66 | }
67 |
68 | public static boolean isAlu(TokenType tokenType) {
69 | return IS_ALU_TYPE[tokenType.ordinal()];
70 | }
71 |
72 | public static boolean isCmp(TokenType tokenType) {
73 | return IS_CMP_TYPE[tokenType.ordinal()];
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/frontend/lexer/TokenList.java:
--------------------------------------------------------------------------------
1 | package frontend.lexer;
2 |
3 | import exception.SyntaxException;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 |
8 | public class TokenList {
9 | private static final boolean ENABLE_DEBUG = false;
10 |
11 | public final ArrayList tokens = new ArrayList<>();
12 | private int index = 0;
13 |
14 | public void append(Token token) {
15 | // System.err.println(token);
16 | tokens.add(token);
17 | }
18 |
19 | public boolean hasNext() {
20 | return index < tokens.size();
21 | }
22 |
23 | public Token get() {
24 | return ahead(0);
25 | }
26 |
27 | public Token ahead(int count) {
28 | return tokens.get(index + count);
29 | }
30 |
31 | private void detectEof() throws SyntaxException {
32 | if (!hasNext()) {
33 | throw new SyntaxException("Unexpected EOF");
34 | }
35 | }
36 |
37 | public Token consume() throws SyntaxException {
38 | detectEof();
39 | if (ENABLE_DEBUG) {
40 | System.err.println("consume: " + tokens.get(index));
41 | }
42 | return tokens.get(index++);
43 | }
44 |
45 | // Usage: tokenList.consumeExpected(TokenType.INT, TokenType.VOID)
46 | public Token consumeExpected(TokenType... types) throws SyntaxException {
47 | detectEof();
48 | Token token = tokens.get(index);
49 | for (TokenType type : types) {
50 | if (token.getType().equals(type)) {
51 | if (ENABLE_DEBUG) {
52 | System.err.println("consume: " + tokens.get(index));
53 | }
54 | index++;
55 | return token;
56 | }
57 | }
58 | for (int i = 0; i < index; i++) {
59 | System.err.println(tokens.get(i));
60 | }
61 | throw new SyntaxException("Expected " + Arrays.toString(types) + " but got " + token);
62 | }
63 |
64 | public Token consumeExpected(TokenType type) throws SyntaxException {
65 | detectEof();
66 | Token token = tokens.get(index);
67 | if (token.getType().equals(type)) {
68 | if (ENABLE_DEBUG) {
69 | System.err.println("consume: " + tokens.get(index));
70 | }
71 | index++;
72 | return token;
73 | }
74 | for (int i = 0; i < index; i++) {
75 | System.err.println(tokens.get(i));
76 | }
77 | throw new SyntaxException("Expected " + type + " but got " + token);
78 | }
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/src/frontend/lexer/TokenType.java:
--------------------------------------------------------------------------------
1 | package frontend.lexer;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.Collections;
6 | import java.util.regex.Pattern;
7 |
8 | public enum TokenType {
9 | // keyword (must have lookahead assertion)
10 | CONST("const", true),
11 | INT("int", true),
12 | FLOAT("float", true),
13 | BREAK("break", true),
14 | CONTINUE("continue", true),
15 | IF("if", true),
16 | ELSE("else", true),
17 | VOID("void", true),
18 | WHILE("while", true),
19 | RETURN("return", true),
20 | // ident
21 | IDENT("[A-Za-z_][A-Za-z0-9_]*"),
22 | // float const
23 | HEX_FLOAT("(0(x|X)[0-9A-Fa-f]*\\.[0-9A-Fa-f]*((p|P|e|E)(\\+|\\-)?[0-9A-Fa-f]*)?)|" +
24 | "(0(x|X)[0-9A-Fa-f]*[\\.]?[0-9A-Fa-f]*(p|P|e|E)((\\+|\\-)?[0-9A-Fa-f]*)?)"),
25 | DEC_FLOAT("([0-9]*\\.[0-9]*((p|P|e|E)(\\+|\\-)?[0-9]+)?)|" +
26 | "([0-9]*[\\.]?[0-9]*(p|P|e|E)((\\+|\\-)?[0-9]+)?)"), // decimal
27 | // DEC_FLOAT("(0|([1-9][0-9]*))\\.[0-9]*((p|P|e|E)(\\+|\\-)?[0-9]+)?"), // decimal
28 | // int const
29 | HEX_INT("0(x|X)[0-9A-Fa-f]+"),
30 | OCT_INT("0[0-7]+"),
31 | DEC_INT("0|([1-9][0-9]*)"), // decimal
32 | // operator (double char)
33 | LAND("&&"),
34 | LOR("\\|\\|"),
35 | LE("<="),
36 | GE(">="),
37 | EQ("=="),
38 | NE("!="),
39 | // operator (single char)
40 | LT("<"),
41 | GT(">"),
42 | ADD("\\+"), // regex
43 | SUB("-"),
44 | MUL("\\*"),
45 | DIV("/"),
46 | MOD("%"),
47 | NOT("!"),
48 | ASSIGN("="),
49 | SEMI(";"),
50 | COMMA(","),
51 | LPARENT("\\("),
52 | RPARENT("\\)"),
53 | LBRACK("\\["),
54 | RBRACK("]"),
55 | LBRACE("\\{"),
56 | RBRACE("}"),
57 | STR_CON(""),
58 | ;
59 |
60 | public static final ArrayList NUM_CON_LIST = new ArrayList<>(Arrays.asList(HEX_INT, DEC_INT, OCT_INT, HEX_FLOAT, DEC_FLOAT));
61 |
62 | private final String pattern; // regex pattern
63 |
64 | private final boolean keyword; // keyword
65 |
66 | TokenType(final String pattern, final boolean keyword) {
67 | this.pattern = pattern;
68 | this.keyword = keyword;
69 | }
70 |
71 | TokenType(String pattern) {
72 | this(pattern, false);
73 | }
74 |
75 | public Pattern getPattern() {
76 | return Pattern.compile("^(" + pattern + ")" + (keyword ? "(?![A-Za-z0-9_])" : ""));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/frontend/semantic/Evaluate.java:
--------------------------------------------------------------------------------
1 | package frontend.semantic;
2 |
3 | import exception.SemanticException;
4 | import frontend.Visitor;
5 | import frontend.lexer.Token;
6 | import frontend.semantic.symbol.SymTable;
7 | import frontend.semantic.symbol.Symbol;
8 | import frontend.syntax.Ast;
9 | import mir.Constant;
10 | import mir.Value;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Iterator;
14 |
15 | /**
16 | * 编译期求值工具类
17 | */
18 | public class Evaluate {
19 | private final SymTable symTable; // 当前的符号表
20 | private final boolean requireConst; // 是否是 ConstExp
21 |
22 | public Evaluate(SymTable symTable, boolean requireConst) {
23 | this.symTable = symTable;
24 | this.requireConst = requireConst;
25 | }
26 |
27 | public static int evalConstIntExp(Ast.Exp exp) throws SemanticException {
28 | return (int) evalConstExp(exp);
29 | }
30 |
31 | public static float evalConstFloatExp(Ast.Exp exp) throws SemanticException {
32 | return (float) evalConstExp(exp);
33 | }
34 |
35 | // 编译期求值
36 | public static Object evalConstExp(Ast.Exp exp) throws SemanticException {
37 | Object ret;
38 | if (exp instanceof Ast.BinaryExp) {
39 | ret = evalBinaryConstExp((Ast.BinaryExp) exp);
40 | } else if (exp instanceof Ast.UnaryExp) {
41 | ret = evalUnaryConstExp((Ast.UnaryExp) exp);
42 | } else {
43 | throw new AssertionError("Bad Exp:" + exp);
44 | }
45 | boolean isFloat = ret instanceof Float;
46 | boolean isInt = ret instanceof Integer;
47 | assert ret instanceof Float || ret instanceof Integer;
48 | return ret;
49 | }
50 |
51 | /***
52 | * src1或src2中只要有Float,就将其提升为float运算,否则按照int运算
53 | * @param op
54 | * @param src1
55 | * @param src2
56 | * @return Integer或Float对象
57 | */
58 | // 二元运算
59 | private static Object binaryCalcHelper(Token op, Object src1, Object src2) {
60 | if (src1 instanceof Float || src2 instanceof Float) {
61 | float f1 = src1 instanceof Integer ? (float) ((int) src1) : (float) src1;
62 | float f2 = src2 instanceof Integer ? (float) ((int) src2) : (float) src2;
63 | return switch (op.getType()) {
64 | case ADD -> f1 + f2;
65 | case SUB -> f1 - f2;
66 | case MUL -> f1 * f2;
67 | case DIV -> f1 / f2;
68 | case MOD -> f1 % f2;
69 | default -> throw new AssertionError("Bad Binary Operator");
70 | };
71 | } else {
72 | assert src1 instanceof Integer && src2 instanceof Integer;
73 | int i1 = (int) src1;
74 | int i2 = (int) src2;
75 | return switch (op.getType()) {
76 | case ADD -> i1 + i2;
77 | case SUB -> i1 - i2;
78 | case MUL -> i1 * i2;
79 | case DIV -> i1 / i2;
80 | case MOD -> i1 % i2;
81 | default -> throw new AssertionError("Bad Binary Operator");
82 | };
83 | }
84 | }
85 |
86 | // 一元运算
87 | private static Object unaryCalcHelper(Token op, Object src) {
88 | if (src instanceof Integer) {
89 | int intConst = (int) src;
90 | return switch (op.getType()) {
91 | case ADD -> intConst;
92 | case SUB -> -intConst;
93 | case NOT -> intConst == 0 ? 1 : 0;
94 | default -> throw new AssertionError("Bad Unary Operator");
95 | };
96 | } else if (src instanceof Float) {
97 | float floatConst = (float) src;
98 | return switch (op.getType()) {
99 | case ADD -> floatConst;
100 | case SUB -> -floatConst;
101 | case NOT -> floatConst == 0.0 ? 1.0 : 0.0;
102 | default -> throw new AssertionError("Bad Unary Operator");
103 | };
104 | } else {
105 | throw new AssertionError("Bad src: " + src);
106 | }
107 | }
108 |
109 | // 从左到右按顺序计算即可
110 | public static Object evalBinaryConstExp(Ast.BinaryExp exp) throws SemanticException {
111 | Ast.Exp first = exp.getFirst();
112 | Iterator iterOp = exp.getOperators().listIterator();
113 | Iterator iterExp = exp.getFollows().listIterator();
114 | Object result = evalConstExp(first);
115 | while (iterExp.hasNext()) {
116 | assert iterOp.hasNext();
117 | Token op = iterOp.next();
118 | Ast.Exp follow = iterExp.next();
119 | result = binaryCalcHelper(op, result, evalConstExp(follow));
120 | }
121 | return result;
122 | }
123 |
124 | public static Object evalUnaryConstExp(Ast.UnaryExp exp) throws SemanticException {
125 | Object primary = evalPrimaryExp(exp.getPrimary());
126 | // 从右向左结合
127 | ArrayList unaryOps = new ArrayList<>(exp.getUnaryOps());
128 | for (int i = unaryOps.size() - 1; i >= 0; i--) {
129 | Token op = unaryOps.get(i);
130 | primary = unaryCalcHelper(op, primary);
131 | }
132 | return primary;
133 | }
134 |
135 | public static Object evalPrimaryExp(Ast.PrimaryExp exp) throws SemanticException {
136 | if (exp instanceof Ast.Number) {
137 | return evalNumber((Ast.Number) exp);
138 | } else if (exp instanceof Ast.Exp) {
139 | return evalConstExp((Ast.Exp) exp);
140 | } else if (exp instanceof Ast.LVal) {
141 | return evalLVal((Ast.LVal) exp);
142 | } else {
143 | // 编译期不能求函数调用的值
144 | throw new AssertionError("Bad Eval Primary Exp: " + exp.getClass().getSimpleName());
145 | }
146 | }
147 |
148 | public static Object evalNumber(Ast.Number number) {
149 | Token num = number.getNumber();
150 | String content = num.getContent();
151 | return switch (num.getType()) {
152 | case HEX_INT -> Integer.parseInt(content.substring(2), 16);
153 | case OCT_INT -> Integer.parseInt(content.substring(1), 8);
154 | case DEC_INT -> Integer.parseInt(content);
155 | case HEX_FLOAT, DEC_FLOAT -> Float.parseFloat(content);
156 | default -> throw new AssertionError("Bad Number: " + number);
157 | };
158 | }
159 |
160 | public static Object evalLVal(Ast.LVal lVal) throws SemanticException {
161 | String ident = lVal.getIdent().getContent();
162 | // 查找符号表
163 | Symbol symbol = Visitor.currentSymTable.get(ident, true);
164 | // if (requireConst && !symbol.isConstant()) {
165 | // throw new SemanticException("Expected Const but got not Const.");
166 | // }
167 | // 必须初始化过,才可以编译期求值
168 | if (symbol.getInitial() == null) {
169 | throw new SemanticException("Symbol not initialized");
170 | }
171 | // 如果是数组, 逐层找偏移量
172 | Initial init = symbol.getInitial();
173 | ArrayList indexes = new ArrayList<>(); // eval indexes
174 | for (Ast.Exp index : lVal.getIndexes()) {
175 | indexes.add((int) evalConstExp(index));
176 | }
177 | for (Integer index : indexes) {
178 | if (init instanceof Initial.ValueInit) {
179 | throw new SemanticException("Should be Array/Zero Init!");
180 | }
181 | if (init instanceof Initial.ZeroInit) {
182 | return 0;
183 | }
184 | assert init instanceof Initial.ArrayInit;
185 | init = ((Initial.ArrayInit) init).get(index);
186 | }
187 | if (!(init instanceof Initial.ValueInit)) {
188 | throw new SemanticException("Should be Value Init");
189 | }
190 | Value ret = ((Initial.ValueInit) init).getValue(); // 取出初始值
191 | assert ret instanceof Constant;
192 | return ((Constant) ret).getConstVal();
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/src/frontend/semantic/symbol/SymTable.java:
--------------------------------------------------------------------------------
1 | package frontend.semantic.symbol;
2 |
3 | import java.util.HashMap;
4 | import java.util.HashMap;
5 |
6 | /**
7 | * 分层结构的符号表
8 | */
9 | public class SymTable {
10 | private final HashMap symbolMap = new HashMap<>();
11 |
12 | private final SymTable parent;
13 |
14 | public SymTable() {
15 | this(null);
16 | }
17 |
18 | public boolean hasParent() {
19 | return parent != null;
20 | }
21 |
22 | public SymTable(SymTable parent) {
23 | this.parent = parent;
24 | }
25 |
26 | public SymTable getParent() {
27 | return parent;
28 | }
29 |
30 | public void add(Symbol symbol) {
31 | assert !symbolMap.containsKey(symbol.getName());
32 | symbolMap.putIfAbsent(symbol.getName(), symbol);
33 | }
34 |
35 | public Symbol get(String name, boolean recursive) {
36 | Symbol symbol = symbolMap.get(name);
37 | if (null == symbol && recursive && null != parent) {
38 | return parent.get(name, true);
39 | }
40 | return symbol;
41 | }
42 |
43 | public boolean contains(String name, boolean recursive) {
44 | return get(name, recursive) != null;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/frontend/semantic/symbol/Symbol.java:
--------------------------------------------------------------------------------
1 | package frontend.semantic.symbol;
2 |
3 | import frontend.semantic.Initial;
4 | import mir.Value;
5 | import mir.type.Type;
6 |
7 | /**
8 | * 符号表中的一条符号信息
9 | */
10 | public class Symbol {
11 | private final String name; // 变量名称
12 | private final Type type; // 变量类型
13 | private final Initial initial; // 初始值(可以为 null, 如果有则必须和变量匹配)
14 | private final boolean constant; // 是否为常量
15 | private final Value allocInst; // IR 中作为该变量地址的 Pointer
16 |
17 | public Symbol(final String name, final Type type, final Initial initial, final boolean constant, final Value allocInst) {
18 | this.name = name;
19 | this.type = type;
20 | this.initial = initial;
21 | this.constant = constant;
22 | this.allocInst = allocInst;
23 | }
24 |
25 | public String getName() {
26 | return this.name;
27 | }
28 |
29 | public Type getType() {
30 | return this.type;
31 | }
32 |
33 | public Initial getInitial() {
34 | return this.initial;
35 | }
36 |
37 | public boolean isConstant() {
38 | return this.constant;
39 | }
40 |
41 | public Value getValue() {
42 | return this.allocInst;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/lir/BJ.java:
--------------------------------------------------------------------------------
1 | package lir;
2 |
3 | import backend.CodeGen;
4 |
5 | import java.io.PrintStream;
6 |
7 | public class BJ extends MachineInst {
8 | public BJ(Tag tag, MC.Block insertAtEnd) {
9 | super(tag, insertAtEnd);
10 | }
11 |
12 | public BJ(Tag tag, MachineInst before) {
13 | super(tag, before);
14 | }
15 |
16 | public MC.Block getTrueBlock() {
17 | return null;
18 | }
19 |
20 | public MC.Block getFalseBlock() {
21 | return null;
22 | }
23 |
24 | public void setTarget(MC.Block onlySuccMB) {
25 | assert false;
26 | }
27 |
28 |
29 | public static class GDJump extends BJ {
30 | public MC.Block getTarget() {
31 | return target;
32 | }
33 |
34 | MC.Block target;
35 |
36 | public GDJump(MC.Block target, MC.Block insertAtEnd) {
37 | super(Tag.Jump, insertAtEnd);
38 | this.target = target;
39 | }
40 |
41 | public GDJump(MC.Block target, MachineInst before) {
42 | super(Tag.Jump, before);
43 | this.target = target;
44 | }
45 |
46 | // public GDJump(Arm.Cond cond, MC.Block target, MC.Block insertAtEnd) {
47 | // super(Tag.Jump, insertAtEnd);
48 | // this.target = target;
49 | // this.cond = cond;
50 | // }
51 |
52 | public MC.Block getTrueBlock() {
53 | return target;
54 | }
55 |
56 | public MC.Block getFalseBlock() {
57 | if (!(mb.getNext() instanceof MC.Block))
58 | System.exit(123);
59 | return (MC.Block) this.mb.getNext();
60 | }
61 |
62 | @Override
63 | public void output(PrintStream os, MC.McFunction f) {
64 | os.println("\t" + this);
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return tag.toString() + "\t" + target.getLabel();
70 | }
71 |
72 | public void setTarget(MC.Block block) {
73 | target = block;
74 | }
75 |
76 |
77 | }
78 |
79 |
80 | public static class GDBranch extends BJ {
81 | public Arm.Cond getCond() {
82 | return cond;
83 | }
84 |
85 | public MC.Block getTrueTargetBlock() {
86 | return target;
87 | }
88 |
89 | public MC.Block getFalseTargetBlock() {
90 | return (MC.Block) mb.getNext();
91 | }
92 |
93 | Arm.Cond cond;
94 | MC.Block target;
95 | // 条件不满足则跳这个块
96 | // MC.Block falseTargetBlock;
97 | boolean isIcmp = true;
98 |
99 | public GDBranch(Arm.Cond cond, MC.Block target, MC.Block insertAtEnd) {
100 | super(Tag.Branch, insertAtEnd);
101 | this.cond = cond;
102 | this.target = target;
103 | }
104 |
105 | public GDBranch(boolean isFcmp, Arm.Cond cond, MC.Block target, MC.Block insertAtEnd) {
106 | super(Tag.Branch, insertAtEnd);
107 | this.cond = cond;
108 | this.target = target;
109 | isIcmp = !isFcmp;
110 | }
111 |
112 | @Override
113 | public String toString() {
114 | return tag.toString() + cond + "\t" + target;
115 | }
116 |
117 |
118 | public MC.Block getTrueBlock() {
119 | return target;
120 | }
121 |
122 | // public MC.Block getFalseBlock() {
123 | // return falseTargetBlock;
124 | // }
125 |
126 | public void setTarget(MC.Block onlySuccMB) {
127 | target = onlySuccMB;
128 | }
129 |
130 | public Arm.Cond getOppoCond() {
131 | return isIcmp ? CodeGen.CODEGEN.getIcmpOppoCond(cond) : CodeGen.CODEGEN.getFcmpOppoCond(cond);
132 | }
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/lir/MICall.java:
--------------------------------------------------------------------------------
1 | package lir;
2 |
3 | import lir.Arm.Reg;
4 | import lir.MC.McFunction;
5 |
6 | import java.io.PrintStream;
7 |
8 | import static backend.CodeGen.*;
9 | import static backend.CodeGen.needFPU;
10 | import static lir.Arm.Regs.FPRs.s0;
11 | import static lir.Arm.Regs.GPRs.*;
12 |
13 | public class MICall extends MachineInst {
14 | public McFunction callee;
15 |
16 | public MICall(McFunction callee, MC.Block insertAtEnd) {
17 | super(Tag.Call, insertAtEnd);
18 | this.callee = callee;
19 | genDefUse();
20 | }
21 |
22 | public void genDefUse() {
23 | defOpds.add(Reg.getR(r12));
24 | defOpds.add(Reg.getR(lr));
25 | // if (callee.mFunc.isExternal) {
26 | // for (int i = 0; i < 2; i++) {
27 | // if(needFPU) {
28 | // useOpds.add(Reg.getS(i));
29 | // }
30 | // useOpds.add(Reg.getR(i));
31 | // }
32 |
33 | if (needFPU) {
34 | for (int i = 0; i < 2; i++) {
35 | useOpds.add(Reg.getS(i));
36 | defOpds.add(Reg.getS(i));
37 | }
38 | }
39 | // TODO: 区分自己定义的函数
40 | for (int i = r0.ordinal(); i < r0.ordinal() + rParamCnt; i++) {
41 | defOpds.add(Reg.getR(i));
42 | }
43 | if (needFPU) {
44 | for (int i = s0.ordinal(); i < s0.ordinal() + sParamCnt; i++) {
45 | defOpds.add(Reg.getS(i));
46 | }
47 | }
48 | // } else {
49 | for (int i = r0.ordinal(); i < r0.ordinal() + Math.min(callee.intParamCount, rParamCnt); i++) {
50 | useOpds.add(Reg.getR(i));
51 | // defOpds.add(Reg.getR(i));
52 | }
53 | if (needFPU) {
54 | for (int i = s0.ordinal(); i < s0.ordinal() + Math.min(callee.floatParamCount, sParamCnt); i++) {
55 | useOpds.add(Reg.getS(i));
56 | // defOpds.add(Reg.getS(i));
57 | }
58 | }
59 | // }
60 | // TODO for bug test!!!
61 | /*
62 | if (callee.mFunc.hasRet()) {
63 | if (callee.mFunc.getRetType().isInt32Type()) {
64 | defOpds.add(Reg.getR(r0));
65 | useOpds.add(Reg.getR(r0));
66 | } else if (callee.mFunc.getRetType().isFloatType()) {
67 | defOpds.add(Reg.getS(s0));
68 | useOpds.add(Reg.getS(s0));
69 | } else {
70 | throw new AssertionError("Wrong call func type: has ret but is type of " + callee.mFunc.getRetType());
71 | }
72 | }
73 | */
74 | }
75 |
76 | @Override
77 | public void output(PrintStream os, McFunction f) {
78 | os.println(this);
79 | }
80 |
81 | @Override
82 | public String toString() {
83 | return tag + "\t" + callee.mFunc.getName();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/lir/MIComment.java:
--------------------------------------------------------------------------------
1 | package lir;
2 |
3 | import java.io.PrintStream;
4 |
5 | public class MIComment extends MachineInst {
6 | String content;
7 |
8 | public MIComment(String content, MC.Block insertAtEnd) {
9 | super(Tag.Comment, insertAtEnd);
10 | this.content = content;
11 | }
12 |
13 | @Override
14 | public void output(PrintStream os, MC.McFunction f) {
15 | os.println(this);
16 | }
17 |
18 | @Override
19 | public String toString() {
20 | return tag.toString() + content;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lir/StackCtl.java:
--------------------------------------------------------------------------------
1 | package lir;
2 |
3 | import java.io.PrintStream;
4 | import java.util.Iterator;
5 |
6 | import static backend.CodeGen.sParamCnt;
7 | import static lir.Arm.Regs.GPRs.*;
8 |
9 | public class StackCtl extends MachineInst {
10 | public StackCtl(Tag tag, MC.Block mb) {
11 | super(tag, mb);
12 | }
13 |
14 | public static class Push extends StackCtl {
15 | MC.McFunction savedRegsMf;
16 | MC.Block mb;
17 |
18 | public Push(MC.McFunction savedRegsMf, MC.Block mb) {
19 | super(Tag.Push, mb);
20 | this.savedRegsMf = savedRegsMf;
21 | this.mb = mb;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | if (savedRegsMf.mFunc.isExternal) {
27 | // throw new AssertionError("push in external func");
28 | // return "\tpush\t{r0,r1,r2,r3}";
29 | return "push\t{r2,r3}";
30 | } else {
31 | StringBuilder sb = new StringBuilder();
32 | if (savedRegsMf.usedCalleeSavedGPRs.size() > 0) {
33 | sb.append("push\t{");
34 | Iterator gprIter = savedRegsMf.usedCalleeSavedGPRs.iterator();
35 | sb.append(gprIter.next());
36 | while (gprIter.hasNext()) {
37 | sb.append(",").append(gprIter.next());
38 | }
39 | sb.append("}");
40 | }
41 | return sb.toString();
42 | }
43 | }
44 |
45 | @Override
46 | public void output(PrintStream os, MC.McFunction f) {
47 | os.println(this);
48 | }
49 | }
50 |
51 | public static class Pop extends MachineInst {
52 | MC.McFunction savedRegsMf;
53 | MC.Block mb;
54 |
55 | public Pop(MC.McFunction savedRegsMf, MC.Block mb) {
56 | super(Tag.Pop, mb);
57 | this.savedRegsMf = savedRegsMf;
58 | this.mb = mb;
59 | }
60 |
61 |
62 | @Override
63 | public String toString() {
64 | if (savedRegsMf.mFunc.isExternal) {
65 | // throw new AssertionError("pop in external func");
66 | // return "\tpop\t{r0,r1,r2,r3}";
67 | return "\tpop\t{r2,r3}";
68 | } else {
69 | StringBuilder sb = new StringBuilder();
70 | if (savedRegsMf.usedCalleeSavedGPRs.size() > 0) {
71 | sb.append("\tpop\t{");
72 | Iterator gprIter = savedRegsMf.usedCalleeSavedGPRs.iterator();
73 | sb.append(gprIter.next());
74 | while (gprIter.hasNext()) {
75 | GPRs gpr = gprIter.next();
76 | sb.append(",").append(gpr);
77 | }
78 | sb.append("}");
79 | }
80 | return sb.toString();
81 | }
82 | }
83 |
84 | @Override
85 | public void output(PrintStream os, MC.McFunction f) {
86 | os.println(this);
87 | }
88 | }
89 |
90 |
91 | public static class VPush extends StackCtl {
92 | MC.McFunction savedRegsMf;
93 | MC.Block mb;
94 |
95 | public VPush(MC.McFunction savedRegsMf, MC.Block mb) {
96 | super(Tag.Push, mb);
97 | this.savedRegsMf = savedRegsMf;
98 | this.mb = mb;
99 | }
100 |
101 | @Override
102 | public void output(PrintStream os, MC.McFunction f) {
103 | os.println(this);
104 | }
105 |
106 | @Override
107 | public String toString() {
108 | StringBuilder sb = new StringBuilder();
109 | if (savedRegsMf.mFunc.isExternal) {
110 | // throw new AssertionError("vpush in external func");
111 | // sb.append(String.format("\tvpush\t{s0-s%d}", sParamCnt - 1));
112 | sb.append(String.format("\tvpush\t{s2-s%d}", sParamCnt - 1));
113 | } else {
114 | if (savedRegsMf.usedCalleeSavedFPRs.size() > 0) {
115 | int fprNum = FPRs.values().length;
116 | boolean[] fprBit = new boolean[fprNum];
117 | for (FPRs fpr : savedRegsMf.usedCalleeSavedFPRs) {
118 | fprBit[fpr.ordinal()] = true;
119 | }
120 | int start = 0;
121 | while (start < fprNum) {
122 | while (start < fprNum && !fprBit[start])
123 | start++;
124 | if (start == fprNum)
125 | break;
126 | int end = start;
127 | while (end < fprNum && fprBit[end])
128 | end++;
129 | end--;
130 | if (end == start) {
131 | throw new AssertionError("illegal vpush");
132 | // assert false;
133 | // sb.append(String.format("\tvpush\t{s%d}%n", start));
134 | } else if (end > start) {
135 | if (end - start > 15) {
136 | end = start + 15;
137 | }
138 | sb.append(String.format("\tvpush\t{s%d-s%d}%n", start, end));
139 | }
140 | start = end + 1;
141 | }
142 | }
143 | }
144 | return sb.toString();
145 | }
146 | }
147 |
148 | public static class VPop extends MachineInst {
149 | MC.McFunction savedRegsMf;
150 | MC.Block mb;
151 |
152 | public VPop(MC.McFunction savedRegsMf, MC.Block mb) {
153 | super(Tag.Pop, mb);
154 | this.savedRegsMf = savedRegsMf;
155 | this.mb = mb;
156 | }
157 |
158 |
159 | @Override
160 | public void output(PrintStream os, MC.McFunction f) {
161 | os.println(this);
162 | }
163 |
164 | @Override
165 | public String toString() {
166 | StringBuilder sb = new StringBuilder();
167 | if (savedRegsMf.mFunc.isExternal) {
168 | // throw new AssertionError("vpop in external func");
169 | // sb.append(String.format("\tvpop\t{s0-s%d}%n", sParamCnt - 1));
170 | sb.append(String.format("\tvpop\t{s2-s%d}", sParamCnt - 1));
171 | } else {
172 | if (savedRegsMf.usedCalleeSavedFPRs.size() > 0) {
173 | int fprNum = FPRs.values().length;
174 | boolean[] fprBit = new boolean[fprNum];
175 | for (FPRs fpr : savedRegsMf.usedCalleeSavedFPRs) {
176 | fprBit[fpr.ordinal()] = true;
177 | }
178 | int end = fprNum - 1;
179 | while (end > -1) {
180 | while (end > -1 && !fprBit[end])
181 | end--;
182 | if (end == -1)
183 | break;
184 | int start = end;
185 | while (start > -1 && fprBit[start])
186 | start--;
187 | start++;
188 | if (start == end) {
189 | throw new AssertionError("illegal vpop");
190 | // sb.append(String.format("\tvpop\t{s%d}%n", end));
191 | } else if (start < end) {
192 | if (end - start > 15) {
193 | start = end - 15;
194 | }
195 | sb.append(String.format("\tvpop\t{s%d-s%d}%n", start, end));
196 | }
197 | end = start - 1;
198 | }
199 | }
200 | }
201 | return sb.toString();
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/manage/Manager.java:
--------------------------------------------------------------------------------
1 | package manage;
2 |
3 | import lir.MC;
4 | import frontend.semantic.Initial;
5 | import frontend.semantic.symbol.Symbol;
6 | import lir.*;
7 | import mir.Function;
8 | import mir.GlobalVal;
9 | import mir.type.Type;
10 | import util.FileDealer;
11 |
12 | import java.io.FileNotFoundException;
13 | import java.io.FileOutputStream;
14 | import java.io.OutputStream;
15 | import java.util.*;
16 |
17 | import static mir.Function.Param.wrapParam;
18 | import static mir.type.Type.BasicType.F32_TYPE;
19 | import static mir.type.Type.BasicType.I32_TYPE;
20 |
21 | /**
22 | * LLVM IR
23 | */
24 | public class Manager {
25 | public static final Manager MANAGER = new Manager();
26 | private static final String MAIN_FUNCTION = "main";
27 | public static boolean external = false;
28 | public final HashMap globals = new HashMap<>();
29 | private final HashMap functions = new HashMap<>(); // 函数定义
30 |
31 | public int RK = 12;
32 | public int SK = 5;
33 |
34 |
35 | public ArrayList getFunctionList() {
36 | ArrayList list = new ArrayList<>();
37 | for (Function function : functions.values()) {
38 | if (function.hasBody()) {
39 | list.add(function);
40 | }
41 | }
42 | return list;
43 | }
44 |
45 | public static class ExternFunction {
46 | public static final Function GET_INT = new Function(true, "getint", new ArrayList<>(), I32_TYPE);
47 | public static final Function GET_CH = new Function(true, "getch", new ArrayList<>(), I32_TYPE);
48 | public static final Function GET_FLOAT = new Function(true, "getfloat", new ArrayList<>(), F32_TYPE);
49 | public static final Function GET_ARR = new Function(true, "getarray", wrapParam(new Type.PointerType(I32_TYPE)), I32_TYPE);
50 | public static final Function GET_FARR = new Function(true, "getfarray", wrapParam(new Type.PointerType(F32_TYPE)), I32_TYPE);
51 | public static final Function PUT_INT = new Function(true, "putint", wrapParam(I32_TYPE), Type.VoidType.getVoidType());
52 | public static final Function PUT_CH = new Function(true, "putch", wrapParam(I32_TYPE), Type.VoidType.getVoidType());
53 | public static final Function PUT_FLOAT = new Function(true, "putfloat", wrapParam(F32_TYPE), Type.VoidType.getVoidType());
54 | public static final Function PUT_ARR = new Function(true, "putarray", wrapParam(I32_TYPE, new Type.PointerType(I32_TYPE)), Type.VoidType.getVoidType());
55 | public static final Function PUT_FARR = new Function(true, "putfarray", wrapParam(I32_TYPE, new Type.PointerType(F32_TYPE)), Type.VoidType.getVoidType());
56 | public static final Function MEM_SET = new Function(true, "memset", wrapParam(new Type.PointerType(I32_TYPE), I32_TYPE, I32_TYPE), Type.VoidType.getVoidType());
57 | public static final Function START_TIME = new Function(true, "starttime", wrapParam(I32_TYPE), Type.VoidType.getVoidType());
58 | public static final Function STOP_TIME = new Function(true, "stoptime", wrapParam(I32_TYPE), Type.VoidType.getVoidType());
59 | public static final Function PARALLEL_START = new Function(true, "parallel_start", new ArrayList<>(), I32_TYPE);
60 | public static final Function PARALLEL_END = new Function(true, "parallel_end", wrapParam(I32_TYPE), Type.VoidType.getVoidType());
61 | }
62 |
63 | public final ArrayList externalFuncList = new ArrayList<>();
64 |
65 | private Manager() {
66 | external = true;
67 | addFunction(ExternFunction.GET_INT);
68 | addFunction(ExternFunction.GET_CH);
69 | addFunction(ExternFunction.GET_FLOAT);
70 | addFunction(ExternFunction.GET_ARR);
71 | addFunction(ExternFunction.GET_FARR);
72 | addFunction(ExternFunction.PUT_INT);
73 | addFunction(ExternFunction.PUT_CH);
74 | addFunction(ExternFunction.PUT_FLOAT);
75 | addFunction(ExternFunction.PUT_ARR);
76 | addFunction(ExternFunction.PUT_FARR);
77 | addFunction(ExternFunction.MEM_SET);
78 | addFunction(ExternFunction.START_TIME);
79 | ExternFunction.START_TIME.isTimeFunc = true;
80 | addFunction(ExternFunction.STOP_TIME);
81 | ExternFunction.STOP_TIME.isTimeFunc = true;
82 |
83 | addFunction(ExternFunction.PARALLEL_START);
84 | addFunction(ExternFunction.PARALLEL_END);
85 | external = false;
86 | }
87 |
88 | public void addGlobal(Symbol symbol) {
89 | assert symbol.getInitial() != null;
90 | assert symbol.getValue() instanceof GlobalVal.GlobalValue;
91 | globals.putIfAbsent((GlobalVal.GlobalValue) symbol.getValue(), symbol.getInitial());
92 | }
93 |
94 | public void addFunction(Function function) {
95 | functions.putIfAbsent(function.getName(), function);
96 | externalFuncList.add(function);
97 | }
98 |
99 | public boolean hasMainFunction() {
100 | return functions.containsKey(MAIN_FUNCTION);
101 | }
102 |
103 | static int outputLLVMCnt = 0;
104 |
105 | public void outputLLVM() throws FileNotFoundException {
106 | outputLLVM("llvmOf-" + outputLLVMCnt++);
107 | }
108 |
109 | public void outputLLVM(String llvmFilename) throws FileNotFoundException {
110 | outputLLVM(new FileOutputStream(llvmFilename + ".ll"));
111 | }
112 |
113 | public void outputLLVM(OutputStream out) {
114 | FileDealer.outputClear();
115 | // 全局变量
116 | for (HashMap.Entry entry : globals.entrySet()) {
117 | FileDealer.addOutputString(entry.getKey().getName() + " = dso_local global " + entry.getValue());
118 | }
119 | // 函数声明
120 | for (Function function : functions.values()) {
121 | if (!function.hasBody()) {
122 | FileDealer.addOutputString(function.getDeclare());
123 | }
124 | }
125 | // 函数定义
126 | for (Function function : functions.values()) {
127 | if (function.getDeleted()) {
128 | continue;
129 | }
130 | if (function.hasBody()) {
131 | FileDealer.addOutputString(function.output());
132 | }
133 | }
134 | FileDealer.outputStringList(out);
135 | }
136 |
137 | static int outputMIcnt = 0;
138 |
139 | public void outputMI(){
140 | try {
141 | outputMI("lirOutput-" + outputMIcnt++);
142 | } catch (FileNotFoundException e) {
143 | throw new RuntimeException(e);
144 | }
145 | }
146 |
147 | public static void outputMI(boolean flag) {
148 | MC.Program p = MC.Program.PROGRAM;
149 | for (MC.McFunction mcFunc : p.funcList) {
150 | System.err.println("\n");
151 | System.err.println(mcFunc.mFunc.getName());
152 | for (MC.Block mb : mcFunc.mbList) {
153 | System.err.println("\n");
154 | System.err.println(mb.getLabel());
155 | for (MachineInst mi : mb.miList) {
156 | // if(mi.isCall())continue;
157 | // if(mi.isBranch())continue;
158 | // if(mi instanceof MIBinary)continue;
159 | // if(mi instanceof MILoad)continue;
160 | // if(mi instanceof MIStore)continue;
161 | // if(mi.isMove())continue;
162 | String str = mi instanceof MIComment ? "" : "\t";
163 | System.err.println(str + mi);
164 | }
165 | }
166 | }
167 | }
168 |
169 | public void outputMI(String miFilename) throws FileNotFoundException {
170 | outputMI(new FileOutputStream(miFilename + ".txt"));
171 | }
172 |
173 | public static void outputMI(OutputStream out) {
174 | FileDealer.outputClear();
175 | MC.Program p = MC.Program.PROGRAM;
176 | for (MC.McFunction mcFunc : p.funcList) {
177 | FileDealer.addOutputString("\n");
178 | FileDealer.addOutputString(mcFunc.mFunc.getName()+":");
179 | for (MC.Block mb : mcFunc.mbList) {
180 | FileDealer.addOutputString("\n");
181 | FileDealer.addOutputString(mb.getLabel()+":");
182 | FileDealer.addOutputString("@ pred:\t"+mb.predMBs.toString());
183 | FileDealer.addOutputString("@ succ:\t"+mb.succMBs.toString());
184 | for (MachineInst mi : mb.miList) {
185 | if(!(mi.getNext() instanceof MachineInst ) && mi.getNext()!=mb.miList.tail){
186 | int a = 0;
187 | }
188 | String str = mi instanceof MIComment ? "" : "\t";
189 | FileDealer.addOutputString(str + mi);
190 | }
191 | }
192 | }
193 |
194 | FileDealer.outputStringList(out);
195 | }
196 |
197 | public HashMap getGlobals() {
198 | return this.globals;
199 | }
200 |
201 |
202 | public HashMap getFunctions() {
203 | HashMap ret = new HashMap<>();
204 | for (String str: functions.keySet()) {
205 | if (!functions.get(str).getDeleted()) {
206 | ret.put(str, functions.get(str));
207 | }
208 | }
209 | return ret;
210 | // return this.functions;
211 | }
212 |
213 | }
214 |
--------------------------------------------------------------------------------
/src/midend/AggressiveMarkParallel.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import manage.Manager;
4 | import mir.*;
5 | import mir.type.Type;
6 | import util.CenterControl;
7 |
8 | import java.util.ArrayList;
9 | import java.util.HashMap;
10 | import java.util.HashSet;
11 |
12 | public class AggressiveMarkParallel {
13 |
14 | private ArrayList functions;
15 | private static int parallel_num = 4;
16 | HashSet know = new HashSet<>();
17 | private HashSet goodFunc = new HashSet<>();
18 | private HashMap> funcLoadArrays = new HashMap<>();
19 |
20 |
21 | public AggressiveMarkParallel(ArrayList functions) {
22 | this.functions = functions;
23 | }
24 |
25 | public void Run() {
26 | init();
27 | for (Function function: functions) {
28 | know.clear();
29 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
30 | if (!know.contains(bb) && bb.isLoopHeader()) {
31 | markLoop(bb.getLoop());
32 | }
33 | }
34 | }
35 | }
36 |
37 | private void init() {
38 | for (Function function: functions) {
39 | funcLoadArrays.put(function, new HashSet<>());
40 | if (check(function)) {
41 | goodFunc.add(function);
42 | }
43 | }
44 | }
45 |
46 | private boolean check(Function function) {
47 | for (Value param: function.getParams()) {
48 | if (param.getType().isPointerType()) {
49 | return false;
50 | }
51 | }
52 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
53 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
54 | if (instr instanceof Instr.Call) {
55 | return false;
56 | }
57 | if (instr instanceof Instr.Store) {
58 | return false;
59 | } else if (instr instanceof Instr.Load) {
60 | Value array = ((Instr.Load) instr).getPointer();
61 | while (array instanceof Instr.GetElementPtr) {
62 | array = ((Instr.GetElementPtr) array).getPtr();
63 | }
64 | funcLoadArrays.get(function).add(array);
65 | }
66 | }
67 | }
68 | return true;
69 | }
70 |
71 | private boolean isPureLoop(Loop loop) {
72 | if (!loop.hasChildLoop()) {
73 | return true;
74 | }
75 | if (loop.getChildrenLoops().size() > 1) {
76 | return false;
77 | }
78 | if (!loop.isSimpleLoop() || !loop.isIdcSet()) {
79 | return false;
80 | }
81 | return isPureLoop(loop.getChildrenLoops().iterator().next());
82 | }
83 |
84 | private void markLoop(Loop loop) {
85 | //当前只考虑main函数内的循环
86 | // if (!loop.getHeader().getFunction().getName().equals("main")) {
87 | // return;
88 | // }
89 | if (!isPureLoop(loop)) {
90 | return;
91 | }
92 | if (loop.hasChildLoop()) {
93 | return;
94 | }
95 | HashSet bbs = new HashSet<>();
96 | HashSet idcVars = new HashSet<>();
97 | HashSet loops = new HashSet<>();
98 | bbs.addAll(loop.getNowLevelBB());
99 | idcVars.add(loop.getIdcPHI());
100 | loops.add(loop);
101 |
102 | HashSet idcInstrs = new HashSet<>();
103 | idcInstrs.add(loop.getIdcPHI());
104 | idcInstrs.add(loop.getIdcCmp());
105 | idcInstrs.add(loop.getIdcAlu());
106 | idcInstrs.add(loop.getHeader().getEndInstr());
107 | idcInstrs.add(loop.getLatchs().iterator().next().getEndInstr());
108 |
109 | for (Instr instr = loop.getHeader().getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
110 | if (instr instanceof Instr.Phi && !instr.equals(loop.getIdcPHI())) {
111 | return;
112 | }
113 | }
114 |
115 | //只有一次调用函数, 读一个数组, 写一个数组
116 | Value loadArray = null, storeArray = null;
117 | Function func = null;
118 |
119 | for (BasicBlock bb: bbs) {
120 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
121 | if (useOutLoops(instr, loops)) {
122 | return;
123 | }
124 | if (idcInstrs.contains(instr)) {
125 |
126 | } else if (instr instanceof Instr.Call) {
127 | if (((Instr.Call) instr).getFunc().isExternal) {
128 | continue;
129 | }
130 | if (func != null) {
131 | return;
132 | }
133 | func = ((Instr.Call) instr).getFunc();
134 | } else if (instr instanceof Instr.GetElementPtr) {
135 | //trivel写法
136 | if (!(((Instr.GetElementPtr) instr).getPtr() instanceof GlobalVal.GlobalValue)) {
137 | return;
138 | }
139 | for (Value idc: ((Instr.GetElementPtr) instr).getIdxList()) {
140 | if (idc instanceof Constant && (int) ((Constant) idc).getConstVal() == 0) {
141 | continue;
142 | }
143 | if (!idcVars.contains(idc)) {
144 | return;
145 | }
146 | }
147 | } else if (instr instanceof Instr.Load) {
148 | if (loadArray != null) {
149 | return;
150 | }
151 | Value array = ((Instr.Load) instr).getPointer();
152 | while (array instanceof Instr.GetElementPtr) {
153 | array = ((Instr.GetElementPtr) array).getPtr();
154 | }
155 | loadArray = array;
156 | } else if (instr instanceof Instr.Store) {
157 | if (storeArray != null) {
158 | return;
159 | }
160 | Value array = ((Instr.Store) instr).getPointer();
161 | while (array instanceof Instr.GetElementPtr) {
162 | array = ((Instr.GetElementPtr) array).getPtr();
163 | }
164 | storeArray = array;
165 | } else {
166 | return;
167 | }
168 | }
169 | }
170 |
171 | if (func == null || loadArray == null || storeArray == null) {
172 | return;
173 | }
174 |
175 | if (!(loadArray instanceof GlobalVal.GlobalValue) || !(storeArray instanceof GlobalVal.GlobalValue)) {
176 | return;
177 | }
178 |
179 | //很强的限制,可以考虑删除
180 | // if (funcLoadArrays.get(func).size() != 1) {
181 | // return;
182 | // }
183 |
184 | for (Value array: funcLoadArrays.get(func)) {
185 | if (!(array instanceof GlobalVal.GlobalValue)) {
186 | return;
187 | }
188 | }
189 | if (funcLoadArrays.get(func).contains(storeArray) || loadArray.equals(storeArray)) {
190 | return;
191 | }
192 |
193 | loop.setCanAggressiveParallel(true);
194 | CenterControl._FUNC_PARALLEL = true;
195 | }
196 |
197 |
198 | private boolean useOutLoops(Value value, HashSet loops) {
199 | for (Use use = value.getBeginUse(); use.getNext() != null; use = (Use) use.getNext()) {
200 | Instr user = use.getUser();
201 | if (!loops.contains(user.parentBB().getLoop())) {
202 | return true;
203 | }
204 | }
205 | return false;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/midend/ArrayLift.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import frontend.semantic.Initial;
4 | import mir.BasicBlock;
5 | import mir.Function;
6 | import mir.GlobalVal;
7 | import mir.Instr;
8 | import mir.type.Type;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 |
13 | public class ArrayLift {
14 |
15 | private ArrayList functions;
16 | private HashMap globalValues;
17 | private static final int length_low_line = 10;
18 |
19 | public ArrayLift(ArrayList functions, HashMap globalValues) {
20 | this.functions = functions;
21 | this.globalValues = globalValues;
22 | }
23 |
24 | public void Run() {
25 | for (Function function: functions) {
26 | if (function.getName().equals("main") || function.onlyOneUser()) {
27 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
28 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
29 | if (instr instanceof Instr.Alloc && instr.parentBB().getLoop().getLoopDepth() == 0) {
30 | //TODO:
31 | Type type = ((Type.PointerType) instr.getType()).getInnerType();
32 | Initial.ZeroInit init = new Initial.ZeroInit(type);
33 | GlobalVal.GlobalValue val = new GlobalVal.GlobalValue(type, "lift_" + instr.getNameWithOutPrefix(), init);
34 | globalValues.put(val, init);
35 | instr.modifyAllUseThisToUseA(val);
36 | instr.remove();
37 | }
38 | }
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/midend/ArraySSA.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import frontend.semantic.Initial;
4 | import mir.BasicBlock;
5 | import mir.Function;
6 | import mir.GlobalVal;
7 | import mir.Instr;
8 | import mir.type.Type;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.HashSet;
13 |
14 | public class ArraySSA {
15 | //只考虑局部数组
16 | //全局可以考虑 遍历支配树, 遇到一个Array的store就删除之前的GVNhash,达到GVN的目的
17 | private ArrayList functions;
18 | private HashMap globalValues;
19 | private HashSet allocs = new HashSet<>();
20 |
21 | public ArraySSA(ArrayList functions, HashMap globalValues) {
22 | this.functions = functions;
23 | this.globalValues = globalValues;
24 | }
25 |
26 | //TODO:插入Def PHI和merge PHI
27 | private void Run() {
28 | GetAllocs();
29 | //局部数组
30 | for (Instr.Alloc alloc: allocs) {
31 |
32 | }
33 |
34 | //全局数组
35 | for (GlobalVal.GlobalValue globalValue: globalValues.keySet()) {
36 | if (((Type.PointerType) globalValue.getType()).getInnerType().isArrType() && globalValue.canLocal()) {
37 | //认为入口块定义全局数组
38 | }
39 | }
40 | }
41 |
42 | private void GetAllocs() {
43 | for (Function function: functions) {
44 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
45 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
46 | if (instr instanceof Instr.Alloc) {
47 | allocs.add((Instr.Alloc) instr);
48 | }
49 | }
50 | }
51 | }
52 | }
53 |
54 | private void insertPHIForLocalArray(Instr instr) {
55 |
56 | }
57 |
58 | private void insertPHIForGlobalArray(GlobalVal.GlobalValue globalValue) {
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/midend/BranchLift.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import mir.*;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.HashSet;
8 |
9 | public class BranchLift {
10 |
11 | private ArrayList functions;
12 |
13 | public BranchLift(ArrayList functions) {
14 | this.functions = functions;
15 | }
16 |
17 | public void Run() {
18 | branchLift();
19 | }
20 |
21 | private void branchLift() {
22 | for (Function function: functions) {
23 | branchLiftForFunc(function);
24 | }
25 | }
26 |
27 | private void branchLiftForFunc(Function function) {
28 | //TODO:一次只能提升一个循环的一个Branch
29 | for (BasicBlock head: function.getLoopHeads()) {
30 | Loop loop = head.getLoop();
31 | HashMap> conds = loop.getConds();
32 | for (int key: conds.keySet()) {
33 | if (conds.get(key).size() == 1) {
34 | Instr br = null;
35 | for (Instr temp: conds.get(key)) {
36 | br = temp;
37 | }
38 | if (!(br instanceof Instr.Branch)) {
39 | continue;
40 | }
41 | // if (loop.getChildrenLoops().size() != 0) {
42 | // continue;
43 | // }
44 | liftBrOutLoop((Instr.Branch) br, loop);
45 | //TODO:只提升一个branch就直接return
46 | return;
47 | }
48 | }
49 | }
50 | }
51 |
52 | private void liftBrOutLoop(Instr.Branch thenBr, Loop thenLoop) {
53 | CloneInfoMap.clear();
54 | Function function = thenLoop.getHeader().getFunction();
55 | BasicBlock thenHead = thenLoop.getHeader();
56 | thenLoop.cloneToFunc(function);
57 | // for (BasicBlock bb: thenLoop.getNowLevelBB()) {
58 | // System.err.println(bb.getLabel() + " to " + ((BasicBlock) CloneInfoMap.getReflectedValue(bb)).getLabel());
59 | // }
60 |
61 | thenLoop.fix();
62 | Loop elseLoop = CloneInfoMap.getReflectedLoop(thenLoop);
63 | BasicBlock elseHead = elseLoop.getHeader();
64 |
65 | BasicBlock transBB = new BasicBlock(function, thenLoop.getParentLoop());
66 | HashSet enterings = thenLoop.getEnterings();
67 |
68 | //entering --> transBB
69 | for (BasicBlock entering: enterings) {
70 | Instr instr = entering.getEndInstr();
71 | if (instr instanceof Instr.Jump) {
72 | instr.modifyUse(transBB, 0);
73 | } else if (instr instanceof Instr.Branch){
74 | ArrayList values = instr.getUseValueList();
75 | if (values.size() == 1) {
76 | instr.modifyUse(transBB, 0);
77 | } else {
78 | int index = values.indexOf(thenHead);
79 | instr.modifyUse(transBB, index);
80 | }
81 | } else {
82 | System.err.println("error");
83 | }
84 | entering.modifySuc(thenHead, transBB);
85 | transBB.addPre(entering);
86 | thenHead.modifyPre(entering, transBB);
87 | elseHead.modifyPre(entering, transBB);
88 |
89 | //transBB.addPre(entering);
90 | }
91 |
92 | //Clone br
93 | // entering --> transBB
94 | // transBB --> thenHead & elseHead
95 | transBB.addSuc(thenHead);
96 | transBB.addSuc(elseHead);
97 |
98 |
99 | Instr.Branch elseBr = (Instr.Branch) CloneInfoMap.getReflectedValue(thenBr);
100 | Instr brInTransBB = thenBr.cloneToBB(transBB);
101 | if (transBB.getLoopDep() > 0) {
102 | brInTransBB.setInLoopCond();
103 | brInTransBB.setCondCount(thenBr.getCondCount());
104 | }
105 |
106 | brInTransBB.modifyUse(thenHead, 1);
107 | brInTransBB.modifyUse(elseHead, 2);
108 |
109 | //修改thenLoop和elseLoop中的br为无条件转跳
110 | //thenBr.modifyUse(new Constant.ConstantInt(1), 0);
111 | Instr.Jump thenJump = new Instr.Jump((BasicBlock) thenBr.getUseValueList().get(1), thenBr.parentBB());
112 | thenBr.insertBefore(thenJump);
113 |
114 |
115 | //elseBr.modifyUse(new Constant.ConstantInt(0), 0);
116 | Instr.Jump elseJump = new Instr.Jump((BasicBlock) elseBr.getUseValueList().get(2), elseBr.parentBB());
117 | elseBr.insertBefore(elseJump);
118 |
119 | thenBr.remove();
120 | elseBr.remove();
121 |
122 |
123 | //修改exiting的数据流
124 | //
125 | //修改exits的(冗余)phi
126 | HashSet exits = thenLoop.getExits();
127 | for (BasicBlock bb: exits) {
128 | ArrayList addBBs = new ArrayList<>();
129 | for (BasicBlock pre: bb.getPrecBBs()) {
130 | if (CloneInfoMap.valueMap.containsKey(pre)) {
131 | addBBs.add((BasicBlock) CloneInfoMap.getReflectedValue(pre));
132 | }
133 | }
134 | for (BasicBlock add: addBBs) {
135 | bb.addPre(add);
136 | }
137 |
138 | Instr instr = bb.getBeginInstr();
139 | while (instr.getNext() != null) {
140 | if (instr instanceof Instr.Phi) {
141 | ArrayList adds = new ArrayList<>();
142 | for (Value used: instr.getUseValueList()) {
143 | int index = instr.getUseValueList().indexOf(used);
144 | if (CloneInfoMap.valueMap.containsKey(bb.getPrecBBs().get(index))) {
145 | adds.add(CloneInfoMap.getReflectedValue(used));
146 | }
147 | // if (CloneInfoMap.valueMap.containsKey(used)) {
148 | // adds.add(CloneInfoMap.getReflectedValue(used));
149 | // }
150 |
151 | //adds.add(CloneInfoMap.getReflectedValue(used));
152 | }
153 | for (Value add: adds) {
154 | ((Instr.Phi) instr).addOptionalValue(add);
155 | }
156 | assert instr.parentBB().getPrecBBs().size() == instr.getUseValueList().size();
157 | }
158 | instr = (Instr) instr.getNext();
159 | }
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/midend/BranchOptimize.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import manage.Manager;
4 | import mir.*;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.HashSet;
9 |
10 | public class BranchOptimize {
11 |
12 | private ArrayList functions;
13 |
14 | public BranchOptimize(ArrayList functions) {
15 | this.functions = functions;
16 | }
17 |
18 | public void Run() {
19 | if (!MidEndRunner.O2) {
20 | RemoveUselessPHI();
21 | ModifyConstBranch();
22 | }
23 |
24 | RemoveUselessPHI();
25 | RemoveUselessJump();
26 | remakeCFG();
27 | ModifyConstBranch();
28 | remakeCFG();
29 | //fixme:check貌似是错的
30 | //RemoveBBOnlyJump();
31 | }
32 |
33 | private void remakeCFG() {
34 | MakeDFG makeDFG = new MakeDFG(functions);
35 | makeDFG.Run();
36 | }
37 |
38 | //删除只有一个use的PHI(冗余PHI)
39 | private void RemoveUselessPHI() {
40 | for (Function function: functions) {
41 | removeUselessPHIForFunc(function);
42 | }
43 | }
44 |
45 | private void RemoveUselessJump() {
46 | for (Function function: functions) {
47 | removeUselessJumpForFunc(function);
48 | }
49 | }
50 |
51 | //branch条件为恒定值的时候,变为JUMP
52 | private void ModifyConstBranch() {
53 | for (Function function: functions) {
54 | modifyConstBranchForFunc(function);
55 | }
56 | }
57 |
58 | private void RemoveBBOnlyJump() {
59 | for (Function function: functions) {
60 | removeBBOnlyJumpForFunc(function);
61 | }
62 | }
63 |
64 | private void removeUselessPHIForFunc(Function function) {
65 | BasicBlock bb = function.getBeginBB();
66 | while (bb.getNext() != null) {
67 | Instr instr = bb.getBeginInstr();
68 | while (instr.getNext() != null) {
69 | if (!(instr instanceof Instr.Phi)) {
70 | break;
71 | }
72 | if (instr.getUseValueList().size() == 1) {
73 | Value value = instr.getUseValueList().get(0);
74 | instr.modifyAllUseThisToUseA(value);
75 | instr.remove();
76 | }
77 |
78 | instr = (Instr) instr.getNext();
79 | }
80 |
81 | bb = (BasicBlock) bb.getNext();
82 | }
83 | }
84 |
85 | private void removeUselessJumpForFunc(Function function) {
86 | HashSet bbCanRemove = new HashSet<>();
87 | BasicBlock bb = function.getBeginBB();
88 | while (bb.getNext() != null) {
89 | if (bb.getPrecBBs().size() == 1) {
90 | bbCanRemove.add(bb);
91 | }
92 | bb = (BasicBlock) bb.getNext();
93 | }
94 | for (BasicBlock mid: bbCanRemove) {
95 | // bbs -> pre -> mid -> bbs
96 | // bbs -> pre -> bbs
97 | // move all instr in mid to pre
98 | BasicBlock pre = mid.getPrecBBs().get(0);
99 | if (pre.getSuccBBs().size() != 1) {
100 | continue;
101 | }
102 | pre.getEndInstr().remove();
103 | ArrayList instrInMid = new ArrayList<>();
104 | for (Instr instr = mid.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
105 | instrInMid.add(instr);
106 | }
107 | for (Instr instr: instrInMid) {
108 | instr.setBb(pre);
109 | pre.insertAtEnd(instr);
110 | }
111 | pre.setSuccBBs(mid.getSuccBBs());
112 | for (BasicBlock temp: mid.getSuccBBs()) {
113 | temp.modifyPre(mid, pre);
114 | }
115 | mid.remove();
116 | }
117 | }
118 |
119 | private void modifyConstBranchForFunc(Function function) {
120 | HashMap modifyBrMap = new HashMap<>();
121 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
122 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
123 | if (instr instanceof Instr.Branch) {
124 | Value cond = ((Instr.Branch) instr).getCond();
125 | if (cond instanceof Constant) {
126 | int val = (int) ((Constant) cond).getConstVal();
127 | boolean tag = val == 1;
128 | modifyBrMap.put((Instr.Branch) instr, tag);
129 | }
130 | }
131 | }
132 | }
133 |
134 | for (Instr.Branch br: modifyBrMap.keySet()) {
135 | BasicBlock tagBB = null;
136 | BasicBlock parentBB = br.parentBB();
137 | if (modifyBrMap.get(br)) {
138 | tagBB = br.getThenTarget();
139 | } else {
140 | tagBB = br.getElseTarget();
141 | }
142 | //br.remove();
143 | Instr.Jump jump = new Instr.Jump(tagBB, parentBB);
144 | br.insertBefore(jump);
145 | //br.getCond().remove();
146 | br.remove();
147 |
148 | }
149 | }
150 |
151 | private void removeBBOnlyJumpForFunc(Function function) {
152 | HashSet removes = new HashSet<>();
153 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
154 | if (function.entry.equals(bb)) {
155 | continue;
156 | }
157 | if (bb.getBeginInstr().equals(bb.getEndInstr())) {
158 | Instr instr = bb.getBeginInstr();
159 | if (instr instanceof Instr.Jump) {
160 | //TODO:
161 | Value next = ((Instr.Jump) instr).getTarget();
162 | BasicBlock target = ((Instr.Jump) instr).getTarget();
163 | bb.modifyAllUseThisToUseA(next);
164 | for (BasicBlock pre: bb.getPrecBBs()) {
165 | pre.modifySuc(bb, target);
166 | target.modifyPre(bb, pre);
167 | }
168 | removes.add(bb);
169 | }
170 | }
171 | }
172 | for (BasicBlock bb: removes) {
173 | bb.remove();
174 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
175 | instr.remove();
176 | }
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/midend/CloneInfoMap.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import mir.Loop;
4 | import mir.Value;
5 |
6 | import java.util.HashMap;
7 | import java.util.HashSet;
8 |
9 | public class CloneInfoMap {
10 |
11 | public static HashMap loopMap = new HashMap<>();
12 | public static HashMap loopCondCntMap = new HashMap<>();
13 | public static HashMap valueMap = new HashMap<>();
14 | //public static HashSet loopNeedFix = new HashSet<>();
15 | //public static HashSet bbNeedFix = new HashSet<>();
16 |
17 | public static void addLoopReflect(Loop srcLoop, Loop tagLoop) {
18 | //assert !loopMap.containsKey(srcLoop);
19 | loopMap.put(srcLoop, tagLoop);
20 | }
21 | //
22 | // public static boolean isReflected(Loop loop) {
23 | // return loopMap.containsKey(loop);
24 | // }
25 |
26 | public static Loop getReflectedLoop(Loop loop) {
27 | if (loopMap.containsKey(loop)) {
28 | return loopMap.get(loop);
29 | } else {
30 | return loop;
31 | }
32 | }
33 |
34 | public static void addLoopCondCntReflect(Integer src, Integer tag) {
35 | loopCondCntMap.put(src, tag);
36 | }
37 |
38 | public static Integer getLoopCondCntReflect(Integer cnt) {
39 | if (loopCondCntMap.containsKey(cnt)) {
40 | return loopCondCntMap.get(cnt);
41 | } else {
42 | return cnt;
43 | }
44 | }
45 |
46 | public static void addValueReflect(Value src, Value tag) {
47 | valueMap.put(src, tag);
48 | }
49 |
50 | public static Value getReflectedValue(Value value) {
51 | if (valueMap.containsKey(value)) {
52 | return valueMap.get(value);
53 | }
54 | return value;
55 | }
56 |
57 | // public static void addLoopNeedFix(Loop loop) {
58 | // loopNeedFix.add(loop);
59 | // }
60 | //
61 | // public static void rmBBNeedFix(BasicBlock bb) {
62 | // bbNeedFix.remove(bb);
63 | // }
64 |
65 | public static void clear() {
66 | loopMap.clear();
67 | loopCondCntMap.clear();
68 | valueMap.clear();
69 | //loopNeedFix.clear();
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/midend/ConstTransFold.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import mir.BasicBlock;
4 | import mir.Constant;
5 | import mir.Function;
6 | import mir.Instr;
7 |
8 | import java.util.ArrayList;
9 |
10 | public class ConstTransFold {
11 |
12 | private ArrayList functions;
13 |
14 | public ConstTransFold(ArrayList functions) {
15 | this.functions = functions;
16 | }
17 |
18 | public void Run() {
19 | for (Function function: functions) {
20 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
21 | for (Instr instr = bb.getBeginInstr(); instr.getNext()!= null; instr = (Instr) instr.getNext()) {
22 | if (instr instanceof Instr.FPtosi && ((Instr.FPtosi) instr).getRVal1() instanceof Constant.ConstantFloat) {
23 | float val = (float) ((Constant.ConstantFloat) ((Instr.FPtosi) instr).getRVal1()).getConstVal();
24 | int ret = (int) val;
25 |
26 | instr.modifyAllUseThisToUseA(new Constant.ConstantInt(ret));
27 | instr.remove();
28 | } else if (instr instanceof Instr.SItofp && ((Instr.SItofp) instr).getRVal1() instanceof Constant.ConstantInt) {
29 | int val = (int) ((Constant.ConstantInt) ((Instr.SItofp) instr).getRVal1()).getConstVal();
30 | float ret = (float) val;
31 |
32 | instr.modifyAllUseThisToUseA(new Constant.ConstantFloat(ret));
33 | instr.remove();
34 | }
35 | }
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/midend/FuncInfo.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import mir.*;
4 |
5 | import java.util.ArrayList;
6 |
7 | public class FuncInfo {
8 |
9 | private ArrayList functions;
10 |
11 | public FuncInfo(ArrayList functions) {
12 | this.functions = functions;
13 | }
14 |
15 | public void Run() {
16 | for (Function function: functions) {
17 | boolean ret = checkCanGVN(function);
18 | function.setCanGVN(ret);
19 | }
20 | }
21 |
22 | private boolean checkCanGVN(Function function) {
23 | for (Function.Param param: function.getParams()) {
24 | if (param.getType().isPointerType()) {
25 | return false;
26 | }
27 | }
28 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
29 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
30 | if (instr instanceof Instr.Call) {
31 | return false;
32 | }
33 | for (Value value: instr.getUseValueList()) {
34 | if (value instanceof GlobalVal.GlobalValue) {
35 | return false;
36 | }
37 | }
38 | }
39 | }
40 | return true;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/midend/GepFuse.java:
--------------------------------------------------------------------------------
1 | package midend;
2 |
3 | import mir.*;
4 | import mir.type.Type;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.HashSet;
9 |
10 | public class GepFuse {
11 |
12 | //考虑不能融合的情况?
13 | //TODO:是否存在不能融合的情况?
14 | private ArrayList functions;
15 | private ArrayList Geps = new ArrayList<>();
16 |
17 | public GepFuse(ArrayList functions) {
18 | this.functions = functions;
19 | }
20 |
21 | public void Run() {
22 | gepFuse();
23 | }
24 |
25 | private void gepFuse() {
26 | for (Function function: functions) {
27 | gepFuseForFunc(function);
28 | }
29 | }
30 |
31 | private void gepFuseForFunc(Function function) {
32 | //删除冗余GEP
33 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
34 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
35 | if (instr instanceof Instr.GetElementPtr && isZeroOffsetGep((Instr.GetElementPtr) instr)) {
36 | instr.modifyAllUseThisToUseA(((Instr.GetElementPtr) instr).getPtr());
37 | }
38 | }
39 | }
40 |
41 | //GEP融合
42 | for (BasicBlock bb = function.getBeginBB(); bb.getNext() != null; bb = (BasicBlock) bb.getNext()) {
43 | for (Instr instr = bb.getBeginInstr(); instr.getNext() != null; instr = (Instr) instr.getNext()) {
44 | if (instr instanceof Instr.GetElementPtr && !(((Instr.GetElementPtr) instr).getPtr() instanceof Instr.GetElementPtr)) {
45 | fuseDFS(instr);
46 | }
47 | }
48 | }
49 |
50 | }
51 |
52 | private boolean isZeroOffsetGep(Instr.GetElementPtr gep) {
53 | // if (!(gep.getPtr() instanceof Instr.GetElementPtr)) {
54 | // return false;
55 | // }
56 | ArrayList values = gep.getIdxList();
57 | if (values.size() > 1) {
58 | return false;
59 | }
60 | for (Value value: values) {
61 | if (!(value instanceof Constant)) {
62 | return false;
63 | }
64 | int val = (int) ((Constant) value).getConstVal();
65 | if (val != 0) {
66 | return false;
67 | }
68 | }
69 | return true;
70 | }
71 |
72 | private void fuseDFS(Instr instr) {
73 | Geps.add((Instr.GetElementPtr) instr);
74 | HashSet