1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-01 13:41:34 +00:00

Merge pull request #1724 from mrdudz/constexpr

Constexpr
This commit is contained in:
Bob Andrews 2022-04-27 11:47:41 +02:00 committed by GitHub
commit e5b08baf56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 349 additions and 4 deletions

View File

@ -172,7 +172,7 @@ ExprNode* FuncHiByte (void);
/* Handle the .HIBYTE builtin function */
ExprNode* MakeBoundedExpr (ExprNode* Expr, unsigned Size);
/* Force the given expression into a specific size of ForceRange is true */
/* Force the given expression into a specific size if ForceRange is true */
ExprNode* BoundedExpr (ExprNode* (*ExprFunc) (void), unsigned Size);
/* Parse an expression and force it within a given size if ForceRange is true */

View File

@ -417,7 +417,7 @@ void SegDone (void)
if ((F->Len == 1 && ED.AddrSize > ADDR_SIZE_ZP) ||
(F->Len == 2 && ED.AddrSize > ADDR_SIZE_ABS) ||
(F->Len == 3 && ED.AddrSize > ADDR_SIZE_FAR)) {
LIError (&F->LI, "Range error");
LIError (&F->LI, "Range error (Address size %u does not match fragment size %u)", ED.AddrSize, F->Len);
}
}

View File

@ -43,6 +43,7 @@
/* ca65 */
#include "error.h"
#include "expr.h"
#include "segment.h"
#include "studyexpr.h"
#include "symtab.h"
@ -187,6 +188,70 @@ static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
}
static void ED_MergeAddrSizeAND (ExprNode* Expr, ExprDesc* ED, const ExprDesc* Right)
/* Merge the address sizes of two expressions into ED, special case for AND operator */
{
int ConstL, ConstR;
int Size, ConstSize;
long Val, ValR;
if (ED->AddrSize == ADDR_SIZE_DEFAULT) {
/* If ED is valid, ADDR_SIZE_DEFAULT gets always overridden, otherwise
** it takes precedence over anything else.
*/
if (ED_IsValid (ED)) {
ED->AddrSize = Right->AddrSize;
}
} else if (Right->AddrSize == ADDR_SIZE_DEFAULT) {
/* If Right is valid, ADDR_SIZE_DEFAULT gets always overridden,
** otherwise it takes precedence over anything else.
*/
if (!ED_IsValid (Right)) {
ED->AddrSize = Right->AddrSize;
}
} else {
/* Neither ED nor Right has a default address size, use the smaller of
** the two.
*/
if (Right->AddrSize < ED->AddrSize) {
ED->AddrSize = Right->AddrSize;
}
}
/* Check if either side of the expression is constant */
ConstL = IsConstExpr (Expr->Left, &Val);
ConstR = IsConstExpr (Expr->Right, &ValR);
if (!ConstL && !ConstR) {
/* If neither part of the expression is constant, the above is all we can do */
return;
}
/* We start assuming the left side is constant, left value is in Val, right
size in Size */
Size = Right->AddrSize;
/* Now check if the right side is constant, and if so put the right value
into Val and the Left size into Size. */
if (ConstR) {
Val = ValR;
Size = ED->AddrSize;
}
/* Figure out the size of the constant value */
if (IsByteRange (Val)) {
ConstSize = ADDR_SIZE_ZP;
} else if (IsWordRange (Val)) {
ConstSize = ADDR_SIZE_ABS;
} else if (IsFarRange (Val)) {
ConstSize = ADDR_SIZE_FAR;
} else {
ConstSize = ADDR_SIZE_LONG;
}
if (Size == ADDR_SIZE_DEFAULT) {
ED->AddrSize = ConstSize;
} else {
/* use the smaller of the two sizes */
ED->AddrSize = (ConstSize < Size) ? ConstSize : Size;
}
}
static ED_SymRef* ED_FindSymRef (ExprDesc* ED, SymEntry* Sym)
/* Find a symbol reference and return it. Return NULL if the reference does
@ -489,7 +554,11 @@ static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
/* Merge references and update address size */
ED_MergeRefs (D, &Right);
ED_MergeAddrSize (D, &Right);
if (Expr->Op == EXPR_AND) {
ED_MergeAddrSizeAND (Expr, D, &Right);
} else {
ED_MergeAddrSize (D, &Right);
}
}

View File

@ -12,7 +12,7 @@ endif
WORKDIR = ../testwrk/asm
SUBDIRS = cpudetect opcodes listing
SUBDIRS = cpudetect opcodes listing val err
.PHONY: all continue mostlyclean clean

45
test/asm/err/Makefile Normal file
View File

@ -0,0 +1,45 @@
# Makefile for the tests that MUST NOT compile
ifneq ($(shell echo),)
CMD_EXE = 1
endif
ifdef CMD_EXE
S = $(subst /,\,/)
NOT = - # Hack
NULLDEV = nul:
MKDIR = mkdir $(subst /,\,$1)
RMDIR = -rmdir /s /q $(subst /,\,$1)
else
S = /
NOT = !
NULLDEV = /dev/null
MKDIR = mkdir -p $1
RMDIR = $(RM) -r $1
endif
ifdef QUIET
.SILENT:
NULLERR = 2>$(NULLDEV)
endif
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
WORKDIR = ../../../testwrk/asm/err
.PHONY: all clean
SOURCES := $(wildcard *.s)
TESTS = $(patsubst %.s,$(WORKDIR)/%.prg,$(SOURCES))
all: $(TESTS)
$(WORKDIR):
$(call MKDIR,$(WORKDIR))
$(WORKDIR)/%.prg: %.s | $(WORKDIR)
$(if $(QUIET),echo asm/err/$*.s)
$(NOT) $(CA65) -o $@ $< $(NULLERR)
clean:
@$(call RMDIR,$(WORKDIR))

3
test/asm/err/bug1538-1.s Normal file
View File

@ -0,0 +1,3 @@
; this should produce a range error
.byte $1234 & $ffff

View File

@ -17,3 +17,16 @@ Overall tests:
--------------
These go into listing/. Refer to listing/readme.txt
val:
----
Works very much like the /val directory used to test the compiler - individual
tests are run in the simulator and should exit with an exit code of 0 when they
pass, or either -1 or a number indicating what part of the test failed on error.
err:
----
Works very much like the /err directory used to test the compiler - individual
tests are assembled and MUST NOT assemble without error.

58
test/asm/val/Makefile Normal file
View File

@ -0,0 +1,58 @@
# Makefile for the regression tests that return an error code on failure
ifneq ($(shell echo),)
CMD_EXE = 1
endif
ifdef CMD_EXE
S = $(subst /,\,/)
NULLDEV = nul:
MKDIR = mkdir $(subst /,\,$1)
RMDIR = -rmdir /s /q $(subst /,\,$1)
else
S = /
NULLDEV = /dev/null
MKDIR = mkdir -p $1
RMDIR = $(RM) -r $1
endif
ifdef QUIET
.SILENT:
NULLOUT = >$(NULLDEV)
NULLERR = 2>$(NULLDEV)
endif
SIM65FLAGS = -x 5000000000
CA65 := $(if $(wildcard ../../../bin/ca65*),..$S..$S..$Sbin$Sca65,ca65)
LD65 := $(if $(wildcard ../../../bin/ld65*),..$S..$S..$Sbin$Sld65,ld65)
SIM65 := $(if $(wildcard ../../../bin/sim65*),..$S..$S..$Sbin$Ssim65,sim65)
WORKDIR = ../../../testwrk/asm/val
.PHONY: all clean
SOURCES := $(wildcard *.s)
TESTS = $(SOURCES:%.s=$(WORKDIR)/%.6502.prg)
TESTS += $(SOURCES:%.s=$(WORKDIR)/%.65c02.prg)
all: $(TESTS)
$(WORKDIR):
$(call MKDIR,$(WORKDIR))
define PRG_template
$(WORKDIR)/%.$1.prg: %.s | $(WORKDIR)
$(if $(QUIET),echo asm/val/$$*.$1.prg)
$(CA65) -t sim$1 -o $$(@:.prg=.o) $$< $(NULLERR)
$(LD65) -C sim6502-asmtest.cfg -o $$@ $$(@:.prg=.o) sim$1.lib $(NULLERR)
$(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT)
endef # PRG_template
$(eval $(call PRG_template,6502))
$(eval $(call PRG_template,65c02))
clean:
@$(call RMDIR,$(WORKDIR))

122
test/asm/val/bug1538.s Normal file
View File

@ -0,0 +1,122 @@
.macpack longbranch
.import _exit
.export _main
offset1 = ($123456 + ((.bank(_main)) * $2345)) ; should produce $123456 + ($23 * $2345) = 1706c5
_main:
ldx #1 ; test counter
;---------------------------------------------------------------------
; first check if we can still force an 16bit address although we are
; ANDing with a 8bit value
test1:
test1a: bit a:$1234 & $ff ; should produce 00 34
lda test1a+1
cmp #$34
jne exiterror
inx
lda test1a+2
cmp #$00
jne exiterror
inx
test1b: bit a:$34 & $ff ; should produce 00 34
lda test1b+1
cmp #$34
jne exiterror
inx
lda test1b+2
cmp #$00
jne exiterror
;---------------------------------------------------------------------
; the original bug report, use an expression that contains a non constant
; part (.bank(_main)) and limit it to 8bit size by ANDing with $ff
test2:
inx
lda #(offset1 >> 0) & $ff
cmp #$c5
jne exiterror
inx
lda #(offset1 >> 8) & $ff
cmp #$06
jne exiterror
inx
lda #(offset1 >> 16) & $ff
cmp #$17
jne exiterror
;---------------------------------------------------------------------
; import a zeropage symbol (1 byte size) and then AND with a constant
; 16bit value - it should not turn into a 16bit address
test3:
jmp test3chk
.importzp tmp1
test3a: .byte tmp1 ; verify its 8bit
test3b: .byte tmp1 & $ff ; AND with $ff should work of course
test3c: .byte tmp1 & $ffff ; AND with $ffff should not change size
test3d: .byte tmp1 & $ffffff ; AND with $ffffff should not change size
test3e: .byte tmp1 & $ffffffff ; AND with $ffffffff should not change size
test3f: .word tmp1 & $ffffff ; AND with $ffffff should not change size
test3g: .word tmp1 & $ffffffff ; AND with $ffffffff should not change size
test3chk:
inx
lda test3a
cmp #tmp1
jne exiterror
inx
lda test3b
cmp #tmp1
jne exiterror
inx
lda test3c
cmp #tmp1
jne exiterror
inx
lda test3d
cmp #tmp1
jne exiterror
inx
lda test3e
cmp #tmp1
jne exiterror
inx
lda test3f
cmp #tmp1
jne exiterror
inx
lda test3f+1
cmp #$00
jne exiterror
inx
lda test3g
cmp #tmp1
jne exiterror
inx
lda test3g+1
cmp #$00
jne exiterror
;---------------------------------------------------------------------
; exit OK
ldx #0
exiterror:
txa
ldx #0
jmp _exit

View File

@ -0,0 +1,35 @@
SYMBOLS {
__EXEHDR__: type = import;
__STACKSIZE__: type = weak, value = $0800; # 2k stack
}
MEMORY {
ZP: file = "", start = $0000, size = $0100;
HEADER: file = %O, start = $0000, size = $000C;
MAIN: file = %O, define = yes, start = $0200, size = $FDF0 - __STACKSIZE__, BANK = $23;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
EXEHDR: load = HEADER, type = ro;
STARTUP: load = MAIN, type = ro;
LOWCODE: load = MAIN, type = ro, optional = yes;
ONCE: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = ro;
RODATA: load = MAIN, type = ro;
DATA: load = MAIN, type = rw;
BSS: load = MAIN, type = bss, define = yes;
}
FEATURES {
CONDES: type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__,
segment = ONCE;
CONDES: type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__,
segment = RODATA;
CONDES: type = interruptor,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__,
segment = RODATA,
import = __CALLIRQ__;
}