Commit Graph

80 Commits

Author SHA1 Message Date
Stephen Heumann d66f6b27b7 Evaluate arithmetic and shifts in long long constant expressions.
This winds up calling functions for these operations in ORCALib, so an up-to-date version of that must now be available to build the ORCA/C compiler.
2021-02-14 20:39:35 -06:00
Stephen Heumann eb49e10ea9 Implement && and || operators for long long types.
This is done by comparing against 0 (similar to how it is done for reals), rather than introducing new intermediate code operations.
2021-02-14 17:37:55 -06:00
Stephen Heumann e8b860f89a Do not corrupt long long expressions that cannot be evaluated at compile time.
The changes to constant expressions were not allowing the unsupported constant expressions to be evaluated at run time when they appear in regular code.
2021-02-13 21:14:26 -06:00
Stephen Heumann a3050c76a9 Evaluate some kinds of long long operations in constant expressions.
Other operations on long long (e.g. arithmetic) are still not supported in constant expressions.
2021-02-13 15:07:16 -06:00
Stephen Heumann 8faafcc7c8 Implement 64-bit shifts. 2021-02-12 15:06:15 -06:00
Stephen Heumann 05868667b2 Implement 64-bit division and remainder, signed and unsigned.
These operations rely on new library routines in ORCALib (~CDIV8 and ~UDIV8).
2021-02-05 12:42:48 -06:00
Stephen Heumann 08cf7a0181 Implement 64-bit multiplication support.
Signed multiplication uses the existing ~MUL8 routine in SysLib. Unsigned multiplication will use a new ~UMUL8 library routine.
2021-02-04 22:23:59 -06:00
Stephen Heumann 7f3ba768cd Allow pointer arithmetic using long long values.
This converts them to 32-bit values before doing computations, which is (more than) sufficient for address calculations on the 65816. Trying to compute an address outside the legal range is undefined behavior, and does not necessarily "wrap around" in a predictable way.
2021-02-04 22:05:02 -06:00
Stephen Heumann fc3bd32e65 Add long long support for a couple lint checks. 2021-02-04 17:53:37 -06:00
Stephen Heumann d2fb8cc27e Add long long support for the ! operator. 2021-02-04 17:53:10 -06:00
Stephen Heumann 5e5434987b Give an error when trying to evaluate constant expressions with long long operands. 2021-02-04 14:56:15 -06:00
Stephen Heumann 2408c9602c Make expressionValue a saturating approximation of the true value for long long expressions.
This gives sensible behavior for several things in the parser, e.g. where all negative values or all very large values should be disallowed.
2021-02-04 12:44:44 -06:00
Stephen Heumann 10cf6e446d Enable automatic comparison with 0 for long longs.
This allows them to be used in if statements and as controlling expressions for loops.
2021-02-04 12:39:27 -06:00
Stephen Heumann a59a2427fd Add some support for ++/-- on long long values.
Some more complex cases require pc_ind, which is not implemented yet.
2021-02-04 12:35:28 -06:00
Stephen Heumann 168a06b7bf Add support for emitting 64-bit constants in statically-initialized data. 2021-02-04 02:17:10 -06:00
Stephen Heumann 793f0a57cc Initial support for constants with long long types.
Currently, the actual values they can have are still constrained to the 32-bit range. Also, there are some bits of functionality (e.g. for initializers) that are not implemented yet.
2021-02-03 23:11:23 -06:00
Stephen Heumann 807a143e51 Implement 64-bit addition and subtraction. 2021-01-30 23:31:18 -06:00
Stephen Heumann 2e44c36c59 Implement unary negation and bitwise complement for 64-bit types. 2021-01-30 13:49:06 -06:00
Stephen Heumann abb0fa0fc1 Implement bitwise and/or/xor for 64-bit types.
This introduces three new intermediate codes for these operations.
2021-01-30 00:25:15 -06:00
Stephen Heumann 8b12b7b734 Handle (unsigned) long long in the front-end code for binary conversions.
There is not yet code generation support for the conversion opcodes (pc_cnv/pc_cnn).
2021-01-29 23:25:21 -06:00
Stephen Heumann b1d4d8d668 Give errors for certain invalid compound assignment expressions.
The following example shows cases that were erroneously permitted before:

int main(void) {
        int i, *p;
        i *= p;
        i <<= 5.0;
        i <<= (void)1;
}
2021-01-29 12:49:28 -06:00
Stephen Heumann f2a66a524a Fix several issues with evaluation of the ++ and -- operators.
These would generally not work correctly on bit-fields, or on floating-point values that were in a structure or were accessed via a pointer.

The below program is an example that would demonstrate problems:

#include <stdio.h>

int main(void) {
        struct {
                signed int i:7;
                unsigned long int j:6;
                _Bool b:1;
                double d;
        } s = {-10, -20, 0, 5.0};

        double d = 70.0, *dp = &d;

        printf("%i\n", (int)s.i++);
        printf("%i\n", (int)s.i--);
        printf("%i\n", (int)++s.i);
        printf("%i\n", (int)--s.i);
        printf("%i\n", (int)s.i);

        printf("%i\n", (int)s.j++);
        printf("%i\n", (int)s.j--);
        printf("%i\n", (int)++s.j);
        printf("%i\n", (int)--s.j);
        printf("%i\n", (int)s.j);

        printf("%i\n", s.b++);
        printf("%i\n", s.b--);
        printf("%i\n", ++s.b);
        printf("%i\n", --s.b);
        printf("%i\n", s.b);

        printf("%f\n", s.d++);
        printf("%f\n", s.d--);
        printf("%f\n", ++s.d);
        printf("%f\n", --s.d);
        printf("%f\n", s.d);

        printf("%f\n", (*dp)++);
        printf("%f\n", (*dp)--);
        printf("%f\n", ++*dp);
        printf("%f\n", --*dp);
        printf("%f\n", *dp);
}
2021-01-26 12:31:54 -06:00
Stephen Heumann 52132db18a Implement the _Bool type from C99. 2021-01-25 21:22:58 -06:00
Stephen Heumann c0b2b44cad Add a new representation of C basic types and use it for type checking.
This allows us to distinguish int from short, etc.
2020-03-01 15:00:02 -06:00
Stephen Heumann 41cb879936 In preprocessor expressions, always replace identifiers with constant 0.
This was not happening for declared identifiers (variables and functions) or for enum constants, as demonstrated in the following example:

enum {a,b,c};
#if b
#error "bad b"
#endif

int x = 0;
#if x
#error "bad x"
#endif
2020-02-05 18:23:45 -06:00
Stephen Heumann 3676e685b9 Disallow dereferencing of non-pointer types in l-values.
This fixes #67.
2020-01-29 22:52:10 -06:00
Stephen Heumann a9f5fb13d8 Introduce a new #pragma lint bit for syntax that C99 disallows.
This currently checks for:
*Calls to undefined functions (same as bit 0)
*Parameters not declared in K&R-style function definitions
*Declarations or type names with no type specifiers (includes but is broader than the condition checked by bit 1)
2020-01-29 18:33:19 -06:00
Stephen Heumann ffe6c4e924 Spellcheck comments throughout the code.
There are no non-comment changes.
2020-01-29 17:09:52 -06:00
Stephen Heumann 6e89dc5883 Give a basic error message for use of _Generic. 2020-01-19 18:03:21 -06:00
Stephen Heumann 8341f71ffc Initial phase of support for new C99/C11 type syntax.
_Bool, _Complex, _Imaginary, _Atomic, restrict, and _Alignas are now recognized in types, but all except restrict and _Alignas will give an error saying they are not supported.

This also introduces uniform definitions of the syntactic classes of tokens that can be used in declaration specifiers and related constructs (currently used in some places but not yet in others).
2020-01-12 15:43:30 -06:00
Stephen Heumann a9fb1ba482 Move TypeName to be a top-level method in Parser.pas.
As of C11, type names are now used as part of the declaration syntax (in _Alignas and _Atomic specifiers), in addition to their uses in expressions. Moving the TypeName method will allow it to be called when processing declarations.
2020-01-06 20:18:58 -06:00
Stephen Heumann 3121a465f1 Implement the _Alignof operator (from C11).
In ORCA/C, the alignment of all object types is 1.
2020-01-06 20:17:29 -06:00
Stephen Heumann cb063afa47 Set expressionType to a default value when LoadAddress encounters an error.
This can occur in cases such as trying to assign to a non-l-value.

This patch ensures consistent handling of errors and prevents null pointer dereferences.
2019-12-23 20:36:27 -06:00
Stephen Heumann 91094e9292 Correctly increment/decrement pointers to large (>=64KiB) types.
Previously, the logic for this was incorrect and would lead to a null pointer dereference in the compiler. In most cases the generated code would not actually change the pointer.

The following program demonstrates the issue:

#include <stdio.h>
#pragma memorymodel 1
typedef char bigarray[0x20000];
bigarray big[5];
int main(void) {
        bigarray *p = big;
        p++;
        printf("%p %p\n", (void*)big, (void*)p);
}
2019-12-23 19:59:18 -06:00
Stephen Heumann 13a14d9389 When an operand is missing, synthesize a "0" operand for post-error processing.
This ensures consistent behavior and avoids null-pointer dereferences in some cases.
2019-12-23 18:57:17 -06:00
Stephen Heumann 7f79b49c3a Set expressionType to a default value when an expression parsing error is encountered.
This ensures consistent handling of errors and prevents possible null pointer dereferences.
2019-12-23 14:03:46 -06:00
Stephen Heumann 17de3914ad Fix problem with using values of enum constants in integer constant expressions.
This could cause spurious errors, or in some cases bad code generation.

The following example illustrates the problem:

#include <stdio.h>

enum {A,B,C};

/* arr was treated as having a size of 1, rather than 3 */
char arr[(int)C+1] = {1,2,3}; /* incorrectly gave an error for initializer */

int main(void) {
        static int i = (int)C+1; /* incorrectly gave an error */

        printf("%zu\n", sizeof(arr));
        printf("%i\n", (int)C+1); /* OK */
        printf("%i\n", i);
}
2019-03-31 18:40:14 -05:00
Kelvin Sherlock 618188c6b2 floating point division by 0.0 is well defined and occasionally used to generate +/- infinite values. 2019-03-10 16:47:18 -04:00
Stephen Heumann 1a2e4772cd Don't generate scalar load operations with bogus types.
This could occur with some operations on function parameters declared with array types, in some cases leading to compiler errors.

Fixes #61.
2019-01-27 11:53:52 -06:00
Stephen Heumann 2d43074d5a Make % operator give proper remainders even if one or both operands are negative.
Per the C standards, the % operator should give a remainder after division, such that (a/b)*b + a%b equals a (provided that a/b is representable). As such, the operation of % is defined for cases where either or both of the operands are negative. Since division truncates toward 0, a%b should give a negative result (or 0) in cases where a is negative.

Previously, the % operator was essentially behaving like the "mod" operator in Pascal, which is equivalent for positive operands but not if either operand is negative. It would generally give incorrect results in those cases, or in some cases give compile-time or run-time errors.

This patch addresses both 16-bit and 32-bit signed computations at run time, and operations in constant expressions. The approach at run time is to call existing division routines, which return the correct remainder, except always as a positive number. The generated code checks the sign of the first operand, and if it is negative negates the remainder.

The code generated is somewhat large (especially for the 32-bit case), so it might be sensible to put it in a library function and call that, but for now it's just generated in-line. This avoids introducing a dependency on a new library function, so the generated code remains compatible with older versions of ORCALib (e.g. the GNO one).

Fixes #10.
2018-09-10 18:21:17 -05:00
Stephen Heumann 6f8546c964 Report errors for use of inappropriate types as operands to various operators.
Mainly, this detects errors in several cases where a pointer could inappropriately be used where an arithmetic type was expected. In some cases, other types (e.g. structs) could be used too.
2018-09-06 21:21:23 -05:00
Stephen Heumann dc1b0aa29f Add lint flag to check for several forms of undefined behavior in computations.
This adds lint bit 5 (a value of 32), which currently enables checking for the following conditions:

*Integer overflow from arithmetic in constant expressions (currently only of type int).
*Invalid constant shift counts (negative, or >= the width of the type)
*Division by (constant) zero.

These (mainly the first two) can be indicative of code that was designed for larger type sizes and needs changes to support 16-bit int.
2018-09-05 23:48:35 -05:00
Stephen Heumann b2785dfe0e Treat constant expressions cast to char as promoting to int, not unsigned int.
The following program demonstrates the problem:

#include <stdio.h>
int main(void) {
    long l = (char)1 - (char)5;
    printf("%li\n", l);  /* should print -4 */
}
2018-09-05 12:49:02 -05:00
Stephen Heumann bfe4416623 Fix some cases where decay of array types to pointer types was not handled correctly.
Specifically:
*The result of pointer arithmetic (or equivalent operations like &a[i]) always has pointer type.
*Array types decay to integer types in the context of comparison operations, so it is legal to compare two differently-sized arrays with the same element type.

The following program (partially derived from a csmith-generated test case) illustrates the issues:

int main(void) {
    int a[2], b[10];
    if (a == b) ; /* legal */
    if (&a[1] != &b[0]) ; /* legal */
    return sizeof(&b[1]); /* Should be sizeof(int*), i.e. 4 on GS */
}
2018-03-29 19:41:32 -05:00
Stephen Heumann 7266b1d613 Properly support use of const structs and unions in assignments and as function arguments.
Here's an example that shows the issues (derived from a csmith-generated test case):

struct S {
   unsigned f;
};

void f1(struct S p) {
    printf("%u\n", p.f);
}

int main(void) {
    const struct S l = {123};
    struct S s;

    f1(l);

    s = l;
    printf("%u\n", s.f);
}
2018-03-25 20:56:15 -05:00
Kelvin Sherlock 6c1ccc5c0d Squashed commit of the following:
commit 4265329097538640e9e21202f1b141bcd42a44f3
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 21:45:32 2018 -0400

    indent to match standard indent.

commit 783518fbeb01d2df43ef2083d3341004c05e4e2e
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 20:21:15 2018 -0400

    clean up the typenames

commit 29b627ecf5ca9b8a143761f85a1807a6ca35ddd9
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 20:18:04 2018 -0400

    enable feature_hh, warn about %n with non-int modifier.

commit fc4ac8129e3772c4eda36658e344ec475938369c
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 15:13:47 2018 -0400

    warn thar %lc, %ls, etc are unsupported.

commit 7e6b433ba0552f7e52f0f034d398e9195c764326
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 13:36:25 2018 -0400

    warn about hh/ll modifier (if not supported)

commit 1943c9979d0013f9f38045ec04a962fbf0269f31
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 11:42:41 2018 -0400

    use error facilities for format errors.

commit 7811168f56dca1387055574ba8d32638da2fad96
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Mar 22 15:34:21 2018 -0400

    add feature flags to disable c99 enhancements until orca lib is updated.

commit c2149cc5953155cfc3c3b4d0483cd25fb946b055
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Mar 22 08:59:10 2018 -0400

    Add printf/scanf format checking [WIP]

    This parses out the xprintf / xscanf format string and compares it with the function arguments.

    enabled via #pragma lint 16.
2018-03-23 21:51:27 -04:00
Stephen Heumann 4a7644e0b5 Don't allocate stack space for varargs stack repair unless it's needed.
If there are no varargs calls (and nothing else that saves stack positions), then space doesn't need to be allocated for the saved stack position. This can also lead to more efficient prolog/epilog code for small functions.
2018-01-13 20:02:43 -06:00
Stephen Heumann ba09d5ee6d Fix issues with addressing/pointer arithmetic using unsigned indexes that generate a displacement of 32K to 64K.
These cases should now always work when using an expression of type unsigned as the index. They will work in some cases but not others when using an int as the index: making those cases work consistently would require more extensive changes and/or a speed hit, so I haven't done it for now.

Note that this now uses an "unsigned multiply" operation for all 16-bit index computations. This should actually work even when the index is a negative signed value, because it will wind up producing (the low-order 16 bits of) the right answer. The signed multiply, on the other hand, generally does not produce the low-order 16 bits of the right answer in cases where it overflows.

The following program is an example that was miscompiled (both with and without optimization):

int c[20000] = {3};

int main(void) {
    int *p;
    unsigned i = 17000;

    p = c + 17000u;
    return *(p-i); /* should return 3 */
}
2017-11-12 17:21:05 -06:00
Stephen Heumann e780043007 When doing arithmetic/indexing on pointers to one-byte types, don't generate code to multiply by one.
This could already be optimized out by the peephole optimizer, but it's bad enough code that it really shouldn't be generated even when not using that optimization.
2017-10-29 20:25:43 -05:00
Stephen Heumann 8d31481182 Report errors for illegal pointer arithmetic operations.
These include arithmetic on pointers to incomplete types or functions, as well as subtraction of pointers to incompatible types.
2017-10-29 20:21:36 -05:00