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 李晓奇 ...@@ -81,13 +81,27 @@ PB20111654 李晓奇
这个在访问`ASTVar`时解决掉:加入全局变量`LV`表式当前处理的是左值,所以要返回对应的地址,否则返回load出来的右值。 这个在访问`ASTVar`时解决掉:加入全局变量`LV`表式当前处理的是左值,所以要返回对应的地址,否则返回load出来的右值。
```cpp LV为`true`时,对应的是赋值语句的左式、函数的指针引用。
struct ASTCall : ASTFactor {
virtual void accept(ASTVisitor &) override final; 另外嵌套递归调用可能导致LV发生变化,要注意。
std::string id;
std::vector<std::shared_ptr<ASTExpression>> args; > 关于函数传参的探讨
}; >
``` > - 值传递:由于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 @@ ...@@ -16,8 +16,9 @@
// definitions if you need to. // definitions if you need to.
// the latest return value // the latest return value
bool LV = false;
Value *cur_value = nullptr; Value *cur_value = nullptr;
// if var is assignment's left part, LV is true
bool LV = false;
// function that is being built // function that is being built
Function *cur_fun = nullptr; Function *cur_fun = nullptr;
...@@ -265,10 +266,16 @@ void CminusfBuilder::visit(ASTParam &node) { ...@@ -265,10 +266,16 @@ void CminusfBuilder::visit(ASTParam &node) {
auto param_value = cur_value; auto param_value = cur_value;
switch (node.type) { switch (node.type) {
case TYPE_INT: { case TYPE_INT: {
if (node.isarray)
cur_value = builder->create_alloca(INT32PTR_T);
else
cur_value = builder->create_alloca(INT32_T); cur_value = builder->create_alloca(INT32_T);
break; break;
} }
case TYPE_FLOAT: { case TYPE_FLOAT: {
if (node.isarray)
cur_value = builder->create_alloca(FLOATPTR_T);
else
cur_value = builder->create_alloca(FLOAT_T); cur_value = builder->create_alloca(FLOAT_T);
break; break;
} }
...@@ -403,20 +410,26 @@ void CminusfBuilder::visit(ASTVar &node) { ...@@ -403,20 +410,26 @@ void CminusfBuilder::visit(ASTVar &node) {
//!TODO: This function is empty now. //!TODO: This function is empty now.
// Add some code here. // Add some code here.
// //
// Goal: calculate address // First it's pointer type, the pointed elements have 3 cases:
// 1. get base // 1. int or float
// 2. get bias if there is, and cast it if needed. // 2. [i32 x n] or [float x n]
// 3. int*
bool old_LV = LV;
auto memory = scope.find(node.id); auto memory = scope.find(node.id);
Value *addr; Value *addr;
if (memory == nullptr) if (memory == nullptr)
error_exit("variable " + node.id + " not declared"); error_exit("variable " + node.id + " not declared");
LOG_DEBUG << "find entry: " << node.id << " " << memory; LOG_DEBUG << "find entry: " << node.id << " " << memory;
if (node.expression) { // e.g. int a[10]; // mem is [i32 x 10]*
assert(memory->get_type()->is_pointer_type()); 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]*
bool old_LV = LV;
LV = false; LV = false;
node.expression->accept(*this); node.expression->accept(*this);
LV = old_LV;
// subscription type cast
if (not Type::is_eq_type(cur_value->get_type(), INT32_T)) { if (not Type::is_eq_type(cur_value->get_type(), INT32_T)) {
if (Type::is_eq_type(cur_value->get_type(), FLOAT_T)) if (Type::is_eq_type(cur_value->get_type(), FLOAT_T))
cur_value = builder->create_fptosi(cur_value, INT32_T); cur_value = builder->create_fptosi(cur_value, INT32_T);
...@@ -436,15 +449,61 @@ void CminusfBuilder::visit(ASTVar &node) { ...@@ -436,15 +449,61 @@ void CminusfBuilder::visit(ASTVar &node) {
builder->set_insert_point(passBB); builder->set_insert_point(passBB);
// 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}); 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* } else { // e.g. int a; // a is i32*
if (element_type->is_float_type() or element_type->is_integer_type()) {
// 1. int or float
// addr is the element's addr
addr = memory; addr = memory;
} } else {
LV = old_LV;
if (LV) 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;
}
}
if (LV) {
LOG_INFO << "directly return addr" << node.id;
cur_value = addr; cur_value = addr;
else { } else {
LOG_INFO << "create load for var: " << node.id;
cur_value = builder->create_load(addr); cur_value = builder->create_load(addr);
} }
} }
...@@ -624,11 +683,18 @@ void CminusfBuilder::visit(ASTCall &node) { ...@@ -624,11 +683,18 @@ void CminusfBuilder::visit(ASTCall &node) {
// type cast // type cast
if (not Type::is_eq_type(param_type, cur_value->get_type())) { if (not Type::is_eq_type(param_type, cur_value->get_type())) {
if (param_type->is_pointer_type()) { if (param_type->is_pointer_type()) {
if (not Type::is_eq_type(param_type->get_pointer_element_type(), // shouldn't need type cast for pointer, logically
cur_value->get_type()->get_array_element_type())) if (param_type->get_pointer_element_type()->is_integer_type() or
error_exit("expected right pointer type"); param_type->get_pointer_element_type()->is_float_type())
// int[] to int* or float[] to flot* error_exit("BUG HERE: ASTVar return value is not int* or float*");
cur_value = builder->create_gep(cur_value, {CONST_INT(0), CONST_INT(0)}); 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()) { } else if (param_type->is_integer_type() or param_type->is_float_type()) {
// need type cast between int and float // 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()) 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