+2005-09-03 Maarten Brock <sourceforge.brock AT dse.nl>
+
+ * .version: changed to version 2.5.3
+ * doc/sdccman.lyx: changed version to 2.5.3,
+ documented --codeseg and --constseg and pragma codeseg and constseg,
+ documented bit parameters (reentrant) and bit returning
+ * src/SDCCicode.c (geniCodeReceive): fixed (possible) bug generating
+ currFunc->recvSize, but is this ok for all ports?
+ (ast2iCode): result of ~ on unsigned char must be cast to int for
+ bool to work
+ * src/SDCCmem.c (allocGlobal, allocLocal): don't put bit returning
+ function pointers in bit space
+ * src/SDCCsymt.c (checkSClass): allow bit returning function pointers,
+ (processFuncArgs): call port.reg_parm() with reentrancy info
+ * src/port.h,
+ * src/avr/main.c,
+ * src/ds390/main.c,
+ * src/hc08/main.c,
+ * src/pic/main.c,
+ * src/pic16/main.c,
+ * src/xa51/main.c,
+ * src/z80/main.c: port.reg_parm prototype extended with
+ "bool reentrant" parameter
+ * src/mcs51/main.c (_mcs51_regparm): use parameter reentrant instead of
+ options.stackAuto for allocating bit register parameters
+ * src/mcs51/gen.c (genNot): optimized complementing direct bit,
+ (genSend): set BitBankUsed if it is,
+ (selectRegBank): factored out of genCall for use in genPcall,
+ (genCall): removed redundant dtype assignmen, use selectRegBank,
+ (genPcall): handle returning in Carry properly, save in F0 if needed,
+ (genReceive): handle bit register parameters
+ * src/mcs51/ralloc.c (updateRegUsage): update BitBankUsed along the way,
+ (mcs51_assignRegisters): enable bit registers for all reentrant
+ functions and don't set BitBankUsed unconditionally
+ * src/mcs51/peeph.def (177.d): fixed bug if %2==%3
+ * support/regression/tests/bitvars.c: enable tests for SDCC_STACK_AUTO
+ * support/regression/tests/funptrs.c: added tests for BOOL and for return
+
2005-08-27 Borut Razem <borut.razem AT siol.net>
* device/lib/Makefile.in: cp on sparc-solaris (SunOS) and on
\size normal
-SDCC 2.5.2
+SDCC 2.5.3
\size footnotesize
\newline
\family typewriter
-code banking
-\begin_inset LatexCommand \index{code banking (not supported)}
+better code banking
+\begin_inset LatexCommand \index{code banking (limited support)}
\end_inset
\newline
WARNING: Visual studio is very picky with line terminations; it expects
the 0x0d, 0x0a DOS style line endings, not the 0x0a Unix style line endings.
- If you are getting a message such as "This makefile was not generated by
- Developer Studio etc.
+ When using the CVS repository it's easiest to configure the cvs client
+ to convert automatically for you.
+ If however you are getting a message such as "This makefile was not generated
+ by Developer Studio etc.
etc.
\begin_inset Quotes srd
\end_inset
details.
If this option is used all source files in the project have to be compiled
with this option.
+ It must also be used when invoking the linker.
\layout List
\labelwidthstring 00.00.0000
\labelwidthstring 00.00.0000
+\series bold
+-
+\begin_inset ERT
+status Collapsed
+
+\layout Standard
+
+\backslash
+/
+\end_inset
+
+-codeseg
+\series default
+
+\begin_inset LatexCommand \index{-\/-codeseg <Value>}
+
+\end_inset
+
+\SpecialChar ~
+<Name> The name to be used for the code
+\begin_inset LatexCommand \index{code}
+
+\end_inset
+
+ segment, default CSEG.
+ This is useful if you need to tell the compiler to put the code in a special
+ segment so you can later on tell the linker to put this segment in a special
+ place in memory.
+ Can be used for instance when using bank switching to put the code in a
+ bank.
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold
+-
+\begin_inset ERT
+status Collapsed
+
+\layout Standard
+
+\backslash
+/
+\end_inset
+
+-constseg
+\series default
+
+\begin_inset LatexCommand \index{-\/-constseg <Value>}
+
+\end_inset
+
+\SpecialChar ~
+<Name> The name to be used for the const
+\begin_inset LatexCommand \index{code}
+
+\end_inset
+
+ segment, default CONST.
+ This is useful if you need to tell the compiler to put the const data in
+ a special segment so you can later on tell the linker to put this segment
+ in a special place in memory.
+ Can be used for instance when using bank switching to put the const data
+ in a bank.
+\layout List
+\labelwidthstring 00.00.0000
+
+
\series bold
more-pedantic
\series default
, (storage classes for parameters will be ignored), their allocation is
governed by the memory model in use, and the reentrancy options.
+\layout Standard
+
+It is however allowed to use bit parameters in reentrant functions and also
+ non-static local bit variables are supported.
+ Efficient use is limited to 8 semi-bitregisters in bit space.
+ They are pushed and popped to stack as a single byte just like the normal
+ registers.
\layout Section
Overlaying
- Follow the C99 standard and disable SDCC features that conflict with the
standard (incomplete support).
+\layout Itemize
+
+codeseg <name>
+\begin_inset LatexCommand \index{\#pragma codeseg}
+
+\end_inset
+
+- Use this name (max.
+ 8 characters) for the code segment.
+\layout Itemize
+
+constseg <name>
+\begin_inset LatexCommand \index{\#pragma constseg}
+
+\end_inset
+
+- Use this name (max.
+ 8 characters) for the const segment.
\layout Standard
SDCPP supports the following #pragma directives:
}
/*-----------------------------------------------------------------*/
-/* geniCodeUnary - for a a generic unary operation */
+/* geniCodeUnary - for a generic unary operation */
/*-----------------------------------------------------------------*/
operand *
geniCodeUnary (operand * op, int oper)
/* for all arguments that are passed in registers */
while (args)
{
- int first = 1;
if (IS_REGPARM (args->etype))
{
operand *opr = operandFromValue (args);
ic = newiCode (RECEIVE, func, NULL);
ic->argreg = SPEC_ARGREG(args->etype);
- if (first) {
+ if (ic->argreg == 1) {
currFunc->recvSize = getSize (sym->type);
- first = 0;
}
IC_RESULT (ic) = opr;
#endif
case '~':
+ {
+ sym_link *ltype = operandType (left);
+ operand *op = geniCodeUnary (geniCodeRValue (left, FALSE), tree->opval.op);
+ if ((SPEC_NOUN(ltype) == V_CHAR) && IS_UNSIGNED(ltype))
+ {
+ setOperandType (op, INTTYPE);
+ }
+ return op;
+ }
case RRC:
case RLC:
case SWAP:
}
/* if this is a bit variable and no storage class */
- if (SPEC_NOUN (sym->etype) == V_BIT
- /*&& SPEC_SCLS (sym->etype) == S_BIT*/)
+ if (IS_SPEC(sym->type) && SPEC_NOUN (sym->type) == V_BIT)
+ /*&& SPEC_SCLS (sym->etype) == S_BIT*/
{
- SPEC_OCLS (sym->etype) = bit;
+ SPEC_OCLS (sym->type) = bit;
allocIntoSeg (sym);
return;
}
}
/* if this is a bit variable and no storage class */
- if (SPEC_NOUN (sym->etype) == V_BIT)
+ if (IS_SPEC(sym->type) && SPEC_NOUN (sym->type) == V_BIT)
{
- SPEC_SCLS (sym->etype) = S_BIT;
- SPEC_OCLS (sym->etype) = bit;
+ SPEC_SCLS (sym->type) = S_BIT;
+ SPEC_OCLS (sym->type) = bit;
allocIntoSeg (sym);
return;
}
/* arrays & pointers cannot be defined for bits */
/* SBITS or SFRs or BIT */
if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
+ !IS_FUNCPTR (sym->type) &&
(SPEC_NOUN (sym->etype) == V_BIT ||
SPEC_NOUN (sym->etype) == V_SBIT ||
SPEC_NOUN (sym->etype) == V_BITFIELD ||
the function does not have VA_ARG
and as port dictates */
if (!IFFUNC_HASVARARGS(funcType) &&
- (argreg = (*port->reg_parm) (val->type)))
+ (argreg = (*port->reg_parm) (val->type, FUNC_ISREENT(funcType))))
{
SPEC_REGPARM (val->etype) = 1;
SPEC_ARGREG(val->etype) = argreg;
}
static int
-_avr_regparm (sym_link * l)
+_avr_regparm (sym_link * l, bool reentrant)
{
/* the first eight bytes will be passed in
registers r16-r23. but we won't split variables
}
static int
-_ds390_regparm (sym_link * l)
+_ds390_regparm (sym_link * l, bool reentrant)
{
if (IS_SPEC(l) && (SPEC_NOUN(l) == V_BIT))
return 0;
}
static int
-_hc08_regparm (sym_link * l)
+_hc08_regparm (sym_link * l, bool reentrant)
{
int size = getSize(l);
/* if in bit space then a special case */
if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
{
- emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
- emitcode ("cpl", "c");
- outBitC (IC_RESULT (ic));
+ /* if left==result then cpl bit */
+ if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
+ {
+ emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+ }
+ else
+ {
+ emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+ emitcode ("cpl", "c");
+ outBitC (IC_RESULT (ic));
+ }
goto release;
}
toBoolean (IC_LEFT (ic));
+ /* set C, if a == 0 */
tlbl = newiTempLabel (NULL);
emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
emitcode ("", "%05d$:", tlbl->key + 100);
emitcode ("mov", "b[%d],c", bit);
}
bit_count++;
+ BitBankUsed = 1;
}
freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
}
}
}
+/*-----------------------------------------------------------------*/
+/* selectRegBank - emit code to select the register bank */
+/*-----------------------------------------------------------------*/
+static void
+selectRegBank (short bank, bool keepFlags)
+{
+ /* if f.e. result is in carry */
+ if (keepFlags)
+ {
+ emitcode ("anl", "psw,#0xE7");
+ if (bank)
+ emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
+ }
+ else
+ {
+ emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
+ }
+}
+
/*-----------------------------------------------------------------*/
/* genCall - generates a call statement */
/*-----------------------------------------------------------------*/
genCall (iCode * ic)
{
sym_link *dtype;
+ sym_link *etype;
// bool restoreBank = FALSE;
bool swapBanks = FALSE;
bool accuse = FALSE;
D(emitcode("; genCall",""));
dtype = operandType (IC_LEFT (ic));
+ etype = getSpec(dtype);
/* if send set is not empty then assign */
if (_G.sendSet)
{
/* if we are calling a not _naked function that is not using
the same register bank then we need to save the
destination registers on the stack */
- dtype = operandType (IC_LEFT (ic));
if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
(FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
!IFFUNC_ISISR (dtype))
}
if (swapBanks)
- {
- /* if result is in carry */
- if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
- {
- emitcode ("anl", "psw,#0xE7");
- if (FUNC_REGBANK(currFunc->type))
- emitcode ("orl", "psw,#0x%02x",
- ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
- }
- else
- {
- emitcode ("mov", "psw,#0x%02x",
- ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
- }
+ {
+ selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
}
/* if we need assign a result value */
symbol *rlbl = newiTempLabel (NULL);
// bool restoreBank=FALSE;
bool swapBanks = FALSE;
+ bool resultInF0 = FALSE;
D(emitcode("; genPCall",""));
+ dtype = operandType (IC_LEFT (ic))->next;
+ etype = getSpec(dtype);
/* if caller saves & we have not saved then */
if (!ic->regsSaved)
saveRegisters (ic);
/* if we are calling a not _naked function that is not using
the same register bank then we need to save the
destination registers on the stack */
- dtype = operandType (IC_LEFT (ic))->next;
if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
(FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
!IFFUNC_ISISR (dtype))
- {
+ {
// saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
// restoreBank=TRUE;
swapBanks = TRUE;
// need caution message to user here
- }
+ }
- etype = getSpec(dtype);
if (IS_LITERAL(etype))
{
/* if send set is not empty then assign */
}
}
if (swapBanks)
- {
- emitcode ("mov", "psw,#0x%02x",
- ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
- }
+ {
+ selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
+ }
/* if we need assign a result value */
if ((IS_ITEMP (IC_RESULT (ic)) &&
+ !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
(OP_SYMBOL (IC_RESULT (ic))->nRegs ||
OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
IS_TRUE_SYMOP (IC_RESULT (ic)))
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
- /* adjust the stack for parameters if
- required */
+ /* adjust the stack for parameters if required */
if (ic->parmBytes)
{
int i;
if (ic->parmBytes > 3)
{
+ if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
+ IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
+ {
+ emitcode ("mov", "F0,c");
+ resultInF0 = TRUE;
+ }
+
emitcode ("mov", "a,%s", spname);
emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
emitcode ("mov", "%s,a", spname);
// if (restoreBank)
// unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
- /* if we hade saved some registers then
- unsave them */
+ /* if we had saved some registers then unsave them */
if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
unsaveRegisters (ic);
+
+ if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
+ {
+ if (resultInF0)
+ emitcode ("mov", "c,F0");
+
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
+ freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+ }
}
/*-----------------------------------------------------------------*/
D(emitcode ("; genReceive",""));
- if (ic->argreg == 1) { /* first parameter */
+ if (ic->argreg == 1)
+ { /* first parameter */
if (isOperandInFarSpace (IC_RESULT (ic)) &&
(OP_SYMBOL (IC_RESULT (ic))->isspilt ||
- IS_TRUE_SYMOP (IC_RESULT (ic)))) {
-
+ IS_TRUE_SYMOP (IC_RESULT (ic))))
+ {
regs *tempRegs[4];
int receivingA = 0;
int roffset = 0;
}
offset = fReturnSizeMCS51 - size;
- while (size--) {
+ while (size--)
+ {
emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
offset++;
- }
+ }
aopOp (IC_RESULT (ic), ic, FALSE);
size = AOP_SIZE (IC_RESULT (ic));
offset = 0;
- while (size--) {
+ while (size--)
+ {
emitcode ("pop", "acc");
aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
- }
-
- } else {
+ }
+ }
+ else
+ {
_G.accInUse++;
aopOp (IC_RESULT (ic), ic, FALSE);
_G.accInUse--;
assignResultValue (IC_RESULT (ic), NULL);
- }
- } else { /* second receive onwards */
+ }
+ }
+ else if (ic->argreg > 12)
+ { /* bit parameters */
+ if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
+ {
+ aopOp (IC_RESULT (ic), ic, FALSE);
+ emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
+ outBitC(IC_RESULT (ic));
+ }
+ }
+ else
+ { /* other parameters */
int rb1off ;
aopOp (IC_RESULT (ic), ic, FALSE);
rb1off = ic->argreg;
- while (size--) {
+ while (size--)
+ {
aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
- }
- }
+ }
+ }
release:
freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
}
static int
-_mcs51_regparm (sym_link * l)
+_mcs51_regparm (sym_link * l, bool reentrant)
{
if (IS_SPEC(l) && (SPEC_NOUN(l) == V_BIT)) {
/* bit parameters go to b0 thru b7 */
- if (options.stackAuto && (regBitParmFlg < 8)) {
+ if (reentrant && (regBitParmFlg < 8)) {
regBitParmFlg++;
return 12 + regBitParmFlg;
}
mov %1,%2
mov %3,%4
; Peephole 177.d removed redundant move
-} if notVolatile(%1 %2),operandsNotRelated(%1 %3)
+} if notVolatile(%1 %2),operandsNotRelated(%1 %2 %3)
// applies to f.e. bug-607243.c
// also check notVolatile %3, as it will return FALSE if it's @r%1
else
{
ic->riu |= (1<<regs8051[reg].offset);
+ BitBankUsed |= (reg >= 8);
}
}
}
setToNull ((void *) &_G.regAssigned);
setToNull ((void *) &_G.totRegAssigned);
mcs51_ptrRegReq = _G.stackExtend = _G.dataExtend = 0;
- if (options.stackAuto)
+ if ((currFunc && IFFUNC_ISREENT (currFunc->type)) || options.stackAuto)
{
mcs51_nRegs = 16;
- BitBankUsed = 1;
}
else
{
}
static int
-_pic14_regparm (sym_link * l)
+_pic14_regparm (sym_link * l, bool reentrant)
{
/* for this processor it is simple
can pass only the first parameter in a register */
}
static int
-_pic16_regparm (sym_link * l)
+_pic16_regparm (sym_link * l, bool reentrant)
{
/* force all parameters via SEND/RECEIVE */
if(0 /*pic16_options.ip_stack*/) {
/* assembler file extension */
const char *file_ext;
/** If non-null will be used to execute the assembler. */
- void (*do_assemble) (set *);
+ void (*do_assemble) (set *);
}
assembler;
void (*do_link) (void);
/** Extension for object files (.rel, .obj, ...) */
const char *rel_ext;
- /** 1 if port needs the .lnk file, 0 otherwise */
+ /** 1 if port needs the .lnk file, 0 otherwise */
const int needLinkerScript;
}
linker;
void (*genExtraAreaLinkOptions)(FILE *);
}
extraAreas;
-
+
/* stack related information */
struct
{
struct
{
- /** One more than the smallest
- mul/div operation the processor can do nativley
+ /** One more than the smallest
+ mul/div operation the processor can do nativley
Eg if the processor has an 8 bit mul, nativebelow is 2 */
unsigned muldiv;
unsigned shift;
int sizeofDispatch;
}
jumptableCost;
-
+
/** Prefix to add to a C function (eg "_") */
const char *fun_prefix;
/* Write any port specific assembler output. */
void (*genAssemblerPreamble) (FILE * of);
- /* invoked at end assembler file */
+ /* invoked at end assembler file */
void (*genAssemblerEnd) (FILE * of);
/* Write the port specific IVT. If genIVT is NULL or if
* it returns zero, default (8051) IVT generation code
- * will be used.
+ * will be used.
*/
int (*genIVT) (FILE * of, symbol ** intTable, int intCount);
void (*genXINIT) (FILE * of);
-
+
/* Write port specific startup code */
void (*genInitStartup) (FILE * of);
/* parameter passing in register related functions */
void (*reset_regparms) (void); /* reset the register count */
- int (*reg_parm) (struct sym_link *); /* will return 1 if can be passed in register */
+ int (*reg_parm) (struct sym_link *, bool reentrant); /* will return 1 if can be passed in register */
/** Process the pragma string 'sz'. Returns 0 if recognised and
processed, 1 otherwise. May be NULL.
*/
int (*process_pragma) (const char *sz);
- /** Mangles a support function name to reflect the calling model.
+ /** Mangles a support function name to reflect the calling model.
*/
char *(*getMangledFunctionName) (char *szOrginial);
manipulation iCodes (RRC, RLC, SWAP, GETHBIT)
*/
bool (*hasExtBitOp) (int op, int size);
-
+
/** Returns the relative expense of accessing a particular output
storage class. Larger values indicate higher expense.
*/
int (*oclsExpense) (struct memmap *oclass);
-
+
/** If TRUE, then tprintf and !dw will be used for some initalisers
*/
bool use_dw_for_init;
bool ne_neq; /* transform a != b --> ! (a == b) */
bool eq_nne; /* transform a == b --> ! (a != b) */
- bool arrayInitializerSuppported;
+ bool arrayInitializerSuppported;
bool (*cseOk) (iCode *ic, iCode *pdic);
builtins *builtintable; /* table of builtin functions */
- int unqualified_pointer; /* unqualified pointers type is */
+ int unqualified_pointer; /* unqualified pointers type is */
int reset_labelKey ; /* reset Label no 1 at the start of a function */
int globals_allowed ; /* global & static locals not allowed ? 0 ONLY TININative*/
#define PORT_MAGIC 0xAC32
}
static int
-_xa51_regparm (sym_link * l)
+_xa51_regparm (sym_link * l, bool reentrant)
{
return 0; // for now
/* for this processor it is simple
}
static int
-_reg_parm (sym_link * l)
+_reg_parm (sym_link * l, bool reentrant)
{
if (options.noRegParams)
{
#pragma disable_warning 180 //no warning about using complement on bit/unsigned char
#endif
-#if defined (SDCC_STACK_AUTO) || defined (SDCC_hc08) || defined (SDCC_z80)
+#if defined (SDCC_hc08) || defined (SDCC_z80)
#define NO_BITS
#endif
/** Function pointer tests.
- type: char, int, long
+ type: BOOL, char, int, long
*/
#include <testfwk.h>
+#include <stdbool.h>
+
+#ifndef BOOL
+#define BOOL bool
+#endif
+
+#define TYPE_{type}
/* Must use a typedef as there is no way of adding the code modifier
on the z80.
typedef void (*NOARGFUNPTR)(void);
typedef void (*ONEARGFUNPTR)({type}) REENTRANT;
typedef long int (*FOURARGFUNPTR)(char, char, long int, long int) REENTRANT;
+typedef {type} (*TYPEFUNPTR)({type}, {type}) REENTRANT;
int count;
FOURARGFUNPTR fafp;
+TYPEFUNPTR tfp;
void
incCount(void)
fptr();
}
+{type} f_ret({type} arg1, {type} arg2) REENTRANT
+{
+ {type} local;
+ local = !arg1;
+ return (local & arg2);
+}
+
void
callViaPtr(incCount);
ASSERT(count == 1);
callViaPtr2(incBy, 7);
- ASSERT(count == 8);
+ ASSERT(count == 8 || count == 2);
ASSERT((*fafp)(0, 0x55, 0x12345678, 0x9abcdef0) == 0);
ASSERT((*fafp)(1, 0x55, 0x12345678, 0x9abcdef0) == 0x55);
callViaPtrAnsi(incCount);
ASSERT(count == 1);
callViaPtr2Ansi(incBy, 7);
- ASSERT(count == 8);
+ ASSERT(count == 8 || count == 2);
ASSERT(fafp(0, 0x55, 0x12345678, 0x9abcdef0) == 0);
ASSERT(fafp(1, 0x55, 0x12345678, 0x9abcdef0) == 0x55);
ASSERT(fafp(3, 0x55, 0x12345678, 0x9abcdef0) == 0x9abcdef0);
}
+void
+testFunPtrReturn(void)
+{
+ tfp = f_ret;
+
+ ASSERT(tfp(0, 0) == 0);
+ ASSERT(tfp(0, 1) == 1);
+ ASSERT(tfp(1, 0) == 0);
+ ASSERT(tfp(1, 1) == 0);
+}
+