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 <divverent@xonotic.org>
This commit is contained in:
Rudolf Polzer 2013-08-27 09:46:58 +02:00
parent fc57fa4064
commit f4f805f4c9
4 changed files with 100 additions and 2 deletions

76
code.c
View file

@ -44,9 +44,81 @@ typedef union {
#define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter) #define CODE_HASH_ENTER(ENTRY) ((ENTRY).enter)
#define CODE_HASH_LEAVE(ENTRY) ((ENTRY).leave) #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->linenums, (int)ctx.line);
vec_push(code->columnnums, (int)ctx.column); vec_push(code->columnnums, (int)ctx.column);
} }

View file

@ -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 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 restricted to a different type than the callee's parameter. Or a list
of unrestricted varargs is passed into restricted varargs. 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 .El
.Sh OPTIMIZATIONS .Sh OPTIMIZATIONS
.Bl -tag -width Ds .Bl -tag -width Ds

View file

@ -273,6 +273,21 @@
UNSAFE_VARARGS = false 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] [warnings]
#Generate a warning about variables which are declared but never #Generate a warning about variables which are declared but never

View file

@ -53,6 +53,8 @@
GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS) GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS)
GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS) GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS)
GMQCC_DEFINE_FLAG(UNSAFE_VARARGS) GMQCC_DEFINE_FLAG(UNSAFE_VARARGS)
GMQCC_DEFINE_FLAG(TYPELESS_STORES)
GMQCC_DEFINE_FLAG(SORT_OPERANDS)
#endif #endif
/* warning flags */ /* warning flags */