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
|
||||
|
||||
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::PushAll, {}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::PopAll, {}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Put, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Literal("hi"))}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Call, {Tram::Parameter("puts")}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Put, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Literal(10))}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::IntToFloat, {Tram::Parameter(Tram::Register::f0), Tram::Parameter(Tram::Register::r0)}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::Divide, {Tram::Parameter(Tram::Register::f0), Tram::Parameter(Tram::Literal(5.0))}));
|
||||
program.addInstruction(Tram::Instruction(Tram::InstructionType::FloatToInt, {Tram::Parameter(Tram::Register::r0), Tram::Parameter(Tram::Register::f0)}));
|
||||
|
||||
Tram::Compiler compiler(program);
|
||||
compiler.setTarget(Tram::Target::x86_64_Linux_libc);
|
||||
compiler.setLogLevel(Tram::LogLevel::All);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "../tram.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tram.h>
|
||||
#include <utility>
|
||||
#include "x86_64_Linux_libc.h"
|
||||
@@ -303,11 +304,11 @@ namespace Tram {
|
||||
std::optional param0 = instruction.getParameter(0);
|
||||
std::optional param1 = instruction.getParameter(1);
|
||||
if (!param0.has_value()) {
|
||||
compiler.errorLog("put: expecting at least 2 parameters");
|
||||
compiler.errorLog("add: expecting at least 2 parameters");
|
||||
return {};
|
||||
}
|
||||
if (!param1.has_value()) {
|
||||
compiler.errorLog("put: expecting at least 2 parameters");
|
||||
compiler.errorLog("add: expecting at least 2 parameters");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -340,7 +341,7 @@ namespace Tram {
|
||||
|
||||
std::string destination = registerToAsmRegister(reg);
|
||||
std::string source = ({
|
||||
const auto _param = parameterToAsmString(param1.value(), compiler);
|
||||
const auto _param = parameterToAsmString(param1.value(), compiler, true);
|
||||
if (!_param.has_value()) {
|
||||
return {};
|
||||
}
|
||||
@@ -348,7 +349,156 @@ namespace Tram {
|
||||
});
|
||||
|
||||
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: {
|
||||
compiler.allLog("instruction: push");
|
||||
@@ -386,7 +536,8 @@ namespace Tram {
|
||||
|
||||
break;
|
||||
}
|
||||
case InstructionType::PushAll:
|
||||
case InstructionType::PushAll: {
|
||||
compiler.allLog("instruction: pushall");
|
||||
body += " push r8\n";
|
||||
body += " push r9\n";
|
||||
body += " push r10\n";
|
||||
@@ -401,7 +552,9 @@ namespace Tram {
|
||||
stackSizeBytes += 16;
|
||||
|
||||
break;
|
||||
case InstructionType::PopAll:
|
||||
}
|
||||
case InstructionType::PopAll: {
|
||||
compiler.allLog("instruction: popall");
|
||||
body += " pop r15\n";
|
||||
body += " pop r14\n";
|
||||
body += " pop r13\n";
|
||||
@@ -415,6 +568,65 @@ namespace Tram {
|
||||
|
||||
stackSizeBytes -= 16;
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Tram {
|
||||
External, Call, Put,
|
||||
CreateLabel, Jump, JumpNotZero, JumpIfZero,
|
||||
Add, Subtract, Multiply, Divide,
|
||||
IntToFloat, FloatToInt,
|
||||
Push, Pop, PushAll, PopAll,
|
||||
None
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user