summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--misc/radare2/Makefile7
-rw-r--r--misc/radare2/asm_fspec.c29
-rw-r--r--spec/ability.fspec106
-rw-r--r--src/bin/fspec-dump.c65
-rw-r--r--src/compiler/compiler.lm57
-rw-r--r--src/compiler/native.c30
6 files changed, 165 insertions, 129 deletions
diff --git a/misc/radare2/Makefile b/misc/radare2/Makefile
index aff2fdb..b8fcdd2 100644
--- a/misc/radare2/Makefile
+++ b/misc/radare2/Makefile
@@ -8,7 +8,7 @@ WARNINGS := -Wall -Wextra -Wformat=2 -Wstrict-aliasing=3 -Wstrict-overflow=5 -Ws
override CFLAGS ?= -g
override CFLAGS += -std=c11 $(WARNINGS)
-libs = asm_fspec.so
+libs = asm_fspec.so anal_fspec.so
all: $(libs)
%.so:
@@ -18,11 +18,16 @@ asm_fspec.so: private CFLAGS += $(shell pkg-config --cflags r_anal)
asm_fspec.so: private LDLIBS += $(shell pkg-config --libs-only-l r_anal)
asm_fspec.so: asm_fspec.c
+anal_fspec.so: private CFLAGS += $(shell pkg-config --cflags r_anal)
+anal_fspec.so: private LDLIBS += $(shell pkg-config --libs-only-l r_anal)
+anal_fspec.so: anal_fspec.c
+
install: $(libs)
install -Dm755 $^ -t "$(R2_PLUGIN_PATH)"
uninstall:
$(RM) "$(R2_PLUGIN_PATH)"/asm_fspec.so
+ $(RM) "$(R2_PLUGIN_PATH)"/anal_fspec.so
clean:
$(RM) $(libs)
diff --git a/misc/radare2/asm_fspec.c b/misc/radare2/asm_fspec.c
index fa7c1ad..9eb28ea 100644
--- a/misc/radare2/asm_fspec.c
+++ b/misc/radare2/asm_fspec.c
@@ -12,7 +12,8 @@ enum fspec_instruction {
INS_REG,
INS_PUSH,
INS_PUSHR,
- INS_STORE,
+ INS_POP,
+ INS_INCR,
INS_OP,
INS_QUEUE,
INS_IO,
@@ -54,7 +55,8 @@ ins_name_str(const enum fspec_instruction name)
case INS_REG: return "reg";
case INS_PUSH: return "push";
case INS_PUSHR: return "pushr";
- case INS_STORE: return "store";
+ case INS_INCR: return "incr";
+ case INS_POP: return "pop";
case INS_OP: return "op";
case INS_QUEUE: return "queue";
case INS_IO: return "io";
@@ -98,26 +100,27 @@ op_name_str(const enum fspec_operation op)
static int
disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len)
{
+ (void)a;
+
union {
struct { unsigned name:5; unsigned n:2; uint64_t v:57; } ins;
- uint8_t v[16];
+ uint8_t v[sizeof(uint64_t)];
} u = {0};
- memcpy(u.v, buf, R_MIN(sizeof(u.v[0]), len));
- const uint8_t insw = sizeof(uint16_t) * (1 << u.ins.n);
+ memcpy(u.v, buf, R_MIN(1, (size_t)len));
+ const uint8_t insw = 1 << u.ins.n;
memcpy(u.v, buf, R_MIN(insw, len));
+
const char *buf_asm = "invalid";
+ const bool reg_arg = (u.ins.name == INS_PUSHR || u.ins.name == INS_INCR || u.ins.name == INS_POP ||
+ u.ins.name == INS_EXEC || u.ins.name == INS_CALL);
if (u.ins.name == INS_OP)
buf_asm = sdb_fmt("%s %s", ins_name_str(u.ins.name), op_name_str(u.ins.v));
- else if (u.ins.n == 0)
- buf_asm = sdb_fmt("%s 0x%02x", ins_name_str(u.ins.name), (uint16_t)u.ins.v);
- else if (u.ins.n == 1)
- buf_asm = sdb_fmt("%s 0x%04x", ins_name_str(u.ins.name), (uint32_t)u.ins.v);
- else if (u.ins.n == 2)
- buf_asm = sdb_fmt("%s 0x%08x", ins_name_str(u.ins.name), (uint64_t)u.ins.v);
+ else if (reg_arg)
+ buf_asm = sdb_fmt("%s r%" PRIu64, ins_name_str(u.ins.name), (uint64_t)u.ins.v);
else
- return 0;
+ buf_asm = sdb_fmt("%s %" PRIu64, ins_name_str(u.ins.name), (uint64_t)u.ins.v);
r_strbuf_set(&op->buf_asm, buf_asm);
return (op->size = insw + (u.ins.name == INS_REG ? u.ins.v : 0));
@@ -128,7 +131,7 @@ RAsmPlugin r_asm_plugin_fspec = {
.license = "LGPL3",
.desc = "fspec disassembly plugin",
.arch = "fspec",
- .bits = 16 | 32 | 64,
+ .bits = 8 | 16 | 32 | 64,
.endian = R_SYS_ENDIAN_LITTLE,
.disassemble = disassemble
};
diff --git a/spec/ability.fspec b/spec/ability.fspec
index aab2bcf..5a695a0 100644
--- a/spec/ability.fspec
+++ b/spec/ability.fspec
@@ -30,60 +30,66 @@ struct dat {
// Inside `[]` brackets are the arguments that will be popped from the stack. `()` parenthesis are used instead,
// if the stack argument is optional.
//
+// Reserved registers:
+// r0: Always empty, used as NULL / empty data indicator
+// r1: Field counter
+//
// List of instructions:
-// Name | Hex | Description
-// VERSION<version> | 0x00 | Indicates the version of this bytecode.
-// REG<len> | 0x01 | Allocates a new register.
-// * * If `len` is not zero, the next `len` bytes will be stored in this register.
-// PUSH<v> | 0x02 | Pushes `v` to the stack.
-// PUSHR<R> | 0x03 | Pushes the contents of register at index `R` to the stack.
-// STORE<R> [v] | 0x04 | Stores `v` into register at index `R`.
-// OP<op> [...] | 0x05 | Performs operation specified by the `op`, and pushes the result to the stack.
-// QUEUE<len> (...) | 0x06 | Queues next `len` bytes for execution for the next `IO` instruction.
-// * * The code is executed before or after `IO` instruction, depending whether VM is packing or unpacking.
-// IO<sz> [R] (...) | 0x07 | Unpacking: Reads data from external VM input (usually a file) to register at index `R`.
-// * * Packing: Writes data to external VM output (usually a file) from register at index `R`.
-// * * `sz` is the size of the element in bits.
-// * * Rest of the stack is the number of elements, if empty, the elements to read/write is 1.
-// EXEC<R> (...) | 0x08 | Executes instructions stored in register at index `R`.
-// * * Rest of the stack is the number of times to execute, if empty, execution happens only once.
-// CALL<R> (...) | 0x09 | Calls a function. The name of the function is stored in register at index `R`.
-// JMP<off> | 0x0A | Jumps to the `off` (in bytes).
-// JMPIF<off> [v] | 0x0B | Performs `JMP`, if `v` is true.
-// STRUCT<R> [R2] | 0x0C | Describes register at index `R` as struct structure. Register at index `R2` contains the name of the struct.
-// SELECT<R> | 0x0D | Describes register at index `R` as select structure.
-// FIELD<R> (...) | 0x0E | Links field to last structure. Register at index `R` contains the name of the field.
-// * * Rest of the stack contains register indices for registers that are instances of this field.
-// BSZ<s:1, v> [sz] | 0x0F | Describes last field as a primitive field. `s` describes whether the field is signed. `v` describes how the
-// * * field should be represented. `sz` contains the size of field in bits.
-// REF<R> | 0x10 | Describes field as a substructure. Register at index `R` contains the structure definition.
-// FDIMENSION<sz> | 0x11 | Adds fixed dimension to a field. `sz` indicates the size of the dimension.
-// VDIMENSION | 0x12 | Adds variable length dimension to a field.
-// ENUM<R> | 0x13 | Links field to a enum
+// Name | Hex | Description
+// VERSION<version> | 0x00 | Indicates the version of this bytecode.
+// REG<len> | 0x01 | Allocates a new register.
+// * * If `len` is not zero, the next `len` bytes will be stored in this register.
+// PUSH<v> | 0x02 | Pushes `v` to the stack.
+// PUSHR<r?> | 0x03 | Pushes the contents of register `r?` to the stack.
+// POP<r?> [v] | 0x04 | Pops `v` into register `r?`.
+// INCR<r?> | 0x05 | Increments the register `r?` by one.
+// OP<op> [...] | 0x06 | Performs operation specified by the `op`, and pushes the result to the stack.
+// QUEUE<len> (...) | 0x07 | Queues next `len` bytes for execution for the next `IO` instruction.
+// * * The code is executed before or after `IO` instruction, depending whether VM is packing or unpacking.
+// IO<sz> (...) | 0x08 | Unpacking: Reads data from external VM input (usually a file) to register pointed by `r1`.
+// * * Packing: Writes data to external VM output (usually a file) from register pointed by `r1`.
+// * * `sz` is the size of the element in bits.
+// * * Rest of the stack is the number of elements, if empty, the elements to read/write is 1.
+// EXEC<r?> [r??] (...) | 0x09 | Sets `r1` to `r??` and executes instructions stored in register `r?`.
+// * * Rest of the stack is the number of times to execute, if empty, execution happens only once.
+// * * `r1` will be saved and restored during this instruction.
+// CALL<r?> (...) | 0x0A | Calls a function. The name of the function is stored in register `r?`.
+// JMP<off> | 0x0B | Jumps to the `off` (in bytes).
+// JMPIF<off> [v] | 0x0C | Performs `JMP`, if `v` is true.
+// STRUCT<r?> [r??] | 0x0D | Describes register `r?` as struct structure. register `r??` contains the name of the struct.
+// SELECT<r?> | 0x0E | Describes register `r?` as select structure.
+// FIELD<r?> (...) | 0x0F | Links field to last structure. register `r?` contains the name of the field.
+// * * Rest of the stack contains register indices for registers that are instances of this field.
+// BSZ<s:1, v> [sz] | 0x10 | Describes last field as a primitive field. `s` describes whether the field is signed. `v` describes how the
+// * * field should be represented. `sz` contains the size of field in bits.
+// REF<r?> | 0x11 | Describes field as a substructure. register `r?` contains the structure definition.
+// FDIMENSION<sz> | 0x12 | Adds fixed dimension to a field. `sz` indicates the size of the dimension.
+// VDIMENSION | 0x13 | Adds variable length dimension to a field.
+// ENUM<r?> | 0x14 | Links field to a enum
//
// List of operations for the `OP` instruction:
// Name | Hex | Argc | Description
-// UNM | 0x00 | 1 | Unary minus operation `-r1`.
-// LNOT | 0x01 | 1 | Logical not operation `!r1`.
-// BNOT | 0x02 | 1 | Bitwise not operation `~r1`.
-// MUL | 0x03 | 2 | Multiplication operation `r1 * r2`.
-// DIV | 0x04 | 2 | Division operation `r1 * r2`.
-// MOD | 0x05 | 2 | Modulo operation `r1 % r2`.
-// ADD | 0x06 | 2 | Addition operation `r1 + r2`.
-// SUB | 0x07 | 2 | Substraction operation `r1 - r2`.
-// SHIFTL | 0x08 | 2 | Left shift operation `r1 << r2`.
-// SHIFTR | 0x09 | 2 | Right shift operation `r1 >> r2`.
-// LESS | 0x0A | 2 | Less than operation `r1 < r2`.
-// LESSEQ | 0x0B | 2 | Less or equal operation `r1 <= r2`.
-// EQ | 0x0C | 2 | Equal operation `r1 == r2`.
-// NOTEQ | 0x0D | 2 | Not equal operation `r1 != r2`.
-// BAND | 0x0E | 2 | Bitwise and operation `r1 & r2`.
-// BOR | 0x0F | 2 | Bitwise or operation `r1 | r2`.
-// BXOR | 0x10 | 2 | Bitwise xor operation `r1 ^ r2`.
-// LAND | 0x11 | 2 | Logical and operation `r1 && r2`.
-// LOR | 0x12 | 2 | Logical or operation `r1 || r2`.
-// CTERNARY | 0x13 | 3 | Conditional ternary operation `r1 ? r2 : r3`
-// SUBSCRIPT | 0x14 | 2 | Subscript operation `r1[r2]`
+// UNM | 0x00 | 1 | Unary minus operation `-v1`.
+// LNOT | 0x01 | 1 | Logical not operation `!v1`.
+// BNOT | 0x02 | 1 | Bitwise not operation `~v1`.
+// MUL | 0x03 | 2 | Multiplication operation `v1 * v2`.
+// DIV | 0x04 | 2 | Division operation `v1 * v2`.
+// MOD | 0x05 | 2 | Modulo operation `v1 % v2`.
+// ADD | 0x06 | 2 | Addition operation `v1 + v2`.
+// SUB | 0x07 | 2 | Substraction operation `v1 - v2`.
+// SHIFTL | 0x08 | 2 | Left shift operation `v1 << v2`.
+// SHIFTR | 0x09 | 2 | Right shift operation `v1 >> v2`.
+// LESS | 0x0A | 2 | Less than operation `v1 < v2`.
+// LESSEQ | 0x0B | 2 | Less or equal operation `v1 <= v2`.
+// EQ | 0x0C | 2 | Equal operation `v1 == v2`.
+// NOTEQ | 0x0D | 2 | Not equal operation `v1 != v2`.
+// BAND | 0x0E | 2 | Bitwise and operation `v1 & v2`.
+// BOR | 0x0F | 2 | Bitwise or operation `v1 | v2`.
+// BXOR | 0x10 | 2 | Bitwise xor operation `v1 ^ v2`.
+// LAND | 0x11 | 2 | Logical and operation `v1 && v2`.
+// LOR | 0x12 | 2 | Logical or operation `v1 || v2`.
+// CTERNARY | 0x13 | 3 | Conditional ternary operation `v1 ? v2 : v3`
+// SUBSCRIPT | 0x14 | 2 | Subscript operation `v1[v2]`
//
// List of visuals for the `PIO` instruction:
// Name | Hex | Representation
diff --git a/src/bin/fspec-dump.c b/src/bin/fspec-dump.c
index 195674f..e7993e6 100644
--- a/src/bin/fspec-dump.c
+++ b/src/bin/fspec-dump.c
@@ -1,3 +1,4 @@
+#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -162,7 +163,8 @@ enum fspec_instruction {
INS_REG,
INS_PUSH,
INS_PUSHR,
- INS_STORE,
+ INS_POP,
+ INS_INCR,
INS_OP,
INS_QUEUE,
INS_IO,
@@ -229,16 +231,42 @@ struct fspec_ctx {
struct fspec_istream ir, binary;
};
+static uint8_t
+bytes_for_v(const uint64_t v)
+{
+ for (uint8_t n = 0; n < 4; ++n) {
+ const uint8_t bytes = (1 << n);
+ if (v < (uint64_t)(1 << (CHAR_BIT * bytes)))
+ return bytes;
+ }
+ errx(EXIT_FAILURE, "number `%" PRIu64 "` is too big", v);
+ return 0;
+}
+
static void
-stack_push_num(struct fspec_stack *stack, struct fspec_buffer *buf, const uint64_t v)
+register_set_num(struct fspec_register *r, struct fspec_buffer *buf, const uint64_t v)
{
- assert(stack->numv < ARRAY_SIZE(stack->value));
- const uint8_t bsz = DIV_ROUND_UP(__builtin_ctzl((v ? v : 1)), CHAR_BIT);
- stack->value[stack->numv++] = (struct fspec_register){ .off = buf->ptr, .len = bsz };
+ const uint8_t bsz = bytes_for_v(v);
+ *r = (struct fspec_register){ .off = buf->ptr, .len = bsz };
const union { uint8_t u8[sizeof(v)]; uint64_t v; } u = { .v = v };
fspec_buffer_write(buf, u.u8, bsz);
}
+static uint64_t
+register_get_num(const struct fspec_register *r, const struct fspec_buffer *buf)
+{
+ union { uint8_t u8[sizeof(uint64_t)]; uint64_t v; } u = {0};
+ memcpy(u.u8, buf->data + r->off, MIN(r->len, sizeof(u.u8)));
+ return (u.v << r->shift[0]) >> r->shift[1];
+}
+
+static void
+stack_push_num(struct fspec_stack *stack, struct fspec_buffer *buf, const uint64_t v)
+{
+ assert(stack->numv < ARRAY_SIZE(stack->value));
+ register_set_num(&stack->value[stack->numv++], buf, v);
+}
+
static void
stack_push(struct fspec_stack *stack, struct fspec_register *value)
{
@@ -257,10 +285,7 @@ static uint64_t
stack_pop_num(struct fspec_stack *stack, const struct fspec_buffer *buf)
{
assert(stack->numv > 0);
- const struct fspec_register v = stack->value[--stack->numv];
- union { uint8_t u8[sizeof(uint64_t)]; uint64_t v; } u = {0};
- memcpy(u.u8, buf->data + v.off, MIN(v.len, sizeof(u.u8)));
- return (u.v << v.shift[0]) >> v.shift[1];
+ return register_get_num(&stack->value[--stack->numv], buf);
}
static bool
@@ -356,11 +381,11 @@ fspec_execute(struct fspec_ctx *ctx, const uint8_t *ir, const uint64_t irlen, co
for (const uint8_t *pc = ir; pc < ir + irlen;) {
union {
struct { unsigned name:5; unsigned n:2; uint64_t v:57; } ins;
- uint8_t v[16];
+ uint8_t v[sizeof(uint64_t)];
} u = {0};
- memcpy(u.v, pc, sizeof(u.v[0]));
- const uint8_t insw = sizeof(uint16_t) * (1 << u.ins.n);
+ memcpy(u.v, pc, 1);
+ const uint8_t insw = 1 << u.ins.n;
memcpy(u.v, pc, insw);
pc += insw;
@@ -386,10 +411,14 @@ fspec_execute(struct fspec_ctx *ctx, const uint8_t *ir, const uint64_t irlen, co
fprintf(stderr, "PUSHR R: %lu\n", insv);
stack_push(&ctx->S, &ctx->R.value[insv]);
break;
- case INS_STORE:
- fprintf(stderr, "STORE R: %lu\n", insv);
+ case INS_POP:
+ fprintf(stderr, "POP R: %lu\n", insv);
stack_pop(&ctx->S, &ctx->R.value[insv]);
break;
+ case INS_INCR:
+ fprintf(stderr, "INCR R: %lu\n", insv);
+ register_set_num(&ctx->R.value[insv], &ctx->mem, register_get_num(&ctx->R.value[insv], &ctx->mem) + 1);
+ break;
case INS_OP:
fprintf(stderr, "OP op: %lu\n", insv);
do_op(ctx, insv);
@@ -408,20 +437,24 @@ fspec_execute(struct fspec_ctx *ctx, const uint8_t *ir, const uint64_t irlen, co
assert(ctx->mem.ptr + szb * nmemb <= ctx->mem.size);
ctx->mem.ptr += ctx->binary.read(ctx, ctx->mem.data + ctx->mem.ptr, szb * nmemb);
} while (ctx->S.numv);
+ ctx->R.value[R].len = ctx->mem.ptr - ctx->R.value[R].off;
if (ctx->mem.ptr == ctx->R.value[R].off)
return true;
- ctx->R.value[R].len = ctx->mem.ptr - ctx->R.value[R].off;
}
break;
case INS_EXEC: {
fprintf(stderr, "EXEC R: %lu\n", insv);
+ const struct fspec_register old_r1 = ctx->R.value[1];
+ stack_pop(&ctx->S, &ctx->R.value[1]);
uint64_t nmemb = 1;
do {
nmemb *= (ctx->S.numv ? stack_pop_num(&ctx->S, &ctx->mem) : 1);
+ fprintf(stderr, "off: %lu len: %lu nmemb: %lu\n", ctx->R.value[insv].off, ctx->R.value[insv].len, nmemb);
for (uint64_t i = 0; i < nmemb; ++i)
if (fspec_execute(ctx, ctx->mem.data + ctx->R.value[insv].off, ctx->R.value[insv].len, ind + INDSTP))
return true;
} while (ctx->S.numv);
+ ctx->R.value[1] = old_r1;
}
break;
case INS_CALL: {
@@ -494,7 +527,7 @@ fspec_execute(struct fspec_ctx *ctx, const uint8_t *ir, const uint64_t irlen, co
pc = (r1 ? ir + insv : pc);
break;
default:
- errx(EXIT_FAILURE, "unknown instruction: %u\n", u.ins.name);
+ errx(EXIT_FAILURE, "unknown instruction: %u :: %u\n", u.ins.name, insw);
}
}
return false;
diff --git a/src/compiler/compiler.lm b/src/compiler/compiler.lm
index 1ca7705..502422d 100644
--- a/src/compiler/compiler.lm
+++ b/src/compiler/compiler.lm
@@ -167,6 +167,7 @@ if (!source) {
struct scope
names:map<str, map<str, any>>
+ roff:int
end
global g_scopes:list<scope> = new list<scope>()
@@ -281,21 +282,23 @@ global INS_VERSION:int = 0
global INS_REG:int = 1
global INS_PUSH:int = 2
global INS_PUSHR:int = 3
-global INS_STORE:int = 4
-global INS_OP:int = 5
-global INS_QUEUE:int = 6
-global INS_IO:int = 7
-global INS_EXEC:int = 8
-global INS_CALL:int = 9
-global INS_JMP:int = 10
-global INS_JMPIF:int = 11
+global INS_POP:int = 4
+global INS_INCR:int = 5
+global INS_OP:int = 6
+global INS_QUEUE:int = 7
+global INS_IO:int = 8
+global INS_EXEC:int = 9
+global INS_CALL:int = 10
+global INS_JMP:int = 11
+global INS_JMPIF:int = 12
int insbuf_written() = c_insbuf_written
str flush_insbuf() = c_flush_insbuf
void write_ins(ins:int, num:int) = c_write_ins
void write_ins_with_data(ins:int, data:str) = c_write_ins_with_data
-global g_regc:int = 1
+global g_r1:int = 1
+global g_regc:int = g_r1 + 1
void
new_reg(v:any, data:str)
@@ -329,6 +332,8 @@ find_data_in(s:any)
}
write_ins(INS_VERSION, 1)
+write_ins_with_data(INS_REG, '')
+
for e:expr::paren::type in source
find_data_in(e.collapsed)
for e:expr::bracket::type in source
@@ -344,10 +349,6 @@ for d:fspec::declaration::type in source {
write_data_if_not_there($d.container.data.name)
}
-global g_fcr:int = g_regc
-write_ins_with_data(INS_REG, '')
-g_regc = g_regc + 1
-
void
write_expr(expr:collapser::reducer::collapsed)
{
@@ -381,7 +382,7 @@ write_expr(expr:collapser::reducer::collapsed)
off = g_offs->find(%d.container)
}
}
- write_ins(INS_PUSHR, off + g_regs->find(%d))
+ write_ins(INS_PUSHR, off + g_regs->find(%d) - off)
} else {
write_ins(INS_OP, g_ops->find($vop.op))
}
@@ -417,6 +418,9 @@ write_declaration(d:fspec::declaration::type, index:int)
c:fspec::container::type = d.container
if (d.cref) c = lookup($d.cref, $d.parent, nil)
+ if (!c && index > 0)
+ write_ins(INS_INCR, g_r1)
+
locs:map<any, int> = new map<any, int>()
if (d.extra) {
for l:fspec::declaration::dimension in repeat(d.extra.dimension) {
@@ -432,15 +436,9 @@ write_declaration(d:fspec::declaration::type, index:int)
}
if (!c) {
- write_ins(INS_PUSHR, g_fcr)
- if (index != 0) {
- write_ins(INS_PUSH, index)
- write_ins(INS_OP, g_ops->find('#+'))
- }
write_ins(INS_IO, d.primitive.bits)
} else {
write_ins(INS_PUSH, g_offs->find(%c))
- write_ins(INS_STORE, g_fcr)
write_ins(INS_EXEC, g_regs->find(%c))
}
@@ -453,20 +451,19 @@ write_declaration(d:fspec::declaration::type, index:int)
void
walk1(d:fspec::declaration::type)
{
- if (!d.container) {
- print('something went wrong!\n')
- exit(1)
- }
+ c:fspec::container::type = d.container
+ if (d.cref) c = lookup($d.cref, $d.parent, nil)
+
+ if (!c || !d.name)
+ return 0
for i:fspec::container::strukt::item in repeat(d.container.data.items)
- if (i.data.container)
- walk1(i.data)
+ walk1(i.data)
for i:fspec::container::select::item in repeat(d.container.data.items)
- if (i.data.container)
- walk1(i.data)
+ walk1(i.data)
- g_offs->insert(%d.container, g_regc)
+ g_offs->insert(%d, g_regc)
for i:fspec::container::enum::item in repeat(d.container.data.items) {
# somehow need to get this constant time (not reg)
@@ -515,7 +512,7 @@ walk2(d:fspec::declaration::type)
if (!d.name) {
write_ins(INS_PUSH, g_offs->find(%d.container))
- write_ins(INS_STORE, g_fcr)
+ write_ins(INS_POP, g_r1)
}
index:int = 0
diff --git a/src/compiler/native.c b/src/compiler/native.c
index bbb0060..feac349 100644
--- a/src/compiler/native.c
+++ b/src/compiler/native.c
@@ -1,5 +1,6 @@
#include <colm/tree.h>
#include <colm/bytecode.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
@@ -111,35 +112,26 @@ c_op_stack_pop(program_t *prg, tree_t **sp, value_t a)
}
static uint8_t
-bits_for_n(const uint8_t n, const uint8_t used)
-{
- return 16 * (1 << n) - used;
-}
-
-static uint8_t
n_for_v(const uint64_t v, const uint8_t used)
{
- const uint8_t bits = __builtin_ctzl((v ? v : 1));
- if (used <= 16 && bits < bits_for_n(0, used))
- return 0;
- else if (used <= 32 && bits < bits_for_n(1, used))
- return 1;
- else if (used <= 64 && bits < bits_for_n(2, used))
- return 2;
-
- errx(EXIT_FAILURE, "numbers over 57 bits not supported right now.. sorry :D");
+ for (uint8_t n = 0; n < 4; ++n) {
+ const uint8_t bits = CHAR_BIT * (1 << n);
+ if (used < bits && v < (uint64_t)(1 << (bits - used)))
+ return n;
+ }
+ errx(EXIT_FAILURE, "number `%" PRIu64 "` is too big to be compiled in instruction", v);
return 3;
}
static void
-vle_instruction(const uint8_t name, const uint64_t v, uint8_t out[16], uint8_t *out_written)
+vle_instruction(const uint8_t name, const uint64_t v, uint8_t out[8], uint8_t *out_written)
{
assert(out && out_written);
const union {
struct { unsigned name:5; unsigned n:2; uint64_t v:57; } ins;
- uint8_t v[16];
+ uint8_t v[sizeof(uint64_t)];
} u = { .ins = { .name = name, .n = n_for_v(v, 7), .v = v } };
- *out_written = sizeof(uint16_t) * (1 << u.ins.n);
+ *out_written = sizeof(u.v[0]) * (1 << u.ins.n);
memcpy(out, u.v, *out_written);
}
@@ -165,7 +157,7 @@ c_insbuf_written(program_t *prg, tree_t **sp)
void
c_write_ins(program_t *prg, tree_t **sp, value_t a, value_t b)
{
- uint8_t out[16], written;
+ uint8_t out[8], written;
vle_instruction(a, b, out, &written);
memcpy(&insbuf.data[insbuf.written], out, written);
insbuf.written += written;