diff --git a/mlibc/include/stdarg.h b/mlibc/include/stdarg.h
index fa5a6332..211ec36f 100644
--- a/mlibc/include/stdarg.h
+++ b/mlibc/include/stdarg.h
@@ -35,7 +35,7 @@ typedef char* va_list;
#define va_start(ap, last) (void)((ap) = (char*)(&(last) + 1))
#else // !__GNUC__
typedef int va_list;
-#define va_start(ap, last) (void)((ap) = (char*)(&(last) + 4))
+#define va_start(ap, last) (void)((ap) = (char*)(&(last) + 1))
#endif // !__GNUC__
#define va_arg(ap, type) (type)(((int*)((ap) = ((ap) + 4)))[-1])
diff --git a/module/language/c99/compiler.mes b/module/language/c99/compiler.mes
index c64429b7..99c430e7 100644
--- a/module/language/c99/compiler.mes
+++ b/module/language/c99/compiler.mes
@@ -792,6 +792,7 @@
((add ,a ,b)
(let* ((ptr (expr->pointer info a))
+ (ptr-b (expr->pointer info b))
(type0 (p-expr->type info a))
(struct? (memq (type:type (ast-type->type info type0)) '(struct union)))
(size (cond ((= ptr 1) (expr->size info a))
@@ -799,11 +800,12 @@
((and struct? (= ptr -2)) 4)
((and struct? (= ptr 2)) 4)
(else 1))))
- (if (= size 1) ((binop->accu info) a b (i386:accu+base))
+ (if (or (= size 1)) ((binop->accu info) a b (i386:accu+base))
(let* ((info ((expr->accu info) b))
- (info (append-text info (wrap-as (i386:value->base size))))
- (info (append-text info (wrap-as (i386:accu*base))))
- (info ((expr->base info) a)))
+ (info (append-text info (wrap-as (append (i386:value->base size)
+ (i386:accu*base)
+ (i386:accu->base)))))
+ (info ((expr->accu info) a)))
(append-text info (wrap-as (i386:accu+base)))))))
((sub ,a (p-expr (fixed ,value)))
@@ -822,6 +824,7 @@
((sub ,a ,b)
(let* ((ptr (expr->pointer info a))
+ (ptr-b (expr->pointer info b))
(type0 (p-expr->type info a))
(struct? (memq (type:type (ast-type->type info type0)) '(struct union)))
(size (cond ((= ptr 1) (expr->size info a))
@@ -829,11 +832,15 @@
((and struct? (= ptr -2)) 4)
((and struct? (= ptr 2)) 4)
(else 1))))
- (if (= size 1) ((binop->accu info) a b (i386:accu-base))
+ (if (or (= size 1) (= ptr-b 1)) (let ((info ((binop->accu info) a b (i386:accu-base))))
+ (if (not (= ptr-b 1)) info
+ (append-text info (wrap-as (append (i386:value->base size)
+ (i386:accu/base))))))
(let* ((info ((expr->accu info) b))
- (info (append-text info (wrap-as (i386:value->base size))))
- (info (append-text info (wrap-as (i386:accu*base))))
- (info ((expr->base info) a)))
+ (info (append-text info (wrap-as (append (i386:value->base size)
+ (i386:accu*base)
+ (i386:accu->base)))))
+ (info ((expr->accu info) a)))
(append-text info (wrap-as (i386:accu-base)))))))
((bitwise-and ,a ,b) ((binop->accu info) a b (i386:accu-and-base)))
@@ -923,6 +930,7 @@
(info ((expr->accu info) b))
(info (if (equal? op "=") info
(let* ((ptr (expr->pointer info a))
+ (ptr-b (expr->pointer info b))
(type0 (p-expr->type info a))
(struct? (memq (type:type (ast-type->type info type0)) '(struct union)))
(size (cond ((= ptr 1) (expr->size info a))
@@ -930,23 +938,27 @@
((and struct? (= ptr -2)) 4)
((and struct? (= ptr 2)) 4)
(else 1)))
- (info (if (= size 1) info
+ (info (if (or (= size 1) (= ptr-b 1)) info
(let ((info (append-text info (wrap-as (i386:value->base size)))))
(append-text info (wrap-as (i386:accu*base))))))
(info (append-text info (wrap-as (i386:push-accu))))
(info ((expr->accu info) a))
- (info (append-text info (wrap-as (i386:pop-base)))))
- (append-text info (cond ((equal? op "+=") (wrap-as (i386:accu+base)))
- ((equal? op "-=") (wrap-as (i386:accu-base)))
- ((equal? op "*=") (wrap-as (i386:accu*base)))
- ((equal? op "/=") (wrap-as (i386:accu/base)))
- ((equal? op "%=") (wrap-as (i386:accu%base)))
- ((equal? op "&=") (wrap-as (i386:accu-and-base)))
- ((equal? op "|=") (wrap-as (i386:accu-or-base)))
- ((equal? op "^=") (wrap-as (i386:accu-xor-base)))
- ((equal? op ">>=") (wrap-as (i386:accu>>base)))
- ((equal? op "<<=") (wrap-as (i386:accu<>=") (wrap-as (i386:accu>>base)))
+ ((equal? op "<<=") (wrap-as (i386:accu<base size)
+ (i386:accu/base)))))
+ (else (error (format #f "invalid operands to binary ~s (have ~s* and ~s*)" op type0 (p-expr->type info b)))))))))
(pmatch a
((p-expr (ident ,name))
(append-text info ((accu->ident info) name)))
diff --git a/scaffold/tests/76-pointer-arithmetic.c b/scaffold/tests/76-pointer-arithmetic.c
index 39469d43..712bea03 100644
--- a/scaffold/tests/76-pointer-arithmetic.c
+++ b/scaffold/tests/76-pointer-arithmetic.c
@@ -27,6 +27,7 @@ struct foo {
int a;
int b;
int c;
+ unsigned char *d;
};
int
@@ -64,7 +65,7 @@ test ()
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
pfoo++;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
- if (pfoo != 12) return 15;
+ if (pfoo != 16) return 15;
pfoo--;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
@@ -72,7 +73,7 @@ test ()
pfoo++;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
- if (pfoo != 12) return 17;
+ if (pfoo != 16) return 17;
int one = 1;
int two = 2;
@@ -82,7 +83,7 @@ test ()
pfoo = pfoo + one;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
- if (pfoo != 12) return 19;
+ if (pfoo != 16) return 19;
pfoo -= one;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
@@ -90,9 +91,36 @@ test ()
pfoo += one;
eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
- if (pfoo != 12) return 21;
+ if (pfoo != 16) return 21;
if (&one - 1 != &two) return 22;
+ struct foo* sym = 32;
+ int d = 16;
+ int i = sym + 16;
+ eputs ("i="); eputs (itoa (i)); eputs ("\n");
+ if (i != 288) return 23;
+
+ i = sym + d;
+ eputs ("i="); eputs (itoa (i)); eputs ("\n");
+ if (i != 288) return 24;
+
+ i = sym - 16;
+ eputs ("i="); eputs (itoa (i)); eputs ("\n");
+ if (i != -224) return 25;
+
+ i = sym - d;
+ eputs ("i="); eputs (itoa (i)); eputs ("\n");
+ if (i != -224) return 26;
+
+ i = sym - (struct foo*)d;
+ eputs ("i="); eputs (itoa (i)); eputs ("\n");
+ if (i != 1) return 27;
+
+ pfoo = sym + 1;
+ pfoo -= sym;
+ eputs ("pfoo="); eputs (itoa (pfoo)); eputs ("\n");
+ if (pfoo != 1) return 28;
+
return 0;
}