aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-28 18:45:34 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-28 18:45:34 +0200
commit8e9ae1c325533818f43efa9577d15cc17295d9ee (patch)
treecd67e9e4d1e34014186c8e426a1729fd8ef6e9f7
parent22c735178dc4126295e9ce376661bf2b38d3af0f (diff)
Try to properly support remainder
-rw-r--r--src/analyzer.c35
-rw-r--r--src/codegen.c11
-rw-r--r--src/common.h3
3 files changed, 33 insertions, 16 deletions
diff --git a/src/analyzer.c b/src/analyzer.c
index 2686e07..fff7716 100644
--- a/src/analyzer.c
+++ b/src/analyzer.c
@@ -331,8 +331,12 @@ analyzeexpr(struct azctx ctx, scope_t *scps, type_t *types, ast_t ast,
idx_t ni = analyzeexpr(ctx, scps, types, ast, aux, toks, rhs);
if (!typecompat(types[lhs], types[rhs]))
err("analyzer: Binary oprand type mismatch");
- if (ast.kinds[i] == ASTBINMOD && types[lhs].isfloat)
- err("analyzer: Modulus is not defined for floating-point types");
+ if (ast.kinds[i] == ASTBINMOD) {
+ if (types[lhs].kind != TYPE_NUM || types[lhs].isfloat)
+ err("analyzer: Remainder is not defined for non-integer types");
+ if (types[rhs].kind != TYPE_NUM || types[rhs].isfloat)
+ err("analyzer: Remainder is not defined for non-integer types");
+ }
types[i] = types[rhs];
return ni;
}
@@ -488,8 +492,8 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
MPQCPY(folds[i], folds[expr]);
if (!MPQ_IS_INIT(folds[i])) {
ctx.si = lvl;
- (void)constfolddecl(ctx, folds, scps, types,
- ast, toks, sym->i);
+ (void)constfolddecl(ctx, folds, scps, types, ast, toks,
+ sym->i);
MPQCPY(folds[i], folds[expr]);
assert(MPQ_IS_INIT(folds[i]));
}
@@ -516,16 +520,14 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
case ASTBINADD:
case ASTBINSUB:
case ASTBINMUL:
- case ASTBINDIV:
- case ASTBINMOD: {
- static void (*const mpq_fns[UINT8_MAX])(mpq_t, const mpq_t, const mpq_t) = {
+ case ASTBINDIV: {
+ static void (*const mpq_fns[UINT8_MAX])(mpq_t, const mpq_t,
+ const mpq_t) = {
['+'] = mpq_add,
['-'] = mpq_sub,
['*'] = mpq_mul,
['/'] = mpq_div,
};
- /* TODO: Support modulus */
-
idx_t lhs, rhs;
lhs = ast.kids[i].lhs;
rhs = ast.kids[i].rhs;
@@ -537,6 +539,21 @@ constfoldexpr(struct cfctx ctx, mpq_t *folds, scope_t *scps, type_t *types,
}
return ni;
}
+ case ASTBINMOD: {
+ idx_t lhs, rhs;
+ lhs = ast.kids[i].lhs;
+ rhs = ast.kids[i].rhs;
+
+ (void)constfoldexpr(ctx, folds, scps, types, ast, toks, lhs);
+ idx_t ni = constfoldexpr(ctx, folds, scps, types, ast, toks, rhs);
+
+ if (MPQ_IS_INIT(folds[lhs]) && MPQ_IS_INIT(folds[rhs])) {
+ mpq_init(folds[i]);
+ mpz_tdiv_r(mpq_numref(folds[i]), mpq_numref(folds[lhs]),
+ mpq_numref(folds[rhs]));
+ }
+ return ni;
+ }
case ASTFN:
return constfoldblk(ctx, folds, scps, types, ast, toks,
ast.kids[i].rhs);
diff --git a/src/codegen.c b/src/codegen.c
index 2f07442..188275b 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -150,13 +150,11 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
if (!type.issigned && mpq_sgn(ctx.folds[i]) == -1)
err("Cannot convert negative value to unsigned type");
- mpz_ptr num, den;
- num = mpq_numref(ctx.folds[i]);
- den = mpq_denref(ctx.folds[i]);
- if (mpz_cmp_ui(den, 1) != 0)
- err("Invalid integer");
+ if (!MPQ_IS_WHOLE(ctx.folds[i]))
+ err("codegen: Invalid integer");
int cmp;
+ mpz_ptr num = mpq_numref(ctx.folds[i]);
assert(type.size != 0);
/* TODO: Can we make the first branch work when the type has the
same size as an unsigned long? */
@@ -243,7 +241,8 @@ codegentypedexpr(struct cgctx ctx, idx_t i, type_t type, LLVMValueRef *outv)
case ASTBINADD:
case ASTBINSUB:
case ASTBINMUL:
- case ASTBINDIV: {
+ case ASTBINDIV:
+ case ASTBINMOD: {
typedef LLVMValueRef llbfn(LLVMBuilderRef, LLVMValueRef, LLVMValueRef,
const char *);
static const struct binop {
diff --git a/src/common.h b/src/common.h
index 2dffe2a..6285a15 100644
--- a/src/common.h
+++ b/src/common.h
@@ -17,7 +17,8 @@
# include <stdio.h>
#endif
-#define MPQ_IS_INIT(x) (mpq_denref(x)->_mp_d != NULL)
+#define MPQ_IS_INIT(x) (mpq_denref(x)->_mp_d != NULL)
+#define MPQ_IS_WHOLE(x) (mpz_cmp_ui(mpq_denref(x), 1) == 0)
/* Some headers like <sys/param.h> may define these */
#ifdef MIN