Hugo Musso Gualandi 5 年 前
コミット
f214c4cdfb
1 ファイル変更82 行追加2 行削除
  1. 82 2
      src/luaot.c

+ 82 - 2
src/luaot.c

@@ -748,8 +748,88 @@ void create_function(Proto *p)
                 println("    return;");
                 break;
             }
-            //case OP_FORLOOP
-            //case OP_FORPREP
+            case OP_FORLOOP: {
+                println("    if (ttisinteger(s2v(ra + 2))) {  /* integer loop? */");
+                println("      lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));");
+                println("      if (count > 0) {  /* still more iterations? */");
+                println("        lua_Integer step = ivalue(s2v(ra + 2));");
+                println("        lua_Integer idx = ivalue(s2v(ra));  /* internal index */");
+                println("        chgivalue(s2v(ra + 1), count - 1);  /* update counter */");
+                println("        idx = intop(+, idx, step);  /* add step to index */");
+                println("        chgivalue(s2v(ra), idx);  /* update internal index */");
+                println("        setivalue(s2v(ra + 3), idx);  /* and control variable */");
+                println("        goto label_%02d; /* jump back */", ((pc+1) - GETARG_Bx(instr))); // (!)
+                println("      }");
+                println("    }");
+                println("    else {  /* floating loop */");
+                println("      lua_Number step = fltvalue(s2v(ra + 2));");
+                println("      lua_Number limit = fltvalue(s2v(ra + 1));");
+                println("      lua_Number idx = fltvalue(s2v(ra));");
+                println("      idx = luai_numadd(L, idx, step);  /* increment index */");
+                println("      if (luai_numlt(0, step) ? luai_numle(idx, limit)");
+                println("                              : luai_numle(limit, idx)) {");
+                println("        chgfltvalue(s2v(ra), idx);  /* update internal index */");
+                println("        setfltvalue(s2v(ra + 3), idx);  /* and control variable */");
+                println("        goto label_%02d; /* jump back */", ((pc+1) - GETARG_Bx(instr))); // (!)
+                println("      }");
+                println("    }");
+                println("    updatetrap(ci);  /* allows a signal to break the loop */");
+                break;
+            }
+            case OP_FORPREP: {
+                println("    TValue *pinit = s2v(ra);");
+                println("    TValue *plimit = s2v(ra + 1);");
+                println("    TValue *pstep = s2v(ra + 2);");
+                println("    savestate(L, ci);  /* in case of errors */");
+                println("    if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */");
+                println("      lua_Integer init = ivalue(pinit);");
+                println("      lua_Integer step = ivalue(pstep);");
+                println("      lua_Integer limit;");
+                println("      if (step == 0)");
+                println("        luaG_runerror(L, \"'for' step is zero\");");
+                println("      setivalue(s2v(ra + 3), init);  /* control variable */");
+                println("      if (forlimit(L, init, plimit, &limit, step))");
+                println("        goto label_%02d; /* skip the loop */", ((pc + 1) + GETARG_Bx(instr) + 1)); // (!)
+                println("      else {  /* prepare loop counter */");
+                println("        lua_Unsigned count;");
+                println("        if (step > 0) {  /* ascending loop? */");
+                println("          count = l_castS2U(limit) - l_castS2U(init);");
+                println("          if (step != 1)  /* avoid division in the too common case */");
+                println("            count /= l_castS2U(step);");
+                println("        }");
+                println("        else {  /* step < 0; descending loop */");
+                println("          count = l_castS2U(init) - l_castS2U(limit);");
+                println("          /* 'step+1' avoids negating 'mininteger' */");
+                println("          count /= l_castS2U(-(step + 1)) + 1u;");
+                println("        }");
+                println("        /* store the counter in place of the limit (which won't be");
+                println("           needed anymore */");
+                println("        setivalue(plimit, l_castU2S(count));");
+                println("      }");
+                println("    }");
+                println("    else {  /* try making all values floats */");
+                println("      lua_Number init; lua_Number limit; lua_Number step;");
+                println("      if (unlikely(!tonumber(plimit, &limit)))");
+                println("        luaG_forerror(L, plimit, \"limit\");");
+                println("      if (unlikely(!tonumber(pstep, &step)))");
+                println("        luaG_forerror(L, pstep, \"step\");");
+                println("      if (unlikely(!tonumber(pinit, &init)))");
+                println("        luaG_forerror(L, pinit, \"initial value\");");
+                println("      if (step == 0)");
+                println("        luaG_runerror(L, \"'for' step is zero\");");
+                println("      if (luai_numlt(0, step) ? luai_numlt(limit, init)");
+                println("                               : luai_numlt(init, limit))");
+                println("        goto label_%02d; /* skip the loop */", ((pc + 1) + GETARG_Bx(instr) + 1)); // (!)
+                println("      else {");
+                println("        /* make sure internal values are all float */");
+                println("        setfltvalue(plimit, limit);");
+                println("        setfltvalue(pstep, step);");
+                println("        setfltvalue(s2v(ra), init);  /* internal index */");
+                println("        setfltvalue(s2v(ra + 3), init);  /* control variable */");
+                println("      }");
+                println("    }");
+                break;
+            }
             //case OP_TFORPREP
             //case OP_TFORCALL
             //case OP_TFORLOOP