Commit Graph

48 Commits

Author SHA1 Message Date
Stephen Heumann
e3b24fb50b Add support for real to long long conversions. 2021-02-16 18:47:28 -06:00
Stephen Heumann
e38be489df Implement comparisons for signed long long.
These use a library function to perform the comparison.
2021-02-15 18:10:34 -06:00
Stephen Heumann
d2d871181a Implement comparisons (>, >=, <, <=) for unsigned long long. 2021-02-15 14:43:26 -06:00
Stephen Heumann
c537153ee5 Implement pc_ind (load indirect) for long long. 2021-02-13 21:42:06 -06:00
Stephen Heumann
c48811add6 Report errors in a few cases where the codegen finds unexpected types.
This makes it more likely that unsupported ops on long long or any other types added in the future will give an error rather than silently generating bad code.

Also, update a comment.
2021-02-13 18:46:00 -06:00
Stephen Heumann
f41cd241f8 Slightly optimize stack save code for calls to long long functions.
The X register is not used as part of the return value, so it does not have to be preserved.
2021-02-13 17:21:13 -06:00
Stephen Heumann
8faafcc7c8 Implement 64-bit shifts. 2021-02-12 15:06:15 -06:00
Stephen Heumann
30f2eda4f3 Generate code for long long to real conversions. 2021-02-11 12:41:58 -06:00
Stephen Heumann
446639badc Don't bogusly push stuff on the stack for conversions to non-long types.
This could happen in some cases when converting between signed and unsigned long long (which should not require any code to be generated).
2021-02-06 12:45:44 -06:00
Stephen Heumann
47fdd9e370 Implement support for functions returning (unsigned) long long.
These use a new calling convention specific to functions returning these types. When such functions are called, the caller must set the X register to the address within bank 0 that the return value is to be saved to. The function is then responsible for saving it there before returning to the caller.

Currently, the calling code always makes space for the return value on the stack and sets X to point to that. (As an optimization, it would be possible to have the return value written directly to a local variable on the direct page, with no change needed to the function being called, but that has not yet been implemented.)
2021-02-05 23:25:46 -06:00
Stephen Heumann
11938d51ff Compute how many bytes of arguments are passed to a function.
This is preparatory to supporting a new calling convention for functions returning long long.
2021-02-05 20:52:03 -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
8992ddc11f Implement indirect store/copy operations for 64-bit types.
These operations (pc_sto and pc_cpi) are used for access through a pointer, and in some cases also for initialization.
2021-02-04 18:32:06 -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
6a2ea6ccc4 Implement equality/inequality comparisons for 64-bit types. 2021-02-02 18:18:50 -06:00
Stephen Heumann
1dc0dc7a19 Implement remaining conversions of integer types to and from long long.
The floating-point conversions are not done yet (but do now give an error).
2021-02-01 22:43:35 -06:00
Stephen Heumann
0e59588191 Merge branch 'master' into longlong 2021-01-31 14:32:31 -06:00
Stephen Heumann
393fb8d635 Make floating point to character type conversions yield values within the type's range.
This affects cases where the floating value, truncated to an integer, is outside the range of the destination type. Previously, the result value might appear to be an int value outside the range of the character type.

These situations are undefined behavior under the C standards, so this was not technically a bug, but the new behavior is less surprising. (Note that it still may not raise the "invalid" floating-point exception in some cases where Annex F would call for that.)
2021-01-31 14:04:27 -06:00
Stephen Heumann
130d332284 Fix bugs with several operations on negative values of type signed char.
The basic issue with all of these is that they failed to sign-extend the 8-bit signed char value to the full 16-bit A register. This could make certain operations on negative signed char values appear to yield positive values outside the range of signed char.

The following example code demonstrates the problems:

#include <stdio.h>
signed char f(void) {return -50;}
int main(void) {
        long l = -123;
        int i = -99;
        signed char sc = -47;
        signed char *scp = &sc;
        printf("%i\n", (signed char)l);
        printf("%i\n", (signed char)i);
        printf("%i\n", f());
        printf("%i\n", (*scp)++);
        printf("%i\n", *scp = -32);
}
2021-01-31 11:40:07 -06:00
Stephen Heumann
cb99b3778e Flag that conversions may not set CPU flags usable for a subsequent comparison.
There are several conversions that do not set the necessary flags, so they must be set separately before doing a comparison. Without this fix, comparisons of a value that was just converted might be mis-evaluated.

This led to bugs where the wrong side of an "if" could be followed in some cases, as in the below examples:

#include <stdio.h>
int g(void) {return 50;}
signed char h(void) {return 50;}
long lf(void) {return 50;}
int main(void) {
    signed char sc = 50;
    if ((int)(signed char)g()) puts("OK1");
    if ((int)h()) puts("OK2");
    if ((int)sc) puts("OK3");
    if ((int)lf()) puts("OK4");
}
2021-01-31 08:52:50 -06:00
Stephen Heumann
e8497c7b8f Begin implementing conversions to and from 64-bit types.
Some conversions are implemented, but others are not yet.
2021-01-31 08:37:21 -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
fa835aca43 Implement basic load/store ops for long long.
The following intermediate codes should now work:
pc_lod
pc_pop
pc_str
pc_cop
pc_sro
pc_cpo
2021-01-29 23:11:08 -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
8b4213cd5a Fix bug where the condition check of the ?: operator may be mis-evaluated.
This could happen in certain cases where the condition codes might not be set at expected. The following program gives an example:

#pragma optimize 1
#include <stdio.h>
int one(void) {return 1;}
int negative_one(void) {return -1;}
int main(void) {
    puts((one() + negative_one()) ? "A" : "B");
}

This could also occur if the condition used the % operator, particularly after the recent changes to it.

Also, add unsigned multiplication, division, and modulo operations to the list of those that may not set the condition codes based on the result value, both in this and other contexts.

Detected based on several programs from FizzBuzz-C.
2018-09-14 13:25:40 -05: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
fd0ff033ad Fix code generation for certain cases where addresses are stored to local variables that don't fit in the direct page.
There was a bug when storing addresses generated by expressions like &a[i], where a is a global array and i is a variable. In certain cases where the destination location was a local variable that didn't fit in the direct page, the result of the address calculation would be stored to the wrong location on the stack. This failed to give the correct result, and could also sometimes cause crashes or other problems due to stack corruption.

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

#pragma optimize 1
long g_87[5];
static int g_242 = 4;

int main(void) {
    char l_298[256];
    long *l_284[3] = {0, 0, &g_87[g_242]};
    return l_284[2]-g_87; /* should be 4 */
}
2018-03-31 15:45:05 -05:00
Stephen Heumann
37cf771eee Fix bug where ++/-- operations would use the wrong location for local variables that don't fit in the direct page.
The code would trash other data on the stack, which could corrupt other variables and in some cases lead to crashes.

The following program (derived from a csmith-generated test case) shows the problem:

#pragma optimize -1
int main(void) {
    char arr[256] = {0};
    char l_565[3][2] = {{3,4}, {5,6}, {7,8}};
    l_565[0][0]++;
    return l_565[0][0];
}
2018-03-27 23:10:49 -05:00
Stephen Heumann
7605b7bbf2 Fix bug where bitwise binary ops on 32-bit values will be miscalculated and trash the stack in certain cases.
The following program (derived from a csmith-generated test case) demonstrates the crash:

#pragma optimize 8+64
#include <stdio.h>
long g = 0;
int main (void) {
    long l = 0x10305070;
    printf("%08lx\n", l ^ (g = (1 , 0x12345678)));
}
2018-03-27 20:11:45 -05:00
Stephen Heumann
29de867039 Fix bug causing functions with 254 bytes of locals to crash on return.
This was a bug with the code for moving the return address. It would generate a "LDA 0" instruction when it was trying to load the value at DP+256.

The following program (derived from a csmith-generated test case) demonstrates the crash:

#pragma optimize 8
int main (int argc, char **argv) {
    char s[0xFC];
}
2018-03-26 23:30:26 -05: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
f24f37aa9f Generate more efficient stack repair code (2).
Previously, the stack repair code always generated code to save and restore a register, but this can be omitted except in cases where a 32-bit value or pointer is returned.
2018-01-12 22:32:12 -06:00
Stephen Heumann
b697094c58 Generate more efficient stack repair code (1).
Previously, when stack repair code was generated, it always included instructions to save and restore a previously-saved stack position, but this was only actually used for function calls nested within the arguments to other function calls using stack repair code. Now that code is only generated in cases where it is needed, and the stack repair code for other calls is simplified to omit it.

This optimization affects all (non-nested) function calls when not using optimize bit 3, and varargs function calls when not using optimize bit 6.
2018-01-12 22:28:47 -06:00
Kelvin Sherlock
dbfa542fba generate function exit cop with profiling / pragma debug 4. Expected by prizm. 2017-12-05 21:31:36 -05:00
Stephen Heumann
103af4c4a4 Generate more efficient code for some indexing operations affected by the previous commit. 2017-11-11 21:55:22 -06:00
Stephen Heumann
3aed2eb8ac Fix problem where array index computations involving a negative variable part of the index could be miscomputed when using the small memory model.
This introduces a function to check whether the index portion of a pc_ixa intermediate code operation (used for array indexing) may be negative. This is also used when generating code for the large memory model, which can allow slightly more efficient code to be generated in some cases.

This fixes #45.
2017-11-11 20:07:46 -06:00
Stephen Heumann
e7cc513ad4 Add support for inline procedure names as documented in IIgs tech note #103.
These are enabled when bit 15 is set in the #pragma debug directive.

Support is still needed to ensure these work properly with pre-compiled headers.

This patch is from Kelvin Sherlock.
2017-10-21 20:36:21 -05:00
Stephen Heumann
ad31ecfcae Fix bug where 32-bit addition and subtraction results are not saved in some cases.
This could happen in certain cases where the destination is not considered "simple" (e.g. because it is a local array location that does not fit in the direct page).

The following program demonstrates the problem:

#pragma optimize 1
int main(void) {
    long temp1 = 1, temp2 = 2, A[64];
    long B[2] = {0};
    B[1] = temp1 + temp2;
    return B[1]; /* should return 3 */
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
fb612e14d1 Fix bug causing functions with 254 bytes of locals and parameters to crash on return.
This bug occurred because the generated code tried to store part of the return address to a direct page offset of 256, but instead an offset of 0 was used, resulting in an invalid return address and (typically) a crash. It could occur if the function took one or more parameters, and the total size of parameters and local variables (including compiler-generated ones) was 254 bytes.

The following program demonstrates the problem:

int main(int argc, char **argv) {
    char x[244];
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
709f9b3f25 Fix bug where comparing 32-bit values in static arrays or structs against 0 may give wrong results with large memory model.
The issue was that 16-bit absolute addressing (in the data bank) was being used to access the data to compare, but with the large memory model the static arrays or structs are not necessarily in the same bank, so absolute long addressing should be used.

This was sometimes causing failures in the C4.6.4.1.CC and C4.6.6.1.CC conformance tests in the ORCA/C test suite.

The following program often demonstrates the problem (depending on memory layout and contents):

#pragma memorymodel 1
#pragma optimize 1

#include <stdio.h>

int i;
char ch1[32000];
long L1[1];

int main (void)
{
    if (L1 [0] != 0)
        printf("%li\n", L1[0]); /* shouldn't print */

    /* buggy behavior can happen if the bank bytes of these pointers differ */
    printf("%p %p\n", &L1[0], &i);
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
0df71da4f1 Change Byte -> UByte conversion to use a "Word -> UByte" conversion, rather than introducing a new "Byte -> UByte" conversion.
The latter would require more changes to the code generator to understand it, whereas this approach doesn't require any changes. This is arguably less clean, but it matches other places where a byte value is subsequently operated on as a word without an explicit conversion, and the assembly instruction generated is the same.
2017-10-21 20:36:20 -05:00
Stephen Heumann
c28e48a54f Do an explicit conversion when converting from signed to unsigned byte values. This is needed because the value is held in a 16-bit register, sign-extended. The high 8 bits need to be cleared to convert to an unsigned byte.
This fixes the compca06.c test case.

Note that this generates inefficient code in the case of loading a signed byte value and then immediately casting it to unsigned (it first sign-extends the value, then masks off the high bits). This should be optimized, but at least the generated code is correct now.
2017-10-21 20:36:20 -05:00
Stephen Heumann
6bd0bef8c5 Fix bug causing wrong code generation for single-byte indirect local stores beyond the first 256 bytes of the stack frame.
This fixes the compca19.c test case.
2017-10-21 20:36:20 -05:00
Stephen Heumann
46b6aa389f Change all text/source files to LF line endings. 2017-10-21 18:40:19 -05:00
mikew50
e72177985e ORCA/C 2.1.0 source from the Opus ][ CD 2017-10-01 17:47:47 -06:00