From a7f115a5416d4ec2ef7d0add2cd115349343507e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 18 Aug 2023 17:52:06 +0200 Subject: [PATCH] classlib: implement Integer.compareUnsigned in Wasm and C --- .../teavm/backend/c/intrinsic/IntegerIntrinsic.java | 8 ++++++++ .../main/java/org/teavm/backend/wasm/WasmRuntime.java | 8 ++++++++ .../backend/wasm/intrinsics/IntegerIntrinsic.java | 10 ++++++++++ .../backend/wasm/intrinsics/WasmRuntimeIntrinsic.java | 8 ++++++++ core/src/main/resources/org/teavm/backend/c/core.h | 3 +++ .../resources/org/teavm/backend/wasm/wasm-runtime.js | 2 +- 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/IntegerIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/IntegerIntrinsic.java index c48df6035..3da6c1317 100644 --- a/core/src/main/java/org/teavm/backend/c/intrinsic/IntegerIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/c/intrinsic/IntegerIntrinsic.java @@ -27,6 +27,7 @@ public class IntegerIntrinsic implements Intrinsic { switch (method.getName()) { case "divideUnsigned": case "remainderUnsigned": + case "compareUnsigned": return true; default: return false; @@ -42,6 +43,13 @@ public class IntegerIntrinsic implements Intrinsic { case "remainderUnsigned": writeBinary(context, invocation, "%"); break; + case "compareUnsigned": + context.writer().print("teavm_compare_u32("); + context.emit(invocation.getArguments().get(0)); + context.writer().print(", "); + context.emit(invocation.getArguments().get(1)); + context.writer().print(")"); + break; } } diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java b/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java index f7d61f49d..384cb1d0d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmRuntime.java @@ -31,6 +31,10 @@ public final class WasmRuntime { return gt(a, b) ? 1 : lt(a, b) ? -1 : 0; } + public static int compareUnsigned(int a, int b) { + return gtu(a, b) ? 1 : ltu(a, b) ? -1 : 0; + } + public static int compare(long a, long b) { return gt(a, b) ? 1 : lt(a, b) ? -1 : 0; } @@ -55,6 +59,10 @@ public final class WasmRuntime { private static native boolean gt(int a, int b); + private static native boolean ltu(int a, int b); + + private static native boolean gtu(int a, int b); + private static native boolean lt(long a, long b); private static native boolean gt(long a, long b); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/IntegerIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/IntegerIntrinsic.java index 3e4a91c1e..b2bd1941b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/IntegerIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/IntegerIntrinsic.java @@ -16,6 +16,8 @@ package org.teavm.backend.wasm.intrinsics; import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.WasmRuntime; +import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmIntBinary; import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation; @@ -23,6 +25,9 @@ import org.teavm.backend.wasm.model.expression.WasmIntType; import org.teavm.model.MethodReference; public class IntegerIntrinsic implements WasmIntrinsic { + private static final MethodReference COMPARE_UNSIGNED = new MethodReference(WasmRuntime.class, + "compareUnsigned", int.class, int.class, int.class); + @Override public boolean isApplicable(MethodReference methodReference) { if (!methodReference.getClassName().equals(Integer.class.getName())) { @@ -32,6 +37,7 @@ public class IntegerIntrinsic implements WasmIntrinsic { switch (methodReference.getName()) { case "divideUnsigned": case "remainderUnsigned": + case "compareUnsigned": return true; default: return false; @@ -49,6 +55,10 @@ public class IntegerIntrinsic implements WasmIntrinsic { return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.REM_UNSIGNED, manager.generate(invocation.getArguments().get(0)), manager.generate(invocation.getArguments().get(1))); + case "compareUnsigned": + return new WasmCall(manager.getNames().forMethod(COMPARE_UNSIGNED), + manager.generate(invocation.getArguments().get(0)), + manager.generate(invocation.getArguments().get(1))); default: throw new AssertionError(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmRuntimeIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmRuntimeIntrinsic.java index fa25dd8a6..9410148fe 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmRuntimeIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmRuntimeIntrinsic.java @@ -37,6 +37,8 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic { switch (methodReference.getName()) { case "gt": case "lt": + case "gtu": + case "ltu": case "initStack": return true; default: @@ -53,6 +55,12 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic { case "gt": return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.GT, invocation, manager); + case "ltu": + return comparison(WasmIntBinaryOperation.LT_UNSIGNED, WasmFloatBinaryOperation.LT, + invocation, manager); + case "gtu": + return comparison(WasmIntBinaryOperation.GT_UNSIGNED, WasmFloatBinaryOperation.GT, + invocation, manager); default: throw new IllegalArgumentException(invocation.getMethod().getName()); } diff --git a/core/src/main/resources/org/teavm/backend/c/core.h b/core/src/main/resources/org/teavm/backend/c/core.h index a0d6669db..ac505363f 100644 --- a/core/src/main/resources/org/teavm/backend/c/core.h +++ b/core/src/main/resources/org/teavm/backend/c/core.h @@ -129,6 +129,9 @@ extern void teavm_throwArrayIndexOutOfBoundsException(); static inline int32_t teavm_compare_i32(int32_t a, int32_t b) { return a > b ? INT32_C(1) : a < b ? INT32_C(-1) : INT32_C(0); } +static inline int32_t teavm_compare_u32(int32_t a, int32_t b) { + return (uint32_t) a > (uint32_t) b ? INT32_C(1) : (uint32_t) a < (uint32_t) b ? INT32_C(-1) : INT32_C(0); +} static inline int32_t teavm_compare_i64(int64_t a, int64_t b) { return a > b ? INT32_C(1) : a < b ? INT32_C(-1) : INT32_C(0); } diff --git a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.js b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.js index 228c6e75c..b9d8a7f17 100644 --- a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.js +++ b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.js @@ -52,7 +52,7 @@ TeaVM.wasm = function() { let length = instance.exports.teavm_arrayLength(arrayPtr); let arrayData = new DataView(memory, instance.exports.teavm_charArrayData(arrayPtr), length * 2); for (let i = 0; i < length; ++i) { - putwchar(arrayData.memory.getUint16(i * 2, true)); + putwchar(arrayData.getUint16(i * 2, true)); } } function logInt(i) {