added math instructions and a way to convert to and from floats and ints
This commit is contained in:
@@ -6,12 +6,12 @@ int main() {
|
|||||||
// The outputted program should have an exit status of 10
|
// The outputted program should have an exit status of 10
|
||||||
|
|
||||||
Tram::Program program;
|
Tram::Program program;
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::External, {Tram::Parameter("puts")}));
|
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::CreateLabel, {Tram::Parameter("main")}));
|
program.addInstruction(Tram::Instruction(Tram::InstructionType::CreateLabel, {Tram::Parameter("main")}));
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::PushAll, {}));
|
program.addInstruction(Tram::Instruction(Tram::InstructionType::Put, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Literal(10))}));
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::PopAll, {}));
|
program.addInstruction(Tram::Instruction(Tram::InstructionType::IntToFloat, {Tram::Parameter(Tram::Register::f0), Tram::Parameter(Tram::Register::r0)}));
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Put, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Literal("hi"))}));
|
program.addInstruction(Tram::Instruction(Tram::InstructionType::Divide, {Tram::Parameter(Tram::Register::f0), Tram::Parameter(Tram::Literal(5.0))}));
|
||||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Call, {Tram::Parameter("puts")}));
|
program.addInstruction(Tram::Instruction(Tram::InstructionType::FloatToInt, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Register::f0)}));
|
||||||
|
|
||||||
Tram::Compiler compiler(program);
|
Tram::Compiler compiler(program);
|
||||||
compiler.setTarget(Tram::Target::x86_64_Linux_libc);
|
compiler.setTarget(Tram::Target::x86_64_Linux_libc);
|
||||||
compiler.setLogLevel(Tram::LogLevel::All);
|
compiler.setLogLevel(Tram::LogLevel::All);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "../tram.h"
|
#include "../tram.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include <tram.h>
|
#include <tram.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "x86_64_Linux_libc.h"
|
#include "x86_64_Linux_libc.h"
|
||||||
@@ -303,11 +304,11 @@ namespace Tram {
|
|||||||
std::optional param0 = instruction.getParameter(0);
|
std::optional param0 = instruction.getParameter(0);
|
||||||
std::optional param1 = instruction.getParameter(1);
|
std::optional param1 = instruction.getParameter(1);
|
||||||
if (!param0.has_value()) {
|
if (!param0.has_value()) {
|
||||||
compiler.errorLog("put: expecting at least 2 parameters");
|
compiler.errorLog("add: expecting at least 2 parameters");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!param1.has_value()) {
|
if (!param1.has_value()) {
|
||||||
compiler.errorLog("put: expecting at least 2 parameters");
|
compiler.errorLog("add: expecting at least 2 parameters");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +341,7 @@ namespace Tram {
|
|||||||
|
|
||||||
std::string destination = registerToAsmRegister(reg);
|
std::string destination = registerToAsmRegister(reg);
|
||||||
std::string source = ({
|
std::string source = ({
|
||||||
const auto _param = parameterToAsmString(param1.value(), compiler);
|
const auto _param = parameterToAsmString(param1.value(), compiler, true);
|
||||||
if (!_param.has_value()) {
|
if (!_param.has_value()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -348,7 +349,156 @@ namespace Tram {
|
|||||||
});
|
});
|
||||||
|
|
||||||
body += " " + instruction + " " + destination + ", " + source + "\n";
|
body += " " + instruction + " " + destination + ", " + source + "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstructionType::Subtract: {
|
||||||
|
compiler.allLog("instruction: subtract");
|
||||||
|
std::optional param0 = instruction.getParameter(0);
|
||||||
|
std::optional param1 = instruction.getParameter(1);
|
||||||
|
if (!param0.has_value()) {
|
||||||
|
compiler.errorLog("subtract: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!param1.has_value()) {
|
||||||
|
compiler.errorLog("subtract: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param0.value().getType() != ParameterType::Register) {
|
||||||
|
compiler.errorLog("subtract: can only subtract a number from a register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Register reg = param0.value().getRegister();
|
||||||
|
LiteralType regType = registers[reg];
|
||||||
|
if (regType == LiteralType::None) {
|
||||||
|
compiler.errorLog("subtract: selected register to subtract to is empty");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string instruction;
|
||||||
|
switch (regType) {
|
||||||
|
case LiteralType::Int: {
|
||||||
|
instruction = "sub";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LiteralType::Float: {
|
||||||
|
instruction = "subsd";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LiteralType::String:
|
||||||
|
case LiteralType::None:
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string destination = registerToAsmRegister(reg);
|
||||||
|
std::string source = ({
|
||||||
|
const auto _param = parameterToAsmString(param1.value(), compiler, true);
|
||||||
|
if (!_param.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
_param.value();
|
||||||
|
});
|
||||||
|
|
||||||
|
body += " " + instruction + " " + destination + ", " + source + "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstructionType::Multiply: {
|
||||||
|
compiler.allLog("instruction: multiply");
|
||||||
|
std::optional param0 = instruction.getParameter(0);
|
||||||
|
std::optional param1 = instruction.getParameter(1);
|
||||||
|
if (!param0.has_value()) {
|
||||||
|
compiler.errorLog("multiply: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!param1.has_value()) {
|
||||||
|
compiler.errorLog("multiply: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param0.value().getType() != ParameterType::Register) {
|
||||||
|
compiler.errorLog("multiply: can only multiply a number and a register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Register reg = param0.value().getRegister();
|
||||||
|
LiteralType regType = registers[reg];
|
||||||
|
if (regType == LiteralType::None) {
|
||||||
|
compiler.errorLog("multiply: selected register to multiply to is empty");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string instruction;
|
||||||
|
switch (regType) {
|
||||||
|
case LiteralType::Int: {
|
||||||
|
instruction = "mul";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LiteralType::Float: {
|
||||||
|
instruction = "mulsd";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LiteralType::String:
|
||||||
|
case LiteralType::None:
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string destination = registerToAsmRegister(reg);
|
||||||
|
std::string source = ({
|
||||||
|
const auto _param = parameterToAsmString(param1.value(), compiler, true);
|
||||||
|
if (!_param.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
_param.value();
|
||||||
|
});
|
||||||
|
|
||||||
|
body += " " + instruction + " " + destination + ", " + source + "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstructionType::Divide: {
|
||||||
|
compiler.allLog("instruction: divide");
|
||||||
|
std::optional param0 = instruction.getParameter(0);
|
||||||
|
std::optional param1 = instruction.getParameter(1);
|
||||||
|
if (!param0.has_value()) {
|
||||||
|
compiler.errorLog("divide: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!param1.has_value()) {
|
||||||
|
compiler.errorLog("divide: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param0.value().getType() != ParameterType::Register || param0->getRegister() < Register::f0) {
|
||||||
|
compiler.errorLog("divide: can only divide a number and a float register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param1.value().getType() == ParameterType::Literal && param1->getLiteral().getType() != LiteralType::Float) {
|
||||||
|
compiler.errorLog("divide: second argument must be a float literal or float register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param1.value().getType() == ParameterType::Register && param1->getRegister() < Register::f0) {
|
||||||
|
compiler.errorLog("divide: if the second argument is a register it must be a float register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Register reg = param0.value().getRegister();
|
||||||
|
LiteralType regType = registers[reg];
|
||||||
|
if (regType == LiteralType::None) {
|
||||||
|
compiler.errorLog("divide: selected register to divide to is empty");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string destination = registerToAsmRegister(reg);
|
||||||
|
std::string source = ({
|
||||||
|
const auto _param = parameterToAsmString(param1.value(), compiler, true);
|
||||||
|
if (!_param.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
_param.value();
|
||||||
|
});
|
||||||
|
|
||||||
|
body += " divsd " + destination + ", " + source + "\n";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case InstructionType::Push: {
|
case InstructionType::Push: {
|
||||||
compiler.allLog("instruction: push");
|
compiler.allLog("instruction: push");
|
||||||
@@ -386,7 +536,8 @@ namespace Tram {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InstructionType::PushAll:
|
case InstructionType::PushAll: {
|
||||||
|
compiler.allLog("instruction: pushall");
|
||||||
body += " push r8\n";
|
body += " push r8\n";
|
||||||
body += " push r9\n";
|
body += " push r9\n";
|
||||||
body += " push r10\n";
|
body += " push r10\n";
|
||||||
@@ -401,7 +552,9 @@ namespace Tram {
|
|||||||
stackSizeBytes += 16;
|
stackSizeBytes += 16;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case InstructionType::PopAll:
|
}
|
||||||
|
case InstructionType::PopAll: {
|
||||||
|
compiler.allLog("instruction: popall");
|
||||||
body += " pop r15\n";
|
body += " pop r15\n";
|
||||||
body += " pop r14\n";
|
body += " pop r14\n";
|
||||||
body += " pop r13\n";
|
body += " pop r13\n";
|
||||||
@@ -415,6 +568,65 @@ namespace Tram {
|
|||||||
|
|
||||||
stackSizeBytes -= 16;
|
stackSizeBytes -= 16;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case InstructionType::IntToFloat: {
|
||||||
|
std::optional param0 = instruction.getParameter(0);
|
||||||
|
std::optional param1 = instruction.getParameter(1);
|
||||||
|
|
||||||
|
if (!param0.has_value() || !param1.has_value()) {
|
||||||
|
compiler.errorLog("inttofloat: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param0->getType() != ParameterType::Register || param1->getType() != ParameterType::Register) {
|
||||||
|
compiler.errorLog("inttofloat: both parameter must be registers");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param0->getRegister() < Register::f0) {
|
||||||
|
compiler.errorLog("inttofloat: parameter 0 must be a float register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param1->getRegister() > Register::r15) {
|
||||||
|
compiler.errorLog("inttofloat: parameter 1 must be an int register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
body += " cvtsi2sd " +
|
||||||
|
parameterToAsmString(param0.value(), compiler).value() + ", " +
|
||||||
|
parameterToAsmString(param1.value(), compiler).value() + "\n";
|
||||||
|
|
||||||
|
registers[param0->getRegister()] = LiteralType::Float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case InstructionType::FloatToInt: {
|
||||||
|
std::optional param0 = instruction.getParameter(0);
|
||||||
|
std::optional param1 = instruction.getParameter(1);
|
||||||
|
|
||||||
|
if (!param0.has_value() || !param1.has_value()) {
|
||||||
|
compiler.errorLog("inttofloat: expecting at least 2 parameters");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param0->getType() != ParameterType::Register || param1->getType() != ParameterType::Register) {
|
||||||
|
compiler.errorLog("inttofloat: both parameter must be registers");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param0->getRegister() > Register::r15) {
|
||||||
|
compiler.errorLog("inttofloat: parameter 0 must be an int register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (param1->getRegister() < Register::f0) {
|
||||||
|
compiler.errorLog("inttofloat: parameter 1 must be a float register");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
body += " cvttsd2si " +
|
||||||
|
parameterToAsmString(param0.value(), compiler).value() + ", " +
|
||||||
|
parameterToAsmString(param1.value(), compiler).value() + "\n";
|
||||||
|
|
||||||
|
registers[param0->getRegister()] = LiteralType::Int;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case InstructionType::None:
|
case InstructionType::None:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace Tram {
|
|||||||
External, Call, Put,
|
External, Call, Put,
|
||||||
CreateLabel, Jump, JumpNotZero, JumpIfZero,
|
CreateLabel, Jump, JumpNotZero, JumpIfZero,
|
||||||
Add, Subtract, Multiply, Divide,
|
Add, Subtract, Multiply, Divide,
|
||||||
|
IntToFloat, FloatToInt,
|
||||||
Push, Pop, PushAll, PopAll,
|
Push, Pop, PushAll, PopAll,
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user