mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-23 20:33:05 +00:00
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:
parent
fc57fa4064
commit
f4f805f4c9
4 changed files with 100 additions and 2 deletions
76
code.c
76
code.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
opts.def
2
opts.def
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue