#include "irgen/IRGen.h" #include #include #include bool IRGenImpl::IsNumeric(const TypedValue& value) const { return !value.is_array && value.type != SemanticType::Void; } bool IRGenImpl::IsSameDims(const std::vector& lhs, const std::vector& rhs) const { if (rhs.empty()) { return true; } if (lhs == rhs) { return true; } if (lhs.size() == rhs.size() + 1) { return std::equal(lhs.begin() + 1, lhs.end(), rhs.begin()); } return false; } IRGenImpl::TypedValue IRGenImpl::CastScalar( TypedValue value, SemanticType target_type, const antlr4::ParserRuleContext* ctx) { if (value.is_array) { ThrowError(ctx, "????????????"); } if (target_type == SemanticType::Void || value.type == SemanticType::Void) { ThrowError(ctx, "void ?????????"); } if (target_type == SemanticType::Int) { if (value.type == SemanticType::Int) { if (value.value->GetType()->IsInt1()) { value.value = builder_.CreateZext(value.value, ir::Type::GetInt32Type(), NextTemp()); } value.type = SemanticType::Int; return value; } value.value = builder_.CreateFtoI(value.value, NextTemp()); value.type = SemanticType::Int; return value; } if (target_type == SemanticType::Float) { if (value.type == SemanticType::Float) { return value; } if (value.value->GetType()->IsInt1()) { value.value = builder_.CreateZext(value.value, ir::Type::GetInt32Type(), NextTemp()); } value.value = builder_.CreateIToF(value.value, NextTemp()); value.type = SemanticType::Float; return value; } ThrowError(ctx, "????????????"); } ir::Value* IRGenImpl::CastToCondition(TypedValue value, const antlr4::ParserRuleContext* ctx) { if (value.is_array) { ThrowError(ctx, "?????????"); } if (value.type == SemanticType::Void) { ThrowError(ctx, "void ???????"); } if (value.value->GetType()->IsInt1()) { return value.value; } if (value.type == SemanticType::Int) { return builder_.CreateICmp(ir::Opcode::ICmpNE, value.value, builder_.CreateConstInt(0), NextTemp()); } return builder_.CreateFCmp(ir::Opcode::FCmpNE, value.value, builder_.CreateConstFloat(0.0f), NextTemp()); } IRGenImpl::TypedValue IRGenImpl::NormalizeLogicalValue( TypedValue value, const antlr4::ParserRuleContext* ctx) { auto* cond = CastToCondition(value, ctx); return {builder_.CreateZext(cond, ir::Type::GetInt32Type(), NextTemp()), SemanticType::Int, false, {}}; } ConstantValue IRGenImpl::ParseNumber(SysYParser::NumberContext& ctx) const { ConstantValue value; if (ctx.IntConst() != nullptr) { value.type = SemanticType::Int; value.int_value = std::stoi(ctx.getText(), nullptr, 0); value.float_value = static_cast(value.int_value); return value; } if (ctx.FloatConst() != nullptr) { value.type = SemanticType::Float; value.float_value = std::strtof(ctx.getText().c_str(), nullptr); value.int_value = static_cast(value.float_value); return value; } ThrowError(&ctx, "?????????"); } ConstantValue IRGenImpl::ConvertConst(ConstantValue value, SemanticType target_type) const { if (target_type == SemanticType::Void) { throw std::runtime_error("void is not a valid constant target type"); } if (value.type == target_type) { return value; } if (target_type == SemanticType::Int) { value.int_value = static_cast(value.float_value); value.type = SemanticType::Int; return value; } value.float_value = static_cast(value.int_value); value.type = SemanticType::Float; return value; } ConstantValue IRGenImpl::EvalConstExp(SysYParser::ExpContext& ctx) { return EvalConstAddExp(*ctx.addExp()); } ConstantValue IRGenImpl::EvalConstAddExp(SysYParser::AddExpContext& ctx) { if (ctx.addExp() == nullptr) { return EvalConstMulExp(*ctx.mulExp()); } auto lhs = EvalConstAddExp(*ctx.addExp()); auto rhs = EvalConstMulExp(*ctx.mulExp()); if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = ConvertConst(lhs, SemanticType::Float); rhs = ConvertConst(rhs, SemanticType::Float); lhs.float_value = ctx.op->getType() == SysYParser::ADD ? lhs.float_value + rhs.float_value : lhs.float_value - rhs.float_value; lhs.int_value = static_cast(lhs.float_value); lhs.type = SemanticType::Float; return lhs; } lhs.int_value = ctx.op->getType() == SysYParser::ADD ? lhs.int_value + rhs.int_value : lhs.int_value - rhs.int_value; lhs.float_value = static_cast(lhs.int_value); lhs.type = SemanticType::Int; return lhs; } ConstantValue IRGenImpl::EvalConstMulExp(SysYParser::MulExpContext& ctx) { if (ctx.mulExp() == nullptr) { return EvalConstUnaryExp(*ctx.unaryExp()); } auto lhs = EvalConstMulExp(*ctx.mulExp()); auto rhs = EvalConstUnaryExp(*ctx.unaryExp()); if (ctx.op->getType() == SysYParser::MOD && (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float)) { ThrowError(&ctx, "?????? % ??"); } if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = ConvertConst(lhs, SemanticType::Float); rhs = ConvertConst(rhs, SemanticType::Float); switch (ctx.op->getType()) { case SysYParser::MUL: lhs.float_value *= rhs.float_value; break; case SysYParser::DIV: lhs.float_value /= rhs.float_value; break; default: ThrowError(&ctx, "??????????"); } lhs.int_value = static_cast(lhs.float_value); lhs.type = SemanticType::Float; return lhs; } switch (ctx.op->getType()) { case SysYParser::MUL: lhs.int_value *= rhs.int_value; break; case SysYParser::DIV: lhs.int_value /= rhs.int_value; break; case SysYParser::MOD: lhs.int_value %= rhs.int_value; break; default: ThrowError(&ctx, "????????"); } lhs.float_value = static_cast(lhs.int_value); lhs.type = SemanticType::Int; return lhs; } ConstantValue IRGenImpl::EvalConstUnaryExp(SysYParser::UnaryExpContext& ctx) { if (ctx.primaryExp() != nullptr) { return EvalConstPrimaryExp(*ctx.primaryExp()); } if (ctx.Ident() != nullptr) { ThrowError(&ctx, "?????????????"); } auto operand = EvalConstUnaryExp(*ctx.unaryExp()); if (ctx.unaryOp()->ADD() != nullptr) { return operand; } if (ctx.unaryOp()->SUB() != nullptr) { if (operand.type == SemanticType::Float) { operand.float_value = -operand.float_value; operand.int_value = static_cast(operand.float_value); } else { operand.int_value = -operand.int_value; operand.float_value = static_cast(operand.int_value); } return operand; } if (ctx.unaryOp()->NOT() != nullptr) { const bool truthy = operand.type == SemanticType::Float ? operand.float_value != 0.0f : operand.int_value != 0; ConstantValue result; result.type = SemanticType::Int; result.int_value = truthy ? 0 : 1; result.float_value = static_cast(result.int_value); return result; } ThrowError(&ctx, "???????"); } ConstantValue IRGenImpl::EvalConstPrimaryExp(SysYParser::PrimaryExpContext& ctx) { if (ctx.exp() != nullptr) { return EvalConstExp(*ctx.exp()); } if (ctx.number() != nullptr) { return ParseNumber(*ctx.number()); } if (ctx.lVal() != nullptr) { return EvalConstLVal(*ctx.lVal()); } ThrowError(&ctx, "???? primaryExp"); } ConstantValue IRGenImpl::EvalConstLVal(SysYParser::LValContext& ctx) { const auto name = ExpectIdent(ctx, ctx.Ident()); auto* symbol = symbols_.Lookup(name); if (symbol == nullptr) { ThrowError(&ctx, "?????: " + name); } if (!symbol->is_const) { ThrowError(&ctx, "?????????????: " + name); } if (!symbol->is_array) { if (!ctx.exp().empty()) { ThrowError(&ctx, "??????????"); } if (!symbol->const_scalar.has_value()) { ThrowError(&ctx, "?????: " + name); } return *symbol->const_scalar; } if (ctx.exp().size() != symbol->dims.size()) { ThrowError(&ctx, "???????????????????: " + name); } std::vector indices; indices.reserve(ctx.exp().size()); for (auto* exp_ctx : ctx.exp()) { auto index = ConvertConst(EvalConstExp(*exp_ctx), SemanticType::Int); indices.push_back(index.int_value); } for (size_t i = 0; i < indices.size(); ++i) { if (indices[i] < 0 || indices[i] >= symbol->dims[i]) { ThrowError(&ctx, "????????: " + name); } } const auto offset = FlattenIndices(symbol->dims, indices); if (symbol->const_array_all_zero) { return ZeroConst(symbol->type); } if (offset >= symbol->const_array.size()) { ThrowError(&ctx, "???????????: " + name); } return symbol->const_array[offset]; } IRGenImpl::TypedValue IRGenImpl::EmitExp(SysYParser::ExpContext& ctx) { return EmitAddExp(*ctx.addExp()); } IRGenImpl::TypedValue IRGenImpl::EmitAddExp(SysYParser::AddExpContext& ctx) { if (ctx.addExp() == nullptr) { return EmitMulExp(*ctx.mulExp()); } auto lhs = EmitAddExp(*ctx.addExp()); auto rhs = EmitMulExp(*ctx.mulExp()); if (!IsNumeric(lhs) || !IsNumeric(rhs)) { ThrowError(&ctx, "???????????"); } if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = CastScalar(lhs, SemanticType::Float, &ctx); rhs = CastScalar(rhs, SemanticType::Float, &ctx); auto* value = ctx.op->getType() == SysYParser::ADD ? builder_.CreateBinary(ir::Opcode::FAdd, lhs.value, rhs.value, NextTemp()) : builder_.CreateBinary(ir::Opcode::FSub, lhs.value, rhs.value, NextTemp()); return {value, SemanticType::Float, false, {}}; } lhs = CastScalar(lhs, SemanticType::Int, &ctx); rhs = CastScalar(rhs, SemanticType::Int, &ctx); auto* value = ctx.op->getType() == SysYParser::ADD ? builder_.CreateAdd(lhs.value, rhs.value, NextTemp()) : builder_.CreateSub(lhs.value, rhs.value, NextTemp()); return {value, SemanticType::Int, false, {}}; } IRGenImpl::TypedValue IRGenImpl::EmitMulExp(SysYParser::MulExpContext& ctx) { if (ctx.mulExp() == nullptr) { return EmitUnaryExp(*ctx.unaryExp()); } auto lhs = EmitMulExp(*ctx.mulExp()); auto rhs = EmitUnaryExp(*ctx.unaryExp()); if (!IsNumeric(lhs) || !IsNumeric(rhs)) { ThrowError(&ctx, "????????????"); } if (ctx.op->getType() == SysYParser::MOD && (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float)) { ThrowError(&ctx, "?????? % ??"); } if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = CastScalar(lhs, SemanticType::Float, &ctx); rhs = CastScalar(rhs, SemanticType::Float, &ctx); ir::Opcode opcode = ir::Opcode::FMul; if (ctx.op->getType() == SysYParser::DIV) { opcode = ir::Opcode::FDiv; } else if (ctx.op->getType() == SysYParser::MUL) { opcode = ir::Opcode::FMul; } else { ThrowError(&ctx, "?????????"); } return {builder_.CreateBinary(opcode, lhs.value, rhs.value, NextTemp()), SemanticType::Float, false, {}}; } lhs = CastScalar(lhs, SemanticType::Int, &ctx); rhs = CastScalar(rhs, SemanticType::Int, &ctx); ir::Value* value = nullptr; switch (ctx.op->getType()) { case SysYParser::MUL: value = builder_.CreateMul(lhs.value, rhs.value, NextTemp()); break; case SysYParser::DIV: value = builder_.CreateDiv(lhs.value, rhs.value, NextTemp()); break; case SysYParser::MOD: value = builder_.CreateRem(lhs.value, rhs.value, NextTemp()); break; default: ThrowError(&ctx, "???????"); } return {value, SemanticType::Int, false, {}}; } IRGenImpl::TypedValue IRGenImpl::EmitUnaryExp(SysYParser::UnaryExpContext& ctx) { if (ctx.primaryExp() != nullptr) { return EmitPrimaryExp(*ctx.primaryExp()); } if (ctx.Ident() != nullptr) { const auto name = ExpectIdent(ctx, ctx.Ident()); auto* symbol = symbols_.Lookup(name); if (symbol == nullptr || symbol->kind != SymbolKind::Function || symbol->function == nullptr) { ThrowError(&ctx, "????????: " + name); } const auto& function_type = symbol->function_type; std::vector args; std::vector arg_exprs; if (ctx.funcRParams() != nullptr) { arg_exprs = ctx.funcRParams()->exp(); } if (arg_exprs.size() != function_type.param_types.size()) { ThrowError(&ctx, "?????????: " + name); } for (size_t i = 0; i < arg_exprs.size(); ++i) { auto arg = EmitExp(*arg_exprs[i]); if (i < function_type.param_is_array.size() && function_type.param_is_array[i]) { if (!arg.is_array || !IsSameDims(arg.dims, function_type.param_dims[i])) { ThrowError(arg_exprs[i], "????????????: " + name); } args.push_back(arg.value); } else { if (arg.is_array) { ThrowError(arg_exprs[i], "??????????: " + name); } arg = CastScalar(arg, function_type.param_types[i], arg_exprs[i]); args.push_back(arg.value); } } if (function_type.return_type == SemanticType::Void) { builder_.CreateCall(symbol->function, args); return {nullptr, SemanticType::Void, false, {}}; } return {builder_.CreateCall(symbol->function, args, NextTemp()), function_type.return_type, false, {}}; } auto operand = EmitUnaryExp(*ctx.unaryExp()); if (!IsNumeric(operand)) { ThrowError(&ctx, "???????????"); } if (ctx.unaryOp()->ADD() != nullptr) { return operand; } if (ctx.unaryOp()->SUB() != nullptr) { if (operand.type == SemanticType::Float) { return {builder_.CreateFNeg(operand.value, NextTemp()), SemanticType::Float, false, {}}; } operand = CastScalar(operand, SemanticType::Int, &ctx); return {builder_.CreateSub(builder_.CreateConstInt(0), operand.value, NextTemp()), SemanticType::Int, false, {}}; } if (ctx.unaryOp()->NOT() != nullptr) { auto* cond = CastToCondition(operand, &ctx); auto* inverted = builder_.CreateXor(cond, builder_.CreateConstBool(true), NextTemp()); return {builder_.CreateZext(inverted, ir::Type::GetInt32Type(), NextTemp()), SemanticType::Int, false, {}}; } ThrowError(&ctx, "???????"); } IRGenImpl::TypedValue IRGenImpl::EmitPrimaryExp(SysYParser::PrimaryExpContext& ctx) { if (ctx.exp() != nullptr) { return EmitExp(*ctx.exp()); } if (ctx.number() != nullptr) { auto number = ParseNumber(*ctx.number()); return {CreateTypedConstant(number), number.type, false, {}}; } if (ctx.lVal() != nullptr) { return EmitLValValue(*ctx.lVal()); } ThrowError(&ctx, "?? primaryExp"); } IRGenImpl::TypedValue IRGenImpl::EmitRelExp(SysYParser::RelExpContext& ctx) { if (ctx.relExp() == nullptr) { return EmitAddExp(*ctx.addExp()); } auto lhs = EmitRelExp(*ctx.relExp()); auto rhs = EmitAddExp(*ctx.addExp()); if (!IsNumeric(lhs) || !IsNumeric(rhs)) { ThrowError(&ctx, "???????????"); } if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = CastScalar(lhs, SemanticType::Float, &ctx); rhs = CastScalar(rhs, SemanticType::Float, &ctx); ir::Opcode opcode = ir::Opcode::FCmpLT; switch (ctx.op->getType()) { case SysYParser::LT: opcode = ir::Opcode::FCmpLT; break; case SysYParser::GT: opcode = ir::Opcode::FCmpGT; break; case SysYParser::LE: opcode = ir::Opcode::FCmpLE; break; case SysYParser::GE: opcode = ir::Opcode::FCmpGE; break; default: ThrowError(&ctx, "????????"); } return {builder_.CreateFCmp(opcode, lhs.value, rhs.value, NextTemp()), SemanticType::Int, false, {}}; } lhs = CastScalar(lhs, SemanticType::Int, &ctx); rhs = CastScalar(rhs, SemanticType::Int, &ctx); ir::Opcode opcode = ir::Opcode::ICmpLT; switch (ctx.op->getType()) { case SysYParser::LT: opcode = ir::Opcode::ICmpLT; break; case SysYParser::GT: opcode = ir::Opcode::ICmpGT; break; case SysYParser::LE: opcode = ir::Opcode::ICmpLE; break; case SysYParser::GE: opcode = ir::Opcode::ICmpGE; break; default: ThrowError(&ctx, "????????"); } return {builder_.CreateICmp(opcode, lhs.value, rhs.value, NextTemp()), SemanticType::Int, false, {}}; } IRGenImpl::TypedValue IRGenImpl::EmitEqExp(SysYParser::EqExpContext& ctx) { if (ctx.eqExp() == nullptr) { return EmitRelExp(*ctx.relExp()); } auto lhs = EmitEqExp(*ctx.eqExp()); auto rhs = EmitRelExp(*ctx.relExp()); if (!IsNumeric(lhs) || !IsNumeric(rhs)) { ThrowError(&ctx, "???????????"); } if (lhs.type == SemanticType::Float || rhs.type == SemanticType::Float) { lhs = CastScalar(lhs, SemanticType::Float, &ctx); rhs = CastScalar(rhs, SemanticType::Float, &ctx); const auto opcode = ctx.op->getType() == SysYParser::EQ ? ir::Opcode::FCmpEQ : ir::Opcode::FCmpNE; return {builder_.CreateFCmp(opcode, lhs.value, rhs.value, NextTemp()), SemanticType::Int, false, {}}; } lhs = CastScalar(lhs, SemanticType::Int, &ctx); rhs = CastScalar(rhs, SemanticType::Int, &ctx); const auto opcode = ctx.op->getType() == SysYParser::EQ ? ir::Opcode::ICmpEQ : ir::Opcode::ICmpNE; return {builder_.CreateICmp(opcode, lhs.value, rhs.value, NextTemp()), SemanticType::Int, false, {}}; } IRGenImpl::LValueInfo IRGenImpl::ResolveLVal(SysYParser::LValContext& ctx) { const auto name = ExpectIdent(ctx, ctx.Ident()); auto* symbol = symbols_.Lookup(name); if (symbol == nullptr) { ThrowError(&ctx, "?????????: " + name); } if (symbol->kind == SymbolKind::Function) { ThrowError(&ctx, "????????: " + name); } std::vector index_values; index_values.reserve(ctx.exp().size()); for (auto* exp_ctx : ctx.exp()) { auto index = CastScalar(EmitExp(*exp_ctx), SemanticType::Int, exp_ctx); if (index.is_array) { ThrowError(exp_ctx, "????????"); } index_values.push_back(index.value); } if (!symbol->is_array) { if (!index_values.empty()) { ThrowError(&ctx, "??????????: " + name); } return {symbol, symbol->ir_value, symbol->type, false, {}, false}; } std::vector selected_dims; if (symbol->is_param_array) { if (index_values.size() > symbol->dims.size() + 1) { ThrowError(&ctx, "????????: " + name); } if (index_values.empty()) { selected_dims = symbol->dims; } else if (index_values.size() <= 1) { selected_dims = symbol->dims; } else { selected_dims.assign(symbol->dims.begin() + static_cast(index_values.size() - 1), symbol->dims.end()); } } else { if (index_values.size() > symbol->dims.size()) { ThrowError(&ctx, "??????: " + name); } selected_dims.assign(symbol->dims.begin() + static_cast(index_values.size()), symbol->dims.end()); } ir::Value* addr = symbol->ir_value; if (!index_values.empty()) { addr = CreateArrayElementAddr(symbol->ir_value, symbol->is_param_array, symbol->type, symbol->dims, index_values, &ctx); } const bool root_param_array_no_index = symbol->is_param_array && index_values.empty(); const bool still_array = !selected_dims.empty() || root_param_array_no_index; return {symbol, addr, symbol->type, still_array, selected_dims, root_param_array_no_index}; } ir::Value* IRGenImpl::GenLValAddr(SysYParser::LValContext& ctx) { auto info = ResolveLVal(ctx); if (info.is_array) { ThrowError(&ctx, "?????????????"); } return info.addr; } IRGenImpl::TypedValue IRGenImpl::EmitLValValue(SysYParser::LValContext& ctx) { auto info = ResolveLVal(ctx); if (!info.is_array) { if (info.symbol != nullptr && info.symbol->const_scalar.has_value()) { return {CreateTypedConstant(*info.symbol->const_scalar), info.type, false, {}}; } return {builder_.CreateLoad(info.addr, GetIRScalarType(info.type), NextTemp()), info.type, false, {}}; } if (info.root_param_array_no_index) { return {info.addr, info.type, true, info.dims}; } auto* decayed = builder_.CreateGEP(info.addr, BuildArrayType(info.type, info.dims), {builder_.CreateConstInt(0), builder_.CreateConstInt(0)}, NextTemp()); std::vector decay_dims; if (!info.dims.empty()) { decay_dims.assign(info.dims.begin() + 1, info.dims.end()); } return {decayed, info.type, true, decay_dims}; } ir::Value* IRGenImpl::CreateArrayElementAddr( ir::Value* base_addr, bool is_param_array, SemanticType base_type, const std::vector& dims, const std::vector& indices, const antlr4::ParserRuleContext* ctx) { if (base_addr == nullptr) { ThrowError(ctx, "???????"); } if (indices.empty()) { return base_addr; } std::vector gep_indices; if (!is_param_array) { gep_indices.push_back(builder_.CreateConstInt(0)); } gep_indices.insert(gep_indices.end(), indices.begin(), indices.end()); auto source_type = dims.empty() ? GetIRScalarType(base_type) : BuildArrayType(base_type, dims); return builder_.CreateGEP(base_addr, source_type, gep_indices, NextTemp()); } void IRGenImpl::EmitCond(SysYParser::CondContext& ctx, ir::BasicBlock* true_block, ir::BasicBlock* false_block) { EmitLOrCond(*ctx.lOrExp(), true_block, false_block); } void IRGenImpl::EmitLOrCond(SysYParser::LOrExpContext& ctx, ir::BasicBlock* true_block, ir::BasicBlock* false_block) { if (ctx.lOrExp() == nullptr) { EmitLAndCond(*ctx.lAndExp(), true_block, false_block); return; } auto* rhs_block = current_function_->CreateBlock(NextBlockName("lor.rhs")); EmitLOrCond(*ctx.lOrExp(), true_block, rhs_block); builder_.SetInsertPoint(rhs_block); EmitLAndCond(*ctx.lAndExp(), true_block, false_block); } void IRGenImpl::EmitLAndCond(SysYParser::LAndExpContext& ctx, ir::BasicBlock* true_block, ir::BasicBlock* false_block) { if (ctx.lAndExp() == nullptr) { auto cond = EmitEqExp(*ctx.eqExp()); builder_.CreateCondBr(CastToCondition(cond, &ctx), true_block, false_block); return; } auto* rhs_block = current_function_->CreateBlock(NextBlockName("land.rhs")); EmitLAndCond(*ctx.lAndExp(), rhs_block, false_block); builder_.SetInsertPoint(rhs_block); auto cond = EmitEqExp(*ctx.eqExp()); builder_.CreateCondBr(CastToCondition(cond, &ctx), true_block, false_block); }