Remove old files
This commit is contained in:
@@ -1,179 +0,0 @@
|
||||
sizes = ["64", "32", "16", "8"]
|
||||
types = ["S64", "U64", "F64"]
|
||||
print_sign = ["%lld", "%llu", "%f"]
|
||||
operations = [
|
||||
["+", "ADD"], ["-", "SUB"], ["/", "DIV"], ["*", "MUL"], ["%", "MOD"],
|
||||
[">>", "SHR"], ["<<", "SHL"], ["&", "BITAND"], ["|", "BITOR"], ["^", "BITXOR"],
|
||||
["~", "BITNOT"], ["==", "EQ"], ["!=", "NEQ"], [">", "GT"], ["<", "LT"], ["||", "OR"],
|
||||
[">=", "GTE"], ["<=", "LTE"]
|
||||
]
|
||||
|
||||
def should_skip(T, op):
|
||||
if T == "F64":
|
||||
if op != "DIV" and op != "SUB" and op != "ADD" and op != "MUL" and op != "EQ" and op != "NEQ"\
|
||||
and op != "GT" and op != "LT" and op != "GTE" and op != "LTE":
|
||||
return True
|
||||
|
||||
# This function inserts generated code into the specified file
|
||||
# it requires a specific comment to be triggered.
|
||||
# Lossing data would be terrible so we also backup that file
|
||||
# in case something bad happens
|
||||
def update_file(filename, comment_name, data_to_write):
|
||||
begin = f"""//
|
||||
// *Begin* of {comment_name} generated using code_generating_script.py
|
||||
//
|
||||
"""
|
||||
end = f"""
|
||||
//
|
||||
// *End* of {comment_name} generated using code_generating_script.py
|
||||
//"""
|
||||
|
||||
with open(filename, 'r+') as file:
|
||||
data = file.read()
|
||||
file.seek(0)
|
||||
|
||||
begin_index = data.find(begin)
|
||||
end_index = data.find(end)
|
||||
if begin_index == -1 or end_index == -1:
|
||||
print(f"Error: Couldn't find comment: {comment_name}")
|
||||
exit(0)
|
||||
|
||||
end_index += len(end)
|
||||
|
||||
with open('backup', 'a') as backup:
|
||||
backup.write(f"\n*** FILE = {filename} NAME = {comment_name} ***")
|
||||
backup.write(f"\n*** FILE = {filename} NAME = {comment_name} ***")
|
||||
backup.write(f"\n*** FILE = {filename} NAME = {comment_name} ***")
|
||||
backup.write(data)
|
||||
|
||||
a_part = data[0:begin_index]
|
||||
b_part = data[begin_index:end_index]
|
||||
c_part = data[end_index:len(data)]
|
||||
|
||||
data_to_write = begin + data_to_write + end
|
||||
|
||||
file.write(a_part + data_to_write + c_part)
|
||||
file.truncate()
|
||||
|
||||
|
||||
|
||||
if False:
|
||||
result = ""
|
||||
enum_members = [
|
||||
"BC_END_OF_INSTRUCTIONS",
|
||||
"BC_POP_STACK",
|
||||
"BC_PUSH_STACK",
|
||||
"BC_LOAD_CONSTANT",
|
||||
"BC_STORE_CONSTANT",
|
||||
"BC_CALL",
|
||||
"BC_CALL_RETURN",
|
||||
]
|
||||
|
||||
load_store = ["LOAD_FROM_MEMORY", "STORE_TO_MEMORY"]
|
||||
for op in load_store:
|
||||
for size in sizes:
|
||||
enum_members.append(f"BC_{op}{size}")
|
||||
|
||||
for T in types:
|
||||
for _, op in operations:
|
||||
if should_skip(T, op):
|
||||
continue
|
||||
enum_members.append(f"BC_{op}_{T}")
|
||||
|
||||
result += "enum Operation: U16{\n"
|
||||
for i in enum_members:
|
||||
result += f" {i},\n"
|
||||
result += "};\n"
|
||||
|
||||
result += "const char *op_name[] = {\n"
|
||||
for i in enum_members:
|
||||
result += f" \"{i}\",\n"
|
||||
result += "};\n"
|
||||
update_file("bytecode_interpreter.cpp", "enum", result)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Generate switch cases
|
||||
#
|
||||
if False:
|
||||
result = ""
|
||||
|
||||
for size in sizes:
|
||||
result += f"""
|
||||
case BC_LOAD_FROM_MEMORY{size}:{{
|
||||
U{size} *load_address = R(instr->index_a).pointer_u{size};
|
||||
R(instr->index_c).u{size} = *load_address;
|
||||
bc_log("load_address[r%u, %llx] dst[r%u] [0x%llx|%lld|%f]", instr->index_a, load_address, instr->index_c, R(instr->index_c).u{size}, R(instr->index_c).u{size}, R(instr->index_c).u{size});
|
||||
}}break;
|
||||
|
||||
case BC_STORE_TO_MEMORY{size}:{{
|
||||
U{size} *store_address = R(instr->index_c).pointer_u{size};
|
||||
*store_address = R(instr->index_a).u{size};
|
||||
bc_log("src[r%u] store_address[r%u, %llx] value_written[0x%llx|%lld|%f]", instr->index_a, instr->index_c, store_address, *store_address, *store_address, *store_address);
|
||||
}}break;
|
||||
"""
|
||||
|
||||
for sign, T in zip(print_sign, types):
|
||||
t = T.lower()
|
||||
|
||||
# Generate arithmetic
|
||||
for symbol, op_name in operations:
|
||||
if should_skip(T, op_name):
|
||||
continue
|
||||
|
||||
###################################
|
||||
# Unary operator special case
|
||||
if symbol == "~":
|
||||
result += f"""
|
||||
case BC_{op_name}_{T}:{{
|
||||
{T} left = ({T})R(instr->index_a).{t};
|
||||
{T} result = {symbol}left;
|
||||
{T} *dst = R(instr->index_c).pointer_{t};
|
||||
*dst = result;
|
||||
bc_log("{symbol} [{sign}] = [{sign}]", left, result);
|
||||
}}break;
|
||||
"""
|
||||
continue
|
||||
################################
|
||||
|
||||
################################
|
||||
# Binary operation
|
||||
result += f"""
|
||||
case BC_{op_name}_{T}:{{
|
||||
{T} left = R(instr->index_a).{t};
|
||||
{T} right = R(instr->index_b).{t};
|
||||
{T} result = left {symbol} right;
|
||||
R(instr->index_c).{t} = result;
|
||||
bc_log("[r%d, {sign}] {symbol} [r%d, {sign}] = [r%d, {sign}]", instr->index_a, left, instr->index_b, right, instr->index_c, result);
|
||||
}}break;
|
||||
"""
|
||||
################################
|
||||
update_file("bytecode_interpreter.cpp", "switch_cases", result)
|
||||
|
||||
|
||||
type_table = [
|
||||
["S", ["Int", "SInt", "4sizes"]],
|
||||
["U", ["Int", "UInt", "4sizes"]],
|
||||
["INT", ["Int", "untyped"]],
|
||||
]
|
||||
|
||||
for name, flags in type_table:
|
||||
names = []
|
||||
if "4sizes" in flags:
|
||||
for size in sizes:
|
||||
names.append(name + size)
|
||||
if "untyped" in flags:
|
||||
names.append("UNTYPED_" + name)
|
||||
|
||||
print(names)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# #
|
||||
# # Copy backup to **WINDOWS** clipboard
|
||||
# #
|
||||
# import subprocess
|
||||
# subprocess.run("clip", universal_newlines=True, input=data)
|
||||
2
main.cpp
2
main.cpp
@@ -103,7 +103,7 @@ For modules it's a bit different cause they should be distributed as valid.
|
||||
#include "base.cpp"
|
||||
#include "base_unicode.cpp"
|
||||
#include "os_windows.cpp"
|
||||
#include "big_int_c3.cpp"
|
||||
#include "c3_big_int.cpp"
|
||||
#include "compiler.h"
|
||||
#include "lexing.cpp"
|
||||
#include "types.h"
|
||||
|
||||
190
x64_funtime.cpp
190
x64_funtime.cpp
@@ -1,190 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define assert(x) do{if(!(x))__debugbreak();}while(0)
|
||||
#define assert_in_range(x, a, b) assert(((x) >= a) && ((x) <= b))
|
||||
#define assert_is_one(x) assert_in_range(x, 0, 1)
|
||||
|
||||
uint8_t* code_start;
|
||||
uint8_t* code;
|
||||
|
||||
void emit(uint8_t c) {
|
||||
*code++ = c;
|
||||
}
|
||||
|
||||
void emit32(uint32_t c) {
|
||||
*(uint32_t*)code = c;
|
||||
code += 4;
|
||||
}
|
||||
|
||||
// Prefix ordering in X64:
|
||||
// 1. Legacy prefixes (optional)
|
||||
// 2. REX prefix (optional)
|
||||
// 3. Opcode (1 or 2 or 3 bytes)
|
||||
// 4. ModR/M (1 byte if required)
|
||||
// 5. SIB (1 byte if required)
|
||||
// 6. Displacement (1 or 2 or 4 bytes)
|
||||
// 7. Immediate (1 or 2 or 4 bytes)
|
||||
|
||||
// Basic op codes
|
||||
const uint8_t OP_BREAK = 0xCC;
|
||||
const uint8_t OP_RETURN = 0xC3;
|
||||
|
||||
// From manual:
|
||||
// The operand-size override prefix allows a program to switch between 16-and 32-bit operand sizes. Either size can
|
||||
// be the default; use of the prefix selects the non-default size.
|
||||
// When using the REX prefix, adding this changes the operand size to 32bits
|
||||
const uint8_t OPERAND_SIZE_OVERRIDE = 0x66;
|
||||
const uint8_t GS_SEGMENT_OVERRIDE = 0x65;
|
||||
|
||||
// Registers
|
||||
// al(8lo), ah(8hi), ax(16), eax(32), rax(64)
|
||||
enum{RAX, RCX, RDX, RBX, RSP, RBP, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15};
|
||||
typedef uint8_t Register;
|
||||
|
||||
// REX - 64 bit mode prefix
|
||||
// we write this when
|
||||
// * instruction references extended(64bit) register
|
||||
// * uses a 64 bit operand.
|
||||
// W 1 bit When 1, a 64 - bit operand size is used. Otherwise, when 0, the default operand size is used(which is 32 - bit for most but not all instructions, see this table).
|
||||
// R 1 bit This 1 - bit value is an extension to the MODRM.reg field.See Registers.
|
||||
// X 1 bit This 1 - bit value is an extension to the SIB.index field.See 64 - bit addressing.
|
||||
// B 1 bit This 1 - bit value is an extension to the MODRM.rm field or the SIB.base field.See 64 - bit addressing.
|
||||
uint8_t rex(uint8_t w, uint8_t r, uint8_t x, uint8_t b) {
|
||||
assert_is_one(w); assert_is_one(r);
|
||||
assert_is_one(x); assert_is_one(b);
|
||||
return 0b0100 << 4 | w << 3 | r << 2 | x << 1 | b;
|
||||
}
|
||||
#define REX_W rex(1,0,0,0)
|
||||
|
||||
// ModR/M
|
||||
//
|
||||
// Addressing
|
||||
// - Indirect : operand is stored under the address specified by one of the registers
|
||||
// - Displaced: operand is stored under the displaced(offset) address specified by one of the registers, [rsp + 32h] other example: [rsp + rax*2 + 32], we use 2 registers - keyword SIB
|
||||
// - Register : operand is stored in the register
|
||||
// - Immediate: operand is stored right in the instruction, seems like existence of immeadiate depends on the instruction
|
||||
enum{ // modr/m modes
|
||||
MODE_INDIRECT_ADDRESSING = 0,
|
||||
MODE_DISPLACED8_ADDRESSING = 1,
|
||||
MODE_DISPLACED32_ADDRESSING = 2,
|
||||
MODE_DISPLACED16_ADDRESSING = 2,
|
||||
MODE_REGISTER_ADDRESSING = 3,
|
||||
};
|
||||
|
||||
// SIB Addressing
|
||||
// 7-6 bits for scale (1, 2, 4, 8)
|
||||
// 5-3 register with index (index * scale)
|
||||
// 2-0 register with base base + (index * scale)
|
||||
const uint8_t SIB_SCALE1 = 0;
|
||||
const uint8_t SIB_SCALE2 = 1;
|
||||
const uint8_t SIB_SCALE4 = 2;
|
||||
const uint8_t SIB_SCALE8 = 3;
|
||||
const uint8_t MODRM_RM_SIB = 4;
|
||||
|
||||
// reg, rm - specify 3 bit register
|
||||
// to address extended registers r8 - r15, you need to set proper REX bit
|
||||
uint8_t modrm(uint8_t mode, uint8_t reg, uint8_t rm) {
|
||||
assert_in_range(mode, 0, 3);
|
||||
assert_in_range(reg, 0, 7);
|
||||
assert_in_range(rm, 0, 7);
|
||||
return (mode << 6) | (reg << 3) | rm;
|
||||
}
|
||||
|
||||
// We need to set appropriate flag on the rex value to
|
||||
// use extended registers
|
||||
uint8_t adjust_registers_and_get_rex(Register *rm, Register *rx) {
|
||||
uint8_t rex_value = REX_W;
|
||||
assert_in_range(*rm, 0, 15);
|
||||
assert_in_range(*rx, 0, 15);
|
||||
|
||||
if (*rm >= 8) {
|
||||
rex_value |= 1 << 2;
|
||||
*rm -= 8;
|
||||
}
|
||||
|
||||
if (*rx >= 8) {
|
||||
rex_value |= 1;
|
||||
*rx -= 8;
|
||||
}
|
||||
|
||||
return rex_value;
|
||||
}
|
||||
|
||||
// add rax, rcx => emit_register_op(0x03, RAX, RCX)
|
||||
void emit_register_op(uint8_t op_code, Register rm, Register rx) {
|
||||
uint8_t rex_value = adjust_registers_and_get_rex(&rm, &rx);
|
||||
|
||||
emit(rex_value);
|
||||
emit(op_code);
|
||||
emit(modrm(MODE_REGISTER_ADDRESSING, rm, rx));
|
||||
}
|
||||
|
||||
// add rax, [rcx] => emit_indirect_op(0x03, RAX, RCX);
|
||||
void emit_indirect_op(uint8_t op_code, Register rx, Register rm) {
|
||||
assert(rx != RSP); // SIB
|
||||
assert(rx != 8 + RSP); // SIB // R12
|
||||
assert(rx != RBP); // Displacement32
|
||||
assert(rx != 8 + RBP); // Displacement32 // R13
|
||||
|
||||
uint8_t rex_value = adjust_registers_and_get_rex(&rm, &rx);
|
||||
emit(rex_value);
|
||||
emit(op_code);
|
||||
emit(modrm(MODE_INDIRECT_ADDRESSING, rm, rx));
|
||||
}
|
||||
|
||||
void emit_indirect_displaced8_op(uint8_t op_code, Register rx, Register rm, uint8_t displacement) {
|
||||
assert(rx != RSP); // SIB
|
||||
assert(rx != 8 + RSP); // SIB // R12
|
||||
|
||||
uint8_t rex_value = adjust_registers_and_get_rex(&rm, &rx);
|
||||
emit(rex_value);
|
||||
emit(op_code);
|
||||
emit(modrm(MODE_DISPLACED8_ADDRESSING, rm, rx));
|
||||
emit(displacement);
|
||||
}
|
||||
|
||||
void emit_indirect_displaced32_op(uint8_t op_code, Register rx, Register rm, uint32_t displacement) {
|
||||
assert(rx != RSP); // SIB
|
||||
assert(rx != 8 + RSP); // SIB // R12
|
||||
|
||||
uint8_t rex_value = adjust_registers_and_get_rex(&rm, &rx);
|
||||
emit(rex_value);
|
||||
emit(op_code);
|
||||
emit(modrm(MODE_DISPLACED32_ADDRESSING, rm, rx));
|
||||
emit32(displacement);
|
||||
}
|
||||
|
||||
|
||||
// extern "C" void asm_test();
|
||||
void test_x64_stuff() {
|
||||
//asm_test();
|
||||
|
||||
code = code_start = (uint8_t*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
emit(OP_BREAK);
|
||||
|
||||
// REX.W + F7 /4
|
||||
#if 0
|
||||
emit(REX_W);
|
||||
emit(0xF7);
|
||||
emit(modrm(MODE_REGISTER_ADDRESSING, 0x4, RCX));
|
||||
#endif
|
||||
|
||||
for (Register dst = RAX; dst <= R15; dst++) {
|
||||
for (Register src = RAX; src <= R15; src++) {
|
||||
if ((dst & 7) != RSP) {
|
||||
emit_indirect_displaced32_op(0x03, dst, src, 0xffffff);
|
||||
emit_indirect_displaced8_op(0x03, dst, src, 0x32);
|
||||
}
|
||||
if ((dst & 7) != RSP && (dst & 7) != RBP)
|
||||
emit_indirect_op(0x03, dst, src);
|
||||
emit_register_op(0x03, dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
emit(OP_RETURN);
|
||||
|
||||
auto add = (uint64_t(*)(uint64_t, uint64_t))code_start;
|
||||
uint64_t result = add(11, 22);
|
||||
}
|
||||
Reference in New Issue
Block a user