#include "irgen/IRGen.h" #include #include #include "SysYParser.h" #include "ir/IR.h" #include "utils/Log.h" namespace { std::shared_ptr BaseTypeFromDecl(SysYParser::BtypeContext* btype) { return (btype && btype->FLOAT()) ? ir::Type::GetFloatType() : ir::Type::GetInt32Type(); } std::shared_ptr StorageType(std::shared_ptr ty) { if (ty->IsInt32()) return ir::Type::GetPtrInt32Type(); if (ty->IsFloat()) return ir::Type::GetPtrFloatType(); return ty; } size_t CountScalars(const std::shared_ptr& ty) { if (!ty->IsArray()) return 1; auto arr_ty = ty->GetAsArrayType(); return arr_ty->GetNumElements() * CountScalars(arr_ty->GetElementType()); } } // namespace void IRGenImpl::ZeroInitializeLocal(ir::Value* ptr, std::shared_ptr ty) { if (ty->IsArray()) { auto arr_ty = ty->GetAsArrayType(); for (uint32_t i = 0; i < arr_ty->GetNumElements(); ++i) { auto* elem_ptr = builder_.CreateGEP(StorageType(arr_ty->GetElementType()), ptr, {builder_.CreateConstInt(0), builder_.CreateConstInt(static_cast(i))}, module_.GetContext().NextTemp()); ZeroInitializeLocal(elem_ptr, arr_ty->GetElementType()); } return; } ir::Value* zero = ty->IsFloat() ? static_cast(builder_.CreateConstFloat(0.0f)) : static_cast(builder_.CreateConstInt(0)); builder_.CreateStore(zero, ptr); } void IRGenImpl::EmitLocalInitValue(ir::Value* ptr, std::shared_ptr ty, SysYParser::InitValueContext* init) { if (!init) return; auto build_flat_scalar_ptr = [&](ir::Value* base_ptr, const std::shared_ptr& base_ty, size_t flat_index) -> ir::Value* { if (!base_ty->IsArray()) return base_ptr; std::vector indices; indices.push_back(builder_.CreateConstInt(0)); auto cur_ty = base_ty; size_t offset = flat_index; while (cur_ty->IsArray()) { auto arr_ty = cur_ty->GetAsArrayType(); const size_t step = CountScalars(arr_ty->GetElementType()); const size_t idx = step == 0 ? 0 : offset / step; offset = step == 0 ? 0 : offset % step; indices.push_back(builder_.CreateConstInt(static_cast(idx))); cur_ty = arr_ty->GetElementType(); } return builder_.CreateGEP(StorageType(cur_ty), base_ptr, indices, module_.GetContext().NextTemp()); }; if (ty->IsArray()) { auto arr_ty = ty->GetAsArrayType(); const auto elem_ty = arr_ty->GetElementType(); const size_t elem_step = CountScalars(elem_ty); if (init->exp()) { auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, 0); EmitLocalInitValue(elem_ptr, elem_ty, init); return; } const auto& children = init->initValue(); size_t scalar_cursor = 0; for (auto* child : children) { if (scalar_cursor >= CountScalars(ty)) break; if (child->exp()) { auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, scalar_cursor); auto scalar_ty = elem_ty; while (scalar_ty->IsArray()) { scalar_ty = scalar_ty->GetAsArrayType()->GetElementType(); } EmitLocalInitValue(elem_ptr, scalar_ty, child); ++scalar_cursor; continue; } const size_t elem_index = elem_step == 0 ? 0 : scalar_cursor / elem_step; if (elem_index >= arr_ty->GetNumElements()) break; auto* elem_ptr = builder_.CreateGEP(StorageType(elem_ty), ptr, {builder_.CreateConstInt(0), builder_.CreateConstInt(static_cast(elem_index))}, module_.GetContext().NextTemp()); EmitLocalInitValue(elem_ptr, elem_ty, child); scalar_cursor = (elem_index + 1) * elem_step; } return; } if (!init->exp()) { return; } ir::Value* value = EvalExpr(*init->exp()); if (ty->IsFloat() && value->GetType()->IsInt32()) { value = builder_.CreateSIToFP(value, ty, module_.GetContext().NextTemp()); } else if (ty->IsInt32() && value->GetType()->IsFloat()) { value = builder_.CreateFPToSI(value, ty, module_.GetContext().NextTemp()); } builder_.CreateStore(value, ptr); } std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) { if (ctx->constDecl()) return ctx->constDecl()->accept(this); if (ctx->varDecl()) return ctx->varDecl()->accept(this); return {}; } std::any IRGenImpl::visitConstDecl(SysYParser::ConstDeclContext* ctx) { for (auto* def : ctx->constDef()) { def->accept(this); } return {}; } std::any IRGenImpl::visitVarDecl(SysYParser::VarDeclContext* ctx) { for (auto* def : ctx->varDef()) { def->accept(this); } return {}; } std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) { const std::string name = ctx->ID()->getText(); auto ty = BaseTypeFromDecl( dynamic_cast(ctx->parent)->btype()); const auto dims = ctx->exp(); for (auto it = dims.rbegin(); it != dims.rend(); ++it) { auto* dim = EvalConstExpr(**it); if (auto* ci = dynamic_cast(dim)) { ty = ir::ArrayType::Get(ty, ci->GetValue()); continue; } throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量")); } ir::Value* slot = nullptr; if (is_global_scope_) { ir::ConstantValue* init = nullptr; if (ctx->initValue() && ctx->initValue()->exp()) { init = EvalConstExpr(*ctx->initValue()->exp()); if (ty->IsInt32() && init->GetType()->IsFloat()) { init = module_.GetContext().GetConstInt( static_cast(static_cast(init)->GetValue())); } else if (ty->IsFloat() && init->GetType()->IsInt32()) { init = module_.GetContext().GetConstFloat( static_cast(static_cast(init)->GetValue())); } } slot = module_.CreateGlobalValue(name, StorageType(ty), init); } else { slot = builder_.CreateAlloca(StorageType(ty), name); ZeroInitializeLocal(slot, ty); EmitLocalInitValue(slot, ty, ctx->initValue()); } storage_map_[ctx] = slot; return {}; } std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) { const std::string name = ctx->ID()->getText(); auto ty = BaseTypeFromDecl( dynamic_cast(ctx->parent)->btype()); const auto dims = ctx->exp(); for (auto it = dims.rbegin(); it != dims.rend(); ++it) { auto* dim = EvalConstExpr(**it); if (auto* ci = dynamic_cast(dim)) { ty = ir::ArrayType::Get(ty, ci->GetValue()); continue; } throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量")); } ir::Value* slot = nullptr; if (is_global_scope_) { ir::ConstantValue* init = nullptr; if (ctx->initValue() && ctx->initValue()->exp()) { init = EvalConstExpr(*ctx->initValue()->exp()); if (ty->IsInt32() && init->GetType()->IsFloat()) { init = module_.GetContext().GetConstInt( static_cast(static_cast(init)->GetValue())); } else if (ty->IsFloat() && init->GetType()->IsInt32()) { init = module_.GetContext().GetConstFloat( static_cast(static_cast(init)->GetValue())); } } slot = module_.CreateGlobalValue(name, StorageType(ty), init); } else { slot = builder_.CreateAlloca(StorageType(ty), name); if (ctx->initValue()) { ZeroInitializeLocal(slot, ty); EmitLocalInitValue(slot, ty, ctx->initValue()); } } storage_map_[ctx] = slot; return {}; }