Compare commits

..

No commits in common. "7f57098eb311b385604c57661b1f3e8ffcfed976" and "06231f466a174b146d034c6e5dfe99e47c1f47ea" have entirely different histories.

5 changed files with 52 additions and 110 deletions

View File

@ -35,14 +35,14 @@ namespace types {
bool_ty bool_ty
}) { }) {
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::Add, ty, ty, false, ty, types::BinOp::Add, ty, ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateAdd(lhs, rhs, "add"); return builder.builder->CreateAdd(lhs, rhs, "add");
}, },
}); });
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::Sub, ty, ty, false, ty, types::BinOp::Sub, ty, ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateSub(lhs, rhs, "sub"); return builder.builder->CreateSub(lhs, rhs, "sub");
}, },
@ -54,14 +54,14 @@ namespace types {
short_int_ty, int_ty, long_int_ty, long_long_int_ty, char_ty, short_int_ty, int_ty, long_int_ty, long_long_int_ty, char_ty,
}) { }) {
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::LessThan, ty, bool_ty, false, ty, types::BinOp::LessThan, ty, bool_ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSLT(lhs, rhs, "icmpslt"); return builder.builder->CreateICmpSLT(lhs, rhs, "icmpslt");
}, },
}); });
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::GreaterThan, ty, bool_ty, false, ty, types::BinOp::GreaterThan, ty, bool_ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpSGT(lhs, rhs, "icmpsgt"); return builder.builder->CreateICmpSGT(lhs, rhs, "icmpsgt");
}, },
@ -74,14 +74,14 @@ namespace types {
bool_ty bool_ty
}) { }) {
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::LessThan, ty, bool_ty, false, ty, types::BinOp::LessThan, ty, bool_ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpULT(lhs, rhs, "icmpult"); return builder.builder->CreateICmpULT(lhs, rhs, "icmpult");
}, },
}); });
definitions.push_back(BinopDefinition{ definitions.push_back(BinopDefinition{
ty, types::BinOp::GreaterThan, ty, bool_ty, false, ty, types::BinOp::GreaterThan, ty, bool_ty,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
return builder.builder->CreateICmpUGT(lhs, rhs, "icmpugt"); return builder.builder->CreateICmpUGT(lhs, rhs, "icmpugt");
}, },
@ -106,20 +106,6 @@ namespace types {
return binop; return binop;
} }
if (op == BinOp::Assignment) {
auto void_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } };;
return BinopDefinition{
lhs, types::BinOp::Assignment, lhs, void_ty, true,
[](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) {
builder.builder->CreateStore(rhs, lhs);
return llvm::dyn_cast<llvm::Value>(llvm::ConstantInt::get(llvm::IntegerType::get(*builder.context, 1), 0));
},
};
}
return {}; return {};
} }

View File

@ -33,7 +33,6 @@ namespace types {
BinOp op; BinOp op;
std::shared_ptr<Type> rhs; std::shared_ptr<Type> rhs;
std::shared_ptr<Type> result; std::shared_ptr<Type> result;
bool lhs_lvalue;
llvm::Value* (*codegen)(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs); llvm::Value* (*codegen)(codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs);
}; };

View File

@ -132,23 +132,27 @@ namespace AST {
codegen::StackValue BinaryOperationExpression::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) { codegen::StackValue BinaryOperationExpression::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) {
auto lvalued = scope.with_lvalue(); auto lvalued = scope.with_lvalue();
auto lhs = this->m_lhs->codegen(builder, this->m_binop == types::BinOp::Assignment ? lvalued : scope, allocator);
auto binop = types::find_binop(
scope.binops,
this->m_lhs->get_codegen_type(scope),
this->m_binop,
this->m_rhs->get_codegen_type(scope));
auto lhs = this->m_lhs->codegen(builder, binop->lhs_lvalue ? lvalued : scope, allocator);
auto rhs = this->m_rhs->codegen(builder, scope, allocator); auto rhs = this->m_rhs->codegen(builder, scope, allocator);
try { try {
if (binop) { switch (this->m_binop) {
return codegen::StackValue{ case types::BinOp::Assignment:
binop->codegen(builder, lhs.value, rhs.value), builder.builder->CreateStore(rhs.value, lhs.value, false);
binop->result return rhs;
}; default:
auto binop = types::find_binop(
scope.binops,
lhs.ty,
this->m_binop,
rhs.ty);
if (binop) {
return codegen::StackValue{
binop->codegen(builder, lhs.value, rhs.value),
binop->result
};
}
throw CompileError("invalid binop", this->m_meta);
} }
throw CompileError("invalid binop", this->m_meta);
} }
catch (std::runtime_error& error) { catch (std::runtime_error& error) {
throw CompileError(error.what(), this->m_meta); throw CompileError(error.what(), this->m_meta);

View File

@ -181,6 +181,21 @@ namespace AST {
auto lhs_ty = lhs_res.type; auto lhs_ty = lhs_res.type;
auto rhs_ty = this->m_rhs->typecheck(state, scope, {}).type; auto rhs_ty = this->m_rhs->typecheck(state, scope, {}).type;
if (this->m_binop == types::BinOp::Assignment) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
// Re-typecheck rhs to actually match lhs
auto rhs_ty = this->m_rhs->typecheck(state, scope, lhs_ty).type;
auto rhs_ty_res = check_type(state, rhs_ty, lhs_ty);
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_ty_res, state);
return { lhs_ty, false, false };
}
// Try to find a binop that matches exactly // Try to find a binop that matches exactly
auto binop = types::find_binop( auto binop = types::find_binop(
state.binops, state.binops,
@ -190,24 +205,6 @@ namespace AST {
); );
if (binop) { if (binop) {
if (binop->lhs_lvalue) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
}
auto lhs_res = this->m_lhs->typecheck(state, scope, binop->lhs);
auto lhs_ty = lhs_res.type;
auto rhs_ty = this->m_rhs->typecheck(state, scope, binop->rhs).type;
auto lhs_ty_res = check_type(state, lhs_ty, binop->lhs);
auto rhs_ty_res = check_type(state, rhs_ty, binop->rhs);
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_ty_res, state);
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_ty_res, state);
return { binop->result, false, false }; return { binop->result, false, false };
} }
@ -215,9 +212,6 @@ namespace AST {
// and is castable on the other side, and would also be perfectly // and is castable on the other side, and would also be perfectly
// assignable to the expected value. // assignable to the expected value.
for (auto& binop : state.binops) { for (auto& binop : state.binops) {
if (binop.op != this->m_binop)
continue;
if (expected_ty) { if (expected_ty) {
// Skip any binops that would not be immediately assignable to // Skip any binops that would not be immediately assignable to
// the expected type // the expected type
@ -231,15 +225,6 @@ namespace AST {
// Skip if not implicitly castable to lhs // Skip if not implicitly castable to lhs
continue; continue;
if (binop.lhs_lvalue) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
}
rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type; rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type;
rhs_res = check_type(state, rhs_ty, binop.rhs); rhs_res = check_type(state, rhs_ty, binop.rhs);
@ -247,23 +232,14 @@ namespace AST {
return { binop.result, false, false }; return { binop.result, false, false };
} }
else if (types::types_equal(binop.rhs, rhs_ty)) { else if (types::types_equal(binop.rhs, rhs_ty)) {
auto lhs_ty_res = check_type(state, lhs_ty, binop.lhs); auto lhs_res = check_type(state, lhs_ty, binop.lhs);
if (!lhs_ty_res.ok()) if (!lhs_res.ok())
// Skip if not implicitly castable to rhs // Skip if not implicitly castable to rhs
continue; continue;
if (binop.lhs_lvalue) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
}
lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type; lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type;
lhs_ty_res = check_type(state, lhs_ty, binop.lhs); lhs_res = check_type(state, lhs_ty, binop.lhs);
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_ty_res, state); this->m_lhs = handle_res(std::move(this->m_lhs), lhs_res, state);
return { binop.result, false, false }; return { binop.result, false, false };
} }
} }
@ -271,9 +247,6 @@ namespace AST {
// if that fails, accept binops that match the result type perfectly and // if that fails, accept binops that match the result type perfectly and
// is able to cast both types successfully // is able to cast both types successfully
for (auto& binop : state.binops) { for (auto& binop : state.binops) {
if (binop.op != this->m_binop)
continue;
if (expected_ty) { if (expected_ty) {
// Skip any binops that would not be immediately assignable to // Skip any binops that would not be immediately assignable to
// the expected type // the expected type
@ -282,35 +255,23 @@ namespace AST {
} }
} }
auto rhs_ty_res = check_type(state, rhs_ty, binop.rhs); auto rhs_res = check_type(state, rhs_ty, binop.rhs);
auto lhs_ty_res = check_type(state, lhs_ty, binop.lhs); auto lhs_res = check_type(state, lhs_ty, binop.lhs);
if (!rhs_ty_res.ok() || !lhs_ty_res.ok()) if (!rhs_res.ok() || !lhs_res.ok())
continue; continue;
if (binop.lhs_lvalue) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
}
lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type; lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type;
rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type; rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type;
lhs_ty_res = check_type(state, lhs_ty, binop.lhs); lhs_res = check_type(state, lhs_ty, binop.lhs);
rhs_ty_res = check_type(state, rhs_ty, binop.rhs); rhs_res = check_type(state, rhs_ty, binop.rhs);
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_ty_res, state); this->m_lhs = handle_res(std::move(this->m_lhs), lhs_res, state);
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_ty_res, state); this->m_rhs = handle_res(std::move(this->m_rhs), rhs_res, state);
return { binop.result, false, false }; return { binop.result, false, false };
} }
// Finally check for any binop that allows the result to be implicitly // Finally check for any binop that allows the result to be implicitly
// casted to the result // casted to the result
for (auto& binop : state.binops) { for (auto& binop : state.binops) {
if (binop.op != this->m_binop)
continue;
if (expected_ty) { if (expected_ty) {
// Skip any binops that would not even be implicitly castable to // Skip any binops that would not even be implicitly castable to
// the expected result // the expected result
@ -318,16 +279,6 @@ namespace AST {
if (!result_res.ok()) if (!result_res.ok())
continue; continue;
} }
if (binop.lhs_lvalue) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
}
lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type; lhs_ty = this->m_lhs->typecheck(state, scope, binop.lhs).type;
rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type; rhs_ty = this->m_rhs->typecheck(state, scope, binop.rhs).type;
auto lhs_result = check_type(state, lhs_ty, binop.lhs); auto lhs_result = check_type(state, lhs_ty, binop.lhs);

2
test.c
View File

@ -72,6 +72,8 @@ long long int main() {
} }
short int sh = 123 + 5; short int sh = 123 + 5;
long int lg = 456;
long long int longer = 789;
return sh; return sh;
} }