|
|
|
|
@ -10,10 +10,15 @@
|
|
|
|
|
|
|
|
|
|
// ─── 辅助 ─────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
// 把 i32 值转成 i1(icmp ne i32 v, 0)
|
|
|
|
|
// 把 i32/float 值转成 i1
|
|
|
|
|
ir::Value* IRGenImpl::ToI1(ir::Value* v) {
|
|
|
|
|
if (!v) throw std::runtime_error(FormatError("irgen", "ToI1: null value"));
|
|
|
|
|
if (v->IsInt1()) return v;
|
|
|
|
|
if (v->IsFloat32()) {
|
|
|
|
|
return builder_.CreateFCmp(ir::FCmpPredicate::ONE, v,
|
|
|
|
|
builder_.CreateConstFloat(0.0f),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
return builder_.CreateICmp(ir::ICmpPredicate::NE, v,
|
|
|
|
|
builder_.CreateConstInt(0),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
@ -87,7 +92,13 @@ void IRGenImpl::EnsureExternalDecl(const std::string& name) {
|
|
|
|
|
} else if (name == "getch") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetInt32Type(), {});
|
|
|
|
|
} else if (name == "getfloat") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(), {}); // 近似
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetFloat32Type(), {});
|
|
|
|
|
} else if (name == "getarray") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetInt32Type(),
|
|
|
|
|
{ir::Type::GetPtrInt32Type()});
|
|
|
|
|
} else if (name == "getfarray") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetInt32Type(),
|
|
|
|
|
{ir::Type::GetPtrFloat32Type()});
|
|
|
|
|
} else if (name == "putint") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetInt32Type()});
|
|
|
|
|
@ -95,10 +106,16 @@ void IRGenImpl::EnsureExternalDecl(const std::string& name) {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetInt32Type()});
|
|
|
|
|
} else if (name == "putfloat") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(), {});
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetFloat32Type()});
|
|
|
|
|
} else if (name == "putarray") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetInt32Type()});
|
|
|
|
|
{ir::Type::GetInt32Type(),
|
|
|
|
|
ir::Type::GetPtrInt32Type()});
|
|
|
|
|
} else if (name == "putfarray") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetInt32Type(),
|
|
|
|
|
ir::Type::GetPtrFloat32Type()});
|
|
|
|
|
} else if (name == "starttime" || name == "stoptime") {
|
|
|
|
|
module_.DeclareExternalFunc(name, ir::Type::GetVoidType(),
|
|
|
|
|
{ir::Type::GetInt32Type()});
|
|
|
|
|
@ -227,13 +244,113 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
|
|
|
|
|
std::vector<ir::Value*> args;
|
|
|
|
|
if (ctx->funcRParams()) {
|
|
|
|
|
for (auto* exp : ctx->funcRParams()->exp()) {
|
|
|
|
|
args.push_back(EvalExpr(*exp));
|
|
|
|
|
// 检查是否是数组变量(无索引的 lVar),若是则传指针而非 load
|
|
|
|
|
ir::Value* arg = nullptr;
|
|
|
|
|
auto* add = exp->addExp();
|
|
|
|
|
if (add && add->mulExp().size() == 1) {
|
|
|
|
|
auto* mul = add->mulExp(0);
|
|
|
|
|
if (mul && mul->unaryExp().size() == 1) {
|
|
|
|
|
auto* unary = mul->unaryExp(0);
|
|
|
|
|
if (unary && !unary->unaryOp() && unary->primaryExp()) {
|
|
|
|
|
auto* primary = unary->primaryExp();
|
|
|
|
|
if (primary && primary->lVar() && primary->lVar()->exp().empty()) {
|
|
|
|
|
auto* lvar = primary->lVar();
|
|
|
|
|
auto* decl = sema_.ResolveVarUse(lvar->Ident());
|
|
|
|
|
if (decl) {
|
|
|
|
|
// 检查是否是数组参数(storage_map_ 里存的是指针)
|
|
|
|
|
auto it = storage_map_.find(decl);
|
|
|
|
|
if (it != storage_map_.end()) {
|
|
|
|
|
auto* val = it->second;
|
|
|
|
|
if (val && (val->IsPtrInt32() || val->IsPtrFloat32())) {
|
|
|
|
|
// 检查是否是 Argument(数组参数,直接传指针)
|
|
|
|
|
if (dynamic_cast<ir::Argument*>(val)) {
|
|
|
|
|
arg = val;
|
|
|
|
|
} else if (array_dims_.count(decl)) {
|
|
|
|
|
// 本地数组(含 dims 记录):传首元素地址
|
|
|
|
|
arg = builder_.CreateGep(val, builder_.CreateConstInt(0),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 检查全局数组
|
|
|
|
|
if (!arg) {
|
|
|
|
|
auto git = global_storage_map_.find(decl);
|
|
|
|
|
if (git != global_storage_map_.end()) {
|
|
|
|
|
auto* gv = dynamic_cast<ir::GlobalVariable*>(git->second);
|
|
|
|
|
if (gv && gv->IsArray()) {
|
|
|
|
|
arg = builder_.CreateGep(git->second,
|
|
|
|
|
builder_.CreateConstInt(0),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Also handle partially-indexed multi-dim arrays: arr[i] where arr is
|
|
|
|
|
// int arr[M][N] should pass &arr[i*N] as i32*, not load arr[i] as i32.
|
|
|
|
|
if (!arg) {
|
|
|
|
|
auto* add2 = exp->addExp();
|
|
|
|
|
if (add2 && add2->mulExp().size() == 1) {
|
|
|
|
|
auto* mul2 = add2->mulExp(0);
|
|
|
|
|
if (mul2 && mul2->unaryExp().size() == 1) {
|
|
|
|
|
auto* unary2 = mul2->unaryExp(0);
|
|
|
|
|
if (unary2 && !unary2->unaryOp() && unary2->primaryExp()) {
|
|
|
|
|
auto* primary2 = unary2->primaryExp();
|
|
|
|
|
if (primary2 && primary2->lVar() && !primary2->lVar()->exp().empty()) {
|
|
|
|
|
auto* lvar2 = primary2->lVar();
|
|
|
|
|
auto* decl2 = sema_.ResolveVarUse(lvar2->Ident());
|
|
|
|
|
if (decl2) {
|
|
|
|
|
std::vector<int> dims2;
|
|
|
|
|
ir::Value* base2 = nullptr;
|
|
|
|
|
auto it2 = array_dims_.find(decl2);
|
|
|
|
|
if (it2 != array_dims_.end()) {
|
|
|
|
|
dims2 = it2->second;
|
|
|
|
|
auto sit = storage_map_.find(decl2);
|
|
|
|
|
if (sit != storage_map_.end()) base2 = sit->second;
|
|
|
|
|
} else {
|
|
|
|
|
auto git2 = global_array_dims_.find(decl2);
|
|
|
|
|
if (git2 != global_array_dims_.end()) {
|
|
|
|
|
dims2 = git2->second;
|
|
|
|
|
auto gsit = global_storage_map_.find(decl2);
|
|
|
|
|
if (gsit != global_storage_map_.end()) base2 = gsit->second;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Partially indexed: fewer indices than dimensions -> pass pointer
|
|
|
|
|
bool is_param = !dims2.empty() && dims2[0] == -1;
|
|
|
|
|
size_t effective_dims = is_param ? dims2.size() - 1 : dims2.size();
|
|
|
|
|
if (base2 && !dims2.empty() &&
|
|
|
|
|
lvar2->exp().size() < effective_dims + (is_param ? 1 : 0)) {
|
|
|
|
|
arg = EvalLVarAddr(lvar2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!arg) arg = EvalExpr(*exp);
|
|
|
|
|
args.push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模块内已知函数?
|
|
|
|
|
ir::Function* callee = module_.GetFunction(callee_name);
|
|
|
|
|
if (callee) {
|
|
|
|
|
// Coerce args to match parameter types
|
|
|
|
|
for (size_t i = 0; i < args.size() && i < callee->GetNumArgs(); ++i) {
|
|
|
|
|
auto* param = callee->GetArgument(i);
|
|
|
|
|
if (!param || !args[i]) continue;
|
|
|
|
|
if (param->IsInt32() && args[i]->IsFloat32()) {
|
|
|
|
|
args[i] = ToInt(args[i]);
|
|
|
|
|
} else if (param->IsFloat32() && args[i]->IsInt32()) {
|
|
|
|
|
args[i] = ToFloat(args[i]);
|
|
|
|
|
} else if (param->IsInt32() && args[i]->IsInt1()) {
|
|
|
|
|
args[i] = ToI32(args[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::string ret_name =
|
|
|
|
|
callee->IsVoidReturn() ? "" : module_.GetContext().NextTemp();
|
|
|
|
|
auto* call =
|
|
|
|
|
@ -246,15 +363,28 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
|
|
|
|
|
|
|
|
|
|
// 外部函数
|
|
|
|
|
EnsureExternalDecl(callee_name);
|
|
|
|
|
// 获取返回类型
|
|
|
|
|
// 获取返回类型和参数类型
|
|
|
|
|
std::shared_ptr<ir::Type> ret_type = ir::Type::GetInt32Type();
|
|
|
|
|
std::vector<std::shared_ptr<ir::Type>> param_types;
|
|
|
|
|
for (const auto& decl : module_.GetExternalDecls()) {
|
|
|
|
|
if (decl.name == callee_name) {
|
|
|
|
|
ret_type = decl.ret_type;
|
|
|
|
|
param_types = decl.param_types;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool is_void = ret_type->IsVoid();
|
|
|
|
|
// Coerce args to match external function parameter types
|
|
|
|
|
for (size_t i = 0; i < args.size() && i < param_types.size(); ++i) {
|
|
|
|
|
if (!args[i]) continue;
|
|
|
|
|
if (param_types[i]->IsInt32() && args[i]->IsFloat32()) {
|
|
|
|
|
args[i] = ToInt(args[i]);
|
|
|
|
|
} else if (param_types[i]->IsFloat32() && args[i]->IsInt32()) {
|
|
|
|
|
args[i] = ToFloat(args[i]);
|
|
|
|
|
} else if (param_types[i]->IsInt32() && args[i]->IsInt1()) {
|
|
|
|
|
args[i] = ToI32(args[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::string ret_name = is_void ? "" : module_.GetContext().NextTemp();
|
|
|
|
|
auto* call = builder_.CreateCallExternal(callee_name, ret_type,
|
|
|
|
|
std::move(args), ret_name);
|
|
|
|
|
@ -331,40 +461,26 @@ ir::Value* IRGenImpl::EvalLVarAddr(SysYParser::LVarContext* ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("irgen", "数组索引维度过多"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir::Value* offset = builder_.CreateConstInt(0);
|
|
|
|
|
ir::Value* offset = nullptr;
|
|
|
|
|
|
|
|
|
|
if (is_array_param) {
|
|
|
|
|
// 数组参数:dims[0]=-1, dims[1..n]是已知维度
|
|
|
|
|
// 索引:indices[0]对应第一维,indices[1]对应第二维...
|
|
|
|
|
for (size_t i = 0; i < indices.size(); ++i) {
|
|
|
|
|
ir::Value* idx = EvalExpr(*indices[i]);
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
// 第一维:stride = dims[1] * dims[2] * ... (如果有的话)
|
|
|
|
|
int stride = 1;
|
|
|
|
|
for (size_t j = 1; j < dims.size(); ++j) {
|
|
|
|
|
stride *= dims[j];
|
|
|
|
|
}
|
|
|
|
|
if (stride > 1) {
|
|
|
|
|
ir::Value* scaled = builder_.CreateMul(
|
|
|
|
|
idx, builder_.CreateConstInt(stride),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
offset = builder_.CreateAdd(offset, scaled,
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
} else {
|
|
|
|
|
offset = builder_.CreateAdd(offset, idx,
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
int stride = 1;
|
|
|
|
|
size_t start = (i == 0) ? 1 : i + 1;
|
|
|
|
|
for (size_t j = start; j < dims.size(); ++j) stride *= dims[j];
|
|
|
|
|
ir::Value* term;
|
|
|
|
|
if (stride == 1) {
|
|
|
|
|
term = idx;
|
|
|
|
|
} else {
|
|
|
|
|
// 后续维度
|
|
|
|
|
int stride = 1;
|
|
|
|
|
for (size_t j = i + 1; j < dims.size(); ++j) {
|
|
|
|
|
stride *= dims[j];
|
|
|
|
|
}
|
|
|
|
|
ir::Value* scaled = builder_.CreateMul(
|
|
|
|
|
idx, builder_.CreateConstInt(stride),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
offset = builder_.CreateAdd(offset, scaled,
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
term = builder_.CreateMul(idx, builder_.CreateConstInt(stride),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
if (!offset) {
|
|
|
|
|
offset = term;
|
|
|
|
|
} else {
|
|
|
|
|
offset = builder_.CreateAdd(offset, term, module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@ -374,15 +490,24 @@ ir::Value* IRGenImpl::EvalLVarAddr(SysYParser::LVarContext* ctx) {
|
|
|
|
|
stride = (i == (int)dims.size() - 1) ? 1 : stride * dims[i + 1];
|
|
|
|
|
if (i < (int)indices.size()) {
|
|
|
|
|
ir::Value* idx = EvalExpr(*indices[i]);
|
|
|
|
|
ir::Value* scaled = builder_.CreateMul(
|
|
|
|
|
idx, builder_.CreateConstInt(stride),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
offset = builder_.CreateAdd(offset, scaled,
|
|
|
|
|
ir::Value* term;
|
|
|
|
|
if (stride == 1) {
|
|
|
|
|
term = idx;
|
|
|
|
|
} else {
|
|
|
|
|
term = builder_.CreateMul(idx, builder_.CreateConstInt(stride),
|
|
|
|
|
module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
if (!offset) {
|
|
|
|
|
offset = term;
|
|
|
|
|
} else {
|
|
|
|
|
offset = builder_.CreateAdd(offset, term, module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!offset) offset = builder_.CreateConstInt(0);
|
|
|
|
|
|
|
|
|
|
return builder_.CreateGep(base, offset, module_.GetContext().NextTemp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -486,8 +611,8 @@ std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) {
|
|
|
|
|
ir::Value* res_ext = ToI32(result);
|
|
|
|
|
builder_.CreateStore(res_ext, res_slot);
|
|
|
|
|
|
|
|
|
|
ir::BasicBlock* rhs_bb = func_->CreateBlock(module_.GetContext().NextTemp() + ".or.rhs");
|
|
|
|
|
ir::BasicBlock* end_bb = func_->CreateBlock(module_.GetContext().NextTemp() + ".or.end");
|
|
|
|
|
ir::BasicBlock* rhs_bb = func_->CreateBlock(module_.GetContext().NextLabel() + ".or.rhs");
|
|
|
|
|
ir::BasicBlock* end_bb = func_->CreateBlock(module_.GetContext().NextLabel() + ".or.end");
|
|
|
|
|
builder_.CreateCondBr(result, end_bb, rhs_bb);
|
|
|
|
|
|
|
|
|
|
builder_.SetInsertPoint(rhs_bb);
|
|
|
|
|
@ -498,6 +623,7 @@ std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) {
|
|
|
|
|
builder_.CreateBr(end_bb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func_->MoveBlockToEnd(end_bb);
|
|
|
|
|
builder_.SetInsertPoint(end_bb);
|
|
|
|
|
result = ToI1(builder_.CreateLoad(res_slot, module_.GetContext().NextTemp()));
|
|
|
|
|
}
|
|
|
|
|
@ -523,8 +649,8 @@ std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) {
|
|
|
|
|
ir::Value* res_ext = ToI32(result);
|
|
|
|
|
builder_.CreateStore(res_ext, res_slot);
|
|
|
|
|
|
|
|
|
|
ir::BasicBlock* rhs_bb = func_->CreateBlock(module_.GetContext().NextTemp() + ".and.rhs");
|
|
|
|
|
ir::BasicBlock* end_bb = func_->CreateBlock(module_.GetContext().NextTemp() + ".and.end");
|
|
|
|
|
ir::BasicBlock* rhs_bb = func_->CreateBlock(module_.GetContext().NextLabel() + ".and.rhs");
|
|
|
|
|
ir::BasicBlock* end_bb = func_->CreateBlock(module_.GetContext().NextLabel() + ".and.end");
|
|
|
|
|
builder_.CreateCondBr(result, rhs_bb, end_bb);
|
|
|
|
|
|
|
|
|
|
builder_.SetInsertPoint(rhs_bb);
|
|
|
|
|
@ -535,6 +661,7 @@ std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) {
|
|
|
|
|
builder_.CreateBr(end_bb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func_->MoveBlockToEnd(end_bb);
|
|
|
|
|
builder_.SetInsertPoint(end_bb);
|
|
|
|
|
result = ToI1(builder_.CreateLoad(res_slot, module_.GetContext().NextTemp()));
|
|
|
|
|
}
|
|
|
|
|
|