Commit 06dd9b3d authored by 李晓奇's avatar 李晓奇

97 points! I was afraid a huge change may lower the score hhhh..

parent 9e13604b
......@@ -81,13 +81,27 @@ PB20111654 李晓奇
这个在访问`ASTVar`时解决掉:加入全局变量`LV`表式当前处理的是左值,所以要返回对应的地址,否则返回load出来的右值。
```cpp
struct ASTCall : ASTFactor {
virtual void accept(ASTVisitor &) override final;
std::string id;
std::vector<std::shared_ptr<ASTExpression>> args;
};
```
LV为`true`时,对应的是赋值语句的左式、函数的指针引用。
另外嵌套递归调用可能导致LV发生变化,要注意。
> 关于函数传参的探讨
>
> - 值传递:由于LV是false,所以访问ASTVar的时候会load出来。可能需要类型转换。
>
> - 指针传递:设置LV是true,这时ASTVar会返回一个指针,**指向基本元素类型**(int|float)。
>
> 所以保证ASTVar返回的Value*变量符合要求,应该可以拿来直接使用,否则抛出异常。
- 针对ASTVar的探讨
- LV:如果标记为true,则做左值,返回数据地址,否则返回提取出来的数据。
- node.expression:如果非空,则有数组下标
- Var的类型:这里断言是指针类型,所有push操作都应该维护这个性质。其指向的类型应该有三种:基本类型(int\*, float\*),数组类型([i32 x n]\*, [float x n]\*),二级指针类型(int\*\*, float\*\*)。
每种类型都有不同的对待逻辑,如何区分不同的Var类型呢?
- 全局变量要特殊对待
......
......@@ -16,8 +16,9 @@
// definitions if you need to.
// the latest return value
bool LV = false;
Value *cur_value = nullptr;
// if var is assignment's left part, LV is true
bool LV = false;
// function that is being built
Function *cur_fun = nullptr;
......@@ -265,11 +266,17 @@ void CminusfBuilder::visit(ASTParam &node) {
auto param_value = cur_value;
switch (node.type) {
case TYPE_INT: {
cur_value = builder->create_alloca(INT32_T);
if (node.isarray)
cur_value = builder->create_alloca(INT32PTR_T);
else
cur_value = builder->create_alloca(INT32_T);
break;
}
case TYPE_FLOAT: {
cur_value = builder->create_alloca(FLOAT_T);
if (node.isarray)
cur_value = builder->create_alloca(FLOATPTR_T);
else
cur_value = builder->create_alloca(FLOAT_T);
break;
}
case TYPE_VOID:
......@@ -403,20 +410,26 @@ void CminusfBuilder::visit(ASTVar &node) {
//!TODO: This function is empty now.
// Add some code here.
//
// Goal: calculate address
// 1. get base
// 2. get bias if there is, and cast it if needed.
bool old_LV = LV;
// First it's pointer type, the pointed elements have 3 cases:
// 1. int or float
// 2. [i32 x n] or [float x n]
// 3. int*
auto memory = scope.find(node.id);
Value *addr;
if (memory == nullptr)
error_exit("variable " + node.id + " not declared");
LOG_DEBUG << "find entry: " << node.id << " " << memory;
assert(memory->get_type()->is_pointer_type());
auto element_type = memory->get_type()->get_pointer_element_type();
if (node.expression) { // e.g. int a[10]; // mem is [i32 x 10]*
assert(memory->get_type()->is_pointer_type());
bool old_LV = LV;
LV = false;
node.expression->accept(*this);
LV = old_LV;
// subscription type cast
if (not Type::is_eq_type(cur_value->get_type(), INT32_T)) {
if (Type::is_eq_type(cur_value->get_type(), FLOAT_T))
cur_value = builder->create_fptosi(cur_value, INT32_T);
......@@ -436,15 +449,61 @@ void CminusfBuilder::visit(ASTVar &node) {
builder->set_insert_point(passBB);
addr = builder->create_gep(memory, {CONST_INT(0), cur_value});
// Now the subscription is in cur_value, which is good value
// We should focus on the var type:
//
// assert it's pointer type
if (element_type->is_float_type() or element_type->is_integer_type()) {
// 1. int or float
error_exit("invalid types for array subscript");
} else if (element_type->is_array_type()) {
// 2. [i32 x n] or [float x n]
//
// addr is actually &memory[0][cur_value]
addr = builder->create_gep(memory, {CONST_INT(0), cur_value});
} else if (element_type->is_pointer_type()) {
// 3. int*
// what to do:
// - int**->int*
// - seek addr
//
// addr is actually &(*memory)[cur_value]
addr = builder->create_load(memory);
addr = builder->create_gep(addr, {cur_value});
}
// The logic for this part is the same as `int|float` without subscription.
// Cause we have subscription to find the particular element(int or float),
// we make `addr` its memory address.
} else { // e.g. int a; // a is i32*
addr = memory;
if (element_type->is_float_type() or element_type->is_integer_type()) {
// 1. int or float
// addr is the element's addr
addr = memory;
} else {
if (LV)
error_exit("error: pointer or array type is not assignable");
// For array* or pointer* type, the right-value behaviour is quite special,
// so treat them apart.
if (element_type->is_array_type()) {
// 2. [i32 x n] or [float x n]
// addr is the first element's address in the array
cur_value = builder->create_gep(memory, {CONST_INT(0), CONST_INT(0)});
} else if (element_type->is_pointer_type()) {
// 3. int*
// addr is the content in the memory, which is actually pointer type
cur_value = builder->create_load(memory);
}
return;
}
}
LV = old_LV;
if (LV)
if (LV) {
LOG_INFO << "directly return addr" << node.id;
cur_value = addr;
else {
} else {
LOG_INFO << "create load for var: " << node.id;
cur_value = builder->create_load(addr);
}
}
......@@ -624,11 +683,18 @@ void CminusfBuilder::visit(ASTCall &node) {
// type cast
if (not Type::is_eq_type(param_type, cur_value->get_type())) {
if (param_type->is_pointer_type()) {
if (not Type::is_eq_type(param_type->get_pointer_element_type(),
cur_value->get_type()->get_array_element_type()))
error_exit("expected right pointer type");
// int[] to int* or float[] to flot*
cur_value = builder->create_gep(cur_value, {CONST_INT(0), CONST_INT(0)});
// shouldn't need type cast for pointer, logically
if (param_type->get_pointer_element_type()->is_integer_type() or
param_type->get_pointer_element_type()->is_float_type())
error_exit("BUG HERE: ASTVar return value is not int* or float*");
else
error_exit("BUG HERE: function param needs weird pointer type");
/* if (not Type::is_eq_type(param_type->get_pointer_element_type(),
* cur_value->get_type()->get_pointer_element_type()->get_array_element_type()))
* error_exit("expected right pointer type");
* // int[] to int* or float[] to flot*
* cur_value = builder->create_gep(cur_value, {CONST_INT(0), CONST_INT(0)}); */
} else if (param_type->is_integer_type() or param_type->is_float_type()) {
// need type cast between int and float
if (not cur_value->get_type()->is_integer_type() and not cur_value->get_type()->is_float_type())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment