diff --git a/src/binops.cpp b/src/binops.cpp index 6af608a..16fffcc 100644 --- a/src/binops.cpp +++ b/src/binops.cpp @@ -47,6 +47,91 @@ namespace types { return builder.builder->CreateSub(lhs, rhs, "sub"); }, }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Mul, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateMul(lhs, rhs, "mul"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::BitAnd, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateAnd(lhs, rhs, "and"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::BitOr, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateOr(lhs, rhs, "or"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::BitXor, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateXor(lhs, rhs, "xor"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::BitShiftLeft, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateShl(lhs, rhs, "shl"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::BitShiftRight, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateAShr(lhs, rhs, "shr"); + }, + }); + } + + // Signed Integer arithmetic binops + for (auto& ty : { + short_int_ty, int_ty, long_int_ty, long_long_int_ty, char_ty, + }) { + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Div, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateSDiv(lhs, rhs, "sdiv"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Modulo, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + auto div_trunc = builder.builder->CreateSDiv(lhs, rhs, "mod.sdiv"); + auto div_mul = builder.builder->CreateMul(div_trunc, rhs, "mod.mul"); + return builder.builder->CreateSub(lhs, div_mul, "mod.value"); + }, + }); + } + + // Unsigned Integer arithmetic binops + for (auto& ty : { + ushort_int_ty, uint_ty, ulong_int_ty, ulong_long_int_ty, uchar_ty, + bool_ty + }) { + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Div, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateUDiv(lhs, rhs, "udiv"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Modulo, ty, ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + auto div_trunc = builder.builder->CreateUDiv(lhs, rhs, "mod.udiv"); + auto div_mul = builder.builder->CreateMul(div_trunc, rhs, "mod.mul"); + return builder.builder->CreateSub(lhs, div_mul, "mod.value"); + }, + }); } // Signed comparisons @@ -66,6 +151,34 @@ namespace types { return builder.builder->CreateICmpSGT(lhs, rhs, "icmpsgt"); }, }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::LessThanEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpSLE(lhs, rhs, "icmpsle"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::GreaterThanEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpSGE(lhs, rhs, "icmpsge"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Equals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpEQ(lhs, rhs, "icmpeq"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::NotEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpNE(lhs, rhs, "icmpne"); + }, + }); } // Unsigned comparisons @@ -86,8 +199,51 @@ namespace types { return builder.builder->CreateICmpUGT(lhs, rhs, "icmpugt"); }, }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::LessThanEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpULE(lhs, rhs, "icmpule"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::GreaterThanEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpUGE(lhs, rhs, "icmpuge"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::Equals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpEQ(lhs, rhs, "icmpeq"); + }, + }); + + definitions.push_back(BinopDefinition{ + ty, types::BinOp::NotEquals, ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateICmpNE(lhs, rhs, "icmpne"); + }, + }); } + + definitions.push_back(BinopDefinition{ + bool_ty, types::BinOp::And, bool_ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateAnd(lhs, rhs, "and"); + }, + }); + + definitions.push_back(BinopDefinition{ + bool_ty, types::BinOp::Or, bool_ty, bool_ty, false, + [](codegen::Builder& builder, llvm::Value* lhs, llvm::Value* rhs) { + return builder.builder->CreateOr(lhs, rhs, "or"); + }, + }); + return definitions; } diff --git a/src/binops.h b/src/binops.h index ea4c33d..97aac73 100644 --- a/src/binops.h +++ b/src/binops.h @@ -9,10 +9,28 @@ namespace types { enum class BinOp { Assignment, + Add, Sub, + Mul, + Div, + Modulo, + + BitAnd, + BitOr, + BitXor, + BitShiftLeft, + BitShiftRight, + + And, + Or, + LessThan, + LessThanEquals, GreaterThan, + GreaterThanEquals, + Equals, + NotEquals, }; enum class Unary { diff --git a/src/parsing.cpp b/src/parsing.cpp index ffc0acc..6cc761d 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -469,13 +469,41 @@ namespace parsing { token::TokenStream inner{ stream }; try { auto token = inner.next(); + auto peeked = inner.peek(); if (token.type != token::Type::Symbol) { throw std::runtime_error("Expected binop"); } + + else if (token.content == "<" && peeked.content == "<") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::BitShiftLeft }; + } + else if (token.content == ">" && peeked.content == ">") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::BitShiftRight }; + } + else if (token.content == "<" && peeked.content == "=") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::LessThanEquals }; + } + else if (token.content == ">" && peeked.content == "=") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::GreaterThanEquals }; + } + else if (token.content == "=" && peeked.content == "=") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::Equals }; + } + else if (token.content == "!" && peeked.content == "=") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::NotEquals }; + } + else if (token.content == "=") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Assignment }; } + else if (token.content == "+") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Add }; @@ -484,6 +512,32 @@ namespace parsing { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::Sub }; } + else if (token.content == "*") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::Mul }; + } + else if (token.content == "/") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::Div }; + } + else if (token.content == "%") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::Modulo }; + } + + else if (token.content == "&") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::BitAnd }; + } + else if (token.content == "|") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::BitOr }; + } + else if (token.content == "^") { + stream.m_position = inner.m_position; + return types::BinOp{ types::BinOp::BitXor }; + } + else if (token.content == "<") { stream.m_position = inner.m_position; return types::BinOp{ types::BinOp::LessThan }; diff --git a/src/types.cpp b/src/types.cpp index 512c607..0b3acc4 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -7,15 +7,43 @@ #include "builder.h" namespace types { + /// @brief https://en.cppreference.com/c/language/operator_precedence int operator_precedence(BinOp& op) { switch (op) { + case BinOp::Mul: + case BinOp::Div: + case BinOp::Modulo: + return 3; + case BinOp::Add: case BinOp::Sub: - return 10; + return 4; + + case BinOp::BitShiftLeft: + case BinOp::BitShiftRight: + return 5; case BinOp::LessThan: case BinOp::GreaterThan: - return 20; + case BinOp::LessThanEquals: + case BinOp::GreaterThanEquals: + return 6; + + case BinOp::Equals: + case BinOp::NotEquals: + return 7; + + case BinOp::BitAnd: + return 8; + case BinOp::BitXor: + return 9; + case BinOp::BitOr: + return 10; + + case BinOp::And: + return 11; + case BinOp::Or: + return 12; case BinOp::Assignment: return 1000; @@ -28,14 +56,41 @@ namespace types { switch (op) { case BinOp::Assignment: return "="; + case BinOp::Add: return "+"; case BinOp::Sub: return "-"; + case BinOp::Mul: + return "*"; + case BinOp::Div: + return "/"; + case BinOp::Modulo: + return "%"; + + case BinOp::BitAnd: + return "&"; + case BinOp::BitOr: + return "|"; + case BinOp::BitXor: + return "^"; + case BinOp::BitShiftLeft: + return "<<"; + case BinOp::BitShiftRight: + return ">>"; + case BinOp::LessThan: return "<"; case BinOp::GreaterThan: return ">"; + case BinOp::LessThanEquals: + return "<="; + case BinOp::GreaterThanEquals: + return ">="; + case BinOp::Equals: + return "=="; + case BinOp::NotEquals: + return "!="; default: return "??"; } diff --git a/test.c b/test.c index c6eaefe..2991a86 100644 --- a/test.c +++ b/test.c @@ -73,5 +73,5 @@ long long int main() { short int sh = 123 + 5; - return sh; + return sh % 10; } \ No newline at end of file