Add rest of the binops, nearly
This commit is contained in:
parent
905c9ce9a5
commit
c232fc3d43
156
src/binops.cpp
156
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;
|
||||
}
|
||||
|
||||
|
||||
18
src/binops.h
18
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 {
|
||||
|
||||
@ -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 };
|
||||
|
||||
@ -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 "??";
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user