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
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);
|
|
}
|