Merge branch 'arithmetic_exceptions' into cooking
authorDale Weiler <weilercdale@gmail.com>
Sun, 25 May 2014 07:01:47 +0000 (03:01 -0400)
committerDale Weiler <weilercdale@gmail.com>
Sun, 25 May 2014 07:01:47 +0000 (03:01 -0400)
Conflicts:
doc/gmqcc.1
gmqcc.ini.example
opts.def
parser.c

1  2 
ast.c
ast.h
doc/gmqcc.1
exec.c
gmqcc.ini.example
opts.c
opts.def
parser.c
test.c

diff --cc ast.c
Simple merge
diff --cc ast.h
Simple merge
diff --cc doc/gmqcc.1
@@@ -582,11 -581,11 +586,16 @@@ breaks decompilers, but causes the outp
  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.
 +.It Fl f Ns Cm emulate-state
 +Emulate OP_STATE operations in code rather than using the instruction.
 +The desired fps can be set via -state-fps=NUM, defaults to 10.
 +Specifying \-state-fps implicitly sets this flag. Defaults to off in all
 +standards.
+ .It Fl f Ns Cm arithmetic-exceptions
+ Turn on arithmetic exception tests in the compiler. In constant expressions
+ which trigger exceptions like division by zero, overflow, underflow, etc,
+ the following flag will produce diagnostics for what triggered that
+ exception.
  .El
  .Sh OPTIMIZATIONS
  .Bl -tag -width Ds
diff --cc exec.c
Simple merge
      SORT_OPERANDS = false
  
  
 +    #Emulate OP_STATE operations in code rather than using the instruction.
 +    #The desired fps can be set via -state-fps=NUM, defaults to 10.
 +
 +    EMULATE_STATE = false
 +
 +
+     #Turn on arithmetic exception tests in the compiler. In constant expressions
+     #which trigger exceptions like division by zero, overflow, underflow, etc,
+     #the following flag will produce diagnostics for what triggered that
+     #exception.
+     ARITHMETIC_EXCEPTIONS = false
  [warnings]
      #Generate a warning about variables which are declared but never
      #used.  This can be avoided by adding the ‘noref’ keyword in front
diff --cc opts.c
Simple merge
diff --cc opts.def
+++ b/opts.def
@@@ -56,7 -56,7 +56,8 @@@
      GMQCC_DEFINE_FLAG(UNSAFE_VARARGS)
      GMQCC_DEFINE_FLAG(TYPELESS_STORES)
      GMQCC_DEFINE_FLAG(SORT_OPERANDS)
 +    GMQCC_DEFINE_FLAG(EMULATE_STATE)
+     GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
  #endif
  
  /* warning flags */
diff --cc parser.c
+++ b/parser.c
@@@ -4015,83 -4015,69 +4015,83 @@@ static bool parse_function_body(parser_
      }
  
      if (has_frame_think) {
 -        lex_ctx_t ctx;
 -        ast_expression *self_frame;
 -        ast_expression *self_nextthink;
 -        ast_expression *self_think;
 -        ast_expression *time_plus_1;
 -        ast_store *store_frame;
 -        ast_store *store_nextthink;
 -        ast_store *store_think;
 -
 -        ctx = parser_ctx(parser);
 -        self_frame     = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_frame);
 -        self_nextthink = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_nextthink);
 -        self_think     = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think);
 -
 -        time_plus_1    = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F,
 -                         gbl_time, (ast_expression*)fold_constgen_float(parser->fold, 0.1f, false));
 -
 -        if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
 -            if (self_frame)     ast_delete(self_frame);
 -            if (self_nextthink) ast_delete(self_nextthink);
 -            if (self_think)     ast_delete(self_think);
 -            if (time_plus_1)    ast_delete(time_plus_1);
 -            retval = false;
 -        }
 -
 -        if (retval)
 -        {
 -            store_frame     = ast_store_new(ctx, INSTR_STOREP_F,   self_frame,     framenum);
 -            store_nextthink = ast_store_new(ctx, INSTR_STOREP_F,   self_nextthink, time_plus_1);
 -            store_think     = ast_store_new(ctx, INSTR_STOREP_FNC, self_think,     nextthink);
 -
 -            if (!store_frame) {
 -                ast_delete(self_frame);
 -                retval = false;
 -            }
 -            if (!store_nextthink) {
 -                ast_delete(self_nextthink);
 -                retval = false;
 -            }
 -            if (!store_think) {
 -                ast_delete(self_think);
 -                retval = false;
 +        if (!OPTS_FLAG(EMULATE_STATE)) {
 +            ast_state *state_op = ast_state_new(parser_ctx(parser), framenum, nextthink);
 +            if (!ast_block_add_expr(block, (ast_expression*)state_op)) {
 +                parseerror(parser, "failed to generate state op for [frame,think]");
 +                ast_unref(nextthink);
 +                ast_unref(framenum);
 +                ast_delete(block);
 +                return false;
              }
 -            if (!retval) {
 -                if (store_frame)     ast_delete(store_frame);
 -                if (store_nextthink) ast_delete(store_nextthink);
 -                if (store_think)     ast_delete(store_think);
 +        } else {
 +            /* emulate OP_STATE in code: */
 +            lex_ctx_t ctx;
 +            ast_expression *self_frame;
 +            ast_expression *self_nextthink;
 +            ast_expression *self_think;
 +            ast_expression *time_plus_1;
 +            ast_store *store_frame;
 +            ast_store *store_nextthink;
 +            ast_store *store_think;
 +
 +            float frame_delta = 1.0f / (float)OPTS_OPTION_U32(OPTION_STATE_FPS);
 +
 +            ctx = parser_ctx(parser);
 +            self_frame     = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_frame);
 +            self_nextthink = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_nextthink);
 +            self_think     = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think);
 +
 +            time_plus_1    = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F,
-                              gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta));
++                             gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta, false));
 +
 +            if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
 +                if (self_frame)     ast_delete(self_frame);
 +                if (self_nextthink) ast_delete(self_nextthink);
 +                if (self_think)     ast_delete(self_think);
 +                if (time_plus_1)    ast_delete(time_plus_1);
                  retval = false;
              }
 -            if (!ast_block_add_expr(block, (ast_expression*)store_frame) ||
 -                !ast_block_add_expr(block, (ast_expression*)store_nextthink) ||
 -                !ast_block_add_expr(block, (ast_expression*)store_think))
 +
 +            if (retval)
              {
 -                retval = false;
 +                store_frame     = ast_store_new(ctx, INSTR_STOREP_F,   self_frame,     framenum);
 +                store_nextthink = ast_store_new(ctx, INSTR_STOREP_F,   self_nextthink, time_plus_1);
 +                store_think     = ast_store_new(ctx, INSTR_STOREP_FNC, self_think,     nextthink);
 +
 +                if (!store_frame) {
 +                    ast_delete(self_frame);
 +                    retval = false;
 +                }
 +                if (!store_nextthink) {
 +                    ast_delete(self_nextthink);
 +                    retval = false;
 +                }
 +                if (!store_think) {
 +                    ast_delete(self_think);
 +                    retval = false;
 +                }
 +                if (!retval) {
 +                    if (store_frame)     ast_delete(store_frame);
 +                    if (store_nextthink) ast_delete(store_nextthink);
 +                    if (store_think)     ast_delete(store_think);
 +                    retval = false;
 +                }
 +                if (!ast_block_add_expr(block, (ast_expression*)store_frame) ||
 +                    !ast_block_add_expr(block, (ast_expression*)store_nextthink) ||
 +                    !ast_block_add_expr(block, (ast_expression*)store_think))
 +                {
 +                    retval = false;
 +                }
              }
 -        }
  
 -        if (!retval) {
 -            parseerror(parser, "failed to generate code for [frame,think]");
 -            ast_unref(nextthink);
 -            ast_unref(framenum);
 -            ast_delete(block);
 -            return false;
 +            if (!retval) {
 +                parseerror(parser, "failed to generate code for [frame,think]");
 +                ast_unref(nextthink);
 +                ast_unref(framenum);
 +                ast_delete(block);
 +                return false;
 +            }
          }
      }
  
diff --cc test.c
Simple merge