Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Version 1.08.0
- github #203: allow casts of addresses on static initializers
- only write debug line information for statements and don't write comments / empty lines / directives for top level source code in assembly debug ouput
- optimize byref 'm += s' string concatenations to fb_StrConcatByref() which will check for same string descriptor at run-time which can't be determined at compile time for byref parameters.
- github #298: allow command line options passed to as, gcc, ld to be longer than 128 characters by using string types internally

[added]
- extern "rtlib": respects the parent namespace, uses default fb calling convention and C style name mangling
Expand Down Expand Up @@ -132,6 +133,8 @@ Version 1.08.0
- fix __FB_EVAL__() incorrectly reading past the end of the expression, and report errors in expressions
- C backend: switch to .text section after writing the exports to the C file in the explicit asm block. gcc can move sections around with optimizations and there is a change between 7.x and 8.x that causes issue with where the directive section is located
- sf.net #917: optimize 'm += s' string concatenations to fix the long compile times in the gcc backend (which makes heavy use of string building).
- github #217: C backend, fix gcc array out of bounds warning when compiled with -O2 or higher optimizations and accessing non-zero lower bound fixed length string arrays
- C backend: inline asm - don't add rsp/esp to the clobber list, it's deprecated in newer gcc versions and silently ignored in older versions


Version 1.07.0
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/fbc.bas
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ enum
end enum

type FBC_EXTOPT
gas as zstring * 128
ld as zstring * 128
gcc as zstring * 128
gas as string
ld as string
gcc as string
end type

type FBCIOFILE
Expand Down
30 changes: 25 additions & 5 deletions src/compiler/ir-hlc.bas
Original file line number Diff line number Diff line change
Expand Up @@ -2678,8 +2678,23 @@ private function exprNewVREG _
l = exprNewUOP( AST_OP_ADDROF, l )
end if
if( have_offset ) then
'' Cast to ubyte ptr to work around C's pointer arithmetic
l = exprNewCAST( typeAddrOf( FB_DATATYPE_UBYTE ), NULL, l )
if( is_c_array ) then
'' Cast to intptr_t to work around gcc out side of array bounds
'' warnings if we are casting from FBSTRING array to pointer
'' fbc uses a kind of virtual pointer for the an array's (0,..)
'' index; technically this is undefinded behaviour in C and is
'' impossible to cast away even when using pointer only casts
'' in the same expression. Some gcc optimizations cause a
'' a warning when setting a pointer for the array's virtual
'' index location. To fix this for compliant C code, would
'' need to rewrite the array descriptor to contain only the
'' offset value from actual memory pointer and compute the
'' array access fully on each array element access.
l = exprNewCAST( FB_DATATYPE_INTEGER, NULL, l )
else
'' Cast to ubyte ptr to work around C's pointer arithmetic
l = exprNewCAST( typeAddrOf( FB_DATATYPE_UBYTE ), NULL, l )
end if
if( vreg->vidx <> NULL ) then
l = exprNewBOP( AST_OP_ADD, l, exprNewVREG( vreg->vidx ) )
end if
Expand Down Expand Up @@ -3557,15 +3572,20 @@ private sub _emitAsmLine( byval asmtokenhead as ASTASMTOK ptr )
ln += " : " + inputconstraints

'' We don't know what registers etc. will be trashed,
'' so assume everything...
'' so assume everything... except for rsp/esp - gcc requires a valid
'' stack to preserve registers and if the asm code clobbers esp/rsp
'' then there is no way to get it back after esp/rsp changes to
'' something else. User is always responsible for handling the stack
'' registers.
''
ln += " : ""cc"", ""memory"""

select case( fbGetCpuFamily( ) )
case FB_CPUFAMILY_X86, FB_CPUFAMILY_X86_64
if( fbGetCpuFamily( ) = FB_CPUFAMILY_X86 ) then
ln += ", ""eax"", ""ebx"", ""ecx"", ""edx"", ""esp"", ""edi"", ""esi"""
ln += ", ""eax"", ""ebx"", ""ecx"", ""edx"", ""edi"", ""esi"""
else
ln += ", ""rax"", ""rbx"", ""rcx"", ""rdx"", ""rsp"", ""rdi"", ""rsi"""
ln += ", ""rax"", ""rbx"", ""rcx"", ""rdx"", ""rdi"", ""rsi"""
ln += ", ""r8"", ""r9"", ""r10"", ""r11"", ""r12"", ""r13"", ""r14"", ""r15"""
end if

Expand Down
135 changes: 0 additions & 135 deletions tests/compound/select_const.bas
Original file line number Diff line number Diff line change
Expand Up @@ -564,139 +564,4 @@ SUITE( fbc_tests.compound.select_const )

END_TEST

TEST( RangeEdges )

dim as integer ok, nok

#macro TEST_RANGE( T, a, b, c_, d_, p, f )
scope
ok = 0
nok = 0
dim v as T
#if LITERAL
#define c c_
#define d d_
#else
const c as T = c_
const d as T = d_
#endif
v = a
do
select case as const v
case (c) to (d)
CU_ASSERT( (v>=(c)) and (v<=(d)) )
ok += 1
case else
CU_ASSERT( not ((v>=(c)) and (v<=(d))) )
nok += 1
end select
if( v = b ) then
exit do
end if
v += 1
loop
CU_ASSERT_EQUAL( p, ok )
CU_ASSERT_EQUAL( f, nok )
end scope
#endmacro

#macro TEST_RANGE_EDGES( T, a, b )
TEST_RANGE( T, a+0, a+10, a+0, a+0, 1, 10 )
TEST_RANGE( T, a+0, a+10, a+0, a+1, 2, 9 )
TEST_RANGE( T, a+0, a+10, a+1, a+1, 1, 10 )
TEST_RANGE( T, a+0, a+10, a+1, a+2, 2, 9 )
TEST_RANGE( T, a+0, a+10, a+2, a+2, 1, 10 )

TEST_RANGE( T, a+0, a+10, a+0, a+3, 4, 7 )
TEST_RANGE( T, a+0, a+10, a+1, a+4, 4, 7 )
TEST_RANGE( T, a+0, a+10, a+2, a+5, 4, 7 )

TEST_RANGE( T, a+1, a+10, a+0, a+0, 0, 10 )
TEST_RANGE( T, a+1, a+10, a+0, a+1, 1, 9 )
TEST_RANGE( T, a+1, a+10, a+1, a+1, 1, 9 )
TEST_RANGE( T, a+1, a+10, a+1, a+2, 2, 8 )
TEST_RANGE( T, a+1, a+10, a+2, a+2, 1, 9 )

TEST_RANGE( T, b-10, b-0, b-0, b-0, 1, 10 )
TEST_RANGE( T, b-10, b-0, b-1, b-0, 2, 9 )
TEST_RANGE( T, b-10, b-0, b-1, b-1, 1, 10 )
TEST_RANGE( T, b-10, b-0, b-2, b-1, 2, 9 )
TEST_RANGE( T, b-10, b-0, b-2, b-2, 1, 10 )

TEST_RANGE( T, b-10, b-0, b-3, b-0, 4, 7 )
TEST_RANGE( T, b-10, b-0, b-4, b-1, 4, 7 )
TEST_RANGE( T, b-10, b-0, b-5, b-2, 4, 7 )

TEST_RANGE( T, b-10, b-1, b-0, b-0, 0, 10 )
TEST_RANGE( T, b-10, b-1, b-1, b-0, 1, 9 )
TEST_RANGE( T, b-10, b-1, b-1, b-1, 1, 9 )
TEST_RANGE( T, b-10, b-1, b-2, b-1, 2, 8 )
TEST_RANGE( T, b-10, b-1, b-2, b-2, 1, 9 )
#endmacro

#macro TEST_RANGES()
'' byte range edges and near zero
TEST_RANGE_EDGES( byte, -128, 127 )
TEST_RANGE_EDGES( byte, -2, 2 )
TEST_RANGE_EDGES( ubyte, 0, 255 )

TEST_RANGE_EDGES( short, -129, 128 )
TEST_RANGE_EDGES( short, -1, 256 )
TEST_RANGE_EDGES( long, -129, 128 )
TEST_RANGE_EDGES( long, -1, 256 )
TEST_RANGE_EDGES( integer, -129, 128 )
TEST_RANGE_EDGES( integer, -1, 256 )
TEST_RANGE_EDGES( longint, -129, 128 )
TEST_RANGE_EDGES( longint, -1, 256 )

'' short range edges and near zero
TEST_RANGE_EDGES( short, -32768, 32767 )
TEST_RANGE_EDGES( short, -2, 2 )
TEST_RANGE_EDGES( ushort, 0, 65535 )

TEST_RANGE_EDGES( long, -32769, 32768 )
TEST_RANGE_EDGES( long, 0, 65536 )
TEST_RANGE_EDGES( integer, -32769, 32768 )
TEST_RANGE_EDGES( integer, 0, 65536 )
TEST_RANGE_EDGES( longint, -32769, 32768 )
TEST_RANGE_EDGES( longint, 0, 65536 )

'' long range edges and near zero
TEST_RANGE_EDGES( long, -2147483648, 2147483647 )
TEST_RANGE_EDGES( long, -2, 2 )
TEST_RANGE_EDGES( ulong, 0, 4294967295 )

TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
TEST_RANGE_EDGES( longint, 0, 4294967296ll )

#ifdef __FB_64BIT__
TEST_RANGE_EDGES( integer, -9223372036854775807ll-1ll, 9223372036854775807ll )
TEST_RANGE_EDGES( integer, -2ll, 2ll )
TEST_RANGE_EDGES( uinteger, 0, 18446744073709551615ull )
#else
TEST_RANGE_EDGES( integer, -2147483648, 2147483647 )
TEST_RANGE_EDGES( integer, -2, 2 )
TEST_RANGE_EDGES( uinteger, 0, 4294967295 )

TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
TEST_RANGE_EDGES( longint, 0, 4294967296ll )
#endif

'' longint range edges and near zero
TEST_RANGE_EDGES( longint, -9223372036854775807ll-1ll, 9223372036854775807ll )
TEST_RANGE_EDGES( longint, -2ll, 2ll )
TEST_RANGE_EDGES( ulongint, 0, 18446744073709551615ull )
#endmacro

'' Test Ranges using literal values
#define LITERAL TRUE
TEST_RANGES()

'' Test Ranges using a CONST symbol
#undef LITERAL
#define LITERAL FALSE
TEST_RANGES()

END_TEST

END_SUITE
177 changes: 177 additions & 0 deletions tests/compound/select_const2.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# include "fbcunit.bi"

'' originally these tests were included in select_const.bas
'' but due the nested macro expansion, the test as written
'' in the gcc backend would generate a C listing 250K+ in length
'' and is very taxing on gcc especially when optimizations and
'' debug information is enabled. In some cases:
'' - gcc (cc1) can run out of memory allocting debug symbols
'' - gcc -O2 is really (really!) slow due that most of the
'' test uses constant symbols and gcc chews away on optimizing
'' for quite some time

'' split the test so we can modify test generation here separately

SUITE( fbc_tests.compound.select_const2 )

const FALSE = 0
const TRUE = not FALSE

#macro TEST_RANGE( T, a, b, c_, d_, p, f )
#if DEFINITION = TRUE
__fb_uniqueid_push__( callstack )
sub __fb_uniqueid__( callstack )
dim as integer ok, nok
ok = 0
nok = 0
dim v as T
#if LITERAL
#define c c_
#define d d_
#else
const c as T = c_
const d as T = d_
#endif
v = a
do
select case as const v
case (c) to (d)
CU_ASSERT( (v>=(c)) and (v<=(d)) )
ok += 1
case else
CU_ASSERT( not ((v>=(c)) and (v<=(d))) )
nok += 1
end select
if( v = b ) then
exit do
end if
v += 1
loop
CU_ASSERT_EQUAL( p, ok )
CU_ASSERT_EQUAL( f, nok )
end sub
#else
'' call the test - the order doesn't matter
__fb_uniqueid__( callstack )()
__fb_uniqueid_pop__( callstack )
#endif
#endmacro

#macro TEST_RANGE_EDGES( T, a, b )
TEST_RANGE( T, a+0, a+10, a+0, a+0, 1, 10 )
TEST_RANGE( T, a+0, a+10, a+0, a+1, 2, 9 )
TEST_RANGE( T, a+0, a+10, a+1, a+1, 1, 10 )
TEST_RANGE( T, a+0, a+10, a+1, a+2, 2, 9 )
TEST_RANGE( T, a+0, a+10, a+2, a+2, 1, 10 )

TEST_RANGE( T, a+0, a+10, a+0, a+3, 4, 7 )
TEST_RANGE( T, a+0, a+10, a+1, a+4, 4, 7 )
TEST_RANGE( T, a+0, a+10, a+2, a+5, 4, 7 )

TEST_RANGE( T, a+1, a+10, a+0, a+0, 0, 10 )
TEST_RANGE( T, a+1, a+10, a+0, a+1, 1, 9 )
TEST_RANGE( T, a+1, a+10, a+1, a+1, 1, 9 )
TEST_RANGE( T, a+1, a+10, a+1, a+2, 2, 8 )
TEST_RANGE( T, a+1, a+10, a+2, a+2, 1, 9 )

TEST_RANGE( T, b-10, b-0, b-0, b-0, 1, 10 )
TEST_RANGE( T, b-10, b-0, b-1, b-0, 2, 9 )
TEST_RANGE( T, b-10, b-0, b-1, b-1, 1, 10 )
TEST_RANGE( T, b-10, b-0, b-2, b-1, 2, 9 )
TEST_RANGE( T, b-10, b-0, b-2, b-2, 1, 10 )

TEST_RANGE( T, b-10, b-0, b-3, b-0, 4, 7 )
TEST_RANGE( T, b-10, b-0, b-4, b-1, 4, 7 )
TEST_RANGE( T, b-10, b-0, b-5, b-2, 4, 7 )

TEST_RANGE( T, b-10, b-1, b-0, b-0, 0, 10 )
TEST_RANGE( T, b-10, b-1, b-1, b-0, 1, 9 )
TEST_RANGE( T, b-10, b-1, b-1, b-1, 1, 9 )
TEST_RANGE( T, b-10, b-1, b-2, b-1, 2, 8 )
TEST_RANGE( T, b-10, b-1, b-2, b-2, 1, 9 )
#endmacro

#macro TEST_RANGES()
'' byte range edges and near zero
TEST_RANGE_EDGES( byte, -128, 127 )
TEST_RANGE_EDGES( byte, -2, 2 )
TEST_RANGE_EDGES( ubyte, 0, 255 )

TEST_RANGE_EDGES( short, -129, 128 )
TEST_RANGE_EDGES( short, -1, 256 )
TEST_RANGE_EDGES( long, -129, 128 )
TEST_RANGE_EDGES( long, -1, 256 )
TEST_RANGE_EDGES( integer, -129, 128 )
TEST_RANGE_EDGES( integer, -1, 256 )
TEST_RANGE_EDGES( longint, -129, 128 )
TEST_RANGE_EDGES( longint, -1, 256 )

'' short range edges and near zero
TEST_RANGE_EDGES( short, -32768, 32767 )
TEST_RANGE_EDGES( short, -2, 2 )
TEST_RANGE_EDGES( ushort, 0, 65535 )

TEST_RANGE_EDGES( long, -32769, 32768 )
TEST_RANGE_EDGES( long, 0, 65536 )
TEST_RANGE_EDGES( integer, -32769, 32768 )
TEST_RANGE_EDGES( integer, 0, 65536 )
TEST_RANGE_EDGES( longint, -32769, 32768 )
TEST_RANGE_EDGES( longint, 0, 65536 )

'' long range edges and near zero
TEST_RANGE_EDGES( long, -2147483648, 2147483647 )
TEST_RANGE_EDGES( long, -2, 2 )
TEST_RANGE_EDGES( ulong, 0, 4294967295 )

TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
TEST_RANGE_EDGES( longint, 0, 4294967296ll )

#ifdef __FB_64BIT__
TEST_RANGE_EDGES( integer, -9223372036854775807ll-1ll, 9223372036854775807ll )
TEST_RANGE_EDGES( integer, -2ll, 2ll )
TEST_RANGE_EDGES( uinteger, 0, 18446744073709551615ull )
#else
TEST_RANGE_EDGES( integer, -2147483648, 2147483647 )
TEST_RANGE_EDGES( integer, -2, 2 )
TEST_RANGE_EDGES( uinteger, 0, 4294967295 )

TEST_RANGE_EDGES( longint, -2147483649ll, 2147483648ll )
TEST_RANGE_EDGES( longint, 0, 4294967296ll )
#endif

'' longint range edges and near zero
TEST_RANGE_EDGES( longint, -9223372036854775807ll-1ll, 9223372036854775807ll )
TEST_RANGE_EDGES( longint, -2ll, 2ll )
TEST_RANGE_EDGES( ulongint, 0, 18446744073709551615ull )
#endmacro

'' generate tests for Test Ranges using literal values
#define LITERAL TRUE
#undef DEFINITION
#define DEFINITION TRUE
TEST_RANGES()

'' call the tests - the order doesn't matter, only that we use & call
'' the correct number of calls from the callstack
#undef DEFINITION
#define DEFINITION FALSE
TEST( RangeEdges_literal )
TEST_RANGES()
END_TEST

'' generate tests for Test Ranges using a CONST symbol
#undef LITERAL
#define LITERAL FALSE
#undef DEFINITION
#define DEFINITION TRUE
TEST_RANGES()

'' call the tests - the order doesn't matter, only that we use & call
'' the correct number of calls from the callstack
#undef DEFINITION
#define DEFINITION FALSE
TEST( RangeEdges_const )
TEST_RANGES()
END_TEST

END_SUITE