#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);
}
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
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
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 */