EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

Lab5-函数和变量

实现功能

本次实验完成了以下功能:

  1. 函数定义与调用
  2. 局部变量

实验设计

本次实验参照助教在文档中的提示,对符号表做了如下设计。注意本次实验中符号表不再依赖 SymbolType 包,而是直接存储 StringLLVMValueRef 的映射。

本次实验重新设计了 LLVMVisitor 类,部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
public class LLVMIRVisitor extends SysYParserBaseVisitor<LLVMValueRef> {
private final LLVMModuleRef module = LLVMModuleCreateWithName("module");
private final LLVMBuilderRef builder = LLVMCreateBuilder();
private final LLVMTypeRef i32Type = LLVMInt32Type();
private final LLVMTypeRef voidType = LLVMVoidType();
private final LLVMValueRef zero = LLVMConstInt(i32Type, 0, 0);

public LLVMIRVisitor() {
LLVMInitializeCore(LLVMGetGlobalPassRegistry());
LLVMLinkInMCJIT();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
LLVMInitializeNativeTarget();
}

@Override
public LLVMValueRef visitTerminal(TerminalNode node) {
if (symbolType == SysYParser.INTEGR_CONST) {
return LLVMConstInt(i32Type, number, 0);
}
return super.visitTerminal(node);
}

@Override
public LLVMValueRef visitFuncDef(SysYParser.FuncDefContext ctx) {
int paramsCount;

PointerPointer<Pointer> paramsTypes = new PointerPointer<>(paramsCount);
String retTypeName = ctx.funcType().getText();
LLVMTypeRef retType = getTypeRef(retTypeName);
LLVMTypeRef functionType = LLVMFunctionType(retType, paramsTypes, paramsCount, 0);
String functionName = ctx.IDENT().getText();
LLVMValueRef function = LLVMAddFunction(module, functionName, functionType);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(function, functionName + "_entry");
LLVMPositionBuilderAtEnd(builder, entry);

for (int i = 0; i < paramsCount; ++i) {
SysYParser.FuncFParamContext funcFParamContext = ctx.funcFParams().funcFParam(i);
LLVMTypeRef paramType = getTypeRef(paramTypeName);
LLVMValueRef varPointer = LLVMBuildAlloca(builder, paramType, "pointer_" + varName);
currentScope.define(varName, varPointer);
LLVMValueRef argValue = LLVMGetParam(function, i);
LLVMBuildStore(builder, argValue, varPointer);
}

return function;
}

@Override
public LLVMValueRef visitVarDecl(SysYParser.VarDeclContext ctx) {
for (SysYParser.VarDefContext varDefContext : ctx.varDef()) {
LLVMValueRef varPointer = LLVMBuildAlloca(builder, varType, "pointer_" + varName);

if (varDefContext.ASSIGN() != null) {
SysYParser.ExpContext expContext = varDefContext.initVal().exp();
if (expContext != null) {
LLVMValueRef initVal = visit(expContext);
LLVMBuildStore(builder, initVal, varPointer);
} else {
int initValCount = varDefContext.initVal().initVal().size();
LLVMValueRef[] initArray = new LLVMValueRef[elementCount];
// fill in initArray
buildGEP(elementCount, varPointer, initArray);
}
}

currentScope.define(varName, varPointer);
}

return null;
}

private void buildGEP(int elementCount, LLVMValueRef varPointer, LLVMValueRef[] initArray) {
// 这里展示的是方法的全部代码
LLVMValueRef[] arrayPointer = new LLVMValueRef[2];
arrayPointer[0] = zero;
for (int i = 0; i < elementCount; i++) {
arrayPointer[1] = LLVMConstInt(i32Type, i, 0);
PointerPointer<LLVMValueRef> indexPointer = new PointerPointer<>(arrayPointer);
LLVMValueRef elementPtr = LLVMBuildGEP(builder, varPointer, indexPointer, 2, "GEP_" + i);
LLVMBuildStore(builder, initArray[i], elementPtr);
}
}

@Override
public LLVMValueRef visitLValExp(SysYParser.LValExpContext ctx) {
LLVMValueRef lValPointer = this.visitLVal(ctx.lVal());
return LLVMBuildLoad(builder, lValPointer, ctx.lVal().getText());
}

@Override
public LLVMValueRef visitFuncCallExp(SysYParser.FuncCallExpContext ctx) {
String functionName = ctx.IDENT().getText();
LLVMValueRef function = currentScope.resolve(functionName);
PointerPointer<Pointer> args = null;
return LLVMBuildCall(builder, function, args, argsCount, "");
}

@Override
public LLVMValueRef visitReturnStmt(SysYParser.ReturnStmtContext ctx) {
LLVMValueRef result;
return LLVMBuildRet(builder, result);
}
}

测试用例

样例输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int f(int i){
return i;
}

void g() {
int j = 1 + 5;
return;
}

void func() {
}

int main(){
int a = 1;
int array[5] = {1, 2, 3};
array[3] = a;
array[4] = a + 5;
g();
return f(a * array[4]);
}
样例输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
; ModuleID = 'module'
source_filename = "module"

define i32 @f(i32 %0) {
f_entry:
%pointer_i = alloca i32, align 4
store i32 %0, i32* %pointer_i, align 4
%i = load i32, i32* %pointer_i, align 4
ret i32 %i
}

define void @g() {
g_entry:
%pointer_j = alloca i32, align 4
store i32 6, i32* %pointer_j, align 4
ret void
}

define void @func() {
func_entry:
ret void
}

define i32 @main() {
main_entry:
%pointer_a = alloca i32, align 4
store i32 1, i32* %pointer_a, align 4
%pointer_array = alloca <5 x i32>, align 32
%GEP_0 = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 0
store i32 1, i32* %GEP_0, align 4
%GEP_1 = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 1
store i32 2, i32* %GEP_1, align 4
%GEP_2 = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 2
store i32 3, i32* %GEP_2, align 4
%GEP_3 = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 3
store i32 0, i32* %GEP_3, align 4
%GEP_4 = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 4
store i32 0, i32* %GEP_4, align 4
%"pointer_array[3]" = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 3
%a = load i32, i32* %pointer_a, align 4
store i32 %a, i32* %"pointer_array[3]", align 4
%"pointer_array[4]" = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 4
%a1 = load i32, i32* %pointer_a, align 4
%add_ = add i32 %a1, 5
store i32 %add_, i32* %"pointer_array[4]", align 4
call void @g()
%a2 = load i32, i32* %pointer_a, align 4
%"pointer_array[4]3" = getelementptr <5 x i32>, <5 x i32>* %pointer_array, i32 0, i32 4
%"array[4]" = load i32, i32* %"pointer_array[4]3", align 4
%mul_ = mul i32 %a2, %"array[4]"
%0 = call i32 @f(i32 %mul_)
ret i32 %0
}