Commit 7df7d267b88 for php
commit 7df7d267b88bc4bddb184d004a1e75b4f36a4fff
Author: Nora Dossche <7771979+ndossche@users.noreply.github.com>
Date: Mon Oct 26 21:09:12 2026 +0100
Update IR (#24756)
So we can pull in https://github.com/dstogov/ir/pull/258 later to lower
branches.
diff --git a/.github/scripts/download-bundled/jit-ir.sh b/.github/scripts/download-bundled/jit-ir.sh
index 594203b7021..74a9789f35a 100755
--- a/.github/scripts/download-bundled/jit-ir.sh
+++ b/.github/scripts/download-bundled/jit-ir.sh
@@ -5,7 +5,7 @@ cd "$(dirname "$0")/../../.."
tmp_dir=/tmp/php-src-download-bundled/jit-ir
rm -rf "$tmp_dir"
-revision=bb044213cc1bc835613d0172ee95c52360a00524
+revision=30a40633b0b8f3e8e66da0a25941c4199d69d38a
git clone --depth 1 --revision="$revision" https://github.com/dstogov/ir.git "$tmp_dir"
diff --git a/ext/opcache/jit/ir/ir.c b/ext/opcache/jit/ir/ir.c
index fd56dd8067c..734e9086648 100644
--- a/ext/opcache/jit/ir/ir.c
+++ b/ext/opcache/jit/ir/ir.c
@@ -635,6 +635,26 @@ static IR_NEVER_INLINE void ir_const_hash_rehash(ir_ctx *ctx)
}
}
+#ifdef IR_DEBUG
+/* Narrow integer constants are kept sign/zero extended to 64 bits, FLOAT has zero upper half */
+static bool ir_const_is_canonical(ir_val val, uint8_t type)
+{
+ uint32_t shift;
+
+ if (type == IR_FLOAT) {
+ return val.u32_hi == 0;
+ }
+ if (!IR_IS_TYPE_INT(type) || ir_type_size[type] == 8) {
+ return 1;
+ }
+ shift = (8 - ir_type_size[type]) * 8;
+ if (IR_IS_TYPE_SIGNED(type)) {
+ return val.i64 == (int64_t)(val.u64 << shift) >> shift;
+ }
+ return val.u64 == (val.u64 << shift) >> shift;
+}
+#endif
+
ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx)
{
ir_insn *insn;
@@ -647,6 +667,8 @@ ir_ref ir_const_ex(ir_ctx *ctx, ir_val val, uint8_t type, uint32_t optx)
return IR_NULL;
}
+ IR_ASSERT(IR_IS_SYM_CONST(optx & IR_OPT_OP_MASK) || ir_const_is_canonical(val, type));
+
hash = ir_const_hash(val, optx) & ctx->const_hash_mask;
ref = ctx->const_hash[hash];
while (ref) {
@@ -1278,12 +1300,7 @@ ir_ref ir_folding(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3,
/* Extend a narrow integer result to its type width so no
* fold rule sees garbage in the upper bits. */
if (IR_IS_TYPE_INT(type) && ir_type_size[type] < 8) {
- uint32_t shift = (8 - ir_type_size[type]) * 8;
- if (IR_IS_TYPE_SIGNED(type)) {
- val.i64 = (int64_t)(val.u64 << shift) >> shift;
- } else {
- val.u64 = (val.u64 << shift) >> shift;
- }
+ val.u64 = ir_fix_int(type, val.u64);
}
if (!ctx->use_lists) {
diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc
index a29e97c4d3e..b9fdbc2e796 100644
--- a/ext/opcache/jit/ir/ir_aarch64.dasc
+++ b/ext/opcache/jit/ir/ir_aarch64.dasc
@@ -10019,7 +10019,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
if (ctx->code_buffer) {
if (ctx->code_buffer->pos == (char*)entry + size) {
/* rollback */
- ctx->code_buffer->pos = (char*)entry - size;
+ ctx->code_buffer->pos = (char*)entry;
}
} else {
ir_mem_unmap(entry, size);
@@ -10142,7 +10142,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
dasm_free(&dasm_state);
if (code_buffer->pos == (char*)entry + size) {
/* rollback */
- code_buffer->pos = (char*)entry - size;
+ code_buffer->pos = (char*)entry;
}
return NULL;
}
diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h
index bd73a3cbf41..16dc6f536b8 100644
--- a/ext/opcache/jit/ir/ir_fold.h
+++ b/ext/opcache/jit/ir/ir_fold.h
@@ -2685,6 +2685,7 @@ IR_FOLD(DIV(NEG, C_FLOAT))
{
op1 = op1_insn->op1;
val.f = -op2_insn->val.f;
+ val.u32_hi = 0;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
}
@@ -3695,7 +3696,8 @@ IR_FOLD(ADD(ADD, C_ADDR))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x + c1) + c2 => x + (c1 + c2) */
- val.u64 = ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64);
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3710,7 +3712,8 @@ IR_FOLD(ADD(ADD, C_I64))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x + c1) + c2 => x + (c1 + c2) */
- val.i64 = ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64);
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3726,13 +3729,15 @@ IR_FOLD(ADD(SUB, C_ADDR))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x - c1) + c2 => x + (c2 - c1) */
- val.u64 = op2_insn->val.u64 - ctx->ir_base[op1_insn->op2].val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ op2_insn->val.u64 - ctx->ir_base[op1_insn->op2].val.u64);
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) {
/* (c1 - x) + c2 => (c1 + c2) - x */
- val.u64 = ctx->ir_base[op1_insn->op1].val.u64 + op2_insn->val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op1].val.u64 + op2_insn->val.u64);
opt++; /* ADD -> SUB */
op2 = op1_insn->op2;
op1 = ir_const(ctx, val, op2_insn->type);
@@ -3748,8 +3753,9 @@ IR_FOLD(ADD(SUB, C_I64))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x - c1) + c2 => x + (c2 - c1) */
- val.i64 = op2_insn->val.u64 - ctx->ir_base[op1_insn->op2].val.u64;
- if (val.i64 < 0 && val.i64 != INT64_MIN) {
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ op2_insn->val.u64 - ctx->ir_base[op1_insn->op2].val.u64);
+ if (val.i64 < 0 && ir_neg_is_safe(IR_OPT_TYPE(opt), val.i64)) {
val.i64 = -val.i64;
opt++; /* ADD -> SUB */
}
@@ -3758,7 +3764,8 @@ IR_FOLD(ADD(SUB, C_I64))
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) {
/* (c1 - x) + c2 => (c1 + c2) - x */
- val.i64 = ctx->ir_base[op1_insn->op1].val.u64 + op2_insn->val.u64;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op1].val.u64 + op2_insn->val.u64);
opt++; /* ADD -> SUB */
op2 = op1_insn->op2;
op1 = ir_const(ctx, val, op2_insn->type);
@@ -3775,7 +3782,8 @@ IR_FOLD(SUB(ADD, C_ADDR))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x + c1) - c2 => x + (c1 - c2) */
- val.u64 = ctx->ir_base[op1_insn->op2].val.u64 - op2_insn->val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 - op2_insn->val.u64);
opt--; /* SUB -> ADD */
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
@@ -3791,8 +3799,9 @@ IR_FOLD(SUB(ADD, C_I64))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x + c1) - c2 => x + (c1 - c2) */
- val.i64 = ctx->ir_base[op1_insn->op2].val.u64 - op2_insn->val.u64;
- if (val.i64 < 0 && val.i64 != INT64_MIN) {
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 - op2_insn->val.u64);
+ if (val.i64 < 0 && ir_neg_is_safe(IR_OPT_TYPE(opt), val.i64)) {
val.i64 = -val.i64;
} else {
opt--; /* SUB -> ADD */
@@ -3812,7 +3821,8 @@ IR_FOLD(SUB(C_ADDR, ADD))
{
if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) {
/* c1 - (x + c2) => (c1 - c2) - x */
- val.u64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op2].val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 - ctx->ir_base[op2_insn->op2].val.u64);
op2 = op2_insn->op1;
op1 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3827,7 +3837,8 @@ IR_FOLD(SUB(C_I64, ADD))
{
if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) {
/* c1 - (x + c2) => (c1 - c2) - x */
- val.i64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op2].val.u64;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 - ctx->ir_base[op2_insn->op2].val.u64);
op2 = op2_insn->op1;
op1 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3843,7 +3854,8 @@ IR_FOLD(SUB(SUB, C_ADDR))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x - c1) - c2 => x - (c1 + c2) */
- val.u64 = ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64);
if (val.i64 < 0 && val.i64 != INT64_MIN) {
val.i64 = -val.i64;
opt--; /* SUB -> ADD */
@@ -3853,7 +3865,8 @@ IR_FOLD(SUB(SUB, C_ADDR))
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) {
/* (c1 - x) - c2 => (c1 - c2) - x */
- val.u64 = ctx->ir_base[op1_insn->op1].val.u64 - op2_insn->val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op1].val.u64 - op2_insn->val.u64);
op2 = op1_insn->op2;
op1 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3868,8 +3881,9 @@ IR_FOLD(SUB(SUB, C_I64))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x - c1) - c2 => x - (c1 + c2) */
- val.i64 = ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64;
- if (val.i64 < 0 && val.i64 != INT64_MIN) {
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 + op2_insn->val.u64);
+ if (val.i64 < 0 && ir_neg_is_safe(IR_OPT_TYPE(opt), val.i64)) {
val.i64 = -val.i64;
opt--; /* SUB -> ADD */
}
@@ -3878,7 +3892,8 @@ IR_FOLD(SUB(SUB, C_I64))
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op1_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op1].op)) {
/* (c1 - x) - c2 => (c1 - c2) - x */
- val.i64 = ctx->ir_base[op1_insn->op1].val.u64 - op2_insn->val.u64;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op1].val.u64 - op2_insn->val.u64);
op2 = op1_insn->op2;
op1 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3894,16 +3909,19 @@ IR_FOLD(SUB(C_ADDR, SUB))
{
if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) {
/* c1 - (x - c2) => (c1 + c2) - x */
- val.u64 = op1_insn->val.u64 + ctx->ir_base[op2_insn->op2].val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 + ctx->ir_base[op2_insn->op2].val.u64);
op2 = op2_insn->op1;
op1 = ir_const(ctx, val, op1_insn->type);
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op2_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op1].op)) {
/* c1 - (c2 - x) => x + (c1 - c2) */
- val.u64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op1].val.u64;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 - ctx->ir_base[op2_insn->op1].val.u64);
if (val.i64 < 0 && val.i64 != INT64_MIN) {
val.i64 = -val.i64;
- opt++; /* ADD -> SUB */
+ } else {
+ opt--; /* SUB -> ADD */
}
op1 = op2_insn->op2;
op2 = ir_const(ctx, val, op1_insn->type);
@@ -3919,16 +3937,19 @@ IR_FOLD(SUB(C_I64, SUB))
{
if (IR_IS_CONST_REF(op2_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op2].op)) {
/* c1 - (x - c2) => (c1 + c2) - x */
- val.i64 = op1_insn->val.u64 + ctx->ir_base[op2_insn->op2].val.u64;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 + ctx->ir_base[op2_insn->op2].val.u64);
op2 = op2_insn->op1;
op1 = ir_const(ctx, val, op1_insn->type);
IR_FOLD_RESTART;
} else if (IR_IS_CONST_REF(op2_insn->op1) && !IR_IS_SYM_CONST(ctx->ir_base[op2_insn->op1].op)) {
/* c1 - (c2 - x) => x + (c1 - c2) */
- val.i64 = op1_insn->val.u64 - ctx->ir_base[op2_insn->op1].val.u64;
- if (val.i64 < 0 && val.i64 != INT64_MIN) {
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ op1_insn->val.u64 - ctx->ir_base[op2_insn->op1].val.u64);
+ if (val.i64 < 0 && ir_neg_is_safe(IR_OPT_TYPE(opt), val.i64)) {
val.i64 = -val.i64;
- opt++; /* ADD -> SUB */
+ } else {
+ opt--; /* SUB -> ADD */
}
op1 = op2_insn->op2;
op2 = ir_const(ctx, val, op1_insn->type);
@@ -3945,9 +3966,8 @@ IR_FOLD(MUL(MUL, C_ADDR))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x * c1) * c2 => x * (c1 * c2) */
- uint32_t shift = (8 - ir_type_size[op2_insn->type]) * 8;
- val.u64 = ctx->ir_base[op1_insn->op2].val.u64 * op2_insn->val.u64;
- val.u64 = (val.u64 << shift) >> shift;
+ val.u64 = ir_fix_unsigned(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 * op2_insn->val.u64);
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
@@ -3962,9 +3982,8 @@ IR_FOLD(MUL(MUL, C_I64))
{
if (IR_IS_CONST_REF(op1_insn->op2) && !IR_IS_SYM_CONST(ctx->ir_base[op1_insn->op2].op)) {
/* (x * c1) * c2 => x * (c1 * c2) */
- uint32_t shift = (8 - ir_type_size[op2_insn->type]) * 8;
- val.u64 = ctx->ir_base[op1_insn->op2].val.u64 * op2_insn->val.u64;
- val.i64 = (int64_t)(val.u64 << shift) >> shift;
+ val.u64 = ir_fix_signed(IR_OPT_TYPE(opt),
+ ctx->ir_base[op1_insn->op2].val.u64 * op2_insn->val.u64);
op1 = op1_insn->op1;
op2 = ir_const(ctx, val, op2_insn->type);
IR_FOLD_RESTART;
diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h
index 028acd66cb7..6fa8efa9cf7 100644
--- a/ext/opcache/jit/ir/ir_private.h
+++ b/ext/opcache/jit/ir/ir_private.h
@@ -958,6 +958,39 @@ IR_ALWAYS_INLINE bool ir_ref_is_true(const ir_ctx *ctx, ir_ref ref)
}
}
+IR_ALWAYS_INLINE bool ir_neg_is_safe(ir_type type, int64_t val)
+{
+ return val != (INT64_MIN >> ((8 - ir_type_size[type]) * 8));
+}
+
+/* Clear the "uvisible" high bits */
+IR_ALWAYS_INLINE uint64_t ir_fix_unsigned(ir_type type, uint64_t val)
+{
+ uint64_t shift;
+
+ shift = (8 - ir_type_size[type]) * 8;
+ return (val << shift) >> shift;
+}
+
+/* Sign extend the value into the "uvisible" high bits */
+IR_ALWAYS_INLINE uint64_t ir_fix_signed(ir_type type, uint64_t val)
+{
+ uint64_t shift;
+
+ shift = (8 - ir_type_size[type]) * 8;
+ return (int64_t)(val << shift) >> shift;
+}
+
+IR_ALWAYS_INLINE uint64_t ir_fix_int(ir_type type, uint64_t val)
+{
+ IR_ASSERT(IR_IS_TYPE_INT(type));
+ if (IR_IS_TYPE_SIGNED(type)) {
+ return ir_fix_signed(type, val);
+ } else {
+ return ir_fix_unsigned(type, val);
+ }
+}
+
/* IR OP flags */
#define IR_OP_FLAG_OPERANDS_SHIFT 3
diff --git a/ext/opcache/jit/ir/ir_sccp.c b/ext/opcache/jit/ir/ir_sccp.c
index 27bb9163dcc..3ad6997b071 100644
--- a/ext/opcache/jit/ir/ir_sccp.c
+++ b/ext/opcache/jit/ir/ir_sccp.c
@@ -3761,6 +3761,9 @@ static ir_ref ir_iter_optimize_condition(ir_ctx *ctx, ir_ref control, ir_ref con
default:
IR_ASSERT(0);
}
+ if (IR_IS_TYPE_SIGNED(condition_insn->type)) {
+ val.u64 = ir_fix_signed(condition_insn->type, val.u64);
+ }
ir_ref c = ir_const(ctx, val, condition_insn->type);
condition_insn = &ctx->ir_base[condition];
@@ -3785,7 +3788,11 @@ static ir_ref ir_iter_optimize_condition(ir_ctx *ctx, ir_ref control, ir_ref con
CLEAR_USES(condition_insn->op1);
condition_insn->type = ctx->ir_base[op1_insn->op1].type;
condition_insn->op1 = op1_insn->op1;
- ir_ref c = ir_const(ctx, val_insn->val, condition_insn->type);
+ ir_val val = val_insn->val;
+ if (IR_IS_TYPE_SIGNED(condition_insn->type)) {
+ val.u64 = ir_fix_signed(condition_insn->type, val.u64);
+ }
+ ir_ref c = ir_const(ctx, val, condition_insn->type);
condition_insn = &ctx->ir_base[condition];
condition_insn->op2 = c;
ir_bitqueue_add(ctx->iter_worklist, condition);
diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc
index 312a72ff175..534f7cd55d7 100644
--- a/ext/opcache/jit/ir/ir_x86.dasc
+++ b/ext/opcache/jit/ir/ir_x86.dasc
@@ -27314,7 +27314,7 @@ next_block:;
if (ctx->code_buffer) {
if (ctx->code_buffer->pos == (char*)entry + size) {
/* rollback */
- ctx->code_buffer->pos = (char*)entry - size;
+ ctx->code_buffer->pos = (char*)entry;
}
} else {
ir_mem_unmap(entry, size);
@@ -27440,7 +27440,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
dasm_free(&dasm_state);
if (code_buffer->pos == (char*)entry + size) {
/* rollback */
- code_buffer->pos = (char*)entry - size;
+ code_buffer->pos = (char*)entry;
}
return NULL;
}