Skip to content

Instantly share code, notes, and snippets.

@jnthn

jnthn/gcd.diff Secret

Created May 17, 2019 13:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnthn/faa05a408bd94321a623d197740f4da0 to your computer and use it in GitHub Desktop.
Save jnthn/faa05a408bd94321a623d197740f4da0 to your computer and use it in GitHub Desktop.
diff --git a/src/jit/graph.c b/src/jit/graph.c
index 1efcd66..77a8b66 100644
--- a/src/jit/graph.c
+++ b/src/jit/graph.c
@@ -1912,6 +1912,7 @@ start:
case MVM_OP_sp_add_bi:
case MVM_OP_sp_sub_bi:
case MVM_OP_sp_mul_bi:
+ case MVM_OP_sp_gcd_bi:
case MVM_OP_sp_unbox_bi:
case MVM_OP_sp_takewrite_bi:
case MVM_OP_sp_materialize_bi:
diff --git a/src/jit/x64/emit.dasc b/src/jit/x64/emit.dasc
index 9d37026..2441e76 100644
--- a/src/jit/x64/emit.dasc
+++ b/src/jit/x64/emit.dasc
@@ -2461,7 +2461,8 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
}
case MVM_OP_sp_add_bi:
case MVM_OP_sp_sub_bi:
- case MVM_OP_sp_mul_bi: {
+ case MVM_OP_sp_mul_bi:
+ case MVM_OP_sp_gcd_bi: {
MVMint16 a = ins->operands[1].reg.orig;
MVMint16 b = ins->operands[2].reg.orig;
MVMint16 c = ins->operands[0].reg.orig;
@@ -2474,8 +2475,7 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
| cmp TMP1d, MVM_BIGINT_32_FLAG;
| jne >1;
- /* Both smallint, so try to do the calculation. If it overflows, fall
- * back to the slow path. */
+ /* Both smallint, so try to do the calculation. */
| mov TMP4d, dword [WORK + 8 * a + 4]
switch (op) {
case MVM_OP_sp_add_bi:
@@ -2487,8 +2487,38 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
case MVM_OP_sp_mul_bi:
| imul TMP4d, dword [WORK + 8 * b + 4]
break;
+ case MVM_OP_sp_gcd_bi:
+ /* Need absolute values first. We'll want the first value in
+ * eax for the GCD itself, but need eax for the absolute too,
+ * so process the second operand first and move it into ecx. */
+ | mov eax, dword [WORK + 8 * b + 4]
+ | cdq
+ | xor eax, edx
+ | sub eax, edx
+ | mov ecx, eax
+ | mov eax, TMP4d
+ | cdq
+ | xor eax, edx
+ | sub eax, edx
+
+ /* We now have the values to do the GCD on in eax and ecx (we
+ * avoid ebx since that is WORK); only eax matters since it's
+ * the implicit argument to div. */
+ |4:
+ | xor edx, edx
+ | div ecx
+ | mov eax, ecx
+ | mov ecx, edx
+ | test ecx, ecx
+ | jnz >4
+ | mov TMP4d, eax
+ break;
}
- | jo >1
+
+ /* If it overflows, fall back to the slow path. (Some operations
+ * always produce a smaller value than the input, so cannot.) */
+ if (op != MVM_OP_sp_gcd_bi)
+ | jo >1
/* No overflow; store the result. */
| mov dword [WORK + 8 * c], MVM_BIGINT_32_FLAG
@@ -2513,6 +2543,9 @@ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJ
case MVM_OP_sp_mul_bi:
| callp &MVM_bigint_fallback_mul;
break;
+ case MVM_OP_sp_gcd_bi:
+ | callp &MVM_bigint_fallback_gcd;
+ break;
}
|3:
break;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment