2018-02-02 00:26:31 -05:00
|
|
|
import io:*
|
|
|
|
|
import mem:*
|
|
|
|
|
import map:*
|
|
|
|
|
import hash_map:*
|
|
|
|
|
import stack:*
|
|
|
|
|
import string:*
|
|
|
|
|
import util:*
|
|
|
|
|
import tree:*
|
|
|
|
|
import symbol:*
|
|
|
|
|
import ast_nodes:*
|
|
|
|
|
// for error with syntax tree
|
|
|
|
|
import pass_common:*
|
|
|
|
|
import poset:*
|
|
|
|
|
|
2018-02-27 23:53:08 +00:00
|
|
|
fun type_size(t: *type): ulong
|
|
|
|
|
return type_size_and_alignment(t).first
|
|
|
|
|
fun type_size_and_alignment(t: *type): pair<ulong,ulong> {
|
|
|
|
|
if (t->indirection)
|
|
|
|
|
return make_pair(#sizeof<*void>, #sizeof<*void>)
|
|
|
|
|
match (t->base) {
|
|
|
|
|
base_type::object() {
|
|
|
|
|
var total_size: ulong = 0
|
|
|
|
|
var max_size: ulong = 0
|
|
|
|
|
var max_align: ulong = 0
|
|
|
|
|
t->type_def->type_def.variables.for_each(fun(i: *ast_node) {
|
|
|
|
|
var individual = type_size_and_alignment(i->declaration_statement.identifier->identifier.type)
|
|
|
|
|
max_size = max(max_size, individual.first)
|
|
|
|
|
max_align = max(max_align, individual.second)
|
|
|
|
|
// increase total size by the individual size + padding to get alignment
|
|
|
|
|
var padding = 0
|
|
|
|
|
if (individual.second != 0)
|
|
|
|
|
padding = (individual.second - (total_size % individual.second)) % individual.second
|
|
|
|
|
total_size += individual.first + padding
|
|
|
|
|
})
|
|
|
|
|
if (t->type_def->type_def.is_union)
|
|
|
|
|
total_size = max_size
|
|
|
|
|
// pad the end so that consecutive objects in memory are aligned
|
|
|
|
|
if (max_align != 0)
|
|
|
|
|
total_size += (max_align - (total_size % max_align)) % max_align
|
|
|
|
|
return make_pair(total_size, max_align)
|
|
|
|
|
}
|
|
|
|
|
base_type::function() return make_pair(#sizeof<*void>, #sizeof<*void>)
|
|
|
|
|
base_type::boolean() return make_pair(#sizeof<bool>, #sizeof<bool>)
|
|
|
|
|
base_type::character() return make_pair(#sizeof<char>, #sizeof<char>)
|
|
|
|
|
base_type::ucharacter() return make_pair(#sizeof<uchar>, #sizeof<uchar>)
|
|
|
|
|
base_type::short_int() return make_pair(#sizeof<short>, #sizeof<short>)
|
|
|
|
|
base_type::ushort_int() return make_pair(#sizeof<ushort>, #sizeof<ushort>)
|
|
|
|
|
base_type::integer() return make_pair(#sizeof<int>, #sizeof<int>)
|
|
|
|
|
base_type::uinteger() return make_pair(#sizeof<uint>, #sizeof<uint>)
|
|
|
|
|
base_type::long_int() return make_pair(#sizeof<long>, #sizeof<long>)
|
|
|
|
|
base_type::ulong_int() return make_pair(#sizeof<ulong>, #sizeof<ulong>)
|
|
|
|
|
base_type::floating() return make_pair(#sizeof<float>, #sizeof<float>)
|
|
|
|
|
base_type::double_precision() return make_pair(#sizeof<double>, #sizeof<double>)
|
|
|
|
|
}
|
|
|
|
|
error(string("Invalid type for type_size: ") + t->to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun offset_into_struct(struct_type: *type, ident: *ast_node): ulong {
|
|
|
|
|
var offset: ulong = 0
|
|
|
|
|
if (struct_type->type_def->type_def.is_union)
|
|
|
|
|
return offset
|
|
|
|
|
for (var i = 0; i < struct_type->type_def->type_def.variables.size; i++;) {
|
|
|
|
|
var size_and_align = type_size_and_alignment(struct_type->type_def->type_def.variables[i]->declaration_statement.identifier->identifier.type)
|
|
|
|
|
var align = size_and_align.second
|
|
|
|
|
if (align != 0)
|
|
|
|
|
offset += (align - (offset % align)) % align
|
|
|
|
|
if (struct_type->type_def->type_def.variables[i]->declaration_statement.identifier == ident)
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
offset += size_and_align.first
|
|
|
|
|
}
|
|
|
|
|
return offset
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
|
2018-03-07 01:58:19 -05:00
|
|
|
var register_size = #sizeof<*void>
|
|
|
|
|
adt operand_size {
|
|
|
|
|
b8,
|
|
|
|
|
b16,
|
|
|
|
|
b32,
|
|
|
|
|
b64
|
|
|
|
|
}
|
|
|
|
|
fun size_to_operand_size(size: ulong): operand_size {
|
|
|
|
|
if (size == 1) return operand_size::b8()
|
|
|
|
|
if (size == 2) return operand_size::b16()
|
|
|
|
|
if (size == 4) return operand_size::b32()
|
|
|
|
|
if (size == 8) return operand_size::b64()
|
|
|
|
|
error("invalid operand size")
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
adt byte_inst {
|
2018-02-03 18:53:13 -05:00
|
|
|
nop,
|
2018-03-07 01:58:19 -05:00
|
|
|
imm: imm,
|
2018-03-12 20:17:26 -04:00
|
|
|
add: reg2,
|
|
|
|
|
addi: reg1i,
|
|
|
|
|
smul: reg2,
|
|
|
|
|
umul: reg2,
|
|
|
|
|
sdiv: reg2,
|
|
|
|
|
udiv: reg2,
|
|
|
|
|
mod: reg2,
|
2018-03-12 23:34:35 -04:00
|
|
|
shl: reg2,
|
|
|
|
|
shr: reg2,
|
|
|
|
|
sar: reg2,
|
2018-03-12 20:17:26 -04:00
|
|
|
and: reg2,
|
|
|
|
|
or: reg2,
|
|
|
|
|
xor: reg2,
|
|
|
|
|
not: reg1,
|
2018-03-12 23:34:35 -04:00
|
|
|
gz: reg1,
|
|
|
|
|
lz: reg1,
|
|
|
|
|
ez: reg1, // also logical not
|
2018-03-12 20:17:26 -04:00
|
|
|
ldr: reg1is,
|
|
|
|
|
str: reg1is,
|
|
|
|
|
jmp: long,
|
|
|
|
|
jz: test,
|
|
|
|
|
call: int,
|
2018-02-27 23:53:08 +00:00
|
|
|
ret
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
|
|
|
|
obj imm {
|
2018-03-12 20:17:26 -04:00
|
|
|
var to_reg: int
|
2018-03-06 23:30:00 -05:00
|
|
|
var val: long
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
obj reg1 {
|
2018-02-27 23:53:08 +00:00
|
|
|
var to_reg: int
|
|
|
|
|
var a: int
|
2018-02-03 22:47:21 -05:00
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
obj reg1i {
|
2018-03-10 00:27:16 -05:00
|
|
|
var to_reg: int
|
|
|
|
|
var a: int
|
|
|
|
|
var bi:long
|
|
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
obj reg1is {
|
|
|
|
|
var reg: int
|
|
|
|
|
var base_reg: int
|
2018-03-06 23:30:00 -05:00
|
|
|
var offset: long
|
2018-03-07 01:58:19 -05:00
|
|
|
var size: operand_size
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
obj reg2 {
|
2018-02-03 18:53:13 -05:00
|
|
|
var to_reg: int
|
2018-03-12 20:17:26 -04:00
|
|
|
var a: int
|
|
|
|
|
var b: int
|
2018-02-27 21:27:29 -05:00
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
obj test {
|
2018-02-27 21:27:29 -05:00
|
|
|
var reg: int
|
2018-03-06 23:30:00 -05:00
|
|
|
var offset: long
|
2018-02-27 21:27:29 -05:00
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
|
|
|
|
|
fun to_string(s: operand_size): string {
|
|
|
|
|
match (s) {
|
|
|
|
|
operand_size::b8() return string("8")
|
|
|
|
|
operand_size::b16() return string("16")
|
|
|
|
|
operand_size::b32() return string("32")
|
|
|
|
|
operand_size::b64() return string("64")
|
|
|
|
|
}
|
|
|
|
|
return string("missed operand size")
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
|
2018-02-03 18:53:13 -05:00
|
|
|
fun to_string(b: byte_inst): string {
|
|
|
|
|
match (b) {
|
2018-02-03 22:47:21 -05:00
|
|
|
byte_inst::nop() return string("nop")
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::imm(i) return string("r") + i.to_reg + " = imm " + i.val
|
2018-02-27 23:53:08 +00:00
|
|
|
byte_inst::add(a) return string("r") + a.to_reg + " = r" + a.a + " + r" + a.b
|
2018-03-10 00:27:16 -05:00
|
|
|
byte_inst::addi(a) return string("r") + a.to_reg + " = r" + a.a + " + " + a.bi
|
2018-03-14 01:16:00 -04:00
|
|
|
byte_inst::smul(a) return string("r") + a.to_reg + " = r" + a.a + " * r" + a.b
|
|
|
|
|
byte_inst::umul(a) return string("r") + a.to_reg + " = r" + a.a + " u* r"+ a.b
|
|
|
|
|
byte_inst::sdiv(a) return string("r") + a.to_reg + " = r" + a.a + " / r" + a.b
|
|
|
|
|
byte_inst::udiv(a) return string("r") + a.to_reg + " = r" + a.a + " u/ r"+ a.b
|
|
|
|
|
byte_inst::mod(a) return string("r") + a.to_reg + " = r" + a.a + " % r" + a.b
|
|
|
|
|
byte_inst::and(a) return string("r") + a.to_reg + " = r" + a.a + " & r" + a.b
|
|
|
|
|
byte_inst::shl(a) return string("r") + a.to_reg + " = r" + a.a + " u<< r" + a.b
|
|
|
|
|
byte_inst::shr(a) return string("r") + a.to_reg + " = r" + a.a + " u>> r" + a.b
|
|
|
|
|
byte_inst::sar(a) return string("r") + a.to_reg + " = r" + a.a + " s>> r" + a.b
|
|
|
|
|
byte_inst::or(a) return string("r") + a.to_reg + " = r" + a.a + " | r" + a.b
|
|
|
|
|
byte_inst::xor(a) return string("r") + a.to_reg + " = r" + a.a + " ^ r" + a.b
|
2018-03-10 00:27:16 -05:00
|
|
|
byte_inst::not(a) return string("r") + a.to_reg + " = ~r" + a.a
|
2018-03-12 23:34:35 -04:00
|
|
|
byte_inst::gz(a) return string("r") + a.to_reg + " = r" + a.a + " > 0"
|
|
|
|
|
byte_inst::lz(a) return string("r") + a.to_reg + " = r" + a.a + " < 0"
|
|
|
|
|
byte_inst::ez(a) return string("r") + a.to_reg + " = r" + a.a + " == 0"
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::ldr(l) return string("r") + l.reg + " = ldr" + to_string(l.size) + " r" + l.base_reg + " (" + l.offset + ")"
|
|
|
|
|
byte_inst::str(s) return "str" + to_string(s.size) + " (r" + s.base_reg + "(" + s.offset + ") <= r" + s.reg + ")"
|
|
|
|
|
byte_inst::jmp(j) return string("jmp(pc += ") + j + ")"
|
2018-03-07 01:58:19 -05:00
|
|
|
byte_inst::jz(j) return string("jmp(r") + j.reg + " == 0, pc += " + j.offset + ")"
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::call(c) return string("call pc = r") + c
|
2018-02-27 23:53:08 +00:00
|
|
|
byte_inst::ret() return string("ret")
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
|
|
|
|
return string("Missed byte_inst case in to_string")
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-07 01:58:19 -05:00
|
|
|
fun bytecode_to_string(functions: ref vector<bytecode_function>, instructions: ref vector<byte_inst>): string {
|
|
|
|
|
return string("\n").join(functions.map(fun(bb: ref bytecode_function): string return bb.to_string(instructions);))
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
|
|
|
|
|
2018-03-07 01:58:19 -05:00
|
|
|
fun bytecode_function(name: ref string, start: int): bytecode_function {
|
|
|
|
|
var to_ret.construct(name, start): bytecode_function
|
2018-02-03 18:53:13 -05:00
|
|
|
return to_ret
|
|
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
obj bytecode_function (Object) {
|
2018-02-03 18:53:13 -05:00
|
|
|
var name: string
|
2018-03-07 01:58:19 -05:00
|
|
|
var instruction_start: int
|
|
|
|
|
var instruction_end: int
|
2018-02-27 23:53:08 +00:00
|
|
|
var var_to_frame_offset: map<*ast_node, int>
|
|
|
|
|
var frame_size: int
|
2018-02-03 18:53:13 -05:00
|
|
|
|
2018-02-27 23:53:08 +00:00
|
|
|
fun construct(): *bytecode_function {
|
2018-03-07 01:58:19 -05:00
|
|
|
instruction_start = 0
|
|
|
|
|
instruction_end = 0
|
2018-02-03 18:53:13 -05:00
|
|
|
name.construct()
|
2018-02-27 23:53:08 +00:00
|
|
|
var_to_frame_offset.construct()
|
2018-03-07 01:58:19 -05:00
|
|
|
frame_size = 0
|
2018-02-03 18:53:13 -05:00
|
|
|
return this
|
|
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
fun construct(name_in: ref string, instruction_start_in: int): *bytecode_function {
|
|
|
|
|
instruction_start = instruction_start_in
|
|
|
|
|
instruction_end = 0
|
2018-02-03 18:53:13 -05:00
|
|
|
name.copy_construct(&name_in)
|
2018-02-27 23:53:08 +00:00
|
|
|
var_to_frame_offset.construct()
|
2018-03-07 01:58:19 -05:00
|
|
|
frame_size = 0
|
2018-02-03 18:53:13 -05:00
|
|
|
return this
|
|
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
fun copy_construct(old: *bytecode_function) {
|
2018-03-07 01:58:19 -05:00
|
|
|
instruction_start = old->instruction_start
|
|
|
|
|
instruction_end = old->instruction_end
|
2018-02-03 18:53:13 -05:00
|
|
|
name.copy_construct(&old->name)
|
2018-02-27 23:53:08 +00:00
|
|
|
var_to_frame_offset.copy_construct(&old->var_to_frame_offset)
|
|
|
|
|
frame_size = old->frame_size
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
fun operator=(other: ref bytecode_function) {
|
2018-02-03 18:53:13 -05:00
|
|
|
destruct()
|
|
|
|
|
copy_construct(&other)
|
|
|
|
|
}
|
|
|
|
|
fun destruct() {
|
|
|
|
|
name.destruct()
|
2018-02-27 23:53:08 +00:00
|
|
|
var_to_frame_offset.destruct()
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
fun to_string(instructions: ref vector<byte_inst>): string {
|
2018-02-27 23:53:08 +00:00
|
|
|
var res = name + "(frame size " + frame_size + "):\n"
|
|
|
|
|
res += "\t frame layout\n"
|
2018-03-07 01:58:19 -05:00
|
|
|
res += "\t\tsaved RBP : RPB = 0\n"
|
2018-02-27 23:53:08 +00:00
|
|
|
var_to_frame_offset.for_each(fun(n: *ast_node, o: int) {
|
2018-03-07 22:57:46 -05:00
|
|
|
res += "\t\t" + n->identifier.name + ": RBP + " + o + "\n"
|
2018-02-27 23:53:08 +00:00
|
|
|
})
|
|
|
|
|
res += "\n\t bytecode\n"
|
2018-03-07 01:58:19 -05:00
|
|
|
for (var i = instruction_start; i < instruction_end; i++;)
|
|
|
|
|
res += string("\t\t") + i + string(": ") + to_string(instructions[i]) + "\n"
|
2018-02-03 18:53:13 -05:00
|
|
|
return res
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj bytecode_generator (Object) {
|
2018-02-03 18:53:13 -05:00
|
|
|
var reg_counter: int
|
2018-02-27 23:53:08 +00:00
|
|
|
var reg_max: int
|
2018-02-02 00:26:31 -05:00
|
|
|
var id_counter: int
|
|
|
|
|
var ast_name_map: hash_map<*ast_node, string>
|
2018-02-27 23:53:08 +00:00
|
|
|
var functions: vector<bytecode_function>
|
2018-03-07 01:58:19 -05:00
|
|
|
var node_function_idx: map<*ast_node, int>
|
|
|
|
|
var instructions: vector<byte_inst>
|
|
|
|
|
var fixup_function_addresses: vector<pair<int, *ast_node>>
|
2018-03-13 00:39:16 -04:00
|
|
|
var fixup_break_addresses: stack<vector<int>>
|
|
|
|
|
var fixup_continue_addresses: stack<vector<int>>
|
2018-02-02 00:26:31 -05:00
|
|
|
fun construct(): *bytecode_generator {
|
|
|
|
|
id_counter = 0
|
|
|
|
|
ast_name_map.construct()
|
2018-02-27 23:53:08 +00:00
|
|
|
functions.construct()
|
2018-03-07 01:58:19 -05:00
|
|
|
node_function_idx.construct()
|
|
|
|
|
instructions.construct()
|
|
|
|
|
fixup_function_addresses.construct()
|
2018-03-13 00:39:16 -04:00
|
|
|
fixup_break_addresses.construct()
|
|
|
|
|
fixup_continue_addresses.construct()
|
2018-03-06 23:30:00 -05:00
|
|
|
reg_counter = 3
|
|
|
|
|
reg_max = 3
|
2018-02-02 00:26:31 -05:00
|
|
|
|
|
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
fun copy_construct(old: *bytecode_generator) {
|
2018-02-03 18:53:13 -05:00
|
|
|
reg_counter = old->reg_counter
|
2018-02-27 23:53:08 +00:00
|
|
|
reg_max = old->reg_max
|
2018-02-02 00:26:31 -05:00
|
|
|
id_counter = old->id_counter
|
|
|
|
|
ast_name_map.copy_construct(&old->ast_name_map)
|
2018-02-27 23:53:08 +00:00
|
|
|
functions.copy_construct(&old->functions)
|
2018-03-07 01:58:19 -05:00
|
|
|
node_function_idx.copy_construct(&old->node_function_idx)
|
|
|
|
|
instructions.copy_construct(&old->instructions)
|
|
|
|
|
fixup_function_addresses.copy_construct(&old->fixup_function_addresses)
|
2018-03-13 00:39:16 -04:00
|
|
|
fixup_break_addresses.copy_construct(&old->fixup_break_addresses)
|
|
|
|
|
fixup_continue_addresses.copy_construct(&old->fixup_continue_addresses)
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
fun operator=(other: ref bytecode_generator) {
|
|
|
|
|
destruct()
|
|
|
|
|
copy_construct(&other)
|
|
|
|
|
}
|
|
|
|
|
fun destruct() {
|
|
|
|
|
ast_name_map.destruct()
|
2018-02-27 23:53:08 +00:00
|
|
|
functions.destruct()
|
2018-03-07 01:58:19 -05:00
|
|
|
node_function_idx.destruct()
|
|
|
|
|
instructions.destruct()
|
|
|
|
|
fixup_function_addresses.destruct()
|
2018-03-13 00:39:16 -04:00
|
|
|
fixup_break_addresses.destruct()
|
|
|
|
|
fixup_continue_addresses.destruct()
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
fun get_id(): string return to_string(id_counter++);
|
2018-03-14 01:16:00 -04:00
|
|
|
fun get_reg(): int return reg_counter++;
|
|
|
|
|
fun peek_reg(): int return reg_counter;
|
|
|
|
|
fun reset_reg() reset_reg(3);
|
|
|
|
|
fun reset_reg(to: int) {
|
2018-02-27 23:53:08 +00:00
|
|
|
if (reg_counter > reg_max) {
|
|
|
|
|
reg_max = reg_counter
|
|
|
|
|
}
|
2018-03-14 01:16:00 -04:00
|
|
|
reg_counter = to
|
2018-02-27 23:53:08 +00:00
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
/*fun generate_bytecode(name_ast_map: map<string, pair<*tree<symbol>,*ast_node>>): pair<vector<bytecode_function>, vector<byte_inst>> {*/
|
|
|
|
|
fun generate_bytecode(name_ast_map: map<string, pair<*tree<symbol>,*ast_node>>) {
|
2018-02-02 00:26:31 -05:00
|
|
|
|
|
|
|
|
// iterate through asts
|
|
|
|
|
name_ast_map.for_each(fun(name: string, tree_pair: pair<*tree<symbol>,*ast_node>) {
|
|
|
|
|
// iterate through children for each ast
|
|
|
|
|
// do lambdas seperatly, so we can reconstitute the enclosing object if it has one
|
|
|
|
|
tree_pair.second->translation_unit.lambdas.for_each(fun(child: *ast_node) {
|
|
|
|
|
generate_function_definition(child)
|
|
|
|
|
})
|
|
|
|
|
tree_pair.second->translation_unit.children.for_each(fun(child: *ast_node) {
|
|
|
|
|
match (*child) {
|
|
|
|
|
ast_node::declaration_statement(backing) generate_declaration_statement(child)
|
|
|
|
|
ast_node::compiler_intrinsic(backing) generate_compiler_intrinsic(child)
|
|
|
|
|
ast_node::function(backing) generate_function_definition(child)
|
|
|
|
|
ast_node::template(backing) {
|
|
|
|
|
backing.instantiated.for_each(fun(node: *ast_node) {
|
|
|
|
|
match (*node) {
|
|
|
|
|
ast_node::function(backing) generate_function_definition(node)
|
|
|
|
|
ast_node::type_def(backing) {
|
|
|
|
|
backing.methods.for_each(fun(method: *ast_node) {
|
|
|
|
|
if (is_template(method))
|
|
|
|
|
method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m);)
|
|
|
|
|
else
|
|
|
|
|
generate_function_definition(method)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
ast_node::type_def(backing) {
|
|
|
|
|
backing.methods.for_each(fun(method: *ast_node) {
|
|
|
|
|
if (is_template(method))
|
|
|
|
|
method->template.instantiated.for_each(fun(m: *ast_node) generate_function_definition(m);)
|
|
|
|
|
else
|
|
|
|
|
generate_function_definition(method)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
2018-03-07 01:58:19 -05:00
|
|
|
fixup_function_addresses.for_each(fun(p: pair<int, *ast_node>) {
|
|
|
|
|
instructions[p.first].imm.val = functions[node_function_idx[p.second]].instruction_start
|
|
|
|
|
})
|
|
|
|
|
for (var i = 0; i < functions.size - 1; i++;)
|
|
|
|
|
functions[i].instruction_end = functions[i+1].instruction_start
|
|
|
|
|
functions.last().instruction_end = instructions.size
|
|
|
|
|
/*return make_pair(functions, instructions)*/
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_function_definition(node: *ast_node): int {
|
2018-03-07 01:58:19 -05:00
|
|
|
reset_reg()
|
|
|
|
|
node_function_idx[node] = functions.size
|
|
|
|
|
functions.add(bytecode_function(get_name(node), instructions.size))
|
2018-03-07 22:57:46 -05:00
|
|
|
var parameter_offset = (register_size*2) cast int // have to pass saved RBP and return address
|
2018-03-17 04:47:24 -04:00
|
|
|
|
|
|
|
|
var return_type = get_ast_type(node)->return_type
|
|
|
|
|
// if we're returning an object, our caller passes the address
|
|
|
|
|
// we should save our return value as as the first parameter
|
|
|
|
|
if (return_type->is_object() && return_type->indirection == 0) {
|
|
|
|
|
var ptr_type = return_type->clone_with_increased_indirection()
|
|
|
|
|
functions.last().var_to_frame_offset[ast_identifier_ptr("bytecode_struct_return_temp_address", ptr_type, null<ast_node>())] = parameter_offset
|
|
|
|
|
parameter_offset += type_size(ptr_type)
|
|
|
|
|
}
|
2018-02-03 22:47:21 -05:00
|
|
|
node->function.parameters.for_each(fun(p: *ast_node) {
|
2018-03-07 22:57:46 -05:00
|
|
|
functions.last().var_to_frame_offset[p] = parameter_offset
|
|
|
|
|
parameter_offset += type_size(p->identifier.type)
|
2018-02-03 22:47:21 -05:00
|
|
|
})
|
2018-03-10 00:27:16 -05:00
|
|
|
emit_addi(0, 0, -register_size) // these two lines push rbp onto the stack, which grows towards negative
|
2018-03-07 01:58:19 -05:00
|
|
|
emit_str(0, 0, 1, operand_size::b64()) // rsp[0] <= rbp
|
2018-03-10 00:27:16 -05:00
|
|
|
emit_addi(1, 0, 0) // note that we start the frame size at register_size for this reason
|
2018-03-06 23:30:00 -05:00
|
|
|
|
2018-03-07 01:58:19 -05:00
|
|
|
var push_frame_idx = instructions.size
|
2018-03-10 00:27:16 -05:00
|
|
|
emit_addi(0, 0, 0) // this has to be fixed afterwards to be the -frame_size
|
2018-03-06 23:30:00 -05:00
|
|
|
|
2018-02-03 18:53:13 -05:00
|
|
|
generate(node->function.body_statement)
|
2018-03-06 23:30:00 -05:00
|
|
|
|
2018-03-10 00:27:16 -05:00
|
|
|
instructions[push_frame_idx].addi.bi = -functions.last().frame_size
|
2018-03-06 23:30:00 -05:00
|
|
|
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_declaration_statement(node: *ast_node): int {
|
2018-02-02 00:26:31 -05:00
|
|
|
var identifier = node->declaration_statement.identifier
|
|
|
|
|
var ident_type = identifier->identifier.type
|
2018-03-06 23:30:00 -05:00
|
|
|
functions.last().frame_size += type_size(ident_type)
|
2018-03-07 22:57:46 -05:00
|
|
|
functions.last().var_to_frame_offset[identifier] = -functions.last().frame_size
|
2018-02-02 00:26:31 -05:00
|
|
|
if (node->declaration_statement.expression) {
|
2018-03-13 00:39:16 -04:00
|
|
|
// STRUCT HERE
|
2018-03-16 01:20:44 -04:00
|
|
|
if (ident_type->is_object() && ident_type->indirection == 0)
|
|
|
|
|
emit_struct_copy(1, functions.last().var_to_frame_offset[identifier], generate(node->declaration_statement.expression), 0, get_ast_type(identifier))
|
|
|
|
|
else
|
|
|
|
|
emit_str(1, functions.last().var_to_frame_offset[identifier], generate(node->declaration_statement.expression), size_to_operand_size(type_size(get_ast_type(identifier))))
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_assignment_statement(node: *ast_node): int {
|
|
|
|
|
var from = generate(node->assignment_statement.from)
|
2018-03-07 01:58:19 -05:00
|
|
|
var to = generate(node->assignment_statement.to, true)
|
2018-03-16 01:20:44 -04:00
|
|
|
var var_type = get_ast_type(node->assignment_statement.to)
|
2018-03-13 00:39:16 -04:00
|
|
|
// STRUCT HERE
|
2018-03-16 01:20:44 -04:00
|
|
|
if (var_type->is_object() && var_type->indirection == 0)
|
|
|
|
|
emit_struct_copy(to, 0, from, 0, var_type)
|
|
|
|
|
else
|
|
|
|
|
emit_str(to, 0, from, size_to_operand_size(type_size(var_type)))
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_if_statement(node: *ast_node): int {
|
2018-02-27 21:27:29 -05:00
|
|
|
var cond_reg = generate(node->if_statement.condition)
|
2018-03-07 01:58:19 -05:00
|
|
|
var jz_index = instructions.size
|
2018-02-27 21:41:57 -05:00
|
|
|
emit_jz(cond_reg,0)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-02-03 18:53:13 -05:00
|
|
|
generate(node->if_statement.then_part)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-02-27 21:27:29 -05:00
|
|
|
if (node->if_statement.else_part) {
|
2018-03-07 01:58:19 -05:00
|
|
|
var jmp_index = instructions.size
|
2018-02-27 21:27:29 -05:00
|
|
|
emit_jmp(0)
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions[jz_index].jz.offset = instructions.size - jz_index
|
2018-02-03 18:53:13 -05:00
|
|
|
generate(node->if_statement.else_part)
|
2018-03-12 20:17:26 -04:00
|
|
|
instructions[jmp_index].jmp = instructions.size - jmp_index
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-02-27 21:27:29 -05:00
|
|
|
} else {
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions[jz_index].jz.offset = instructions.size - jz_index
|
2018-02-27 21:27:29 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_while_loop(node: *ast_node): int {
|
2018-03-13 00:39:16 -04:00
|
|
|
var top_index = instructions.size
|
|
|
|
|
var cond_reg = generate(node->while_loop.condition)
|
|
|
|
|
var jz_index = instructions.size
|
|
|
|
|
emit_jz(cond_reg,0)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-03-13 00:39:16 -04:00
|
|
|
fixup_break_addresses.push(vector<int>())
|
|
|
|
|
fixup_continue_addresses.push(vector<int>())
|
2018-02-03 18:53:13 -05:00
|
|
|
generate(node->while_loop.statement)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-03-13 00:39:16 -04:00
|
|
|
emit_jmp(top_index - instructions.size)
|
|
|
|
|
instructions[jz_index].jz.offset = instructions.size - jz_index
|
|
|
|
|
fixup_continue_addresses.pop().for_each(fun(i: int) {
|
|
|
|
|
instructions[i].jmp = instructions.size - i
|
|
|
|
|
})
|
|
|
|
|
fixup_break_addresses.pop().for_each(fun(i: int) {
|
|
|
|
|
instructions[i].jmp = instructions.size - i
|
|
|
|
|
})
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_for_loop(node: *ast_node): int {
|
|
|
|
|
if (node->for_loop.init)
|
|
|
|
|
generate(node->for_loop.init)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-03-13 00:39:16 -04:00
|
|
|
var top_index = instructions.size
|
|
|
|
|
var cond_reg = 0
|
2018-02-03 18:53:13 -05:00
|
|
|
if (node->for_loop.condition)
|
2018-03-13 00:39:16 -04:00
|
|
|
cond_reg = generate(node->for_loop.condition)
|
|
|
|
|
else
|
|
|
|
|
cond_reg = emit_imm(1)
|
|
|
|
|
var jz_index = instructions.size
|
|
|
|
|
emit_jz(cond_reg,0)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-03-13 00:39:16 -04:00
|
|
|
fixup_break_addresses.push(vector<int>())
|
|
|
|
|
fixup_continue_addresses.push(vector<int>())
|
|
|
|
|
|
|
|
|
|
generate(node->for_loop.body)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
2018-03-13 00:39:16 -04:00
|
|
|
|
|
|
|
|
fixup_continue_addresses.pop().for_each(fun(i: int) {
|
|
|
|
|
instructions[i].jmp = instructions.size - i
|
|
|
|
|
})
|
|
|
|
|
|
2018-03-14 01:16:00 -04:00
|
|
|
if (node->for_loop.update) {
|
2018-02-03 18:53:13 -05:00
|
|
|
generate(node->for_loop.update)
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg()
|
|
|
|
|
}
|
2018-03-13 00:39:16 -04:00
|
|
|
|
|
|
|
|
emit_jmp(top_index - instructions.size)
|
|
|
|
|
|
|
|
|
|
instructions[jz_index].jz.offset = instructions.size - jz_index
|
|
|
|
|
fixup_break_addresses.pop().for_each(fun(i: int) {
|
|
|
|
|
instructions[i].jmp = instructions.size - i
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
fun generate_branching_statement(node: *ast_node): int {
|
|
|
|
|
match(node->branching_statement.b_type) {
|
|
|
|
|
branching_type::break_stmt() {
|
|
|
|
|
fixup_break_addresses.top().add(instructions.size)
|
|
|
|
|
emit_jmp(0)
|
|
|
|
|
}
|
|
|
|
|
branching_type::continue_stmt() {
|
|
|
|
|
fixup_continue_addresses.top().add(instructions.size)
|
|
|
|
|
emit_jmp(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 22:47:21 -05:00
|
|
|
fun generate_identifier(node: *ast_node, lvalue: bool): int {
|
2018-03-13 00:39:16 -04:00
|
|
|
// STRUCT HERE
|
2018-03-15 00:29:21 -04:00
|
|
|
var ident_type = get_ast_type(node)
|
|
|
|
|
if (lvalue || (ident_type->is_object() && ident_type->indirection == 0))
|
2018-03-10 00:27:16 -05:00
|
|
|
return emit_addi(1, functions.last().var_to_frame_offset[node])
|
2018-03-15 00:29:21 -04:00
|
|
|
else
|
|
|
|
|
return emit_ldr(1, functions.last().var_to_frame_offset[node], size_to_operand_size(type_size(ident_type)))
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_return_statement(node: *ast_node): int {
|
2018-03-13 00:39:16 -04:00
|
|
|
// STRUCT HERE
|
2018-02-27 23:53:08 +00:00
|
|
|
if (node->return_statement.return_value) {
|
2018-03-17 04:47:24 -04:00
|
|
|
var return_value_reg = generate(node->return_statement.return_value)
|
|
|
|
|
var return_type = get_ast_type(node->return_statement.return_value)
|
|
|
|
|
if (return_type->is_object() && return_type->indirection == 0) {
|
|
|
|
|
// fix this up to be nicer
|
|
|
|
|
// this is the hardcoded offset of the "first parameter" which
|
|
|
|
|
// is the address into which we should save our resulting struct
|
|
|
|
|
emit_struct_copy(emit_ldr(1, (register_size*2) cast int, size_to_operand_size(register_size)), 0, return_value_reg, 0, return_type)
|
|
|
|
|
} else {
|
|
|
|
|
emit_addi(2, return_value_reg, 0)
|
|
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
}
|
2018-03-17 04:47:24 -04:00
|
|
|
|
|
|
|
|
emit_addi(0, 1, register_size)
|
|
|
|
|
emit_ldr(1, 1, 0, operand_size::b64())
|
|
|
|
|
reset_reg()
|
|
|
|
|
emit_ret()
|
|
|
|
|
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_cast(node: *ast_node): int {
|
|
|
|
|
return generate(node->cast.value)
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_value(node: *ast_node): int {
|
2018-02-27 21:27:29 -05:00
|
|
|
if (node->value.value_type->is_bool())
|
|
|
|
|
return emit_imm((node->value.string_value == "true") cast int)
|
|
|
|
|
else
|
|
|
|
|
return emit_imm(string_to_num<int>(node->value.string_value))
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_code_block(node: *ast_node): int {
|
2018-02-27 23:53:08 +00:00
|
|
|
node->code_block.children.for_each(fun(child: *ast_node) {
|
2018-03-06 23:30:00 -05:00
|
|
|
// registers aren't used between statements (only stack reg)
|
|
|
|
|
reset_reg()
|
|
|
|
|
generate(child)
|
2018-02-27 23:53:08 +00:00
|
|
|
})
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
// this generates the function as a value, not the actual function
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_function(node: *ast_node): int {
|
2018-03-07 01:58:19 -05:00
|
|
|
fixup_function_addresses.add(make_pair(instructions.size,node))
|
2018-02-03 18:53:13 -05:00
|
|
|
return emit_imm(-2)
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 22:47:21 -05:00
|
|
|
fun generate_function_call(node: *ast_node, lvalue: bool): int {
|
2018-03-08 23:25:48 -05:00
|
|
|
var func = node->function_call.func
|
|
|
|
|
if (is_function(func) && func->function.body_statement == null<ast_node>()) {
|
|
|
|
|
var name = func->function.name
|
2018-03-10 15:32:51 -05:00
|
|
|
var parameter_nodes = node->function_call.parameters
|
|
|
|
|
// generate with lvalue=true to make return a pointer
|
|
|
|
|
if (name == "&" && parameter_nodes.size == 1)
|
|
|
|
|
return generate(parameter_nodes[0], true)
|
2018-03-14 23:43:52 -04:00
|
|
|
if (name == "++" || name == "++p" || name == "--" || name == "--p") {
|
|
|
|
|
var op_size = size_to_operand_size(type_size(get_ast_type(parameter_nodes[0])))
|
|
|
|
|
var addr_reg = generate(parameter_nodes[0], true)
|
|
|
|
|
var value_reg = emit_ldr(addr_reg, 0, op_size)
|
|
|
|
|
var mod_reg = -1
|
|
|
|
|
if (name[0] == '+')
|
|
|
|
|
mod_reg = emit_addi(value_reg, 1)
|
|
|
|
|
else
|
|
|
|
|
mod_reg = emit_addi(value_reg, -1)
|
|
|
|
|
emit_str(addr_reg, 0, mod_reg, op_size)
|
|
|
|
|
// if preincrement, return modified value, else unmodified
|
|
|
|
|
if (name.length() == 2)
|
|
|
|
|
return mod_reg
|
|
|
|
|
else
|
|
|
|
|
return value_reg
|
|
|
|
|
}
|
2018-03-10 15:32:51 -05:00
|
|
|
|
2018-03-15 00:29:21 -04:00
|
|
|
// STRUCT HERE
|
|
|
|
|
if (name == "." || name == "->") {
|
|
|
|
|
var base = generate(parameter_nodes[0])
|
|
|
|
|
if (!is_identifier(parameter_nodes[1]))
|
|
|
|
|
error("trying to access not an identifier")
|
|
|
|
|
var val_type = get_ast_type(parameter_nodes[1])
|
|
|
|
|
var offset = offset_into_struct(get_ast_type(parameter_nodes[0]), parameter_nodes[1])
|
|
|
|
|
var member_ptr = emit_addi(base, offset)
|
|
|
|
|
if (lvalue || (val_type->is_object() && val_type->indirection == 0))
|
|
|
|
|
return member_ptr
|
|
|
|
|
return emit_ldr(member_ptr, 0, size_to_operand_size(type_size(get_ast_type(parameter_nodes[1]))))
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-10 15:32:51 -05:00
|
|
|
var params = parameter_nodes.map(fun(n: *ast_node): int return generate(n);)
|
2018-03-08 23:25:48 -05:00
|
|
|
if (name == "+") {
|
|
|
|
|
if (params.size == 1)
|
2018-03-12 23:34:35 -04:00
|
|
|
return emit_smul(params[0], emit_or(emit_gz(params[0]), emit_smul(emit_lz(params[0]), emit_imm(-1))))
|
2018-03-08 23:25:48 -05:00
|
|
|
else
|
|
|
|
|
return emit_add(params[0], params[1])
|
|
|
|
|
} else if (name == "-") {
|
2018-03-10 00:27:16 -05:00
|
|
|
if (params.size == 1)
|
|
|
|
|
return emit_addi(emit_not(params[0]), 1)
|
|
|
|
|
else
|
|
|
|
|
return emit_add(params[0], emit_addi(emit_not(params[1]), 1))
|
2018-03-08 23:25:48 -05:00
|
|
|
} else if (name == "!") {
|
2018-03-12 23:34:35 -04:00
|
|
|
return emit_ez(params[0])
|
2018-03-15 00:29:21 -04:00
|
|
|
} else if (name == "[]" || (name == "*" && params.size == 1)) {
|
2018-03-10 15:32:51 -05:00
|
|
|
if (name == "[]") {
|
2018-03-12 23:34:35 -04:00
|
|
|
if (lvalue)
|
|
|
|
|
return emit_add(params[0], params[1])
|
|
|
|
|
else
|
|
|
|
|
return emit_ldr(emit_add(params[0], params[1]), 0, size_to_operand_size(type_size(get_ast_type(parameter_nodes[0])->clone_with_decreased_indirection())))
|
|
|
|
|
}
|
2018-03-10 15:32:51 -05:00
|
|
|
if (name == "*") {
|
2018-03-12 23:34:35 -04:00
|
|
|
if (lvalue)
|
|
|
|
|
return params[0]
|
|
|
|
|
else
|
|
|
|
|
return emit_ldr(params[0], 0, size_to_operand_size(type_size(get_ast_type(parameter_nodes[0])->clone_with_decreased_indirection())))
|
|
|
|
|
}
|
2018-03-08 23:25:48 -05:00
|
|
|
} else if (name == "==" || name == "<=" || name == ">=" || name == "!=" || name == "<" || name == ">") {
|
2018-03-12 23:34:35 -04:00
|
|
|
var diff = emit_add(params[0], emit_addi(emit_not(params[1]), 1))
|
|
|
|
|
if (name == "==") return emit_ez(diff)
|
|
|
|
|
if (name == "<=") return emit_or(emit_ez(diff), emit_lz(diff))
|
|
|
|
|
if (name == ">=") return emit_or(emit_ez(diff), emit_gz(diff))
|
|
|
|
|
if (name == "!=") return emit_ez(emit_ez(diff))
|
|
|
|
|
if (name == "<") return emit_lz(diff)
|
|
|
|
|
if (name == ">") return emit_gz(diff)
|
2018-03-08 23:25:48 -05:00
|
|
|
} else if (name == "|" || (name == "&" && params.size == 2) || name == "^" || name == "~") {
|
2018-03-10 00:27:16 -05:00
|
|
|
if (name == "|") return emit_or(params[0], params[1])
|
|
|
|
|
if (name == "&") return emit_and(params[0], params[1])
|
2018-03-12 00:43:51 -04:00
|
|
|
if (name == "^") return emit_xor(params[0], params[1])
|
2018-03-10 00:27:16 -05:00
|
|
|
if (name == "~") return emit_not(params[0])
|
2018-03-08 23:25:48 -05:00
|
|
|
} else if (name == ">>" || name == "<<") {
|
2018-03-12 23:34:35 -04:00
|
|
|
if (name == "<<")
|
|
|
|
|
return emit_shl(params[0], params[1])
|
|
|
|
|
if (get_ast_type(parameter_nodes[0])->is_signed_type())
|
|
|
|
|
return emit_sar(params[0], params[1])
|
|
|
|
|
else
|
|
|
|
|
return emit_shr(params[0], params[1])
|
2018-03-08 23:25:48 -05:00
|
|
|
} else if (name == "/" || name == "%" || (name == "*" && params.size == 2)) {
|
2018-03-12 20:17:26 -04:00
|
|
|
if (get_ast_type(parameter_nodes[0])->is_signed_type()) {
|
|
|
|
|
if (name == "/") return emit_sdiv(params[0], params[1])
|
|
|
|
|
if (name == "*") return emit_smul(params[0], params[1])
|
|
|
|
|
} else {
|
|
|
|
|
if (name == "/") return emit_udiv(params[0], params[1])
|
|
|
|
|
if (name == "*") return emit_umul(params[0], params[1])
|
|
|
|
|
}
|
|
|
|
|
if (name == "%") return emit_mod(params[0], params[1])
|
2018-03-08 23:25:48 -05:00
|
|
|
}
|
2018-03-12 00:43:51 -04:00
|
|
|
error("unknown operator " + name)
|
2018-03-08 23:25:48 -05:00
|
|
|
} else {
|
2018-03-17 04:47:24 -04:00
|
|
|
// if this function returns a struct, we have to allocate space for it on the top of the stack
|
|
|
|
|
// before we save registers, as it has to persist beyond the call (for whatever happens to it next)
|
|
|
|
|
// We stick it in the function as if this is the declaration of a temporary variable, basically
|
|
|
|
|
|
|
|
|
|
var return_type = get_ast_type(func)->return_type
|
|
|
|
|
var struct_return_temp_ident = null<ast_node>()
|
|
|
|
|
if (return_type->is_object() && return_type->indirection == 0) {
|
|
|
|
|
struct_return_temp_ident = ast_identifier_ptr("bytecode_struct_return_temp", return_type, null<ast_node>())
|
|
|
|
|
functions.last().frame_size += type_size(return_type)
|
|
|
|
|
functions.last().var_to_frame_offset[struct_return_temp_ident] = -functions.last().frame_size
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 01:16:00 -04:00
|
|
|
// save regs
|
|
|
|
|
var save_til = peek_reg()
|
|
|
|
|
var save_size = (save_til - 3) * register_size
|
|
|
|
|
if (save_size != 0) {
|
|
|
|
|
emit_addi(0, 0, -save_size)
|
|
|
|
|
for (var i = 3; i < save_til; i++;) {
|
|
|
|
|
emit_str(0, ((i-3)*register_size) cast int, i, operand_size::b64())
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-13 00:39:16 -04:00
|
|
|
// STRUCT HERE
|
2018-03-08 23:25:48 -05:00
|
|
|
// reverse order
|
2018-03-14 01:16:00 -04:00
|
|
|
var total_param_size = 0
|
2018-03-08 23:25:48 -05:00
|
|
|
node->function_call.parameters.reverse().for_each(fun(child: *ast_node) {
|
|
|
|
|
// push param onto stack
|
2018-03-16 01:31:03 -04:00
|
|
|
var param_type = get_ast_type(child)
|
|
|
|
|
var param_size = type_size(param_type)
|
|
|
|
|
var param_reg = generate(child)
|
2018-03-10 00:27:16 -05:00
|
|
|
emit_addi(0, 0, -param_size)
|
2018-03-14 01:16:00 -04:00
|
|
|
total_param_size += param_size
|
2018-03-16 01:31:03 -04:00
|
|
|
if (param_type->is_object() && param_type->indirection == 0)
|
|
|
|
|
emit_struct_copy(0, 0, param_reg, 0, param_type)
|
|
|
|
|
else
|
|
|
|
|
emit_str(0, 0, param_reg, size_to_operand_size(param_size))
|
2018-03-14 01:16:00 -04:00
|
|
|
reset_reg(save_til)
|
2018-03-08 23:25:48 -05:00
|
|
|
})
|
2018-03-17 04:47:24 -04:00
|
|
|
// pass the address to save the struct into as a parameter
|
|
|
|
|
if (return_type->is_object() && return_type->indirection == 0) {
|
|
|
|
|
emit_addi(0, 0, -(register_size) cast int)
|
|
|
|
|
total_param_size += (register_size) cast int
|
|
|
|
|
emit_str(0, 0, emit_addi(1, functions.last().var_to_frame_offset[struct_return_temp_ident]), size_to_operand_size(register_size))
|
|
|
|
|
reset_reg(save_til)
|
|
|
|
|
}
|
2018-03-08 23:25:48 -05:00
|
|
|
var return_reg = emit_call(generate_function(node->function_call.func))
|
2018-03-17 04:47:24 -04:00
|
|
|
|
|
|
|
|
if (return_type->is_object() && return_type->indirection == 0) {
|
|
|
|
|
// if returned struct, then the struct was saved where we asked for it to be
|
|
|
|
|
// return pointer with that address
|
|
|
|
|
return_reg = emit_addi(1, functions.last().var_to_frame_offset[struct_return_temp_ident])
|
|
|
|
|
} else {
|
|
|
|
|
// returning through r2 every time doesn't give unique regs for functions used together in an expression
|
|
|
|
|
// so get a new one for this time
|
|
|
|
|
return_reg = emit_addi(return_reg, 0)
|
|
|
|
|
}
|
2018-03-14 01:16:00 -04:00
|
|
|
emit_addi(0, 0, total_param_size)
|
|
|
|
|
|
|
|
|
|
// restore regs
|
|
|
|
|
for (var i = 3; i < save_til; i++;) {
|
|
|
|
|
emit_ldr(i, 0, ((i-3)*register_size) cast int, operand_size::b64())
|
|
|
|
|
}
|
|
|
|
|
if (save_size != 0)
|
|
|
|
|
emit_addi(0, 0, save_size)
|
|
|
|
|
|
2018-03-08 23:25:48 -05:00
|
|
|
return return_reg
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
|
2018-02-03 18:53:13 -05:00
|
|
|
fun generate_compiler_intrinsic(node: *ast_node): int {
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions.add(byte_inst::nop())
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
|
2018-02-03 22:47:21 -05:00
|
|
|
fun generate(node: *ast_node): int return generate(node, false)
|
|
|
|
|
fun generate(node: *ast_node, lvalue: bool): int {
|
2018-02-02 00:26:31 -05:00
|
|
|
match (*node) {
|
2018-02-03 18:53:13 -05:00
|
|
|
ast_node::declaration_statement(backing) return generate_declaration_statement(node)
|
|
|
|
|
ast_node::assignment_statement(backing) return generate_assignment_statement(node)
|
|
|
|
|
ast_node::if_statement(backing) return generate_if_statement(node)
|
|
|
|
|
ast_node::while_loop(backing) return generate_while_loop(node)
|
|
|
|
|
ast_node::for_loop(backing) return generate_for_loop(node)
|
|
|
|
|
ast_node::function(backing) return generate_function(node)
|
2018-02-03 22:47:21 -05:00
|
|
|
ast_node::function_call(backing) return generate_function_call(node, lvalue)
|
2018-02-03 18:53:13 -05:00
|
|
|
ast_node::compiler_intrinsic(backing) return generate_compiler_intrinsic(node)
|
|
|
|
|
ast_node::code_block(backing) return generate_code_block(node)
|
|
|
|
|
ast_node::return_statement(backing) return generate_return_statement(node)
|
|
|
|
|
ast_node::branching_statement(backing) return generate_branching_statement(node)
|
|
|
|
|
ast_node::cast(backing) return generate_cast(node)
|
|
|
|
|
ast_node::value(backing) return generate_value(node)
|
2018-02-03 22:47:21 -05:00
|
|
|
ast_node::identifier(backing) return generate_identifier(node, lvalue)
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
2018-02-03 18:53:13 -05:00
|
|
|
error("Bad node")
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|
|
|
|
|
fun get_name(node: *ast_node): string {
|
|
|
|
|
var maybe_it = ast_name_map.get_ptr_or_null(node);
|
|
|
|
|
if (maybe_it)
|
|
|
|
|
return *maybe_it
|
2018-02-03 18:53:13 -05:00
|
|
|
var result = get_ast_name(node) + get_id()
|
|
|
|
|
if (is_function(node) && node->function.name == "main")
|
|
|
|
|
result = "main"
|
2018-02-02 00:26:31 -05:00
|
|
|
ast_name_map.set(node, result)
|
|
|
|
|
return result
|
|
|
|
|
}
|
2018-03-16 01:20:44 -04:00
|
|
|
fun emit_struct_copy(to: int, to_offset: int, from: int, from_offset: int, t: *type) {
|
|
|
|
|
for (var i = 0; i < t->type_def->type_def.variables.size; i++;) {
|
|
|
|
|
var member_var = t->type_def->type_def.variables[i]->declaration_statement.identifier
|
|
|
|
|
var member_type = get_ast_type(member_var)
|
|
|
|
|
var member_offset = offset_into_struct(t, member_var)
|
|
|
|
|
if (member_type->is_object() && member_type->indirection == 0) {
|
|
|
|
|
emit_struct_copy(to, (to_offset + member_offset) cast int, from, (from_offset + member_offset) cast int, member_type)
|
|
|
|
|
} else {
|
|
|
|
|
var member_size = size_to_operand_size(type_size(member_type))
|
|
|
|
|
emit_str(to, (to_offset + member_offset) cast int, emit_ldr(from, (from_offset + member_offset) cast int, member_size), member_size)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-06 23:30:00 -05:00
|
|
|
fun emit_imm(value: ulong): int { return emit_imm((value) cast int); }
|
2018-02-03 18:53:13 -05:00
|
|
|
fun emit_imm(value: int): int {
|
|
|
|
|
var i: imm
|
2018-03-12 20:17:26 -04:00
|
|
|
i.to_reg = get_reg()
|
2018-02-03 18:53:13 -05:00
|
|
|
i.val = value
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions.add(byte_inst::imm(i))
|
2018-03-12 20:17:26 -04:00
|
|
|
return i.to_reg
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-03-10 00:27:16 -05:00
|
|
|
fun emit_add(a: int, b: int): int { return emit_add(get_reg(), a, b); }
|
2018-03-06 23:30:00 -05:00
|
|
|
fun emit_add(dest: int, a: int, b: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg2
|
2018-03-06 23:30:00 -05:00
|
|
|
i.to_reg = dest
|
2018-02-27 23:53:08 +00:00
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions.add(byte_inst::add(i))
|
2018-02-27 23:53:08 +00:00
|
|
|
return i.to_reg
|
2018-02-03 22:47:21 -05:00
|
|
|
}
|
2018-03-10 00:27:16 -05:00
|
|
|
fun emit_addi(a: int, bi: long): int { return emit_addi(get_reg(), a, bi); }
|
|
|
|
|
fun emit_addi(a: int, bi: int): int { return emit_addi(get_reg(), a, (bi) cast long); }
|
|
|
|
|
fun emit_addi(dest: int, a: int, bi: int): int { return emit_addi(dest, a, (bi) cast long); }
|
|
|
|
|
fun emit_addi(a: int, bi: ulong): int { return emit_addi(get_reg(), a, (bi) cast long); }
|
|
|
|
|
fun emit_addi(dest: int, a: int, bi: ulong): int { return emit_addi(dest, a, (bi) cast long); }
|
|
|
|
|
fun emit_addi(dest: int, a: int, bi: long): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg1i
|
2018-03-10 00:27:16 -05:00
|
|
|
i.to_reg = dest
|
|
|
|
|
i.a = a
|
|
|
|
|
i.bi = bi
|
|
|
|
|
instructions.add(byte_inst::addi(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
fun emit_umul(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::umul(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_smul(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::smul(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_udiv(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::udiv(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_sdiv(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::sdiv(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_mod(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::mod(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-12 23:34:35 -04:00
|
|
|
fun emit_shr(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::shr(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_sar(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::sar(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_shl(a: int, b: int): int {
|
|
|
|
|
var i: reg2
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::shl(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-10 00:27:16 -05:00
|
|
|
fun emit_and(a: int, b: int): int { return emit_and(get_reg(), a, b); }
|
|
|
|
|
fun emit_and(dest: int, a: int, b: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg2
|
2018-03-10 00:27:16 -05:00
|
|
|
i.to_reg = dest
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::and(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_or(a: int, b: int): int { return emit_or(get_reg(), a, b); }
|
|
|
|
|
fun emit_or(dest: int, a: int, b: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg2
|
2018-03-10 00:27:16 -05:00
|
|
|
i.to_reg = dest
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::or(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-12 00:43:51 -04:00
|
|
|
fun emit_xor(a: int, b: int): int { return emit_xor(get_reg(), a, b); }
|
|
|
|
|
fun emit_xor(dest: int, a: int, b: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg2
|
2018-03-12 00:43:51 -04:00
|
|
|
i.to_reg = dest
|
|
|
|
|
i.a = a
|
|
|
|
|
i.b = b
|
|
|
|
|
instructions.add(byte_inst::xor(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-10 00:27:16 -05:00
|
|
|
fun emit_not(a: int): int { return emit_not(get_reg(), a); }
|
|
|
|
|
fun emit_not(dest: int, a: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var i: reg1
|
2018-03-10 00:27:16 -05:00
|
|
|
i.to_reg = dest
|
|
|
|
|
i.a = a
|
|
|
|
|
instructions.add(byte_inst::not(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-12 23:34:35 -04:00
|
|
|
fun emit_gz(a: int): int {
|
|
|
|
|
var i: reg1
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
instructions.add(byte_inst::gz(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_lz(a: int): int {
|
|
|
|
|
var i: reg1
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
instructions.add(byte_inst::lz(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
|
|
|
|
fun emit_ez(a: int): int {
|
|
|
|
|
var i: reg1
|
|
|
|
|
i.to_reg = get_reg()
|
|
|
|
|
i.a = a
|
|
|
|
|
instructions.add(byte_inst::ez(i))
|
|
|
|
|
return i.to_reg
|
|
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
fun emit_ldr(reg: int, offset: int, size: operand_size): int { return emit_ldr(get_reg(), reg, offset, size); }
|
|
|
|
|
fun emit_ldr(dest: int, reg: int, offset: int, size: operand_size): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var l: reg1is
|
|
|
|
|
l.reg = dest
|
|
|
|
|
l.base_reg = reg
|
2018-02-27 23:53:08 +00:00
|
|
|
l.offset = offset
|
2018-03-07 01:58:19 -05:00
|
|
|
l.size = size
|
|
|
|
|
instructions.add(byte_inst::ldr(l))
|
2018-03-12 20:17:26 -04:00
|
|
|
return l.reg
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
fun emit_str(to_reg: int, offset: int, from_reg: int, size: operand_size): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var s: reg1is
|
|
|
|
|
s.reg = from_reg
|
2018-02-27 23:53:08 +00:00
|
|
|
s.offset = offset
|
2018-03-12 20:17:26 -04:00
|
|
|
s.base_reg = to_reg
|
2018-03-07 01:58:19 -05:00
|
|
|
s.size = size
|
|
|
|
|
instructions.add(byte_inst::str(s))
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
|
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
fun emit_jmp(offset: int): int { return emit_jmp((offset) cast long); }
|
|
|
|
|
fun emit_jmp(offset: long): int {
|
|
|
|
|
instructions.add(byte_inst::jmp(offset))
|
2018-02-27 21:27:29 -05:00
|
|
|
return -1
|
|
|
|
|
}
|
2018-02-27 21:41:57 -05:00
|
|
|
fun emit_jz(reg: int, offset: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
var j: test
|
2018-02-27 21:27:29 -05:00
|
|
|
j.reg = reg
|
|
|
|
|
j.offset = offset
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions.add(byte_inst::jz(j))
|
2018-02-27 21:27:29 -05:00
|
|
|
return -1
|
|
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
fun emit_ret(): int {
|
2018-03-07 01:58:19 -05:00
|
|
|
instructions.add(byte_inst::ret())
|
2018-02-03 18:53:13 -05:00
|
|
|
return -1
|
|
|
|
|
}
|
2018-03-07 01:58:19 -05:00
|
|
|
fun emit_call(reg: int): int {
|
2018-03-12 20:17:26 -04:00
|
|
|
instructions.add(byte_inst::call(reg))
|
2018-03-07 01:58:19 -05:00
|
|
|
return 2
|
2018-02-03 18:53:13 -05:00
|
|
|
}
|
2018-02-03 22:47:21 -05:00
|
|
|
|
2018-03-06 23:30:00 -05:00
|
|
|
// Stack ABI
|
2018-03-15 00:29:21 -04:00
|
|
|
// it's system v x64ish, but all params passed on stack
|
2018-02-03 22:47:21 -05:00
|
|
|
fun evaluate(): int {
|
|
|
|
|
println("evaling main")
|
2018-03-07 01:58:19 -05:00
|
|
|
println(bytecode_to_string(functions, instructions))
|
2018-02-27 23:53:08 +00:00
|
|
|
var main_entry = functions.find_first_satisfying(fun(block: bytecode_function): bool return block.name == "main";)
|
2018-03-06 23:30:00 -05:00
|
|
|
var registers.construct(reg_max): vector<long>
|
2018-02-27 23:53:08 +00:00
|
|
|
registers.size = reg_max
|
2018-03-07 01:58:19 -05:00
|
|
|
registers[0] = -register_size // with the stack being zeroed out, this makes it a return address of 0
|
|
|
|
|
registers[1] = 0xdeadbeefcafebabe
|
2018-03-06 23:30:00 -05:00
|
|
|
var stack_size = 8 * 1024 * 1024
|
|
|
|
|
var stack = new<uchar>(stack_size) + stack_size
|
|
|
|
|
for (var i = 0; i < stack_size; i++;)
|
|
|
|
|
stack[-i + -1] = 0
|
2018-03-07 01:58:19 -05:00
|
|
|
for (var i = main_entry.instruction_start; i < instructions.size; i++;) {
|
|
|
|
|
println(string("evaling: ") + i + ": " + to_string(instructions[i]))
|
|
|
|
|
match(instructions[i]) {
|
2018-02-03 22:47:21 -05:00
|
|
|
byte_inst::nop() {}
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::imm(i) registers[i.to_reg] = i.val
|
2018-02-27 23:53:08 +00:00
|
|
|
byte_inst::add(a) registers[a.to_reg] = registers[a.a] + registers[a.b]
|
2018-03-10 00:27:16 -05:00
|
|
|
byte_inst::addi(a) registers[a.to_reg] = registers[a.a] + a.bi
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::umul(a) registers[a.to_reg] = (registers[a.a]) cast ulong * (registers[a.b]) cast ulong
|
|
|
|
|
byte_inst::smul(a) registers[a.to_reg] = registers[a.a] * registers[a.b]
|
|
|
|
|
byte_inst::udiv(a) registers[a.to_reg] = (registers[a.a]) cast ulong / (registers[a.b]) cast ulong
|
|
|
|
|
byte_inst::sdiv(a) registers[a.to_reg] = registers[a.a] / registers[a.b]
|
|
|
|
|
byte_inst::mod(a) registers[a.to_reg] = (registers[a.a]) cast ulong % (registers[a.b]) cast ulong
|
2018-03-12 23:34:35 -04:00
|
|
|
byte_inst::shr(a) registers[a.to_reg] = (registers[a.a]) cast ulong >>(registers[a.b]) cast ulong
|
|
|
|
|
byte_inst::sar(a) registers[a.to_reg] = registers[a.a] >> registers[a.b]
|
|
|
|
|
byte_inst::shl(a) registers[a.to_reg] = (registers[a.a]) cast ulong <<(registers[a.b]) cast ulong
|
2018-03-10 00:27:16 -05:00
|
|
|
byte_inst::and(a) registers[a.to_reg] = registers[a.a] & registers[a.b]
|
|
|
|
|
byte_inst::or(a) registers[a.to_reg] = registers[a.a] | registers[a.b]
|
2018-03-12 00:43:51 -04:00
|
|
|
byte_inst::xor(a) registers[a.to_reg] = registers[a.a] ^ registers[a.b]
|
2018-03-10 00:27:16 -05:00
|
|
|
byte_inst::not(a) registers[a.to_reg] = ~registers[a.a]
|
2018-03-12 23:34:35 -04:00
|
|
|
byte_inst::gz(a) registers[a.to_reg] = registers[a.a] > 0
|
|
|
|
|
byte_inst::lz(a) registers[a.to_reg] = registers[a.a] < 0
|
|
|
|
|
byte_inst::ez(a) registers[a.to_reg] = registers[a.a] == 0
|
2018-03-07 01:58:19 -05:00
|
|
|
byte_inst::ldr(l) match (l.size) {
|
2018-03-12 20:17:26 -04:00
|
|
|
operand_size::b8() registers[l.reg] = *(stack + registers[l.base_reg] + l.offset) cast *char
|
|
|
|
|
operand_size::b16() registers[l.reg] = *(stack + registers[l.base_reg] + l.offset) cast *short
|
|
|
|
|
operand_size::b32() registers[l.reg] = *(stack + registers[l.base_reg] + l.offset) cast *int
|
|
|
|
|
operand_size::b64() registers[l.reg] = *(stack + registers[l.base_reg] + l.offset) cast *long
|
2018-03-07 01:58:19 -05:00
|
|
|
}
|
|
|
|
|
byte_inst::str(s) match (s.size) {
|
2018-03-12 20:17:26 -04:00
|
|
|
operand_size::b8() *(stack + registers[s.base_reg] + s.offset) cast *uchar = registers[s.reg]
|
|
|
|
|
operand_size::b16() *(stack + registers[s.base_reg] + s.offset) cast *ushort = registers[s.reg]
|
|
|
|
|
operand_size::b32() *(stack + registers[s.base_reg] + s.offset) cast *uint = registers[s.reg]
|
|
|
|
|
operand_size::b64() *(stack + registers[s.base_reg] + s.offset) cast *ulong = registers[s.reg]
|
2018-03-07 01:58:19 -05:00
|
|
|
}
|
2018-03-12 20:17:26 -04:00
|
|
|
byte_inst::jmp(offset) i += offset - 1 // to counteract pc inc
|
2018-02-27 21:41:57 -05:00
|
|
|
byte_inst::jz(j) if (registers[j.reg] == 0)
|
2018-02-27 21:27:29 -05:00
|
|
|
i += j.offset - 1 // to counteract pc inc
|
2018-03-07 01:58:19 -05:00
|
|
|
byte_inst::call(c) {
|
|
|
|
|
/*registers[0] -= register_size*/
|
|
|
|
|
registers[0] = registers[0] - register_size
|
|
|
|
|
*(stack + registers[0]) cast *long = i + 1
|
2018-03-12 20:17:26 -04:00
|
|
|
i = registers[c] - 1
|
2018-03-07 22:57:46 -05:00
|
|
|
print("call!")
|
|
|
|
|
println("first part of memory is (after push)")
|
|
|
|
|
for (var i = 0; i < 8*8; i+=8;) {
|
|
|
|
|
print(string("-") + i + string(": "))
|
|
|
|
|
for (var j = 0; j < 8; j++;) {
|
|
|
|
|
if (j == 4)
|
|
|
|
|
print(" ")
|
|
|
|
|
print(*(stack - (i+j)*#sizeof<uchar> - 1) cast *uchar)
|
|
|
|
|
print(" ")
|
|
|
|
|
}
|
|
|
|
|
println()
|
|
|
|
|
}
|
|
|
|
|
println("Done")
|
2018-03-06 23:30:00 -05:00
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
byte_inst::ret() {
|
2018-03-07 01:58:19 -05:00
|
|
|
var pc = *(stack + registers[0]) cast *long
|
|
|
|
|
/*registers[0] += register_size*/
|
|
|
|
|
registers[0] = registers[0] + register_size
|
2018-02-27 23:53:08 +00:00
|
|
|
print("returning! return value is\n\t")
|
2018-03-06 23:30:00 -05:00
|
|
|
var value = registers[2]
|
|
|
|
|
println(value)
|
|
|
|
|
println("first part of memory is")
|
|
|
|
|
for (var i = 0; i < 8*8; i+=8;) {
|
|
|
|
|
print(string("-") + i + string(": "))
|
|
|
|
|
for (var j = 0; j < 8; j++;) {
|
|
|
|
|
if (j == 4)
|
|
|
|
|
print(" ")
|
|
|
|
|
print(*(stack - (i+j)*#sizeof<uchar> - 1) cast *uchar)
|
|
|
|
|
print(" ")
|
|
|
|
|
}
|
|
|
|
|
println()
|
|
|
|
|
}
|
|
|
|
|
println("Done")
|
2018-03-07 01:58:19 -05:00
|
|
|
if (pc == 0) {
|
|
|
|
|
return value
|
|
|
|
|
} else {
|
|
|
|
|
i = pc - 1
|
|
|
|
|
println(string("returning to ") + pc)
|
|
|
|
|
}
|
2018-02-27 23:53:08 +00:00
|
|
|
}
|
2018-02-03 22:47:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1
|
|
|
|
|
}
|
2018-02-02 00:26:31 -05:00
|
|
|
}
|