classlib: implement Integer.compareUnsigned in Wasm and C

This commit is contained in:
Alexey Andreev 2023-08-18 17:52:06 +02:00
parent a3f0ec52d4
commit a7f115a541
6 changed files with 38 additions and 1 deletions

View File

@ -27,6 +27,7 @@ public class IntegerIntrinsic implements Intrinsic {
switch (method.getName()) { switch (method.getName()) {
case "divideUnsigned": case "divideUnsigned":
case "remainderUnsigned": case "remainderUnsigned":
case "compareUnsigned":
return true; return true;
default: default:
return false; return false;
@ -42,6 +43,13 @@ public class IntegerIntrinsic implements Intrinsic {
case "remainderUnsigned": case "remainderUnsigned":
writeBinary(context, invocation, "%"); writeBinary(context, invocation, "%");
break; 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;
} }
} }

View File

@ -31,6 +31,10 @@ public final class WasmRuntime {
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0; 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) { public static int compare(long a, long b) {
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0; 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 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 lt(long a, long b);
private static native boolean gt(long a, long b); private static native boolean gt(long a, long b);

View File

@ -16,6 +16,8 @@
package org.teavm.backend.wasm.intrinsics; package org.teavm.backend.wasm.intrinsics;
import org.teavm.ast.InvocationExpr; 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.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmIntBinary; import org.teavm.backend.wasm.model.expression.WasmIntBinary;
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation; 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; import org.teavm.model.MethodReference;
public class IntegerIntrinsic implements WasmIntrinsic { public class IntegerIntrinsic implements WasmIntrinsic {
private static final MethodReference COMPARE_UNSIGNED = new MethodReference(WasmRuntime.class,
"compareUnsigned", int.class, int.class, int.class);
@Override @Override
public boolean isApplicable(MethodReference methodReference) { public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(Integer.class.getName())) { if (!methodReference.getClassName().equals(Integer.class.getName())) {
@ -32,6 +37,7 @@ public class IntegerIntrinsic implements WasmIntrinsic {
switch (methodReference.getName()) { switch (methodReference.getName()) {
case "divideUnsigned": case "divideUnsigned":
case "remainderUnsigned": case "remainderUnsigned":
case "compareUnsigned":
return true; return true;
default: default:
return false; return false;
@ -49,6 +55,10 @@ public class IntegerIntrinsic implements WasmIntrinsic {
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.REM_UNSIGNED, return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.REM_UNSIGNED,
manager.generate(invocation.getArguments().get(0)), manager.generate(invocation.getArguments().get(0)),
manager.generate(invocation.getArguments().get(1))); 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: default:
throw new AssertionError(); throw new AssertionError();
} }

View File

@ -37,6 +37,8 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
switch (methodReference.getName()) { switch (methodReference.getName()) {
case "gt": case "gt":
case "lt": case "lt":
case "gtu":
case "ltu":
case "initStack": case "initStack":
return true; return true;
default: default:
@ -53,6 +55,12 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
case "gt": case "gt":
return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.GT, return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.GT,
invocation, manager); 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: default:
throw new IllegalArgumentException(invocation.getMethod().getName()); throw new IllegalArgumentException(invocation.getMethod().getName());
} }

View File

@ -129,6 +129,9 @@ extern void teavm_throwArrayIndexOutOfBoundsException();
static inline int32_t teavm_compare_i32(int32_t a, int32_t b) { 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); 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) { 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); return a > b ? INT32_C(1) : a < b ? INT32_C(-1) : INT32_C(0);
} }

View File

@ -52,7 +52,7 @@ TeaVM.wasm = function() {
let length = instance.exports.teavm_arrayLength(arrayPtr); let length = instance.exports.teavm_arrayLength(arrayPtr);
let arrayData = new DataView(memory, instance.exports.teavm_charArrayData(arrayPtr), length * 2); let arrayData = new DataView(memory, instance.exports.teavm_charArrayData(arrayPtr), length * 2);
for (let i = 0; i < length; ++i) { for (let i = 0; i < length; ++i) {
putwchar(arrayData.memory.getUint16(i * 2, true)); putwchar(arrayData.getUint16(i * 2, true));
} }
} }
function logInt(i) { function logInt(i) {