diff --git a/src/fh_runtime.c b/src/fh_runtime.c index 123d56f..c824851 100644 --- a/src/fh_runtime.c +++ b/src/fh_runtime.c @@ -133,7 +133,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) uint32_t strl; uint32_t val; - uint32_t limit, index, index0; + uint32_t limit, index; LOG("0x%08x: Instr %s, 0x%08x", fh->execptr, instr_name(instr->kind), instr->data); @@ -271,20 +271,28 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) TRY(rs_peek(fh, &limit)); LOG("+LOOP, i=%d, step %d, limit %d", fh->loop_i, val, limit); - - index0 = fh->loop_i; - fh->loop_i += val; - - LOG("after add: %d", fh->loop_i); - - // FIXME this is probably wrong - // FIXME yes it actually is wrong - if (((int32_t)index0 < (int32_t)limit) == ((int32_t)fh->loop_i < (int32_t)limit) && fh->loop_i != limit) { // boundary not crossed, continue - fh->execptr = instr->data; // go to beginning - } else { + + const int32_t vi = (int32_t)val; + const int32_t bdr = (int32_t)limit - (int32_t)1; + const int32_t i0 = (int32_t)fh->loop_i; + fh->loop_i += val; // this can overflow + const int32_t i1 = (int32_t)fh->loop_i; + + // TODO this can probably be optimized + if ( + (vi > 0 && i0 <= bdr && i1 > bdr) + || (vi > 0 && i0 > 0 && i1 < 0 && (bdr >= i0 || bdr <= i1)) + || (vi < 0 && i0 > bdr && i1 <= bdr) + || (vi < 0 && i0 < 0 && i1 > 0 && (bdr <= i0 || bdr >= i1)) + ) { + //LOGE("end of loop"); // end of loop TRY(rs_pop(fh, &limit)); TRY(fh_loop_unnest(fh)); + } else { + //LOGE("continue loop"); + // continue the loop + fh->execptr = instr->data; } goto instr; diff --git a/testfiles/ovfloop.f b/testfiles/ovfloop.f new file mode 100644 index 0000000..6c4a2ce --- /dev/null +++ b/testfiles/ovfloop.f @@ -0,0 +1,3 @@ +: x 2147483647 -2147483648 DO I . -1 +LOOP ; +x +