Compare commits

...

12 Commits

Author SHA1 Message Date
Stephen Heumann 83537fd3c7 Disable a peephole optimization that can produce bad code.
The optimization applies to code sequences like:
	dec abs
	lda abs
	beq ...
where the dec and lda were supposed to refer to the same location.

There were two problems with this optimization as written:
-It considered the dec and lda to refer to the same location even if they were actually references to different elements of the same array.
-It did not work in the case where the A register value was needed in subsequent code.

The first of these was already an issue in previous ORCA/C releases, as in the following example:

#pragma optimize -1
int x[2] = {0,0};
int main(void) {
        --x[0];
        if (x[1] != 0)
                return 123;
        return 0; /* should return 0 */
}

I do not believe the second problem was triggered by any code sequences generated in previous releases of ORCA/C, but it can be triggered after commit 4c402fc88, e.g. by the following example:

#pragma optimize -1
int x = 1;
int main(void) {
        int y = 123;
        --x;
        return x == 0; /* should return 1 */
}

Since the circumstances where this peephole optimization was triggered validly are pretty obscure, just disabling it should have a minimal impact on the generated code.
2024-03-17 21:31:18 -05:00
Stephen Heumann 81934109fc Fix issues with type names in the third expression of a for loop.
There were a couple issues here:
*If the type name contained a semicolon (for struct/union member declarations), a spurious error would be reported.
*Tags or enumeration constants declared in the type name should be in scope within the loop, but were not.

These both stemmed from the way the parser handled the third expression, which was to save the tokens from it and re-inject them at the end of the loop. To get the scope issues right, the expression really needs to be evaluated at the point where it occurs, so we now do that. To enable that while still placing the code at the end of the loop, a mechanism to remove and re-insert sections of generated code is introduced.

Here is an example illustrating the issues:

int main(void) {
        int i, j, x;
        for (i = 0; i < 123; i += sizeof(struct {int a;}))
                for (j = 0; j < 123; j += sizeof(enum E {A,B,C}))
                        x = i + j + A;
}
2024-03-13 22:09:25 -05:00
Stephen Heumann 72234a4f2b Generate better code for most unsigned 32-bit comparisons. 2024-03-10 21:24:33 -05:00
Stephen Heumann 36f766a662 Generate better code for comparisons against constant 1 or 2. 2024-03-06 21:57:27 -06:00
Stephen Heumann 4c402fc883 Generate better code for certain equality/inequality comparisons. 2024-03-06 21:18:50 -06:00
Stephen Heumann ca0147507b Generate slightly better code for logical negation. 2024-03-06 17:04:51 -06:00
Stephen Heumann 24c6e72a83 Simplify some conditional branches.
This affects certain places where code like the following could be generated:

	bCC lab2
lab1	brl ...
lab2 ...

If lab1 is no longer referenced due to previous optimizations, it can be removed. This then allows the bCC+brl combination to be shortened to a single conditional branch, if the target is close enough.

This introduces a flag for tracking and potentially removing labels that are only used as the target of one branch. This could be used more widely, but currently it is only used for the specific code sequences shown above. Using it in other places could potentially open up possibilities for invalid native-code optimizations that were previously blocked due to the presence of the label.
2024-03-05 22:20:34 -06:00
Stephen Heumann 0f18fa63b5 Optimize some additional cases of a branch to a branch.
This covers patterns like

	bCC lab
	???
	???
lab:	bra/brl ...

These can come up in the new code for 32-bit ||, but also in cases like "if (i > 0) ...".
2024-03-05 17:16:17 -06:00
Stephen Heumann 8f07ca5d6c Generate better code for && and || with 32-bit operands. 2024-03-05 17:09:21 -06:00
Stephen Heumann 60b472a99e Optimize generated code for some indexing ops in large memory model.
This generates slightly better code for indexing a global/static char array with a signed 16-bit index and a positive offset, e.g. a[i+1].

Here is an example that is affected:

#pragma memorymodel 1
#pragma optimize -1
char a[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int main(int argc, char *argv[]) {
        return a[argc+2];
}
2024-03-04 19:38:39 -06:00
Stephen Heumann 995885540b Correct a comment. 2024-03-04 19:03:13 -06:00
Stephen Heumann 34c5be5cab Update readme files for version 2.2.1. 2024-02-28 20:11:13 -06:00
8 changed files with 460 additions and 220 deletions

View File

@ -1,18 +1,20 @@
Welcome to ORCA/C 2.2.0! This is a release containing updates from
Welcome to ORCA/C 2.2.1! This is a release containing updates from
community members (Stephen Heumann and Kelvin Sherlock).
ORCA/C 2.2.0 adds support for almost all of the new language and library
ORCA/C 2.2 adds support for almost all of the new language and library
features required by the C17 standard. It also has several other new
features, such as additional lint checks to help identify bugs and
portability problems. In addition to these new features, ORCA/C 2.2.0
portability problems. In addition to these new features, ORCA/C 2.2
includes hundreds of bug fixes in the compiler and libraries.
The ORCA/C manual has been fully updated to cover ORCA/C 2.2.0, so new
ORCA/C 2.2.1 includes additional bug fixes to ORCA/C 2.2.0.
The ORCA/C manual has been fully updated to cover ORCA/C 2.2, so new
users should simply refer to that. Users familiar with older versions
of ORCA/C can refer to the cc.notes file in the Release.Notes directory
for a description of the changes between ORCA/C 2.0 and ORCA/C 2.2.0.
for a description of the changes between ORCA/C 2.0 and ORCA/C 2.2.1.
ORCA/C 2.2.0 requires a real or emulated Apple IIGS with at least the
ORCA/C 2.2.1 requires a real or emulated Apple IIGS with at least the
following specifications:
* 2 MB of RAM (3 MB or more recommended)

View File

@ -1,25 +1,25 @@
This is an update package that can be used to update ORCA/C 2.1.0 to
ORCA/C 2.2.0. You must have an existing copy of ORCA/C 2.1.0 in order
to use this update. If you do not already have a copy, you can get it
as part of Opus ][: The Software, a collection of Byte Works software
which is sold by Juiced.GS:
This is an update package that can be used to update ORCA/C 2.1.0 or
2.2.0 to ORCA/C 2.2.1. You must have an existing copy of ORCA/C 2.1.0
or 2.2.0 in order to use this update. If you do not already have a
copy, you can get it as part of Opus ][: The Software, a collection of
Byte Works software which is sold by Juiced.GS:
https://juiced.gs/store/opus-ii-software/
This update must be applied to an existing ORCA installation containing
ORCA/C 2.1.0 or an ORCA/C 2.2.0 beta (including the one provided on
Opus ][: The Software). To apply the update, you just need to copy
the files from this distribution into the corresponding locations in
your ORCA installation, replacing any older versions.
ORCA/C 2.1.0 or ORCA/C 2.2.0 (including the one provided on Opus ][:
The Software). To apply the update, you just need to copy the files
from this distribution into the corresponding locations in your ORCA
installation, replacing any older versions.
If you received this update as a SHK file, you can simply extract the
the files from it directly on top of your ORCA installation.
files from it directly on top of your ORCA installation.
If you received this update as a disk image, you can apply the update
by copying the files into place using the Finder, or by running the
following command within the root directory of your ORCA installation
using the text-based ORCA shell:
COPY -C :ORCAC.220:=
COPY -C :ORCAC.221:=
In addition to the ORCA shell environment, this update can also be
used under other environments that are compatible with ORCA/C, such as

View File

@ -139,7 +139,7 @@ opt[pc_ckn] := 'ckn';
end; {InitWriteCode}
procedure PrintDAG (tag: stringPtr; code: icptr);
procedure PrintDAG {tag: stringPtr; code: icptr};
{ print a DAG }
{ }

108
CGI.pas
View File

@ -48,6 +48,7 @@ const
forFlags = 256; {instruction used for effect on flags only}
subtract1 = 512; {subtract 1 from address operand}
shiftLeft8 = 1024; {shift operand left 8 bits}
labelUsedOnce = 2048; {only one branch targets this label}
m_adc_abs = $6D; {op code #s for 65816 instructions}
m_adc_dir = $65;
@ -292,6 +293,8 @@ type
ccPointer : (pval: longint; pstr: longStringPtr);
end;
codeRef = icptr; {reference to a code location}
{basic blocks}
{------------}
iclist = ^iclistRecord; {used to form lists of records}
@ -657,6 +660,21 @@ procedure GenTool (fop: pcodes; fp1, fp2: integer; dispatcher: longint);
{ dispatcher - tool entry point }
function GetCodeLocation: codeRef;
{ Get a reference to the current location in the generated }
{ code, suitable to be passed to RemoveCode. }
procedure InsertCode (theCode: codeRef);
{ Insert a section of already-generated code that was }
{ previously removed with RemoveCode. }
{ }
{ parameters: }
{ theCode - code removed (returned from RemoveCode) }
{procedure PrintBlocks (tag: stringPtr; bp: blockPtr); {debug}
{ print a series of basic blocks }
@ -666,6 +684,28 @@ procedure GenTool (fop: pcodes; fp1, fp2: integer; dispatcher: longint);
{ bp - first block to print }
{procedure PrintDAG (tag: stringPtr; code: icptr); {debug}
{ print a DAG }
{ }
{ parameters: }
{ tag - label for lines }
{ code - first node in DAG }
function RemoveCode (start: codeRef): codeRef;
{ Remove a section of already-generated code, from immediately }
{ after start up to the latest code generated. Returns the }
{ code removed, so it may be re-inserted later. }
{ }
{ parameters: }
{ start - location to start removing from }
{ }
{ Note: start must be a top-level pcode (not a subexpression). }
{ Note: The region removed must not include a dc_enp. }
function TypeSize (tp: baseTypeEnum): integer;
{ Find the size, in bytes, of a variable }
@ -1430,6 +1470,74 @@ if codeGeneration then begin
end; {GenLdcReal}
function GetCodeLocation{: codeRef};
{ Get a reference to the current location in the generated }
{ code, suitable to be passed to RemoveCode. }
begin {GetCodeLocation}
GetCodeLocation := DAGhead;
end {GetCodeLocation};
procedure InsertCode {theCode: codeRef};
{ Insert a section of already-generated code that was }
{ previously removed with RemoveCode. }
{ }
{ parameters: }
{ theCode - code removed (returned from RemoveCode) }
var
lcode: icptr;
begin {InsertCode}
if theCode <> nil then
if codeGeneration then begin
lcode := theCode;
{ PrintDAG(@'Inserting: ', lcode); {debug}
while lcode^.next <> nil do
lcode := lcode^.next;
lcode^.next := DAGhead;
DAGhead := theCode;
end; {if}
end; {InsertCode}
function RemoveCode {start: codeRef): codeRef};
{ Remove a section of already-generated code, from immediately }
{ after start up to the latest code generated. Returns the }
{ code removed, so it may be re-inserted later. }
{ }
{ parameters: }
{ start - location to start removing from }
{ }
{ Note: start must be a top-level pcode (not a subexpression). }
{ Note: The region removed must not include a dc_enp. }
var
lcode: icptr;
begin {RemoveCode}
if start = DAGhead then
RemoveCode := nil
else begin
RemoveCode := DAGhead;
if codeGeneration then begin
lcode := DAGhead;
while (lcode^.next <> start) and (lcode^.next <> nil) do
lcode := lcode^.next;
if lcode^.next = nil then
Error(cge1);
lcode^.next := nil;
{ PrintDAG(@'Removing: ', DAGhead); {debug}
DAGhead := start;
end; {if}
end; {else}
end; {RemoveCode}
function TypeSize {tp: baseTypeEnum): integer};
{ Find the size, in bytes, of a variable }

419
Gen.pas
View File

@ -618,7 +618,7 @@ function NeedsCondition (opcode: pcodes): boolean;
begin {NeedsCondition}
NeedsCondition := opcode in
[pc_and,pc_ior,pc_cui,pc_cup,pc_lor,pc_lnd,pc_ldl,pc_lil,pc_lld,
[pc_and,pc_ior,pc_cui,pc_cup,pc_ldl,pc_lil,pc_lld,
pc_lli,pc_gil,pc_gli,pc_gdl,pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,
pc_cop,pc_cpo,pc_cpi,pc_dvi,pc_mpi,pc_adi,pc_sbi,pc_mod,pc_bno,
pc_udi,pc_uim,pc_umi,pc_cnv,pc_rbo,pc_shl,pc_shr,pc_usr,pc_lbf,
@ -1068,8 +1068,22 @@ var
end; {ReverseConditional}
function SimpleLongOp(op: icptr): boolean;
{ Is op an operation on cg(U)Long that can be done using the }
{ addressing modes of CPX? }
begin {SimpleLongOp}
SimpleLongOp :=
(op^.opcode = pc_ldc)
or (op^.opcode = pc_lao)
or ((op^.opcode = pc_lod) and (LabelToDisp(op^.r) + op^.q <= 253))
or ((op^.opcode = pc_ldo) and smallMemoryModel);
end; {SimpleLongOp}
begin {GenCmp}
{To reduct the number of possibilities that must be handled, pc_les }
{To reduce the number of possibilities that must be handled, pc_les }
{and pc_leq compares are reduced to their equivalent pc_grt and }
{pc_geq instructions. }
if op^.opcode = pc_les then begin
@ -1113,15 +1127,16 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
if NeedsCondition(op^.left^.opcode) then
GenImpliedForFlags(m_tax);
if (num >= 0) and (num < 3) then begin
if num <> 0 then begin
if num = 0 then
GenNative(m_bpl, relative, lab1, nil, 0)
else begin
lab2 := GenLabel;
GenNative(m_bmi, relative, lab2, nil, 0);
for i := 1 to num do
GenImplied(m_dea);
end; {if}
GenNative(m_bpl, relative, lab1, nil, 0);
if num <> 0 then
GenLab(lab2);
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
GenLabUsedOnce(lab2);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if (num >= 0) and (num < 3)}
@ -1134,7 +1149,7 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab2, nil, 0);
if num > 0 then begin
GenLab(lab1);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
@ -1147,8 +1162,17 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end; {if}
@ -1163,9 +1187,9 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
if (num >= 0) and (num < 3) then begin
GenNative(m_bmi, relative, lab1, nil, 0);
if num > 0 then begin
for i := 1 to num do
GenImplied(m_dea);
GenNative(m_bmi, relative, lab1, nil, 0);
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
@ -1184,7 +1208,7 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenLab(lab1);
end {if}
else begin
GenLab(lab1);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end; {else}
@ -1192,8 +1216,17 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
if num <> 0 then
@ -1282,7 +1315,7 @@ else
else
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
@ -1330,50 +1363,134 @@ else
end; {case optype of cgByte,cgUByte,cgWord,cgUWord}
cgULong: begin
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_ply);
GenImplied(m_pla);
lab1 := GenLabel;
lab2 := GenLabel;
simple := false;
if SimpleLongOp(op^.right) then
simple := true
else if rOpcode in [pc_fjp,pc_tjp] then
if SimpleLongOp(op^.left) then begin
ReverseConditional;
simple := true;
end; {if}
if simple then begin
if op^.opcode = pc_grt then begin
if SimpleLongOp(op^.left) then
ReverseConditional;
if op^.opcode = pc_grt then
if op^.right^.opcode = pc_ldc then
if op^.right^.lval <> $ffffffff then begin
op^.right^.lval := op^.right^.lval + 1;
op^.opcode := pc_geq;
end; {if}
end; {if}
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
if op^.opcode = pc_grt then
if not (rOpcode in [pc_fjp,pc_tjp]) then
GenNative(m_ldy_imm, immediate, 0, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cpx_imm, immediate, long(lval).msw, nil, 0);
pc_lao:
GenNative(m_cpx_imm, immediate, q, lab, shift16);
pc_lod:
GenNative(m_cpx_dir, direct, LabelToDisp(r)+q+2, nil, 0);
pc_ldo:
GenNative(m_cpx_abs, absolute, q+2, lab, 0);
end; {case}
GenNative(m_bne, relative, lab1, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cmp_imm, immediate, long(lval).lsw, nil, 0);
pc_lao:
GenNative(m_cmp_imm, immediate, q, lab, 0);
pc_lod:
GenNative(m_cmp_dir, direct, LabelToDisp(r)+q, nil, 0);
pc_ldo:
GenNative(m_cmp_abs, absolute, q, lab, 0);
end; {case}
GenLab(lab1);
if rOpcode = pc_fjp then begin
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
else if rOpcode = pc_tjp then begin
if op^.opcode = pc_grt then
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {else if}
else if op^.opcode = pc_geq then begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_rol_a);
end {else if}
else {if op^.opcode = pc_grt then} begin
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenImplied(m_iny);
GenLab(lab2);
GenImplied(m_tya);
end; {else}
end {if}
else begin
GenImplied(m_tay);
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_ply);
GenImplied(m_pla);
end {if}
else begin
GenImplied(m_tay);
GenImplied(m_txa);
end; {else}
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_s, direct, 1, nil, 0);
GenLab(lab1);
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab4 := GenLabel;
GenNative(m_bne, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end {if}
else if rOpcode = pc_tjp then begin
lab4 := GenLabel;
GenNative(m_beq, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end; {else if}
end; {else}
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_s, direct, 1, nil, 0);
GenLab(lab1);
lab2 := GenLabel;
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab4 := GenLabel;
GenNative(m_bne, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end {if}
else if rOpcode = pc_tjp then begin
lab4 := GenLabel;
GenNative(m_beq, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end; {else if}
end;
cgReal,cgDouble,cgComp,cgExtended: begin
@ -2135,10 +2252,14 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
num := op^.right^.q;
lab1 := GenLabel;
if opcode in [pc_fjp,pc_tjp] then begin
if num <> 0 then
GenNative(m_cmp_imm, immediate, num, nil, 0)
else if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tay);
if num = 0 then begin
if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tay);
end {if}
else if num = 1 then
GenImplied(m_dea)
else
GenNative(m_cmp_imm, immediate, num, nil, 0);
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
@ -2147,12 +2268,20 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenLab(lab1);
end {if}
else begin
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(bne, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
GenImplied(m_txa);
if num <> 0 then
GenNative(m_eor_imm, immediate, num, nil, 0)
else if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else if (op^.optype in [cgLong,cgULong]) and (leftOp in [pc_ldo,pc_lod])
@ -2167,24 +2296,20 @@ else if (op^.optype in [cgLong,cgULong]) and (leftOp in [pc_ldo,pc_lod])
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else if op^.opcode = pc_equ then begin
lab1 := GenLabel;
lab2 := GenLabel;
DoOr(op^.left);
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_bra, relative, lab2, nil, 0);
GenLab(lab1);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenLab(lab2);
end {else if}
else {if op^.opcode = pc_neq then} begin
else begin
lab1 := GenLabel;
DoOr(op^.left);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else if}
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {else if}
else if (op^.optype in [cgLong,cgULong]) and (rightOp in [pc_ldo,pc_lod]) then begin
gLong.preference := A_X;
@ -2229,8 +2354,7 @@ else
if Complex(op^.right) or (not (opcode in [pc_fjp,pc_tjp])) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenImplied(m_sec);
GenNative(m_sbc_s, direct, 1, nil, 0);
GenNative(m_eor_s, direct, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_tax);
if opcode in [pc_fjp,pc_tjp] then begin
@ -2245,10 +2369,15 @@ else
else begin
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
if op^.opcode = pc_equ then
GenNative(m_eor_imm, immediate, 1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else begin
@ -2392,10 +2521,15 @@ else
else begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab3);
if op^.opcode = pc_equ then
GenNative(m_eor_imm, immediate, 1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab3);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab3);
end; {else}
end; {else}
end; {case optype of cgQuad,cgUQuad}
@ -3617,11 +3751,17 @@ else begin
else begin
if op^.left^.opcode = pc_lao then begin
GenTree(op^.right);
if signed then
GenImplied(m_tay);
GenNative(m_ldx_imm, immediate, op^.left^.q, op^.left^.lab, shift16);
if signed then begin
GenImpliedForFlags(m_tay);
lab2 := GenLabel;
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_dex);
GenLab(lab2);
signed := false;
end; {if}
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, op^.left^.q, op^.left^.lab, 0);
GenNative(m_ldx_imm, immediate, op^.left^.q, op^.left^.lab, shift16);
end {if}
else begin
gLong.preference := onStack;
@ -3696,7 +3836,7 @@ var
GenNative(m_inc_dirx, direct, 2, nil, 0);
GenLab(lab1);
end {if}
else {if op in [pc_gdl,pc_gld] then} begin
else {if op in [pc_ldl,pc_lld] then} begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_lda_dirx, direct, 0, nil, 0);
@ -5493,10 +5633,11 @@ procedure GenTree {op: icptr};
lab1: integer;
operandIsBoolean: boolean;
begin {GenntNgiNot}
begin {GenBntNgiNot}
if op^.opcode = pc_not then
operandIsBoolean := op^.left^.opcode in
[pc_and,pc_ior,pc_neq,pc_equ,pc_geq,pc_leq,pc_les,pc_grt,pc_not];
[pc_and,pc_ior,pc_lnd,pc_lor,pc_not,pc_neq,pc_equ,pc_geq,pc_leq,
pc_les,pc_grt];
GenTree(op^.left);
case op^.opcode of
pc_bnt:
@ -5507,16 +5648,17 @@ procedure GenTree {op: icptr};
GenImplied(m_ina);
end; {case pc_ngi}
pc_not: begin
pc_not:
if not operandIsBoolean then begin
lab1 := GenLabel;
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
end; {if}
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {if}
GenImplied(m_ina);
end {if}
else
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {case}
end; {GenBntNgiNot}
@ -6504,49 +6646,50 @@ procedure GenTree {op: icptr};
{ Generate code for a pc_lor or pc_lnd }
var
lab1,lab2: integer; {label}
opc: pcodes; {operation code}
procedure DoOra;
{ do some common oring operations to reduce space }
begin {DoOra}
if gLong.where = onStack then begin
GenImplied(m_pla);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenImplied(m_pla);
end {if}
else
GenNative(m_stx_dir, direct, dworkLoc, nil, 0);
GenNative(m_ora_dir, direct, dworkLoc, nil, 0);
end; {DoOra}
lab1,lab2,lab3,lab4: integer; {labels}
begin {GenLorLnd}
opc := op^.opcode;
lab1 := GenLabel;
lab3 := GenLabel;
lab4 := GenLabel;
gLong.preference := A_X;
GenTree(op^.left);
DoOra;
lab2 := GenLabel;
if opc = pc_lnd then
GenNative(m_bne, relative, lab2, nil, 0)
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_brl, longrelative, lab1, nil, 0);
GenLab(lab2);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_txa);
if op^.opcode = pc_lor then begin
lab2 := GenLabel;
GenNative(m_beq, relative, lab2, nil, 0);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lab3, nil, 0);
GenLab(lab2);
end {if}
else begin
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lab4, nil, 0);
GenLab(lab1);
end; {if}
gLong.preference := A_X;
GenTree(op^.right);
DoOra;
GenNative(m_beq, relative, lab1, nil, 0);
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_bne, relative, lab3, nil, 0);
GenImplied(m_txa);
GenNative(m_beq, relative, lab4, nil, 0);
GenLab(lab3);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
GenLab(lab4);
end; {GenLorLnd}
@ -7723,7 +7866,7 @@ var
localSize := localSize + size;
end {else if}
else if opcode in
[pc_les,pc_leq,pc_grt,pc_geq,pc_sto,pc_cpi,pc_ind,pc_lor,pc_lnd,
[pc_les,pc_leq,pc_grt,pc_geq,pc_sto,pc_cpi,pc_ind,
pc_ili,pc_iil,pc_idl,pc_ild,pc_ixa]
then begin
if dworkLoc = 0 then begin

View File

@ -110,6 +110,14 @@ procedure GenLab (lnum: integer);
{ lnum - label number }
procedure GenLabUsedOnce (lnum: integer);
{ generate a label that is only targeted by one branch }
{ }
{ parameters: }
{ lnum - label number }
procedure InitFile (keepName: gsosOutStringPtr; keepFlag: integer; partial: boolean);
{ Set up the object file }
@ -1637,7 +1645,7 @@ var
end; {if}
m_bcs,m_beq,m_bne,m_bmi,m_bpl,m_bcc:
if npeep[ns+2].opcode = d_lab then
if npeep[ns+2].opcode = d_lab then begin
if npeep[ns+2].operand = operand then
if npeep[ns+1].opcode = m_brl then begin
if Short(ns,npeep[ns+1].operand) then begin
@ -1674,8 +1682,20 @@ var
opcode := m_bmi;
end {else if m_bra}
else if npeep[ns+3].opcode in [m_bra,m_brl] then
if Short(ns,npeep[ns+3].operand) then
if Short(ns,npeep[ns+3].operand) then begin
operand := npeep[ns+3].operand;
if (npeep[ns+2].flags & labelUsedOnce) <> 0 then
Remove(ns+2);
end; {if}
end {if}
else if npeep[ns+3].opcode = d_lab then
if npeep[ns+3].operand = operand then
if npeep[ns+4].opcode in [m_bra,m_brl] then
if Short(ns,npeep[ns+4].operand) then begin
operand := npeep[ns+4].operand;
if (npeep[ns+3].flags & labelUsedOnce) <> 0 then
Remove(ns+3);
end; {if}
m_brl:
if Short(ns,operand) then begin
@ -1700,11 +1720,12 @@ var
Remove(ns+3);
end; {if}
m_dec_abs:
{disabled - can generate bad code}
{m_dec_abs:
if npeep[ns+1].opcode = m_lda_abs then
if name^ = npeep[ns+1].name^ then
if npeep[ns+2].opcode = m_beq then
Remove(ns+1);
Remove(ns+1);}
m_lda_abs:
if npeep[ns+1].opcode = m_clc then begin
@ -2301,6 +2322,18 @@ GenNative(d_lab, gnrlabel, lnum, nil, 0);
end; {GenLab}
procedure GenLabUsedOnce {lnum: integer};
{ generate a label that is only targeted by one branch }
{ }
{ parameters: }
{ lnum - label number }
begin {GenLabUsedOnce}
GenNative(d_lab, gnrlabel, lnum, nil, labelUsedOnce);
end; {GenLabUsedOnce}
procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: boolean};
{ Set up the object file }
@ -2625,7 +2658,7 @@ yRegister.condition := regUnknown;
lastRegOpcode := 0; {BRK}
nnextspot := 1;
nleadOpcodes := [m_asl_a,m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_brl,{m_bvs,}
m_dec_abs,m_lda_abs,m_lda_dir,m_lda_imm,m_ldx_imm,m_sta_abs,m_sta_dir,
{m_dec_abs,}m_lda_abs,m_lda_dir,m_lda_imm,m_ldx_imm,m_sta_abs,m_sta_dir,
m_pha,m_plb,{m_plx,}m_tax,m_tya,m_tyx,m_phy,m_pei_dir,m_ldy_imm,m_rep,
m_ora_dir,m_ora_abs,m_and_imm,m_pea,m_tcd];
nstopOpcodes := [d_end,d_pin];

View File

@ -122,13 +122,6 @@ type
val: longlong; {switch value}
end;
{token stack}
{-----------}
tokenStackPtr = ^tokenStackRecord;
tokenStackRecord = record
next: tokenStackPtr;
token: tokenType;
end;
{statement stack}
{---------------}
statementPtr = ^statementRecord;
@ -157,7 +150,7 @@ type
);
forSt: (
forLoop: integer; {branch here to loop}
e3List: tokenStackPtr; {tokens for last expression}
e3Code: codeRef; {code for last expression}
);
switchSt: (
maxVal: longint; {max switch value}
@ -690,11 +683,9 @@ var
{ handle a for statement }
var
errorFound: boolean; {did we find an error?}
e3Start: codeRef; {ref to start of code for expression 3}
forLoop, continueLab, breakLab: integer; {branch points}
parencount: integer; {number of unmatched '(' chars}
stPtr: statementPtr; {work pointer}
tl,tk: tokenStackPtr; {for forming expression list}
begin {ForStatement}
NextToken; {skip the 'for' token}
@ -733,29 +724,12 @@ var
end; {if}
Match(semicolonch,22);
tl := nil; {collect the tokens for the last expression}
parencount := 0;
errorFound := false;
while (token.kind <> eofsy)
and ((token.kind <> rparench) or (parencount <> 0))
and (token.kind <> semicolonch) do begin
new(tk); {place the token in the list}
tk^.next := tl;
tl := tk;
tk^.token := token;
if token.kind = lparench then {allow parens in the expression}
parencount := parencount+1
else if token.kind = rparench then
parencount := parencount-1;
NextToken; {next token}
end; {while}
if errorFound then {if an error was found, dump the list}
while tl <> nil do begin
tk := tl;
tl := tl^.next;
dispose(tk);
end; {while}
stPtr^.e3List := tl; {save the list}
e3Start := GetCodeLocation; {generate and save code for expression 3}
if token.kind <> rparench then begin
Expression(normalExpression, [rparench]);
Gen0t(pc_pop, UsualUnaryConversions);
end; {if}
stPtr^.e3Code := RemoveCode(e3Start);
Match(rparench,12); {get the closing for loop paren}
if c99Scope then PushTable;
@ -1128,37 +1102,13 @@ procedure EndForStatement;
{ finish off a for statement }
var
ltoken: tokenType; {for putting ; on stack}
stPtr: statementPtr; {work pointer}
tl,tk: tokenStackPtr; {for forming expression list}
lSuppressMacroExpansions: boolean; {local copy of suppressMacroExpansions}
begin {EndForStatement}
if c99Scope then PopTable;
stPtr := statementList;
Gen1(dc_lab, stPtr^.continueLab); {define the continue label}
tl := stPtr^.e3List; {place the expression back in the list}
if tl <> nil then begin
PutBackToken(token, false, false);
ltoken.kind := semicolonch;
ltoken.class := reservedSymbol;
PutBackToken(ltoken, false, false);
while tl <> nil do begin
PutBackToken(tl^.token, false, false);
tk := tl;
tl := tl^.next;
dispose(tk);
end; {while}
lSuppressMacroExpansions := suppressMacroExpansions; {inhibit token echo}
suppressMacroExpansions := true;
NextToken; {evaluate the expression}
Expression(normalExpression, [semicolonch]);
Gen0t(pc_pop, UsualUnaryConversions);
NextToken; {skip the semicolon}
suppressMacroExpansions := lSuppressMacroExpansions;
end; {if}
InsertCode(stPtr^.e3Code); {insert code for expression 3}
Gen1(pc_ujp, stPtr^.forLoop); {loop to the test}
Gen1(dc_lab, stPtr^.breakLab); {create the exit label}
statementList := stPtr^.next; {pop the statement record}

View File

@ -1616,6 +1616,10 @@ If you use #pragma debug 0x0010 to enable stack check debug code, the compiler w
13. If an empty argument was passed for a macro parameter that was used as an operand of the ## preprocessing operator, the result would likely be incorrect, and subsequent uses of the same macro also might not be expanded correctly.
14. If a struct, union, or enum type name appeared within the third expression in a for loop statement (e.g. in a cast or as the argument to sizeof), ORCA/C could behave incorrectly. It could report a spurious error if a semicolon occurred within the type name as part of a structure or union member declaration. Also, any tags or enumeration constants declared by such a type name should be in scope within the loop body, but they were not.
15. Native code peephole optimization might produce invalid code in some obscure circumstances where one element of a global or static array was decremented and then another element of the same array was accessed immediately thereafter.
-- Bugs from C 2.1.1 B3 that have been fixed in C 2.2.0 ---------------------
1. There were various bugs that could cause incorrect code to be generated in certain cases. Some of these were specific to certain optimization passes, alone or in combination.