You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

697 lines
23 KiB

#include "irgen/IRGen.h"
#include <cstdlib>
#include <stdexcept>
#include <utility>
bool IRGenImpl::IsNumeric(const TypedValue& value) const {
return !value.is_array && value.type != SemanticType::Void;
}
bool IRGenImpl::IsSameDims(const std::vector<int>& lhs,
const std::vector<int>& 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<float>(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<int>(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<int>(value.float_value);
value.type = SemanticType::Int;
return value;
}
value.float_value = static_cast<float>(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<int>(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<float>(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<int>(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<float>(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<int>(operand.float_value);
} else {
operand.int_value = -operand.int_value;
operand.float_value = static_cast<float>(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<float>(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<int> 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<ir::Value*> args;
std::vector<SysYParser::ExpContext*> 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<ir::Value*> 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<int> 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<long long>(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<long long>(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<int> 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<int>& dims, const std::vector<ir::Value*>& indices,
const antlr4::ParserRuleContext* ctx) {
if (base_addr == nullptr) {
ThrowError(ctx, "???????");
}
if (indices.empty()) {
return base_addr;
}
std::vector<ir::Value*> 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);
}