From f4f805f4c980f5e509447a965b4ef811c0741581 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Tue, 27 Aug 2013 09:46:58 +0200 Subject: [PATCH] New options: -ftypeless-stores and -fsort-operands These flags reduce entropy, but not size, of the generated assembly code. This helps compressability of the files. Additionally, -ftypeless-stores might SLIGHTLY improve engine performance due to less instructions being used (so branch prediction might work better). Probably cannot be measured though. Signed-off-by: Rudolf Polzer --- code.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-- doc/gmqcc.1 | 9 ++++++ gmqcc.ini.example | 15 ++++++++++ opts.def | 2 ++ 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/code.c b/code.c index 9251360..2cf0a85 100644 --- a/code.c +++ b/code.c @@ -44,9 +44,81 @@ typedef union { #define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter) #define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave) -void code_push_statement(code_t *code, prog_section_statement_t *stmt, lex_ctx_t ctx) +void code_push_statement(code_t *code, prog_section_statement_t *stmt_in, lex_ctx_t ctx) { - vec_push(code->statements, *stmt); + prog_section_statement_t stmt = *stmt_in; + + if (OPTS_FLAG(TYPELESS_STORES)) { + switch (stmt.opcode) { + case INSTR_LOAD_S: + case INSTR_LOAD_ENT: + case INSTR_LOAD_FLD: + case INSTR_LOAD_FNC: + stmt.opcode = INSTR_LOAD_F; + break; + case INSTR_STORE_S: + case INSTR_STORE_ENT: + case INSTR_STORE_FLD: + case INSTR_STORE_FNC: + stmt.opcode = INSTR_STORE_F; + break; + case INSTR_STOREP_S: + case INSTR_STOREP_ENT: + case INSTR_STOREP_FLD: + case INSTR_STOREP_FNC: + stmt.opcode = INSTR_STOREP_F; + break; + } + } + + if (OPTS_FLAG(SORT_OPERANDS)) { + switch (stmt.opcode) { +#define SINGLE(a) \ + case INSTR_##a: \ + if (stmt.o1.u1 < stmt.o2.u1) { \ + uint16_t x = stmt.o1.u1; stmt.o1.u1 = stmt.o2.u1; stmt.o2.u1 = x; \ + } \ + break +#define PAIR(a,b) \ + case INSTR_##a: \ + if (stmt.o1.u1 < stmt.o2.u1) { \ + uint16_t x = stmt.o1.u1; stmt.o1.u1 = stmt.o2.u1; stmt.o2.u1 = x; \ + stmt.opcode = INSTR_##b; \ + } \ + break; \ + case INSTR_##b: \ + if (stmt.o1.u1 < stmt.o2.u1) { \ + uint16_t x = stmt.o1.u1; stmt.o1.u1 = stmt.o2.u1; stmt.o2.u1 = x; \ + stmt.opcode = INSTR_##a; \ + } \ + break + PAIR(MUL_VF, MUL_FV); + PAIR(LT, GT); + PAIR(LE, GE); + SINGLE(MUL_F); + SINGLE(MUL_V); + SINGLE(ADD_F); + SINGLE(ADD_V); + SINGLE(EQ_F); + SINGLE(EQ_V); + SINGLE(EQ_S); + SINGLE(EQ_E); + SINGLE(EQ_FNC); + SINGLE(NE_F); + SINGLE(NE_V); + SINGLE(NE_S); + SINGLE(NE_E); + SINGLE(NE_FNC); + SINGLE(AND); + SINGLE(OR); + SINGLE(BITAND); + SINGLE(BITOR); +#undef PAIR +#undef SINGLE + } + } + + vec_push(code->statements, stmt); vec_push(code->linenums, (int)ctx.line); vec_push(code->columnnums, (int)ctx.column); } diff --git a/doc/gmqcc.1 b/doc/gmqcc.1 index dbdae03..f3f6517 100644 --- a/doc/gmqcc.1 +++ b/doc/gmqcc.1 @@ -535,6 +535,15 @@ When passing on varargs to a different functions, this turns some static error cases into warnings. Like when the caller's varargs are restricted to a different type than the callee's parameter. Or a list of unrestricted varargs is passed into restricted varargs. +.It Fl f Ns Cm typeless-stores +Always use STORE_F, LOAD_F, STOREP_F when accessing scalar variables. +This is somewhat incorrect assembly instruction use, but in all engines +they do exactly the same. This makes disassembly output harder to read, +breaks decompilers, but causes the output file to be better compressible. +.It Fl f Ns Cm sort-operands +In commutative instructions, always put the lower-numbered operand first. +This shaves off 1 byte of entropy from all these instructions, reducing +compressed size of the output file. .El .Sh OPTIMIZATIONS .Bl -tag -width Ds diff --git a/gmqcc.ini.example b/gmqcc.ini.example index 520fb54..9dbb6fb 100644 --- a/gmqcc.ini.example +++ b/gmqcc.ini.example @@ -273,6 +273,21 @@ UNSAFE_VARARGS = false + #Always use STORE_F, LOAD_F, STOREP_F when accessing scalar variables. + #This is somewhat incorrect assembly instruction use, but in all engines + #they do exactly the same. This makes disassembly output harder to read, + #breaks decompilers, but causes the output file to be better compressible. + + TYPELESS_STORES = false + + + #In commutative instructions, always put the lower-numbered operand first. + #This shaves off 1 byte of entropy from all these instructions, reducing + #compressed size of the output file. + + SORT_OPERANDS = false + + [warnings] #Generate a warning about variables which are declared but never diff --git a/opts.def b/opts.def index ef249a3..977272a 100644 --- a/opts.def +++ b/opts.def @@ -53,6 +53,8 @@ GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS) GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS) GMQCC_DEFINE_FLAG(UNSAFE_VARARGS) + GMQCC_DEFINE_FLAG(TYPELESS_STORES) + GMQCC_DEFINE_FLAG(SORT_OPERANDS) #endif /* warning flags */