qbe macros
This commit is contained in:
194
source/qbe_helpers.c
Normal file
194
source/qbe_helpers.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* QBE Helper Functions
|
||||
*
|
||||
* Thin C wrappers called from QBE-generated code for operations
|
||||
* that are too complex to inline: float arithmetic, float comparison,
|
||||
* string comparison, bitwise ops on floats, and boolean conversion.
|
||||
*/
|
||||
|
||||
#include "quickjs-internal.h"
|
||||
#include <math.h>
|
||||
|
||||
/* Comparison op IDs (must match qbe.cm float_cmp_op_id values) */
|
||||
enum {
|
||||
QBE_CMP_EQ = 0,
|
||||
QBE_CMP_NE = 1,
|
||||
QBE_CMP_LT = 2,
|
||||
QBE_CMP_LE = 3,
|
||||
QBE_CMP_GT = 4,
|
||||
QBE_CMP_GE = 5
|
||||
};
|
||||
|
||||
/* ============================================================
|
||||
Float binary arithmetic
|
||||
============================================================ */
|
||||
|
||||
static inline JSValue qbe_float_binop(JSContext *ctx, JSValue a, JSValue b,
|
||||
double (*op)(double, double)) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
double r = op(da, db);
|
||||
if (!isfinite(r))
|
||||
return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
|
||||
static double op_add(double a, double b) { return a + b; }
|
||||
static double op_sub(double a, double b) { return a - b; }
|
||||
static double op_mul(double a, double b) { return a * b; }
|
||||
|
||||
JSValue qbe_float_add(JSContext *ctx, JSValue a, JSValue b) {
|
||||
return qbe_float_binop(ctx, a, b, op_add);
|
||||
}
|
||||
|
||||
JSValue qbe_float_sub(JSContext *ctx, JSValue a, JSValue b) {
|
||||
return qbe_float_binop(ctx, a, b, op_sub);
|
||||
}
|
||||
|
||||
JSValue qbe_float_mul(JSContext *ctx, JSValue a, JSValue b) {
|
||||
return qbe_float_binop(ctx, a, b, op_mul);
|
||||
}
|
||||
|
||||
JSValue qbe_float_div(JSContext *ctx, JSValue a, JSValue b) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
if (db == 0.0)
|
||||
return JS_NULL;
|
||||
double r = da / db;
|
||||
if (!isfinite(r))
|
||||
return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
|
||||
JSValue qbe_float_mod(JSContext *ctx, JSValue a, JSValue b) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
if (db == 0.0)
|
||||
return JS_NULL;
|
||||
double r = fmod(da, db);
|
||||
if (!isfinite(r))
|
||||
return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
|
||||
JSValue qbe_float_pow(JSContext *ctx, JSValue a, JSValue b) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
double r = pow(da, db);
|
||||
if (!isfinite(r) && isfinite(da) && isfinite(db))
|
||||
return JS_NULL;
|
||||
return JS_NewFloat64(ctx, r);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Float unary ops
|
||||
============================================================ */
|
||||
|
||||
JSValue qbe_float_neg(JSContext *ctx, JSValue v) {
|
||||
double d;
|
||||
JS_ToFloat64(ctx, &d, v);
|
||||
return JS_NewFloat64(ctx, -d);
|
||||
}
|
||||
|
||||
JSValue qbe_float_inc(JSContext *ctx, JSValue v) {
|
||||
double d;
|
||||
JS_ToFloat64(ctx, &d, v);
|
||||
return JS_NewFloat64(ctx, d + 1);
|
||||
}
|
||||
|
||||
JSValue qbe_float_dec(JSContext *ctx, JSValue v) {
|
||||
double d;
|
||||
JS_ToFloat64(ctx, &d, v);
|
||||
return JS_NewFloat64(ctx, d - 1);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Float comparison — returns 0 or 1 for QBE branching
|
||||
============================================================ */
|
||||
|
||||
int qbe_float_cmp(JSContext *ctx, int op, JSValue a, JSValue b) {
|
||||
double da, db;
|
||||
JS_ToFloat64(ctx, &da, a);
|
||||
JS_ToFloat64(ctx, &db, b);
|
||||
switch (op) {
|
||||
case QBE_CMP_EQ: return da == db;
|
||||
case QBE_CMP_NE: return da != db;
|
||||
case QBE_CMP_LT: return da < db;
|
||||
case QBE_CMP_LE: return da <= db;
|
||||
case QBE_CMP_GT: return da > db;
|
||||
case QBE_CMP_GE: return da >= db;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Boolean conversion wrapper
|
||||
============================================================ */
|
||||
|
||||
int qbe_to_bool(JSContext *ctx, JSValue v) {
|
||||
return JS_ToBool(ctx, v);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Bitwise not on non-int (float -> int32 -> ~)
|
||||
============================================================ */
|
||||
|
||||
JSValue qbe_bnot(JSContext *ctx, JSValue v) {
|
||||
int32_t i;
|
||||
JS_ToInt32(ctx, &i, v);
|
||||
return JS_NewInt32(ctx, ~i);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Bitwise binary ops on floats (convert both to int32, apply, re-tag)
|
||||
============================================================ */
|
||||
|
||||
JSValue qbe_bitwise_and(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, ia & ib);
|
||||
}
|
||||
|
||||
JSValue qbe_bitwise_or(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, ia | ib);
|
||||
}
|
||||
|
||||
JSValue qbe_bitwise_xor(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, ia ^ ib);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Shift ops on floats (convert to int32, shift, re-tag)
|
||||
============================================================ */
|
||||
|
||||
JSValue qbe_shift_shl(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, ia << (ib & 31));
|
||||
}
|
||||
|
||||
JSValue qbe_shift_sar(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, ia >> (ib & 31));
|
||||
}
|
||||
|
||||
JSValue qbe_shift_shr(JSContext *ctx, JSValue a, JSValue b) {
|
||||
int32_t ia, ib;
|
||||
JS_ToInt32(ctx, &ia, a);
|
||||
JS_ToInt32(ctx, &ib, b);
|
||||
return JS_NewInt32(ctx, (uint32_t)ia >> (ib & 31));
|
||||
}
|
||||
Reference in New Issue
Block a user