Syscall* ASTNodes and LLVM IR generation for x86

Inline assembly for the win!
This commit is contained in:
apio 2022-07-18 15:57:16 +02:00
parent 7522858897
commit 085677bc2b
3 changed files with 346 additions and 0 deletions

View File

@ -47,6 +47,8 @@ add_executable(
src/AST/NumberNode.h
src/AST/SumNode.cpp
src/AST/SumNode.h
src/AST/SyscallNode.cpp
src/AST/SyscallNode.h
src/utils.cpp
src/utils.h
src/Parser.cpp

258
src/AST/SyscallNode.cpp Normal file
View File

@ -0,0 +1,258 @@
#include "SyscallNode.h"
#include "../Arguments.h"
#include "../Error.h"
#include "llvm/IR/InlineAsm.h"
Syscall0Node::Syscall0Node(int syscall_number) : sys_num(syscall_number), ExprNode()
{
}
Syscall0Node::~Syscall0Node()
{
}
Syscall1Node::Syscall1Node(int syscall_number, std::shared_ptr<ASTNode> arg1)
: sys_num(syscall_number), arg1(arg1), ExprNode()
{
}
Syscall1Node::~Syscall1Node()
{
}
Syscall2Node::Syscall2Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), ExprNode()
{
}
Syscall2Node::~Syscall2Node()
{
}
Syscall3Node::Syscall3Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), ExprNode()
{
}
Syscall3Node::~Syscall3Node()
{
}
Syscall4Node::Syscall4Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), ExprNode()
{
}
Syscall4Node::~Syscall4Node()
{
}
Syscall5Node::Syscall5Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4, std::shared_ptr<ASTNode> arg5)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), ExprNode()
{
}
Syscall5Node::~Syscall5Node()
{
}
llvm::Value* Syscall0Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}
llvm::Value* Syscall1Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
arg1->codegen(generator)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80),
arg1->codegen(generator)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}
llvm::Value* Syscall2Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
arg1->codegen(generator), arg2->codegen(generator)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80),
arg1->codegen(generator), arg2->codegen(generator)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}
llvm::Value* Syscall3Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rcx}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}
llvm::Value* Syscall4Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rdx},{rcx}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx},{esi}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}
llvm::Value* Syscall5Node::codegen(IRBuilder* generator)
{
switch (Arguments::TargetTriple.getArch())
{
case llvm::Triple::x86_64: {
auto i64Type =
llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rdx},{rcx},{r8}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator),
arg5->codegen(generator)});
break;
}
case llvm::Triple::x86: {
auto i32Type =
llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false);
auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx},{esi},{edi}", true);
return generator->getBuilder()->CreateCall(
inlineAsm,
{llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num),
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80),
arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator),
arg5->codegen(generator)});
break;
}
default:
Error::throw_error_without_location(
std::string("Unsupported arch for syscalls: ") +
Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str());
break;
}
}

86
src/AST/SyscallNode.h Normal file
View File

@ -0,0 +1,86 @@
#pragma once
#include "ExprNode.h"
class Syscall0Node final : public ExprNode
{
int sys_num;
public:
Syscall0Node(int syscall_number);
~Syscall0Node();
llvm::Value* codegen(IRBuilder* generator) override;
};
class Syscall1Node final : public ExprNode
{
int sys_num;
std::shared_ptr<ASTNode> arg1;
public:
Syscall1Node(int syscall_number, std::shared_ptr<ASTNode> arg1);
~Syscall1Node();
llvm::Value* codegen(IRBuilder* generator) override;
};
class Syscall2Node final : public ExprNode
{
int sys_num;
std::shared_ptr<ASTNode> arg1;
std::shared_ptr<ASTNode> arg2;
public:
Syscall2Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2);
~Syscall2Node();
llvm::Value* codegen(IRBuilder* generator) override;
};
class Syscall3Node final : public ExprNode
{
int sys_num;
std::shared_ptr<ASTNode> arg1;
std::shared_ptr<ASTNode> arg2;
std::shared_ptr<ASTNode> arg3;
public:
Syscall3Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3);
~Syscall3Node();
llvm::Value* codegen(IRBuilder* generator) override;
};
class Syscall4Node final : public ExprNode
{
int sys_num;
std::shared_ptr<ASTNode> arg1;
std::shared_ptr<ASTNode> arg2;
std::shared_ptr<ASTNode> arg3;
std::shared_ptr<ASTNode> arg4;
public:
Syscall4Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4);
~Syscall4Node();
llvm::Value* codegen(IRBuilder* generator) override;
};
class Syscall5Node final : public ExprNode
{
int sys_num;
std::shared_ptr<ASTNode> arg1;
std::shared_ptr<ASTNode> arg2;
std::shared_ptr<ASTNode> arg3;
std::shared_ptr<ASTNode> arg4;
std::shared_ptr<ASTNode> arg5;
public:
Syscall5Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4, std::shared_ptr<ASTNode> arg5);
~Syscall5Node();
llvm::Value* codegen(IRBuilder* generator) override;
};