diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/ds390 | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/ds390')
| -rw-r--r-- | src/ds390/Makefile | 7 | ||||
| -rw-r--r-- | src/ds390/Makefile.in | 7 | ||||
| -rw-r--r-- | src/ds390/ds390.vcxproj | 151 | ||||
| -rw-r--r-- | src/ds390/ds390.vcxproj.filters | 43 | ||||
| -rw-r--r-- | src/ds390/gen.c | 14414 | ||||
| -rw-r--r-- | src/ds390/gen.h | 83 | ||||
| -rw-r--r-- | src/ds390/main.c | 1710 | ||||
| -rw-r--r-- | src/ds390/main.h | 46 | ||||
| -rw-r--r-- | src/ds390/peeph.def | 2856 | ||||
| -rw-r--r-- | src/ds390/ralloc.c | 3501 | ||||
| -rw-r--r-- | src/ds390/ralloc.h | 75 |
11 files changed, 22893 insertions, 0 deletions
diff --git a/src/ds390/Makefile b/src/ds390/Makefile new file mode 100644 index 0000000..cb704c7 --- /dev/null +++ b/src/ds390/Makefile @@ -0,0 +1,7 @@ + +srcdir = . +top_builddir = ../.. +top_srcdir = ../.. + +# Make all in this directory +include $(srcdir)/../port.mk diff --git a/src/ds390/Makefile.in b/src/ds390/Makefile.in new file mode 100644 index 0000000..dfb8a52 --- /dev/null +++ b/src/ds390/Makefile.in @@ -0,0 +1,7 @@ +VPATH = @srcdir@ +srcdir = @srcdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Make all in this directory +include $(srcdir)/../port.mk diff --git a/src/ds390/ds390.vcxproj b/src/ds390/ds390.vcxproj new file mode 100644 index 0000000..5d9e3df --- /dev/null +++ b/src/ds390/ds390.vcxproj @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{14A8A991-BAD6-49EB-84FB-6F6CF12B436D}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\SDCC.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">port</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">port</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeaderOutputFile>.\Debug/ds390.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug/ds390.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..;.;..\..;..\..\support\util;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;WIN32;_LIB;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeaderOutputFile>.\Release/ds390.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <Lib>
+ <OutputFile>$(Configuration)\$(TargetFileName)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release/ds390.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="gen.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="gen.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="ralloc.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\config.vcxproj">
+ <Project>{2f87ba6f-8ee1-48d0-9817-6ba30bddb3c1}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) >peeph.rul</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">gawk -f ../SDCCpeeph.awk %(Identity) >peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Generating Peephole Rule: peeph.rul</Message>
+ </CustomBuild>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/src/ds390/ds390.vcxproj.filters b/src/ds390/ds390.vcxproj.filters new file mode 100644 index 0000000..1dbe72d --- /dev/null +++ b/src/ds390/ds390.vcxproj.filters @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{ffbdd525-702b-4916-87ec-0dc8643d6ed5}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{72ff9e14-dc43-44b3-b62b-b2c627e1029b}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Custom Build">
+ <UniqueIdentifier>{e572d796-594f-4954-afda-65ca354e9b7f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="gen.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ralloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="gen.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ralloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="peeph.def">
+ <Filter>Custom Build</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/src/ds390/gen.c b/src/ds390/gen.c new file mode 100644 index 0000000..8ecc330 --- /dev/null +++ b/src/ds390/gen.c @@ -0,0 +1,14414 @@ +/*------------------------------------------------------------------------- + gen.c - source file for code generation for DS80C390 + + Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net + Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com + Bug Fixes - Wojciech Stryjewski wstryj1@tiger.lsu.edu (1999 v2.1.9a) + DS390 adaptation: + Copyright (C) 2000, Kevin Vigor <kevin@vigor.nu> + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +-------------------------------------------------------------------------*/ + +//#define D(x) +#define D(x) do if (options.verboseAsm) {x;} while(0) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "gen.h" +#include "dbuf_string.h" + +extern int allocInfo; + +/* this is the down and dirty file with all kinds of + kludgy & hacky stuff. This is what it is all about + CODE GENERATION for a specific MCU . some of the + routines may be reusable, will have to see */ + +static char *zero = "#0x00"; +static char *one = "#0x01"; +static char *spname; + +#define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); } +#define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); } + +unsigned fReturnSizeDS390 = 9; +static char *fReturn24[] = { "dpl", "dph", "dpx", "b", "a", "r4", "r5", "r6", "r7" }; +static char *fReturn16[] = { "dpl", "dph", "b", "a", "r4", "r5", "r6", "r7" }; + +static char **fReturn = fReturn24; +char **fReturnDS390 = fReturn24; +static char *accUse[] = { "a", "b" }; + +static char *dptrn[2][3]; +static char *javaRet[] = { "r0", "r1", "r2", "r3" }; + +static short rbank = -1; + +#define REG_WITH_INDEX ds390_regWithIdx + +#define AOP(op) op->aop +#define AOP_TYPE(op) AOP(op)->type +#define AOP_SIZE(op) AOP(op)->size +#define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \ + AOP_TYPE(x) == AOP_R0)) + +#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY || \ + AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \ + AOP(x)->paged)) + +#define AOP_INPREG(x) (x && (x->type == AOP_REG && \ + (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \ + x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) ))) +#define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn) +#define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR)) +#define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn)) + +// The following macro can be used even if the aop has not yet been aopOp'd. +#define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr) + +/* Workaround for DS80C390 bug: div ab may return bogus results + * if A is accessed in instruction immediately before the div. + * + * Will be fixed in B4 rev of processor, Dallas claims. + */ + +#define LOAD_AB_FOR_DIV(LEFT, RIGHT) \ + if (!AOP_NEEDSACC (RIGHT)) \ + { \ + /* We can load A first, then B, since \ + * B (the RIGHT operand) won't clobber A, \ + * thus avoiding touching A right before the div. \ + */ \ + D (emitcode (";", "DS80C390 div bug: rearranged ops.")); \ + MOVA (aopGet (LEFT, 0, FALSE, FALSE, NULL)); \ + MOVB (aopGet (RIGHT, 0, FALSE, FALSE, "b")); \ + } \ + else \ + { \ + /* Just stuff in a nop after loading A. */ \ + emitcode ("mov", "b,%s", aopGet (RIGHT, 0, FALSE, FALSE, NULL)); \ + MOVA (aopGet (LEFT, 0, FALSE, FALSE, NULL)); \ + emitcode("nop", "; workaround for DS80C390 div bug."); \ + } + +#define EQ(a, b) (strcmp (a, b) == 0) + +#define R0INB _G.bu.bs.r0InB +#define R1INB _G.bu.bs.r1InB +#define OPINB _G.bu.bs.OpInB +#define BINUSE _G.bu.BInUse + +static struct +{ + short r0Pushed; + short r1Pushed; + union + { + struct + { + short r0InB: 2; //2 so we can see it overflow + short r1InB: 2; //2 so we can see it overflow + short OpInB: 2; //2 so we can see it overflow + } bs; + short BInUse; + } bu; + short accInUse; + short nRegsSaved; + short dptrInUse; + short dptr1InUse; + set *sendSet; + symbol *currentFunc; +} +_G; + +static char *rb1regs[] = +{ + "b1_0", "b1_1", "b1_2", "b1_3", "b1_4", "b1_5", "b1_6", "b1_7", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7" +}; + +static void saveRBank (int, iCode *, bool); + +#define RESULTONSTACK(x) \ + (IC_RESULT (x) && IC_RESULT (x)->aop && \ + IC_RESULT (x)->aop->type == AOP_STK ) + +#define MOVA(x) mova (x) /* use function to avoid multiple eval */ +#define MOVB(x) movb (x) + +#define CLRC emitcode ("clr","c") +#define SETC emitcode ("setb","c") + +/* A scratch register which will be used to hold + * result bytes from operands in far space via DPTR2. */ +#define DP2_RESULT_REG "acc1" + +static unsigned char SLMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, + 0xE0, 0xC0, 0x80, 0x00 + }; + +static unsigned char SRMask[] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, + 0x07, 0x03, 0x01, 0x00 + }; + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 +#define PROTECT_SP { \ + if (options.protect_sp_update) \ + { \ + symbol *lbl = newiTempLabel (NULL); \ + emitcode ("setb", "F1"); \ + emitcode ("jbc", "EA,!tlabel", labelKey2num (lbl->key)); \ + emitcode ("clr", "F1"); \ + emitLabel (lbl); \ + } \ + } +#define UNPROTECT_SP { \ + if (options.protect_sp_update) \ + { \ + emitcode ("mov", "EA,F1"); \ + } \ + } + +static int _currentDPS; /* Current processor DPS. */ +static int _desiredDPS; /* DPS value compiler thinks we should be using. */ +static int _lazyDPS = 0; /* if non-zero, we are doing lazy evaluation of DPS changes. */ + +/*-----------------------------------------------------------------*/ +/* ds390_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +ds390_emitDebuggerSymbol (const char *debugSym) +{ + genLine.lineElement.isDebug = 1; + emitcode ("", "%s ==.", debugSym); + genLine.lineElement.isDebug = 0; +} + +/*-----------------------------------------------------------------*/ +/* mova - moves specified value into accumulator */ +/*-----------------------------------------------------------------*/ +static void +mova (const char *x) +{ + /* do some early peephole optimization */ + if (!strncmp (x, "a", 2) || !strncmp (x, "acc", 4)) + return; + + /* another early peephole optimization */ + if (EQ (x, "#0x00")) + { + emitcode ("clr", "a"); + return; + } + + emitcode ("mov", "a,%s", x); +} + +/*-----------------------------------------------------------------*/ +/* movb - moves specified value into register b */ +/*-----------------------------------------------------------------*/ +static void +movb (const char *x) +{ + /* do some early peephole optimization */ + if (!strncmp (x, "b", 2)) + return; + + emitcode ("mov", "b,%s", x); +} + +/*-----------------------------------------------------------------*/ +/* emitpush - push something on internal stack */ +/*-----------------------------------------------------------------*/ +static void +emitpush (const char *arg) +{ + char buf[] = "ar?"; + + if (!arg) + { + emitcode ("inc", "sp"); + return; + } + else if (EQ (arg, "a")) + { + arg = "acc"; + } + else if ((*arg == '@') || (*arg == '#')) + { + MOVA (arg); + arg = "acc"; + } + else if (EQ (arg, "r0") || EQ (arg, "r1") || EQ (arg, "r2") || EQ (arg, "r3") || + EQ (arg, "r4") || EQ (arg, "r5") || EQ (arg, "r6") || EQ (arg, "r7")) + { + buf[2] = arg[1]; + arg = buf; + } + emitcode ("push", arg); +} + +/*-----------------------------------------------------------------*/ +/* emitpop - pop something from internal stack */ +/*-----------------------------------------------------------------*/ +static void +emitpop (const char *arg) +{ + if (!arg) + emitcode ("dec", "sp"); + else + emitcode ("pop", arg); +} + +/*-----------------------------------------------------------------*/ +/* pushB - saves register B if necessary */ +/*-----------------------------------------------------------------*/ +static bool +pushB (void) +{ + bool pushedB = FALSE; + + if (BINUSE) + { + emitpush ("b"); +// printf("B was in use !\n"); + pushedB = TRUE; + } + else + { + OPINB++; + } + return pushedB; +} + +/*-----------------------------------------------------------------*/ +/* popB - restores value of register B if necessary */ +/*-----------------------------------------------------------------*/ +static void +popB (bool pushedB) +{ + if (pushedB) + { + emitpop ("b"); + } + else + { + OPINB--; + } +} + +/*-----------------------------------------------------------------*/ +/* pushReg - saves register */ +/*-----------------------------------------------------------------*/ +static bool +pushReg (int index, bool bits_pushed) +{ + const reg_info *reg = REG_WITH_INDEX (index); + if (reg->type == REG_BIT) + { + if (!bits_pushed) + emitpush (reg->base); + return TRUE; + } + else + emitpush (reg->dname); + return bits_pushed; +} + +/*-----------------------------------------------------------------*/ +/* popReg - restores register */ +/*-----------------------------------------------------------------*/ +static bool +popReg (int index, bool bits_popped) +{ + const reg_info *reg = REG_WITH_INDEX (index); + if (reg->type == REG_BIT) + { + if (!bits_popped) + emitpop (reg->base); + return TRUE; + } + else + emitpop (reg->dname); + return bits_popped; +} + +/*-----------------------------------------------------------------*/ +/* getFreePtr - returns r0 or r1 whichever is free or can be pushed */ +/*-----------------------------------------------------------------*/ +static reg_info * +getFreePtr (iCode * ic, asmop ** aopp, bool result) +{ + bool r0iu, r1iu; + bool r0ou, r1ou; + + /* the logic: if r0 & r1 used in the instruction + then we are in trouble otherwise */ + + /* first check if r0 & r1 are used by this + instruction, in which case we are in trouble */ + r0iu = bitVectBitValue (ic->rUsed, R0_IDX); + r1iu = bitVectBitValue (ic->rUsed, R1_IDX); + if (r0iu && r1iu) + { + goto endOfWorld; + } + + r0ou = bitVectBitValue (ic->rMask, R0_IDX); + r1ou = bitVectBitValue (ic->rMask, R1_IDX); + + /* if no usage of r0 then return it */ + if (!r0iu && !r0ou) + { + ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX); + } + + /* if no usage of r1 then return it */ + if (!r1iu && !r1ou) + { + ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX); + (*aopp)->type = AOP_R1; + + return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX); + } + + /* now we know they both have usage */ + /* if r0 not used in this instruction */ + if (!r0iu) + { + /* push it if not already pushed */ + if (!_G.r0Pushed) + { + emitpush (REG_WITH_INDEX (R0_IDX)->dname); + _G.r0Pushed++; + } + + ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX); + (*aopp)->type = AOP_R0; + + return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX); + } + + /* if r1 not used then */ + + if (!r1iu) + { + /* push it if not already pushed */ + if (!_G.r1Pushed) + { + emitpush (REG_WITH_INDEX (R1_IDX)->dname); + _G.r1Pushed++; + } + + ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX); + (*aopp)->type = AOP_R1; + return REG_WITH_INDEX (R1_IDX); + } + +endOfWorld: + /* I said end of world, but not quite end of world yet */ + /* if this is a result then we can push it on the stack */ + if (result) + { + (*aopp)->type = AOP_STK; + return NULL; + } + + /* now this is REALLY the end of the world */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "getFreePtr should never reach here"); + exit (EXIT_FAILURE); + + return NULL; // notreached, but makes compiler happy. +} + + +/*-----------------------------------------------------------------*/ +/* genSetDPTR: generate code to select which DPTR is in use (zero */ +/* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390 */ +/* alternate DPTR (DPL1/DPH1/DPX1). */ +/*-----------------------------------------------------------------*/ +static void +genSetDPTR (int n) +{ + /* If we are doing lazy evaluation, simply note the desired + * change, but don't emit any code yet. + */ + if (_lazyDPS) + { + _desiredDPS = n; + return; + } + + if (!n) + { + emitcode ("mov", "dps,#0"); + } + else + { + TR_DPTR ("#1"); + emitcode ("mov", "dps,#1"); + } +} + +/*------------------------------------------------------------------*/ +/* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */ +/* */ +/* Any code that operates on DPTR (NB: not on the individual */ +/* components, like DPH) *must* call _flushLazyDPS() before using */ +/* DPTR within a lazy DPS evaluation block. */ +/* */ +/* Note that aopPut and aopGet already contain the proper calls to */ +/* _flushLazyDPS, so it is safe to use these calls within a lazy */ +/* DPS evaluation block. */ +/* */ +/* Also, _flushLazyDPS must be called before any flow control */ +/* operations that could potentially branch out of the block. */ +/* */ +/* Lazy DPS evaluation is simply an optimization (though an */ +/* important one), so if in doubt, leave it out. */ +/*------------------------------------------------------------------*/ +static void +_startLazyDPSEvaluation (void) +{ + _currentDPS = 0; + _desiredDPS = 0; + _lazyDPS++; +} + +/*------------------------------------------------------------------*/ +/* _flushLazyDPS: emit code to force the actual DPS setting to the */ +/* desired one. Call before using DPTR within a lazy DPS evaluation */ +/* block. */ +/*------------------------------------------------------------------*/ +static void +_flushLazyDPS (void) +{ + if (!_lazyDPS) + { + /* nothing to do. */ + return; + } + + if (_desiredDPS != _currentDPS) + { + if (_desiredDPS) + { + emitcode ("inc", "dps"); + } + else + { + emitcode ("dec", "dps"); + } + _currentDPS = _desiredDPS; + } +} + +/*-----------------------------------------------------------------*/ +/* _endLazyDPSEvaluation: end lazy DPS evaluation block. */ +/* */ +/* Forces us back to the safe state (standard DPTR selected). */ +/*-----------------------------------------------------------------*/ +static void +_endLazyDPSEvaluation (void) +{ + _lazyDPS--; + if (!_lazyDPS) + { + if (_currentDPS) + { + genSetDPTR (0); + _flushLazyDPS (); + } + _currentDPS = 0; + _desiredDPS = 0; + } +} + + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop * +newAsmop (short type) +{ + asmop *aop; + + aop = Safe_calloc (1, sizeof (asmop)); + aop->type = type; + aop->allocated = 1; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* pointerCode - returns the code for a pointer type */ +/*-----------------------------------------------------------------*/ +static int +pointerCode (sym_link * etype) +{ + return PTR_TYPE (SPEC_OCLS (etype)); +} + +/*-----------------------------------------------------------------*/ +/* leftRightUseAcc - returns size of accumulator use by operands */ +/*-----------------------------------------------------------------*/ +static int +leftRightUseAcc (iCode * ic) +{ + operand *op; + int size; + int accuseSize = 0; + int accuse = 0; + + if (!ic) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "null iCode pointer"); + return 0; + } + + if (ic->op == IFX) + { + op = IC_COND (ic); + if (IS_OP_ACCUSE (op)) + { + accuse = 1; + size = getSize (OP_SYMBOL (op)->type); + if (size > accuseSize) + accuseSize = size; + } + } + else if (ic->op == JUMPTABLE) + { + op = IC_JTCOND (ic); + if (IS_OP_ACCUSE (op)) + { + accuse = 1; + size = getSize (OP_SYMBOL (op)->type); + if (size > accuseSize) + accuseSize = size; + } + } + else + { + op = IC_LEFT (ic); + if (IS_OP_ACCUSE (op)) + { + accuse = 1; + size = getSize (OP_SYMBOL (op)->type); + if (size > accuseSize) + accuseSize = size; + } + op = IC_RIGHT (ic); + if (IS_OP_ACCUSE (op)) + { + accuse = 1; + size = getSize (OP_SYMBOL (op)->type); + if (size > accuseSize) + accuseSize = size; + } + } + + if (accuseSize) + return accuseSize; + else + return accuse; +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2) +{ + asmop *aop; + memmap *space; + bool accuse = leftRightUseAcc (ic) || _G.accInUse; + char *dpl = useDP2 ? "dpl1" : "dpl"; + char *dph = useDP2 ? "dph1" : "dph"; + char *dpx = useDP2 ? "dpx1" : "dpx"; + + wassertl (ic != NULL, "Got a null iCode"); + wassertl (sym != NULL, "Got a null symbol"); + + space = SPEC_OCLS (sym->etype); + + /* if already has one */ + if (sym->aop) + { + if ((sym->aop->type == AOP_DPTR && useDP2) || (sym->aop->type == AOP_DPTR2 && !useDP2)) + sym->aop = NULL; + else + { + sym->aop->allocated++; + return sym->aop; + } + } + + /* assign depending on the storage class */ + /* if it is on the stack or indirectly addressable */ + /* space we need to assign either r0 or r1 to it */ + if ((sym->onStack && !options.stack10bit) || sym->iaccess) + { + sym->aop = aop = newAsmop (0); + aop->aopu.aop_ptr = getFreePtr (ic, &aop, result); + aop->size = getSize (sym->type); + + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) + { + if (sym->onStack) + { + signed char offset = ((sym->stack < 0) ? + ((signed char) (sym->stack - _G.nRegsSaved)) : ((signed char) sym->stack)) & 0xff; + + if ((abs (offset) <= 3) || (accuse && (abs (offset) <= 7))) + { + emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name); + while (offset < 0) + { + emitcode ("dec", aop->aopu.aop_ptr->name); + offset++; + } + while (offset > 0) + { + emitcode ("inc", aop->aopu.aop_ptr->name); + offset--; + } + } + else + { + if (accuse) + emitcode ("push", "acc"); + emitcode ("mov", "a,_bp"); + emitcode ("add", "a,#!constbyte", offset); + emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name); + if (accuse) + emitcode ("pop", "acc"); + } + } + else + { + emitcode ("mov", "%s,#%s", aop->aopu.aop_ptr->name, sym->rname); + } + aop->paged = space->paged; + } + else + aop->aopu.aop_stk = sym->stack; + return aop; + } + + if (sym->onStack && options.stack10bit) + { + short stack_val = -((sym->stack < 0) ? ((short) (sym->stack - _G.nRegsSaved)) : ((short) sym->stack)); + if (_G.dptrInUse) + { + emitcode ("push", dpl); + emitcode ("push", dph); + emitcode ("push", dpx); + } + /* It's on the 10 bit stack, which is located in + * far data space. + */ + if (stack_val < 0 && stack_val > -5) + { + /* between -5 & -1 */ + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "%s,#!constbyte", dpx, (options.stack_loc >> 16) & 0xff); + } + emitcode ("mov", "%s,_bpx+1", dph); + emitcode ("mov", "%s,_bpx", dpl); + if (useDP2) + { + emitcode ("mov", "dps,#1"); + } + stack_val = -stack_val; + while (stack_val--) + { + emitcode ("inc", "dptr"); + } + if (useDP2) + { + emitcode ("mov", "dps,#0"); + } + } + else + { + if (accuse) + emitcode ("push", "acc"); + + emitcode ("mov", "a,_bpx"); + emitcode ("clr", "c"); + emitcode ("subb", "a,#!constbyte", stack_val & 0xff); + emitcode ("mov", "%s,a", dpl); + emitcode ("mov", "a,_bpx+1"); + emitcode ("subb", "a,#!constbyte", (stack_val >> 8) & 0xff); + emitcode ("mov", "%s,a", dph); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "%s,#!constbyte", dpx, (options.stack_loc >> 16) & 0xff); + } + + if (accuse) + emitcode ("pop", "acc"); + } + sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR)); + aop->size = getSize (sym->type); + return aop; + } + + /* if in bit space */ + if (IN_BITSPACE (space)) + { + sym->aop = aop = newAsmop (AOP_CRY); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + return aop; + } + /* if it is in direct space */ + if (IN_DIRSPACE (space)) + { + sym->aop = aop = newAsmop (AOP_DIR); + aop->aopu.aop_dir = sym->rname; + aop->size = getSize (sym->type); + return aop; + } + + /* special case for a function */ + if (IS_FUNC (sym->type) && !(sym->isitmp)) + { + sym->aop = aop = newAsmop (AOP_IMMD); + aop->aopu.aop_immd.aop_immd1 = Safe_strdup (sym->rname); + aop->size = getSize (sym->type); + return aop; + } + + /* only remaining is far space */ + /* in which case DPTR gets the address */ + sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR)); + if (useDP2) + { + genSetDPTR (1); + _flushLazyDPS (); + emitcode ("mov", "dptr,#%s", sym->rname); + genSetDPTR (0); + } + else + { + emitcode ("mov", "dptr,#%s", sym->rname); + } + aop->size = getSize (sym->type); + + /* if it is in code space */ + if (IN_CODESPACE (space)) + aop->code = 1; + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerializes an object */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForRemat (symbol * sym) +{ + iCode *ic = sym->rematiCode; + asmop *aop = newAsmop (AOP_IMMD); + int ptr_type = 0; + int val = 0; + struct dbuf_s dbuf; + + for (;;) + { + if (ic->op == '+') + val += (int) operandLitValue (IC_RIGHT (ic)); + else if (ic->op == '-') + val -= (int) operandLitValue (IC_RIGHT (ic)); + else if (IS_CAST_ICODE (ic)) + { + sym_link *from_type = operandType (IC_RIGHT (ic)); + aop->aopu.aop_immd.from_cast_remat = 1; + ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + ptr_type = pointerTypeToGPByte (DCL_TYPE (from_type), + IS_SYMOP (IC_RIGHT (ic)) ? OP_SYMBOL (IC_RIGHT (ic))->name : NULL, sym->name); + continue; + } + else + break; + + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + } + + dbuf_init (&dbuf, 128); + if (val) + { + dbuf_printf (&dbuf, "(%s %c 0x%06x)", OP_SYMBOL (IC_LEFT (ic))->rname, val >= 0 ? '+' : '-', abs (val) & 0xffffff); + } + else + { + if (IS_ASSIGN_ICODE (ic) && isOperandLiteral (IC_RIGHT (ic))) + { + dbuf_printf (&dbuf, "0x%06x", (int) operandLitValue (IC_RIGHT (ic))); + } + else + { + dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname); + } + } + + aop->aopu.aop_immd.aop_immd1 = dbuf_detach_c_str (&dbuf); + /* set immd2 field if required */ + if (aop->aopu.aop_immd.from_cast_remat) + { + dbuf_init (&dbuf, 128); + dbuf_tprintf (&dbuf, "#!constbyte", ptr_type); + aop->aopu.aop_immd.aop_immd2 = dbuf_detach_c_str (&dbuf); + } + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopHasRegs - returns true if aop has regs between from-to */ +/*-----------------------------------------------------------------*/ +static int +aopHasRegs (asmop * aop, int from, int to) +{ + int size = 0; + + if (aop->type != AOP_REG) + return 0; /* if not assigned to regs */ + + for (; size < aop->size; size++) + { + int reg; + for (reg = from; reg <= to; reg++) + if (aop->aopu.aop_reg[size] == REG_WITH_INDEX (reg)) + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* regsInCommon - two operands have some registers in common */ +/*-----------------------------------------------------------------*/ +static bool +regsInCommon (operand * op1, operand * op2) +{ + symbol *sym1, *sym2; + int i; + + /* if they have registers in common */ + if (!IS_SYMOP (op1) || !IS_SYMOP (op2)) + return FALSE; + + sym1 = OP_SYMBOL (op1); + sym2 = OP_SYMBOL (op2); + + if (sym1->nRegs == 0 || sym2->nRegs == 0) + return FALSE; + + for (i = 0; i < sym1->nRegs; i++) + { + int j; + if (!sym1->regs[i]) + continue; + + for (j = 0; j < sym2->nRegs; j++) + { + if (!sym2->regs[j]) + continue; + + if (sym2->regs[j] == sym1->regs[i]) + return TRUE; + } + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* operandsEqu - equivalent */ +/*-----------------------------------------------------------------*/ +static bool +operandsEqu (operand * op1, operand * op2) +{ + symbol *sym1, *sym2; + + /* if they're not symbols */ + if (!IS_SYMOP (op1) || !IS_SYMOP (op2)) + return FALSE; + + sym1 = OP_SYMBOL (op1); + sym2 = OP_SYMBOL (op2); + + /* if both are itemps & one is spilt + and the other is not then false */ + if (IS_ITEMP (op1) && IS_ITEMP (op2) && sym1->isspilt != sym2->isspilt) + return FALSE; + + /* if they are the same */ + if (sym1 == sym2) + return TRUE; + + /* if they have the same rname */ + if (sym1->rname[0] && sym2->rname[0] && EQ (sym1->rname, sym2->rname) && !(IS_PARM (op2) && IS_ITEMP (op1))) + return TRUE; + + /* if left is a tmp & right is not */ + if (IS_ITEMP (op1) && !IS_ITEMP (op2) && sym1->isspilt && (sym1->usl.spillLoc == sym2)) + return TRUE; + + if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (sym2->usl.spillLoc == sym1)) + return TRUE; + + /* are they spilt to the same location */ + if (IS_ITEMP (op2) && IS_ITEMP (op1) && sym2->isspilt && sym1->isspilt && (sym1->usl.spillLoc == sym2->usl.spillLoc)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* sameByte - two asmops have the same address at given offsets */ +/*-----------------------------------------------------------------*/ +static bool +sameByte (asmop * aop1, int off1, asmop * aop2, int off2) +{ + if (aop1 == aop2 && off1 == off2) + return TRUE; + + if (aop1->type != AOP_REG && aop1->type != AOP_CRY) + return FALSE; + + if (aop1->type != aop2->type) + return FALSE; + + if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2]) + return FALSE; + + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +static bool +sameRegs (asmop * aop1, asmop * aop2) +{ + int i; + + if (aop1 == aop2) + { + if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2) + { + return FALSE; + } + return TRUE; + } + + if (aop1->type != AOP_REG && aop1->type != AOP_CRY) + return FALSE; + + if (aop1->type != aop2->type) + return FALSE; + + if (aop1->size != aop2->size) + return FALSE; + + for (i = 0; i < aop1->size; i++) + if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i]) + return FALSE; + + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* aopOp - allocates an asmop for an operand : */ +/*-----------------------------------------------------------------*/ +static void +aopOp (operand * op, iCode * ic, bool result, bool useDP2) +{ + asmop *aop; + symbol *sym; + int i; + + if (!op) + return; + + /* if this a literal */ + if (IS_OP_LITERAL (op)) + { + op->aop = aop = newAsmop (AOP_LIT); + aop->aopu.aop_lit = OP_VALUE (op); + aop->size = getSize (operandType (op)); + return; + } + + /* if already has a asmop then continue */ + if (op->aop) + { + if ((op->aop->type == AOP_DPTR && useDP2) || (op->aop->type == AOP_DPTR2 && !useDP2)) + op->aop = NULL; + else + { + op->aop->allocated++; + return; + } + } + + /* if the underlying symbol has a aop */ + if (IS_SYMOP (op) && OP_SYMBOL (op)->aop) + { + op->aop = OP_SYMBOL (op)->aop; + if ((op->aop->type == AOP_DPTR && useDP2) || (op->aop->type == AOP_DPTR2 && !useDP2)) + op->aop = NULL; + else + { + op->aop->allocated++; + return; + } + } + + /* if this is a true symbol */ + if (IS_TRUE_SYMOP (op)) + { + op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2); + return; + } + + /* this is a temporary : this has + only five choices : + a) register + b) spillocation + c) rematerialize + d) conditional + e) can be a return use only */ + + sym = OP_SYMBOL (op); + + /* if the type is a conditional */ + if (sym->regType == REG_CND) + { + sym->aop = op->aop = aop = newAsmop (AOP_CRY); + aop->size = 0; + return; + } + + /* if it is spilt then two situations + a) is rematerialize + b) has a spill location */ + if (sym->isspilt || sym->nRegs == 0) + { + /* rematerialize it NOW */ + if (sym->remat) + { + sym->aop = op->aop = aop = aopForRemat (sym); + aop->size = operandSize (op); + return; + } + + if (sym->accuse) + { + int i; + sym->aop = op->aop = aop = newAsmop (AOP_ACC); + aop->size = getSize (sym->type); + for (i = 0; i < 2; i++) + aop->aopu.aop_str[i] = accUse[i]; + return; + } + + if (sym->ruonly) + { + unsigned i; + + if (useDP2) + { + /* a AOP_STR uses DPTR, but DPTR is already in use; + * we're just hosed. + */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "AOP_STR with DPTR in use!"); + } + + sym->aop = op->aop = aop = newAsmop (AOP_STR); + aop->size = getSize (sym->type); + for (i = 0; i < fReturnSizeDS390; i++) + aop->aopu.aop_str[i] = fReturn[i]; + return; + } + + if (sym->dptr) + { + /* has been allocated to a DPTRn */ + sym->aop = op->aop = aop = newAsmop (AOP_DPTRn); + aop->size = getSize (sym->type); + aop->aopu.dptr = sym->dptr; + return; + } + + if (sym->isspilt && sym->usl.spillLoc) + { + asmop *oldAsmOp = NULL; + + if (getSize (sym->type) != getSize (sym->usl.spillLoc->type)) + { + /* force a new aop if sizes differ */ + oldAsmOp = sym->usl.spillLoc->aop; + sym->usl.spillLoc->aop = NULL; + } + sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, result, useDP2); + if (getSize (sym->type) != getSize (sym->usl.spillLoc->type)) + { + /* Don't reuse the new aop, go with the last one */ + sym->usl.spillLoc->aop = oldAsmOp; + } + aop->size = getSize (sym->type); + return; + } + + /* else must be a dummy iTemp */ + sym->aop = op->aop = aop = newAsmop (AOP_DUMMY); + aop->size = getSize (sym->type); + return; + } + + /* if the type is a bit register */ + if (sym->regType == REG_BIT) + { + sym->aop = op->aop = aop = newAsmop (AOP_CRY); + aop->size = sym->nRegs; //1??? + aop->aopu.aop_reg[0] = sym->regs[0]; + aop->aopu.aop_dir = sym->regs[0]->name; + return; + } + + /* must be in a register */ + sym->aop = op->aop = aop = newAsmop (AOP_REG); + aop->size = sym->nRegs; + for (i = 0; i < sym->nRegs; i++) + aop->aopu.aop_reg[i] = sym->regs[i]; +} + +/*-----------------------------------------------------------------*/ +/* freeAsmop - free up the asmop given to an operand */ +/*-----------------------------------------------------------------*/ +static void +freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop) +{ + asmop *aop; + + if (!op) + aop = aaop; + else + aop = op->aop; + + if (!aop) + return; + + aop->allocated--; + + if (aop->allocated) + goto dealloc; + + /* depending on the asmop type only three cases need work + AOP_R0, AOP_R1 & AOP_STK */ + switch (aop->type) + { + case AOP_R0: + if (_G.r0Pushed) + { + if (pop) + { + emitpop ("ar0"); + _G.r0Pushed--; + } + } + bitVectUnSetBit (ic->rUsed, R0_IDX); + break; + + case AOP_R1: + if (_G.r1Pushed) + { + if (pop) + { + emitpop ("ar1"); + _G.r1Pushed--; + } + } + bitVectUnSetBit (ic->rUsed, R1_IDX); + break; + + case AOP_STK: + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit (ic->rUsed, R0_IDX); + bitVectUnSetBit (ic->rUsed, R1_IDX); + + getFreePtr (ic, &aop, FALSE); + + if (options.stack10bit) + { + /* I'm not sure what to do here yet... */ + /* #STUB */ + fprintf (stderr, "*** Warning: probably generating bad code for " "10 bit stack mode.\n"); + } + + if (stk) + { + emitcode ("mov", "a,_bp"); + emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff); + emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name); + } + else + { + emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name); + } + + while (sz--) + { + emitpop ("acc"); + emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name); + if (!sz) + break; + emitcode ("dec", "%s", aop->aopu.aop_ptr->name); + } + op->aop = aop; + freeAsmop (op, NULL, ic, TRUE); + if (_G.r1Pushed) + { + emitpop ("ar1"); + _G.r1Pushed--; + } + if (_G.r0Pushed) + { + emitpop ("ar0"); + _G.r0Pushed--; + } + } + case AOP_DPTR2: + if (_G.dptr1InUse) + { + emitpop ("dpx1"); + emitpop ("dph1"); + emitpop ("dpl1"); + } + break; + case AOP_DPTR: + if (_G.dptrInUse) + { + emitpop ("dpx"); + emitpop ("dph"); + emitpop ("dpl"); + } + break; + } + +dealloc: + /* all other cases just dealloc */ + if (op) + { + op->aop = NULL; + if (IS_SYMOP (op)) + { + OP_SYMBOL (op)->aop = NULL; + /* if the symbol has a spill */ + if (SPIL_LOC (op)) + SPIL_LOC (op)->aop = NULL; + } + } +} + +#define DEFAULT_ACC_WARNING 0 +static int saveAccWarn = DEFAULT_ACC_WARNING; + +/*-----------------------------------------------------------------*/ +/* opIsGptr: returns non-zero if the passed operand is */ +/* a generic pointer type. */ +/*-----------------------------------------------------------------*/ +static int +opIsGptr (operand * op) +{ + if (op && (AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (operandType (op))) + { + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* swapOperands - swap two operands */ +/*-----------------------------------------------------------------*/ +static void +swapOperands (operand ** left, operand ** right) +{ + operand *t = *right; + *right = *left; + *left = t; +} + +/*-----------------------------------------------------------------*/ +/* aopGetUsesAcc - indicates ahead of time whether aopGet() will */ +/* clobber the accumulator */ +/*-----------------------------------------------------------------*/ +static bool +aopGetUsesAcc (operand * oper, int offset) +{ + asmop *aop = AOP (oper); + + if (offset > (aop->size - 1)) + return FALSE; + + switch (aop->type) + { + case AOP_R0: + case AOP_R1: + if (aop->paged) + return TRUE; + return FALSE; + case AOP_DPTR: + case AOP_DPTR2: + case AOP_DPTRn: + return TRUE; + case AOP_IMMD: + return FALSE; + case AOP_DIR: + return FALSE; + case AOP_REG: + wassert (!EQ (aop->aopu.aop_reg[offset]->name, "a")); + return FALSE; + case AOP_CRY: + return TRUE; + case AOP_ACC: + if (offset) + return FALSE; + return TRUE; + case AOP_LIT: + return FALSE; + case AOP_STR: + if (EQ (aop->aopu.aop_str[offset], "a")) + return TRUE; + return FALSE; + case AOP_DUMMY: + return FALSE; + default: + /* Error case --- will have been caught already */ + wassert (0); + return FALSE; + } +} + +/*-------------------------------------------------------------------*/ +/* aopGet - for fetching value of the aop */ +/* */ +/* Set saveAcc to NULL if you are sure it is OK to clobber the value */ +/* in the accumulator. Set it to the name of a free register */ +/* if acc must be preserved; the register will be used to preserve */ +/* acc temporarily and to return the result byte. */ +/*-------------------------------------------------------------------*/ +/* + * NOTE: function returns a pointer to a reusable dynamically allocated + * buffer, which should never be freed! + * Subsequent call to aopGet() will rewrite the result of the previous + * call, so the content of the result should be copied to an other + * location, usually using Safe_strdup(), in order to perserve it. + */ +static const char * +aopGet (operand * oper, int offset, bool bit16, bool dname, char *saveAcc) +{ + asmop *aop = AOP (oper); + static struct dbuf_s dbuf = { 0 }; + + if (dbuf_is_initialized (&dbuf)) + { + /* reuse the dynamically allocated buffer */ + dbuf_set_length (&dbuf, 0); + } + else + { + /* first time: initialize the dynamically allocated buffer */ + dbuf_init (&dbuf, 128); + } + + /* offset is greater than + size then zero */ + if (offset > (aop->size - 1) && aop->type != AOP_LIT) + { + dbuf_append_str (&dbuf, zero); + } + else + { + /* depending on type */ + switch (aop->type) + { + case AOP_DUMMY: + dbuf_append_str (&dbuf, zero); + break; + + case AOP_R0: + case AOP_R1: + /* if we need to increment it */ + while (offset > aop->coff) + { + emitcode ("inc", "%s", aop->aopu.aop_ptr->name); + aop->coff++; + } + + while (offset < aop->coff) + { + emitcode ("dec", "%s", aop->aopu.aop_ptr->name); + aop->coff--; + } + + aop->coff = offset; + if (aop->paged) + { + emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name); + dbuf_append_str (&dbuf, dname ? "acc" : "a"); + } + else + { + dbuf_printf (&dbuf, "@%s", aop->aopu.aop_ptr->name); + } + break; + + case AOP_DPTRn: + assert (offset <= 3); + dbuf_append_str (&dbuf, dptrn[aop->aopu.dptr][offset]); + break; + + case AOP_DPTR: + case AOP_DPTR2: + + if (aop->type == AOP_DPTR2) + { + genSetDPTR (1); + } + + if (saveAcc) + { + TR_AP ("#1"); +// if (aop->type != AOP_DPTR2) +// { +// if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); } +// emitcode(";", "spanky: saveAcc for DPTR"); +// } + + emitcode ("xch", "a, %s", saveAcc); + } + + _flushLazyDPS (); + + while (offset > aop->coff) + { + emitcode ("inc", "dptr"); + aop->coff++; + } + + while (offset < aop->coff) + { + emitcode ("lcall", "__decdptr"); + aop->coff--; + } + + aop->coff = offset; + if (aop->code) + { + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + } + else + { + emitcode ("movx", "a,@dptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR (0); + } + + if (saveAcc) + { + TR_AP ("#2"); + emitcode ("xch", "a, %s", saveAcc); +// if (strcmp(saveAcc, "acc1")) +// { +// emitcode(";", "spiffy: non acc1 return from aopGet."); +// } + + dbuf_append_str (&dbuf, saveAcc); + } + else + { + dbuf_append_str (&dbuf, dname ? "acc" : "a"); + } + break; + + case AOP_IMMD: + if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size - 1))) + { + dbuf_printf (&dbuf, "%s", aop->aopu.aop_immd.aop_immd2); + } + else if (bit16) + { + dbuf_printf (&dbuf, "#%s", aop->aopu.aop_immd.aop_immd1); + } + else if (offset) + { + switch (offset) + { + case 1: + dbuf_tprintf (&dbuf, "#!his", aop->aopu.aop_immd.aop_immd1); + break; + case 2: + dbuf_tprintf (&dbuf, "#!hihis", aop->aopu.aop_immd.aop_immd1); + break; + case 3: + dbuf_tprintf (&dbuf, "#!hihihis", aop->aopu.aop_immd.aop_immd1); + break; + default: /* should not need this (just in case) */ + dbuf_printf (&dbuf, "#(%s >> %d)", aop->aopu.aop_immd.aop_immd1, offset * 8); + } + } + else + { + dbuf_printf (&dbuf, "#%s", aop->aopu.aop_immd.aop_immd1); + } + break; + + case AOP_DIR: + if ((SPEC_SCLS (getSpec (operandType (oper))) == S_SFR) && (aop->size > 1)) + { + dbuf_printf (&dbuf, "((%s >> %d) & 0xFF)", aop->aopu.aop_dir, offset * 8); + } + else if (offset) + { + dbuf_printf (&dbuf, "(%s + %d)", aop->aopu.aop_dir, offset); + } + else + { + dbuf_printf (&dbuf, "%s", aop->aopu.aop_dir); + } + break; + + case AOP_REG: + dbuf_append_str (&dbuf, dname ? aop->aopu.aop_reg[offset]->dname : aop->aopu.aop_reg[offset]->name); + break; + + case AOP_CRY: + emitcode ("mov", "c,%s", aop->aopu.aop_dir); + emitcode ("clr", "a"); + emitcode ("rlc", "a"); + dbuf_append_str (&dbuf, dname ? "acc" : "a"); + break; + + case AOP_ACC: + dbuf_append_str (&dbuf, (!offset && dname) ? "acc" : aop->aopu.aop_str[offset]); + break; + + case AOP_LIT: + { + int size = 1 + (bit16 ? (options.model == MODEL_FLAT24 ? 2 : 1) : 0); + dbuf_append_str (&dbuf, aopLiteralLong (aop->aopu.aop_lit, offset, size)); + } + break; + + case AOP_STR: + aop->coff = offset; + if (EQ (aop->aopu.aop_str[offset], "a") && dname) + dbuf_append_str (&dbuf, "acc"); + else + dbuf_append_str (&dbuf, aop->aopu.aop_str[offset]); + break; + + default: + dbuf_destroy (&dbuf); + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopget got unsupported aop->type"); + exit (EXIT_FAILURE); + } + } + return dbuf_c_str (&dbuf); +} + +/*-----------------------------------------------------------------*/ +/* aopPutUsesAcc - indicates ahead of time whether aopPut() will */ +/* clobber the accumulator */ +/*-----------------------------------------------------------------*/ +static bool +aopPutUsesAcc (operand * oper, const char *s, int offset) +{ + asmop *aop = AOP (oper); + + if (offset > (aop->size - 1)) + return FALSE; + + switch (aop->type) + { + case AOP_DUMMY: + return TRUE; + case AOP_DIR: + return FALSE; + case AOP_REG: + wassert (!EQ (aop->aopu.aop_reg[offset]->name, "a")); + return FALSE; + case AOP_DPTRn: + return FALSE; + case AOP_DPTR: + case AOP_DPTR2: + return TRUE; + case AOP_R0: + case AOP_R1: + return ((aop->paged) || (*s == '@')); + case AOP_STK: + return (*s == '@'); + case AOP_CRY: + return (!aop->aopu.aop_dir || !EQ (s, aop->aopu.aop_dir)); + case AOP_STR: + return FALSE; + case AOP_IMMD: + return FALSE; + case AOP_ACC: + return FALSE; + default: + /* Error case --- will have been caught already */ + wassert (0); + return FALSE; + } +} + +/*-----------------------------------------------------------------*/ +/* aopPut - puts a string for a aop and indicates if acc is in use */ +/*-----------------------------------------------------------------*/ +static bool +aopPut (operand * result, const char *s, int offset) +{ + bool bvolatile = isOperandVolatile (result, FALSE); + bool accuse = FALSE; + asmop *aop = AOP (result); + const char *d = NULL; + static struct dbuf_s dbuf = { 0 }; + + if (dbuf_is_initialized (&dbuf)) + { + /* reuse the dynamically allocated buffer */ + dbuf_set_length (&dbuf, 0); + } + else + { + /* first time: initialize the dynamically allocated buffer */ + dbuf_init (&dbuf, 128); + } + + if (aop->size && offset > (aop->size - 1)) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got offset > aop->size"); + exit (EXIT_FAILURE); + } + + /* will assign value to value */ + /* depending on where it is ofcourse */ + switch (aop->type) + { + case AOP_DUMMY: + MOVA (s); /* read s in case it was volatile */ + accuse = TRUE; + break; + + case AOP_DIR: + if ((SPEC_SCLS (getSpec (operandType (result))) == S_SFR) && (aop->size > 1)) + { + dbuf_printf (&dbuf, "((%s >> %d) & 0xFF)", aop->aopu.aop_dir, offset * 8); + } + else if (offset) + { + dbuf_printf (&dbuf, "(%s + %d)", aop->aopu.aop_dir, offset); + } + else + { + dbuf_append_str (&dbuf, aop->aopu.aop_dir); + } + + if (!EQ (dbuf_c_str (&dbuf), s) || bvolatile) + { + emitcode ("mov", "%s,%s", dbuf_c_str (&dbuf), s); + } + if (EQ (dbuf_c_str (&dbuf), "acc")) + { + accuse = TRUE; + } + break; + + case AOP_REG: + if (!EQ (aop->aopu.aop_reg[offset]->name, s) && !EQ (aop->aopu.aop_reg[offset]->dname, s)) + { + if (*s == '@' || + EQ (s, "r0") || EQ (s, "r1") || EQ (s, "r2") || EQ (s, "r3") || + EQ (s, "r4") || EQ (s, "r5") || EQ (s, "r6") || EQ (s, "r7")) + { + emitcode ("mov", "%s,%s", aop->aopu.aop_reg[offset]->dname, s); + } + else + { + emitcode ("mov", "%s,%s", aop->aopu.aop_reg[offset]->name, s); + } + } + break; + + case AOP_DPTRn: + emitcode ("mov", "%s,%s", dptrn[aop->aopu.dptr][offset], s); + break; + + case AOP_DPTR: + case AOP_DPTR2: + + if (aop->type == AOP_DPTR2) + { + genSetDPTR (1); + } + _flushLazyDPS (); + + if (aop->code) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut writing to code space"); + exit (EXIT_FAILURE); + } + + while (offset > aop->coff) + { + aop->coff++; + emitcode ("inc", "dptr"); + } + + while (offset < aop->coff) + { + aop->coff--; + emitcode ("lcall", "__decdptr"); + } + + aop->coff = offset; + + /* if not in accumulator */ + MOVA (s); + + emitcode ("movx", "@dptr,a"); + + if (aop->type == AOP_DPTR2) + { + genSetDPTR (0); + } + break; + + case AOP_R0: + case AOP_R1: + while (offset > aop->coff) + { + aop->coff++; + emitcode ("inc", "%s", aop->aopu.aop_ptr->name); + } + while (offset < aop->coff) + { + aop->coff--; + emitcode ("dec", "%s", aop->aopu.aop_ptr->name); + } + aop->coff = offset; + + if (aop->paged) + { + MOVA (s); + emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name); + } + else if (*s == '@') + { + MOVA (s); + emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name); + } + else if (EQ (s, "r0") || EQ (s, "r1") || EQ (s, "r2") || EQ (s, "r3") || + EQ (s, "r4") || EQ (s, "r5") || EQ (s, "r6") || EQ (s, "r7")) + { + dbuf_printf (&dbuf, "a%s", s); + emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, dbuf_c_str (&dbuf)); + } + else + { + emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s); + } + break; + + case AOP_STK: + emitpush (s); + break; + + case AOP_CRY: + // destination is carry for return-use-only + d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir; + + // source is no literal and not in carry + if (!EQ (s, zero) && !EQ (s, one) && !EQ (s, "c")) + { + MOVA (s); + /* set C, if a >= 1 */ + emitcode ("add", "a,#!constbyte", 0xff); + s = "c"; + } + // now source is zero, one or carry + + /* if result no bit variable */ + if (!d) + { + if (EQ (s, "c")) + { + /* inefficient: move carry into A and use jz/jnz */ + emitcode ("clr", "a"); + emitcode ("rlc", "a"); + accuse = TRUE; + } + else + { + MOVA (s); + accuse = TRUE; + } + } + else if (EQ (s, zero)) + emitcode ("clr", "%s", d); + else if (EQ (s, one)) + emitcode ("setb", "%s", d); + else if (!EQ (s, d)) + emitcode ("mov", "%s,c", d); + break; + + case AOP_STR: + aop->coff = offset; + if (!EQ (aop->aopu.aop_str[offset], s) || bvolatile) + emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s); + break; + + case AOP_ACC: + accuse = TRUE; + aop->coff = offset; + if (!offset && EQ (s, "acc") && !bvolatile) + break; + + if (!EQ (aop->aopu.aop_str[offset], s) && !bvolatile) + emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type"); + exit (EXIT_FAILURE); + } + + return accuse; +} + +/*--------------------------------------------------------------------*/ +/* loadDptrFromOperand - load dptr (and optionally B) from operand op */ +/*--------------------------------------------------------------------*/ +static int +loadDptrFromOperand (operand * op, bool loadBToo) +{ + int dopi = 1; + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (op) != AOP_STR && !AOP_INDPTRn (op)) + { + /* if this is rematerializable */ + if (AOP_TYPE (op) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE, NULL)); + if (loadBToo) + { + if (AOP (op)->aopu.aop_immd.from_cast_remat) + emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE, NULL)); + else + { + wassertl (FALSE, "need pointerCode"); + emitcode (";", "mov b,???"); + /* genPointerGet and genPointerSet originally did different + ** things for this case. Both seem wrong. + ** from genPointerGet: + ** emitcode ("mov", "b,#%d", pointerCode (retype)); + ** from genPointerSet: + ** emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, ANY)); + */ + } + } + } + else if (AOP_TYPE (op) == AOP_LIT) + { + emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE, NULL)); + if (loadBToo) + emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE, NULL)); + } + else if (AOP_TYPE (op) == AOP_DPTR) + { + /* we need to get it byte by byte */ + _startLazyDPSEvaluation (); + /* We need to generate a load to DPTR indirect through DPTR. */ + D (emitcode (";", "genFarPointerGet -- indirection special case.")); + emitpush (aopGet (op, 0, FALSE, TRUE, NULL)); + if (loadBToo || options.model == MODEL_FLAT24) + { + emitpush (aopGet (op, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + { + if (loadBToo) + { + emitpush (aopGet (op, 2, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE, NULL)); + emitpop ("dpx"); + } + else + { + emitcode ("mov", "dpx,%s", aopGet (op, 2, FALSE, FALSE, NULL)); + } + } + else + { + emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE, NULL)); + } + emitpop ("dph"); + } + emitpop ("dpl"); + _endLazyDPSEvaluation (); + dopi = 0; + } + else + { + /* we need to get it byte by byte */ + _startLazyDPSEvaluation (); + emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (op, 2, FALSE, FALSE, NULL)); + if (loadBToo) + emitcode ("mov", "b,%s", aopGet (op, AOP_SIZE (op) - 1, FALSE, FALSE, NULL)); + _endLazyDPSEvaluation (); + } + } + return dopi; +} + +/*--------------------------------------------------------------------*/ +/* reAdjustPreg - points a register back to where it should (coff==0) */ +/*--------------------------------------------------------------------*/ +static void +reAdjustPreg (asmop * aop) +{ + if ((aop->coff == 0) || (aop->size <= 1)) + return; + + switch (aop->type) + { + case AOP_R0: + case AOP_R1: + while (aop->coff--) + emitcode ("dec", "%s", aop->aopu.aop_ptr->name); + break; + case AOP_DPTR: + case AOP_DPTR2: + if (aop->type == AOP_DPTR2) + { + genSetDPTR (1); + _flushLazyDPS (); + } + while (aop->coff--) + { + emitcode ("lcall", "__decdptr"); + } + + if (aop->type == AOP_DPTR2) + { + genSetDPTR (0); + } + break; + } + aop->coff = 0; +} + +/*-----------------------------------------------------------------*/ +/* getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +static int +getDataSize (operand * op) +{ + int size = AOP_SIZE (op); + + if (size == GPTRSIZE) + { + sym_link *type = operandType (op); + if (IS_GENPTR (type)) + { + /* generic pointer; arithmetic operations + * should ignore the high byte (pointer type). + */ + size--; + } + } + return size; +} + +/*-----------------------------------------------------------------*/ +/* outAcc - output Acc */ +/*-----------------------------------------------------------------*/ +static void +outAcc (operand * result) +{ + int size, offset; + size = getDataSize (result); + if (size) + { + aopPut (result, "a", 0); + size--; + offset = 1; + /* unsigned or positive */ + while (size--) + { + aopPut (result, zero, offset++); + } + } +} + +/*-----------------------------------------------------------------*/ +/* outBitC - output a bit C */ +/*-----------------------------------------------------------------*/ +static void +outBitC (operand * result) +{ + /* if the result is bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + aopPut (result, "c", 0); + } + else if (AOP_TYPE (result) != AOP_DUMMY) + { + emitcode ("clr", "a"); + emitcode ("rlc", "a"); + outAcc (result); + } +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +static void +toBoolean (operand * oper) +{ + int size = AOP_SIZE (oper) - 1; + int offset = 1; + bool AccUsed; + sym_link *type = operandType (oper); + bool pushedB; + + /* always need B for float */ + AccUsed = IS_FLOAT (type); + + while (!AccUsed && size--) + { + AccUsed |= aopGetUsesAcc (oper, offset++); + } + + /* The generic part of a generic pointer should + * not participate in it's truth value. + * + * i.e. 0x10000000 is zero. + */ + if (opIsGptr (oper)) + { + D (emitcode (";", "toBoolean: generic ptr special case.")); + size = AOP_SIZE (oper) - 2; + } + else + { + size = AOP_SIZE (oper) - 1; + } + + offset = 0; + _startLazyDPSEvaluation (); + if (size && AccUsed && (AOP (oper)->type != AOP_ACC)) + { + pushedB = pushB (); + MOVB (aopGet (oper, offset++, FALSE, FALSE, NULL)); + while (--size) + { + MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL)); + emitcode ("orl", "b,a"); + } + MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL)); + if (IS_FLOAT (type)) + emitcode ("anl", "a,#0x7F"); //clear sign bit + emitcode ("orl", "a,b"); + popB (pushedB); + } + else + { + MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL)); + while (size--) + { + emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); +} + +/*-----------------------------------------------------------------*/ +/* toCarry - make boolean and move into carry */ +/*-----------------------------------------------------------------*/ +static void +toCarry (operand * oper) +{ + /* if the operand is a literal then + we know what the value is */ + if (AOP_TYPE (oper) == AOP_LIT) + { + if ((int) operandLitValue (oper)) + SETC; + else + CLRC; + } + else if (AOP_TYPE (oper) == AOP_CRY) + { + if (!IS_OP_ACCUSE (oper)) + emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir); + } + else + { + /* or the operand into a */ + toBoolean (oper); + /* set C, if a >= 1 */ + emitcode ("add", "a,#0xff"); + } +} +#if 0 // as of yet still unused +/*-----------------------------------------------------------------*/ +/* assignBit - assign operand to bit operand */ +/*-----------------------------------------------------------------*/ +static void +assignBit(operand * result, operand * right) +{ + /* if the right side is a literal then + we know what the value is */ + if (AOP_TYPE(right) == AOP_LIT) + { + if ((int)operandLitValue(right)) + aopPut(result, one, 0); + else + aopPut(result, zero, 0); + } + else + { + toCarry(right); + outBitC(result); + } +} +#endif +/*-------------------------------------------------------------------*/ +/* xch_a_aopGet - for exchanging acc with value of the aop */ +/*-------------------------------------------------------------------*/ +static const char * +xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname, char *saveAcc) +{ + const char *l; + + if (aopGetUsesAcc (oper, offset)) + { + emitcode ("mov", "b,a"); + MOVA (aopGet (oper, offset, bit16, dname, saveAcc)); + emitcode ("xch", "a,b"); + aopPut (oper, "a", offset); + emitcode ("xch", "a,b"); + l = "b"; + } + else + { + l = aopGet (oper, offset, bit16, dname, saveAcc); + emitcode ("xch", "a,%s", l); + } + return l; +} + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void +genNot (iCode * ic) +{ + symbol *tlbl; + + D (emitcode (";", "genNot")); + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR (IC_LEFT (ic))); + + /* if in bit space then a special case */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) + { + /* 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 + { + toCarry (IC_LEFT (ic)); + 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,!tlabel", labelKey2num (tlbl->key)); + emitLabel (tlbl); + outBitC (IC_RESULT (ic)); + +release: + /* release the aops */ + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); +} + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void +genCpl (iCode * ic) +{ + int offset = 0; + int size; + symbol *tlbl; + sym_link *letype = getSpec (operandType (IC_LEFT (ic))); + + D (emitcode (";", "genCpl")); + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR (IC_LEFT (ic))); + + /* special case if in bit space */ + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) + { + const char *l; + + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY || (SPEC_USIGN (letype) && IS_CHAR (letype))) + { + /* promotion rules are responsible for this strange result: + bit -> int -> ~int -> bit + uchar -> int -> ~int -> bit + */ + emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir); + goto release; + } + + tlbl = newiTempLabel (NULL); + l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL); + if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) || + AOP_TYPE (IC_LEFT (ic)) == AOP_REG || IS_AOP_PREG (IC_LEFT (ic))) + { + emitcode ("cjne", "%s,#0xFF,!tlabel", l, labelKey2num (tlbl->key)); + } + else + { + MOVA (l); + emitcode ("cjne", "a,#0xFF,!tlabel", labelKey2num (tlbl->key)); + } + emitLabel (tlbl); + outBitC (IC_RESULT (ic)); + goto release; + } + + size = AOP_SIZE (IC_RESULT (ic)); + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + emitcode ("cpl", "a"); + aopPut (IC_RESULT (ic), "a", offset++); + } + _endLazyDPSEvaluation (); + +release: + /* release the aops */ + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void +genUminusFloat (operand * op, operand * result) +{ + int size, offset = 0; + + D (emitcode (";", "genUminusFloat")); + + /* for this we just copy and then flip the bit */ + + _startLazyDPSEvaluation (); + size = AOP_SIZE (op) - 1; + + while (size--) + { + aopPut (result, aopGet (op, offset, FALSE, FALSE, NULL), offset); + offset++; + } + + MOVA (aopGet (op, offset, FALSE, FALSE, NULL)); + + emitcode ("cpl", "acc[7]"); + aopPut (result, "a", offset); + _endLazyDPSEvaluation (); +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void +genUminus (iCode * ic) +{ + int offset, size; + sym_link *optype; + + D (emitcode (";", "genUminus")); + + /* assign asmops */ + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)); + + /* if both in bit space then special + case */ + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) + { + + emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir); + emitcode ("cpl", "c"); + emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir); + goto release; + } + + optype = operandType (IC_LEFT (ic)); + + /* if float then do float stuff */ + if (IS_FLOAT (optype)) + { + genUminusFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; + } + + /* otherwise subtract from zero */ + size = AOP_SIZE (IC_LEFT (ic)); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + const char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL); + if (EQ (l, "a")) + { + if (offset == 0) + SETC; + emitcode ("cpl", "a"); + emitcode ("addc", "a,#0x00"); + } + else + { + if (offset == 0) + CLRC; + emitcode ("clr", "a"); + emitcode ("subb", "a,%s", l); + } + aopPut (IC_RESULT (ic), "a", offset++); + } + _endLazyDPSEvaluation (); + + /* if any remaining bytes in the result */ + /* we just need to propagate the sign */ + if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic))))) + { + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + while (size--) + aopPut (IC_RESULT (ic), "a", offset++); + } + +release: + /* release the aops */ + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); +} + +/*-----------------------------------------------------------------*/ +/* savermask - saves registers in the mask */ +/*-----------------------------------------------------------------*/ +static void +savermask (bitVect * rs_mask) +{ + int i; + + if (options.useXstack) + { + if (bitVectBitValue (rs_mask, R0_IDX)) + emitcode ("mov", "b,r0"); + emitcode ("mov", "r0,%s", spname); + for (i = 0; i < ds390_nRegs; i++) + { + if (bitVectBitValue (rs_mask, i)) + { + if (i == R0_IDX) + emitcode ("mov", "a,b"); + else + emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name); + emitcode ("movx", "@r0,a"); + emitcode ("inc", "r0"); + } + } + emitcode ("mov", "%s,r0", spname); + if (bitVectBitValue (rs_mask, R0_IDX)) + emitcode ("mov", "r0,b"); + } + else + { + bool bits_pushed = FALSE; + for (i = 0; i < ds390_nRegs; i++) + { + if (bitVectBitValue (rs_mask, i)) + { + bits_pushed = pushReg (i, bits_pushed); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* saveRegisters - will look for a call and save the registers */ +/*-----------------------------------------------------------------*/ +static void +saveRegisters (iCode * lic) +{ + iCode *ic; + bitVect *rsave; + + /* look for call */ + for (ic = lic; ic; ic = ic->next) + if (ic->op == CALL || ic->op == PCALL) + break; + + if (!ic) + { + fprintf (stderr, "found parameter push with no function call\n"); + return; + } + + /* if the registers have been saved already or don't need to be then + do nothing */ + if (ic->regsSaved) + return; + if (IS_SYMOP (IC_LEFT (ic))) + { + sym_link *type = OP_SYM_TYPE (IC_LEFT (ic)); + if (IFFUNC_ISNAKED (type) && !TARGET_IS_DS400) + return; + } + + /* special case if DPTR alive across a function call then must save it + even though callee saves */ + if (IS_SYMOP (IC_LEFT (ic)) && IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type)) + { + int i; + rsave = newBitVect (ic->rMask->size); + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectCplAnd (rsave, ds390_rUmaskForOp (IC_RESULT (ic))); + } + else + { + /* save the registers in use at this time but skip the + ones for the result */ + rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic))); + } + ic->regsSaved = 1; + savermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* unsavermask - restore registers with mask */ +/*-----------------------------------------------------------------*/ +static void +unsavermask (bitVect * rs_mask) +{ + int i; + + if (options.useXstack) + { + emitcode ("mov", "r0,%s", spname); + for (i = ds390_nRegs; i >= 0; i--) + { + if (bitVectBitValue (rs_mask, i)) + { + reg_info *reg = REG_WITH_INDEX (i); + emitcode ("dec", "r0"); + emitcode ("movx", "a,@r0"); + if (i == R0_IDX) + { + emitcode ("push", "acc"); + } + else + { + emitcode ("mov", "%s,a", reg->name); + } + } + } + emitcode ("mov", "%s,r0", spname); + if (bitVectBitValue (rs_mask, R0_IDX)) + { + emitcode ("pop", "ar0"); + } + } + else + { + bool bits_popped = FALSE; + for (i = ds390_nRegs; i >= 0; i--) + { + if (bitVectBitValue (rs_mask, i)) + { + bits_popped = popReg (i, bits_popped); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* unsaveRegisters - pop the pushed registers */ +/*-----------------------------------------------------------------*/ +static void +unsaveRegisters (iCode * ic) +{ + bitVect *rsave; + + if (IS_SYMOP (IC_LEFT (ic)) && IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type)) + { + int i; + rsave = newBitVect (ic->rMask->size); + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectCplAnd (rsave, ds390_rUmaskForOp (IC_RESULT (ic))); + } + else + { + /* restore the registers in use at this time but skip the + ones for the result */ + rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic))); + } + unsavermask (rsave); +} + + +/*-----------------------------------------------------------------*/ +/* pushSide - */ +/*-----------------------------------------------------------------*/ +static void +pushSide (operand * oper, int size, iCode * ic) +{ + int offset = 0; + int nPushed = _G.r0Pushed + _G.r1Pushed; + + aopOp (oper, ic, FALSE, FALSE); + + if (nPushed != _G.r0Pushed + _G.r1Pushed) + { + while (offset < size) + { + const char *l = aopGet (oper, offset, FALSE, TRUE, NULL); + emitcode ("mov", "%s,%s", fReturn[offset++], l); + } + freeAsmop (oper, NULL, ic, TRUE); + offset = 0; + while (offset < size) + { + emitpush (fReturn[offset++]); + } + return; + } + + _startLazyDPSEvaluation (); + while (size--) + { + const char *l = aopGet (oper, offset++, FALSE, TRUE, NULL); + if (AOP_TYPE (oper) != AOP_REG && AOP_TYPE (oper) != AOP_DIR && strcmp (l, "a")) + { + MOVA (l); + emitpush ("acc"); + } + else + { + emitpush (l); + } + } + _endLazyDPSEvaluation (); + freeAsmop (oper, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - also indicates if acc is in use afterwards */ +/*-----------------------------------------------------------------*/ +static bool +assignResultValue (operand * oper, operand * func) +{ + int offset = 0; + int size = AOP_SIZE (oper); + bool accuse = FALSE; + bool pushedA = FALSE; + + if (func && IS_BIT (OP_SYM_ETYPE (func))) + { + outBitC (oper); + return FALSE; + } + + if (AOP_NEEDSACC (oper)) + { + int i; + for (i=0; i<size; i++) + { + if (strcmp(fReturn[i],"a")==0) + { + emitcode (";", "assignResultValue special case for ACC."); + emitpush ("acc"); + pushedA = TRUE; + break; + } + } + } + + _startLazyDPSEvaluation (); + while (size--) + { + if (pushedA && strcmp(fReturn[offset],"a")==0) + emitpop ("acc"); + accuse |= aopPut (oper, fReturn[offset], offset); + offset++; + } + _endLazyDPSEvaluation (); + + return accuse; +} + + +/*-----------------------------------------------------------------*/ +/* genXpush - pushes onto the external stack */ +/*-----------------------------------------------------------------*/ +static void +genXpush (iCode * ic) +{ + asmop *aop = newAsmop (0); + reg_info *r; + int size, offset = 0; + + D (emitcode (";", "genXpush")); + + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + r = getFreePtr (ic, &aop, FALSE); + + size = AOP_SIZE (IC_LEFT (ic)); + + if (size == 1) + { + MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL)); + emitcode ("mov", "%s,_spx", r->name); + emitcode ("inc", "_spx"); // allocate space first + emitcode ("movx", "@%s,a", r->name); + } + else + { + // allocate space first + emitcode ("mov", "%s,_spx", r->name); + MOVA (r->name); + emitcode ("add", "a,#%d", size); + emitcode ("mov", "_spx,a"); + + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL)); + emitcode ("movx", "@%s,a", r->name); + emitcode ("inc", "%s", r->name); + } + _endLazyDPSEvaluation (); + } + + freeAsmop (NULL, aop, ic, TRUE); + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIpush - generate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void +genIpush (iCode * ic) +{ + int size, offset = 0; + char *prev; + + D (emitcode (";", "genIpush")); + + /* if this is not a parm push : ie. it is spill push + and spill push is always done on the local stack */ + if (!ic->parmPush) + { + /* and the item is spilt then do nothing */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr) + return; + + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + /* push it on the stack */ + _startLazyDPSEvaluation (); + while (size--) + { + emitpush (aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL)); + } + _endLazyDPSEvaluation (); + return; + } + + /* this is a parameter push: in this case we call + the routine to find the call and save those + registers that need to be saved */ + saveRegisters (ic); + + /* if use external stack then call the external + stack pushing routine */ + if (options.useXstack) + { + genXpush (ic); + return; + } + + /* then do the push */ + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + + // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic))); + size = AOP_SIZE (IC_LEFT (ic)); + + _startLazyDPSEvaluation (); + prev = Safe_strdup (""); + while (size--) + { + const char *l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL); + if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG && AOP_TYPE (IC_LEFT (ic)) != AOP_DIR && strcmp (l, "acc")) + { + if (!EQ (l, prev) || *l == '@') + MOVA (l); + emitpush ("acc"); + } + else + { + emitpush (l); + } + Safe_free (prev); + prev = Safe_strdup (l); + } + Safe_free (prev); + _endLazyDPSEvaluation (); + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void +genIpop (iCode * ic) +{ + int size, offset; + + D (emitcode (";", "genIpop")); + + /* if the temp was not pushed then */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr) + return; + + aopOp (IC_LEFT (ic), ic, FALSE, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + offset = (size - 1); + _startLazyDPSEvaluation (); + while (size--) + { + emitpop (aopGet (IC_LEFT (ic), offset--, FALSE, TRUE, NULL)); + } + _endLazyDPSEvaluation (); + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* popForBranch - recover the spilt registers for a branch */ +/*-----------------------------------------------------------------*/ +static void +popForBranch (iCode * ic, bool markGenerated) +{ + while (ic && ic->op == IPOP) + { + genIpop (ic); + if (markGenerated) + ic->generated = 1; /* mark the icode as generated */ + ic = ic->next; + } +} + +/*-----------------------------------------------------------------*/ +/* saveRBank - saves an entire register bank on the stack */ +/*-----------------------------------------------------------------*/ +static void +saveRBank (int bank, iCode * ic, bool pushPsw) +{ + int i; + int count = 8 + (ds390_nBitRegs / 8) + (pushPsw ? 1 : 0); + asmop *aop = NULL; + reg_info *r = NULL; + + if (options.useXstack) + { + if (!ic) + { + /* Assume r0 is available for use. */ + r = REG_WITH_INDEX (R0_IDX); + } + else + { + aop = newAsmop (0); + r = getFreePtr (ic, &aop, FALSE); + } + // allocate space first + emitcode ("mov", "%s,_spx", r->name); + MOVA (r->name); + emitcode ("add", "a,#!constbyte", count); + emitcode ("mov", "_spx,a"); + } + + for (i = 0; i < 8; i++) /* only R0-R7 needs saving */ + { + if (options.useXstack) + { + emitcode ("mov", "a,(%s+%d)", regs390[i].base, 8 * bank + regs390[i].offset); + emitcode ("movx", "@%s,a", r->name); + if (--count) + emitcode ("inc", "%s", r->name); + } + else + emitcode ("push", "(%s+%d)", regs390[i].base, 8 * bank + regs390[i].offset); + } + + if (ds390_nBitRegs > 0) + { + if (options.useXstack) + { + emitcode ("mov", "a,bits"); + emitcode ("movx", "@%s,a", r->name); + if (--count) + emitcode ("inc", "%s", r->name); + } + else + { + emitpush ("bits"); + } + BitBankUsed = 1; + } + + if (pushPsw) + { + if (options.useXstack) + { + emitcode ("mov", "a,psw"); + emitcode ("movx", "@%s,a", r->name); + } + else + { + emitpush ("psw"); + } + + emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff); + } + + if (aop) + { + freeAsmop (NULL, aop, ic, TRUE); + } + + if (ic) + { + ic->bankSaved = 1; + } +} + +/*-----------------------------------------------------------------*/ +/* unsaveRBank - restores the register bank from stack */ +/*-----------------------------------------------------------------*/ +static void +unsaveRBank (int bank, iCode * ic, bool popPsw) +{ + int i; + asmop *aop = NULL; + reg_info *r = NULL; + + if (options.useXstack) + { + if (!ic) + { + /* Assume r0 is available for use. */ + r = REG_WITH_INDEX (R0_IDX); + } + else + { + aop = newAsmop (0); + r = getFreePtr (ic, &aop, FALSE); + } + emitcode ("mov", "%s,_spx", r->name); + } + + if (popPsw) + { + if (options.useXstack) + { + emitcode ("dec", "%s", r->name); + emitcode ("movx", "a,@%s", r->name); + emitcode ("mov", "psw,a"); + } + else + { + emitpop ("psw"); + } + } + + if (ds390_nBitRegs > 0) + { + if (options.useXstack) + { + emitcode ("dec", "%s", r->name); + emitcode ("movx", "a,@%s", r->name); + emitcode ("mov", "bits,a"); + } + else + { + emitpop ("bits"); + } + } + + for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */ + { + if (options.useXstack) + { + emitcode ("dec", "%s", r->name); + emitcode ("movx", "a,@%s", r->name); + emitcode ("mov", "(%s+%d),a", regs390[i].base, 8 * bank + regs390[i].offset); + } + else + { + char buf[16] = ""; + SNPRINTF (buf, 16, "(%s+%d)", regs390[i].base, 8 * bank + regs390[i].offset); + emitpop (buf); + } + } + + if (options.useXstack) + { + emitcode ("mov", "_spx,%s", r->name); + } + + if (aop) + { + freeAsmop (NULL, aop, ic, TRUE); + } +} + +/*-----------------------------------------------------------------*/ +/* genSend - gen code for SEND */ +/*-----------------------------------------------------------------*/ +static void +genSend (set * sendSet) +{ + iCode *sic; + int bit_count = 0; + int sendCount = 0; + static int rb1_count = 0; + + /* first we do all bit parameters */ + for (sic = setFirstItem (sendSet); sic; sic = setNextItem (sendSet)) + { + if (sic->argreg > 12) + { + int bit = sic->argreg - 13; + + aopOp (IC_LEFT (sic), sic, FALSE, (IS_OP_RUONLY (IC_LEFT (sic)) ? FALSE : TRUE)); + + /* if left is a literal then + we know what the value is */ + if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT) + { + if (((int) operandLitValue (IC_LEFT (sic)))) + emitcode ("setb", "b[%d]", bit); + else + emitcode ("clr", "b[%d]", bit); + } + else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY) + { + char *l = AOP (IC_LEFT (sic))->aopu.aop_dir; + if (strcmp (l, "c")) + emitcode ("mov", "c,%s", l); + emitcode ("mov", "b[%d],c", bit); + } + else + { + /* we need to or */ + toCarry (IC_LEFT (sic)); + emitcode ("mov", "b[%d],c", bit); + } + bit_count++; + BitBankUsed = 1; + + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + } + + if (bit_count) + { + saveRegisters (setFirstItem (sendSet)); + emitcode ("mov", "bits,b"); + } + + /* then we do all other parameters */ + for (sic = setFirstItem (sendSet); sic; sic = setNextItem (sendSet)) + { + if (sic->argreg <= 12) + { + int size, offset = 0; + + size = getSize (operandType (IC_LEFT (sic))); + D (emitcode (";", "genSend argreg = %d, size = %d ", sic->argreg, size)); + if (sendCount == 0) + { + bool pushedA = FALSE; + /* first parameter */ + // we know that dpl(hxb) is the result, so + rb1_count = 0; + _startLazyDPSEvaluation (); + if (size > 1) + { + aopOp (IC_LEFT (sic), sic, FALSE, (IS_OP_RUONLY (IC_LEFT (sic)) ? FALSE : TRUE)); + } + else + { + aopOp (IC_LEFT (sic), sic, FALSE, FALSE); + } + while (size--) + { + const char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL); + if (!EQ (l, fReturn[offset])) + if (fReturn[offset][0] == 'r' && (AOP_TYPE (IC_LEFT (sic)) == AOP_REG || AOP_TYPE (IC_LEFT (sic)) == AOP_R0 || AOP_TYPE (IC_LEFT (sic)) == AOP_R1)) + emitcode ("mov", "a%s,%s", fReturn[offset], l); // use register's direct address instead of name + else + emitcode ("mov", "%s,%s", fReturn[offset], l); + if (size && (strcmp(fReturn[offset],"a")==0) && AOP_NEEDSACC( IC_LEFT (sic))) + { + emitpush ("acc"); + pushedA = TRUE; + } + offset++; + } + if (pushedA) + { + emitpop ("acc"); + pushedA = FALSE; + } + _endLazyDPSEvaluation (); + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + rb1_count = 0; + } + else + { + /* if more parameter in registers */ + aopOp (IC_LEFT (sic), sic, FALSE, TRUE); + while (size--) + { + emitcode ("mov", "b1_%d,%s", rb1_count++, aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL)); + offset++; + } + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + sendCount++; + } + } +} + +static void +adjustEsp (const char *reg) +{ + emitcode ("anl", "%s,#3", reg); + if (TARGET_IS_DS400) + { + emitcode ("orl", "%s,#!constbyte", reg, (options.stack_loc >> 8) & 0xff); + } +} + +/*-----------------------------------------------------------------*/ +/* 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 */ +/*-----------------------------------------------------------------*/ +static void +genCall (iCode * ic) +{ + sym_link *dtype; + sym_link *etype; + bool restoreBank = FALSE; + bool swapBanks = FALSE; + bool accuse = FALSE; + bool accPushed = FALSE; + bool resultInF0 = FALSE; + bool assignResultGenerated = FALSE; + + D (emitcode (";", "genCall")); + + /* 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)); + etype = getSpec (dtype); + if (currFunc && dtype && (!IFFUNC_ISNAKED (dtype) || TARGET_IS_DS400) && + (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) && IFFUNC_ISISR (currFunc->type)) + { + if (!ic->bankSaved) + { + /* This is unexpected; the bank should have been saved in + * genFunction. + */ + saveRBank (FUNC_REGBANK (dtype), ic, FALSE); + restoreBank = TRUE; + } + swapBanks = TRUE; + } + + /* if caller saves & we have not saved then */ + if (!ic->regsSaved) + saveRegisters (ic); + + /* if send set is not empty then assign */ + /* We've saved all the registers we care about; + * therefore, we may clobber any register not used + * in the calling convention (i.e. anything not in + * fReturn. + */ + if (_G.sendSet) + { + if (IFFUNC_ISREENT (dtype)) + { + /* need to reverse the send set */ + genSend (reverseSet (_G.sendSet)); + } + else + { + genSend (_G.sendSet); + } + _G.sendSet = NULL; + } + + if (swapBanks) + { + emitcode ("mov", "psw,#!constbyte", ((FUNC_REGBANK (dtype)) << 3) & 0xff); + } + + /* make the call */ + if (IS_LITERAL (etype)) + { + if (options.model == MODEL_FLAT24) + emitcode ("lcall", "0x%06X", ulFromVal (OP_VALUE (IC_LEFT (ic)))); + else + emitcode ("lcall", "0x%04X", ulFromVal (OP_VALUE (IC_LEFT (ic)))); + } + else + { + emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ? + OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name)); + } + + if (swapBanks) + { + 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))->accuse || OP_SYMBOL (IC_RESULT (ic))->spildir)) || IS_TRUE_SYMOP (IC_RESULT (ic))) + { + if (isOperandInFarSpace (IC_RESULT (ic)) && getSize (operandType (IC_RESULT (ic))) <= 2) + { + int size = getSize (operandType (IC_RESULT (ic))); + bool pushedB = FALSE; + + /* Special case for 1 or 2 byte return in far space. */ + MOVA (fReturn[0]); + if (size > 1) + { + pushedB = pushB (); + emitcode ("mov", "b,%s", fReturn[1]); + } + + _G.accInUse++; + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + _G.accInUse--; + + popB (pushedB); + + aopPut (IC_RESULT (ic), "a", 0); + + if (size > 1) + { + aopPut (IC_RESULT (ic), "b", 1); + } + assignResultGenerated = TRUE; + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + else + { + bool pushedB = pushB (); + aopOp (IC_RESULT (ic), ic, FALSE, TRUE); + popB (pushedB); + + accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic)); + assignResultGenerated = TRUE; + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + } + + /* adjust the stack for parameters if required */ + if (ic->parmBytes) + { + int i; + if (options.stack10bit) + { + if (ic->parmBytes <= 10) + { + emitcode (";", "stack adjustment for parms"); + for (i = 0; i < ic->parmBytes; i++) + { + emitpop ("acc"); + } + } + else + { + PROTECT_SP; + emitcode ("clr", "c"); + emitcode ("mov", "a,sp"); + emitcode ("subb", "a,#!constbyte", ic->parmBytes & 0xff); + emitcode ("mov", "sp,a"); + emitcode ("mov", "a,esp"); + adjustEsp ("a"); + emitcode ("subb", "a,#!constbyte", (ic->parmBytes >> 8) & 0xff); + emitcode ("mov", "esp,a"); + UNPROTECT_SP; + } + } + else + { + if (ic->parmBytes > 3) + { + if (accuse) + { + emitcode ("push", "acc"); + accPushed = TRUE; + } + if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) && IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated) + { + emitcode ("mov", "F0,c"); + resultInF0 = TRUE; + } + + emitcode ("mov", "a,%s", spname); + emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff); + emitcode ("mov", "%s,a", spname); + + /* unsaveRegisters from xstack needs acc, but */ + /* unsaveRegisters from stack needs this popped */ + if (accPushed && !options.useXstack) + { + emitpop ("acc"); + accPushed = FALSE; + } + } + else + for (i = 0; i < ic->parmBytes; i++) + emitcode ("dec", "%s", spname); + } + } + + /* if we had saved some registers then unsave them */ + if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype)) + { + if (accuse && !accPushed && options.useXstack) + { + /* xstack needs acc, but doesn't touch normal stack */ + emitpush ("acc"); + accPushed = TRUE; + } + unsaveRegisters (ic); + } + + /* if register bank was saved then pop them */ + if (restoreBank) + unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE); + + if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated) + { + if (resultInF0) + emitcode ("mov", "c,F0"); + + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + assignResultValue (IC_RESULT (ic), IC_LEFT (ic)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + if (accPushed) + emitpop ("acc"); +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void +genPcall (iCode * ic) +{ + sym_link *dtype; + symbol *rlbl = newiTempLabel (NULL); + bool restoreBank = FALSE; + bool resultInF0 = FALSE; + + D (emitcode (";", "genPcall")); + + dtype = operandType (IC_LEFT (ic))->next; + /* 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 */ + if (currFunc && dtype && (!IFFUNC_ISNAKED (dtype) || TARGET_IS_DS400) && + IFFUNC_ISISR (currFunc->type) && (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) + { + saveRBank (FUNC_REGBANK (dtype), ic, TRUE); + restoreBank = TRUE; + } + + /* push the return address on to the stack */ + emitcode ("mov", "a,#!tlabel", labelKey2num (rlbl->key)); + emitpush ("acc"); + emitcode ("mov", "a,#!hil", labelKey2num (rlbl->key)); + emitpush ("acc"); + + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "a,#!hihil", labelKey2num (rlbl->key)); + emitpush ("acc"); + } + + /* now push the function address */ + pushSide (IC_LEFT (ic), FARPTRSIZE, ic); + + /* if send set is not empty then assign */ + if (_G.sendSet) + { + genSend (reverseSet (_G.sendSet)); + _G.sendSet = NULL; + } + + /* make the call */ + emitcode ("ret", ""); + emitLabel (rlbl); + + /* 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))) + { + _G.accInUse++; + aopOp (IC_RESULT (ic), ic, FALSE, TRUE); + _G.accInUse--; + + assignResultValue (IC_RESULT (ic), IC_LEFT (ic)); + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + /* adjust the stack for parameters if required */ + if (ic->parmBytes) + { + int i; + if (options.stack10bit) + { + if (ic->parmBytes <= 10) + { + emitcode (";", "stack adjustment for parms"); + for (i = 0; i < ic->parmBytes; i++) + { + emitpop ("acc"); + } + } + else + { + if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) && IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic)))) + { + emitcode ("mov", "F0,c"); + resultInF0 = TRUE; + } + + PROTECT_SP; + emitcode ("clr", "c"); + emitcode ("mov", "a,sp"); + emitcode ("subb", "a,#!constbyte", ic->parmBytes & 0xff); + emitcode ("mov", "sp,a"); + emitcode ("mov", "a,esp"); + adjustEsp ("a"); + emitcode ("subb", "a,#!constbyte", (ic->parmBytes >> 8) & 0xff); + emitcode ("mov", "esp,a"); + UNPROTECT_SP; + } + } + else + { + 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,#!constbyte", (-ic->parmBytes) & 0xff); + emitcode ("mov", "%s,a", spname); + } + else + for (i = 0; i < ic->parmBytes; i++) + emitcode ("dec", "%s", spname); + } + } + /* if register bank was saved then unsave them */ + if (restoreBank) + unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE); + + /* if we had saved some registers then unsave them */ + if (ic->regsSaved) + unsaveRegisters (ic); + + if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic)))) + { + if (resultInF0) + emitcode ("mov", "c,F0"); + + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + assignResultValue (IC_RESULT (ic), IC_LEFT (ic)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } +} + +/*-----------------------------------------------------------------*/ +/* resultRemat - result is rematerializable */ +/*-----------------------------------------------------------------*/ +static int +resultRemat (iCode * ic) +{ + if (SKIP_IC (ic) || ic->op == IFX) + return 0; + + if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic))) + { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + if (sym->remat && !POINTER_SET (ic)) + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* inExcludeList - return 1 if the string is in exclude Reg list */ +/*-----------------------------------------------------------------*/ +static int +regsCmp (void *p1, void *p2) +{ + return (STRCASECMP ((char *) p1, (char *) (p2)) == 0); +} + +static bool +inExcludeList (char *s) +{ + const char *p = setFirstItem (options.excludeRegsSet); + + if (p == NULL || STRCASECMP (p, "none") == 0) + return FALSE; + + return isinSetWith (options.excludeRegsSet, s, regsCmp); +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void +genFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + sym_link *ftype; + bool switchedPSW = FALSE; + bool fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto); + + D (emitcode (";", "genFunction")); + + _G.nRegsSaved = 0; + /* create the function header */ + emitcode (";", "-----------------------------------------"); + emitcode (";", " function %s", sym->name); + emitcode (";", "-----------------------------------------"); + + emitcode ("", "%s:", sym->rname); + genLine.lineCurr->isLabel = 1; + ftype = operandType (IC_LEFT (ic)); + _G.currentFunc = sym; + + if (IFFUNC_ISNAKED (ftype)) + { + emitcode (";", "naked function: no prologue."); + return; + } + + if (options.stack_probe) + emitcode ("lcall", "__stack_probe"); + + /* here we need to generate the equates for the + register bank if required */ + if (FUNC_REGBANK (ftype) != rbank) + { + int i; + + rbank = FUNC_REGBANK (ftype); + for (i = 0; i < ds390_nRegs; i++) + { + if (regs390[i].print) + { + if (strcmp (regs390[i].base, "0") == 0) + emitcode ("", "%s !equ !constbyte", regs390[i].dname, 8 * rbank + regs390[i].offset); + else + emitcode ("", "%s !equ %s + !constbyte", regs390[i].dname, regs390[i].base, 8 * rbank + regs390[i].offset); + } + } + } + + /* if this is an interrupt service routine then + save acc, b, dpl, dph */ + if (IFFUNC_ISISR (sym->type)) + { + if (!inExcludeList ("acc")) + emitpush ("acc"); + if (!inExcludeList ("b")) + emitpush ("b"); + if (!inExcludeList ("dpl")) + emitpush ("dpl"); + if (!inExcludeList ("dph")) + emitpush ("dph"); + if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx")) + { + emitpush ("dpx"); + /* Make sure we're using standard DPTR */ + emitpush ("dps"); + emitcode ("mov", "dps,#0"); + if (options.stack10bit) + { + /* This ISR could conceivably use DPTR2. Better save it. */ + emitpush ("dpl1"); + emitpush ("dph1"); + emitpush ("dpx1"); + emitpush (DP2_RESULT_REG); + } + } + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!FUNC_REGBANK (sym->type)) + { + int i; + + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (!IFFUNC_HASFCALL (sym->type)) + { + /* if any registers used */ + if (!bitVectIsZero (sym->regsUsed)) + { + bool bits_pushed = FALSE; + /* save the registers used */ + for (i = 0; i < sym->regsUsed->size; i++) + { + if (bitVectBitValue (sym->regsUsed, i)) + bits_pushed = pushReg (i, bits_pushed); + } + } + } + else + { + /* this function has a function call. We cannot + determine register usage so we will have to push the + entire bank */ + saveRBank (0, ic, FALSE); + if (options.parms_in_bank1) + { + for (i = 0; i < 8; i++) + { + emitpush (rb1regs[i]); + } + } + } + } + else + { + /* This ISR uses a non-zero bank. + * + * We assume that the bank is available for our + * exclusive use. + * + * However, if this ISR calls a function which uses some + * other bank, we must save that bank entirely. + */ + unsigned long banksToSave = 0; + + if (IFFUNC_HASFCALL (sym->type)) + { + +#define MAX_REGISTER_BANKS 4 + + iCode *i; + int ix; + + for (i = ic; i; i = i->next) + { + sym_link *dtype = NULL; + + if (i->op == ENDFUNCTION) + { + /* we got to the end OK. */ + break; + } + + if (i->op == CALL) + { + dtype = operandType (IC_LEFT (i)); + } + if (i->op == PCALL) + { + /* This is a mess; we have no idea what + * register bank the called function might + * use. + * + * The only thing I can think of to do is + * throw a warning and hope. + */ +// werror (W_FUNCPTR_IN_USING_ISR); + dtype = operandType (IC_LEFT (i))->next; + } + if (dtype && FUNC_REGBANK (dtype) != FUNC_REGBANK (sym->type)) + { + /* Mark this bank for saving. */ + if (FUNC_REGBANK (dtype) >= MAX_REGISTER_BANKS) + { + werror (E_NO_SUCH_BANK, FUNC_REGBANK (dtype)); + } + else + { + banksToSave |= (1 << FUNC_REGBANK (dtype)); + } + + /* And note that we don't need to do it in + * genCall. + */ + i->bankSaved = 1; + } + } + + if (banksToSave && options.useXstack) + { + /* Since we aren't passing it an ic, + * saveRBank will assume r0 is available to abuse. + * + * So switch to our (trashable) bank now, so + * the caller's R0 isn't trashed. + */ + emitpush ("psw"); + emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff); + switchedPSW = TRUE; + } + + for (ix = 0; ix < MAX_REGISTER_BANKS; ix++) + { + if (banksToSave & (1 << ix)) + { + saveRBank (ix, NULL, FALSE); + } + } + } + // TODO: this needs a closer look + SPEC_ISR_SAVED_BANKS (currFunc->etype) = banksToSave; + } + } + else + { + /* if callee-save to be used for this function + then save the registers being used in this function */ + if (IFFUNC_CALLEESAVES (sym->type)) + { + int i; + + /* if any registers used */ + if (sym->regsUsed) + { + bool bits_pushed = FALSE; + /* save the registers used */ + for (i = 0; i < sym->regsUsed->size; i++) + { + if (bitVectBitValue (sym->regsUsed, i)) + { + bits_pushed = pushReg (i, bits_pushed); + _G.nRegsSaved++; + } + } + } + } + } + + /* set the register bank to the desired value */ + if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type)) && !switchedPSW) + { + emitpush ("psw"); + emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff); + } + + if (fReentrant && (sym->stack || FUNC_HASSTACKPARM (sym->type))) + { + if (options.stack10bit) + { + emitcode ("push", "_bpx"); + emitcode ("push", "_bpx+1"); + emitcode ("mov", "_bpx,%s", spname); + emitcode ("mov", "_bpx+1,esp"); + adjustEsp ("_bpx+1"); + } + else + { + if (options.useXstack) + { + emitcode ("mov", "r0,%s", spname); + emitcode ("mov", "a,_bp"); + emitcode ("movx", "@r0,a"); + emitcode ("inc", "%s", spname); + } + else + { + /* set up the stack */ + emitcode ("push", "_bp"); /* save the callers stack */ + } + emitcode ("mov", "_bp,%s", spname); + } + } + + /* adjust the stack for the function */ + if (sym->stack) + { + int i = sym->stack; + if (options.stack10bit) + { + if (i > 1024) + werror (W_STACK_OVERFLOW, sym->name); + assert (sym->recvSize <= 4); + if (sym->stack <= 8) + { + while (i--) + emitcode ("push", "acc"); + } + else + { + PROTECT_SP; + emitcode ("mov", "a,sp"); + emitcode ("add", "a,#!constbyte", ((short) sym->stack & 0xff)); + emitcode ("mov", "sp,a"); + emitcode ("mov", "a,esp"); + adjustEsp ("a"); + emitcode ("addc", "a,#!constbyte", (((short) sym->stack) >> 8) & 0xff); + emitcode ("mov", "esp,a"); + UNPROTECT_SP; + } + } + else + { + if (i > 256) + werror (W_STACK_OVERFLOW, sym->name); + + if (i > 3 && sym->recvSize < 4) + { + + emitcode ("mov", "a,sp"); + emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff)); + emitcode ("mov", "sp,a"); + + } + else + { + while (i--) + emitcode ("inc", "sp"); + } + } + } + + if (sym->xstack) + { + + emitcode ("mov", "a,_spx"); + emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff)); + emitcode ("mov", "_spx,a"); + } + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (ftype)) + { + symbol *tlbl = newiTempLabel (NULL); + emitcode ("setb", "c"); + emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */ + emitcode ("clr", "c"); + emitLabel (tlbl); + emitpush ("psw"); /* save old ea via c in psw */ + } +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void +genEndFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + lineNode *lnp = genLine.lineCurr; + bitVect *regsUsed; + bitVect *regsUsedPrologue; + bitVect *regsUnneeded; + int idx; + + D (emitcode (";", "genEndFunction")); + + _G.currentFunc = NULL; + if (IFFUNC_ISNAKED (sym->type)) + { + emitcode (";", "naked function: no epilogue."); + if (options.debug && currFunc) + debugFile->writeEndFunction (currFunc, ic, 0); + return; + } + + if (IFFUNC_ISCRITICAL (sym->type)) + { + if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic)))) + { + emitcode ("rlc", "a"); /* save c in a */ + emitpop ("psw"); /* restore ea via c in psw */ + emitcode ("mov", "ea,c"); + emitcode ("rrc", "a"); /* restore c from a */ + } + else + { + emitpop ("psw"); /* restore ea via c in psw */ + emitcode ("mov", "ea,c"); + } + } + + if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) && (sym->stack || FUNC_HASSTACKPARM (sym->type))) + { + + if (options.stack10bit) + { + PROTECT_SP; + emitcode ("mov", "sp,_bpx", spname); + emitcode ("mov", "esp,_bpx+1", spname); + UNPROTECT_SP; + } + else + { + emitcode ("mov", "%s,_bp", spname); + } + } + + /* if use external stack but some variables were + added to the local stack then decrement the + local stack */ + if (options.useXstack && sym->stack) + { + emitcode ("mov", "a,sp"); + emitcode ("add", "a,#!constbyte", ((char) - sym->stack) & 0xff); + emitcode ("mov", "sp,a"); + } + + + if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) && (sym->stack || FUNC_HASSTACKPARM (sym->type))) + { + + if (options.useXstack) + { + emitcode ("mov", "r0,%s", spname); + emitcode ("movx", "a,@r0"); + emitcode ("mov", "_bp,a"); + emitcode ("dec", "%s", spname); + } + else + { + if (options.stack10bit) + { + emitcode ("pop", "_bpx+1"); + emitcode ("pop", "_bpx"); + } + else + { + emitcode ("pop", "_bp"); + } + } + } + + /* restore the register bank */ + if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type)) + { + if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type) || !options.useXstack) + { + /* Special case of ISR using non-zero bank with useXstack + * is handled below. + */ + emitpop ("psw"); + } + } + + if (IFFUNC_ISISR (sym->type)) + { + + /* now we need to restore the registers */ + /* if this isr has no bank i.e. is going to + run with bank 0 , then we need to save more + registers :-) */ + if (!FUNC_REGBANK (sym->type)) + { + int i; + /* if this function does not call any other + function then we can be economical and + save only those registers that are used */ + if (!IFFUNC_HASFCALL (sym->type)) + { + /* if any registers used */ + if (sym->regsUsed) + { + bool bits_popped = FALSE; + /* restore the registers used */ + for (i = sym->regsUsed->size; i >= 0; i--) + { + if (bitVectBitValue (sym->regsUsed, i)) + bits_popped = popReg (i, bits_popped); + } + } + } + else + { + /* this function has a function call. We cannot + determine register usage so we will have to pop the + entire bank */ + if (options.parms_in_bank1) + { + for (i = 7; i >= 0; i--) + { + emitpop (rb1regs[i]); + } + } + unsaveRBank (0, ic, FALSE); + } + } + else + { + /* This ISR uses a non-zero bank. + * + * Restore any register banks saved by genFunction + * in reverse order. + */ + unsigned savedBanks = SPEC_ISR_SAVED_BANKS (currFunc->etype); + int ix; + + for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--) + { + if (savedBanks & (1 << ix)) + { + unsaveRBank (ix, NULL, FALSE); + } + } + + if (options.useXstack) + { + /* Restore bank AFTER calling unsaveRBank, + * since it can trash r0. + */ + emitpop ("psw"); + } + } + + if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx")) + { + if (options.stack10bit) + { + emitpop (DP2_RESULT_REG); + emitpop ("dpx1"); + emitpop ("dph1"); + emitpop ("dpl1"); + } + emitpop ("dps"); + emitpop ("dpx"); + } + if (!inExcludeList ("dph")) + emitpop ("dph"); + if (!inExcludeList ("dpl")) + emitpop ("dpl"); + if (!inExcludeList ("b")) + emitpop ("b"); + if (!inExcludeList ("acc")) + emitpop ("acc"); + + /* if debug then send end of function */ + if (options.debug && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + emitcode ("reti", ""); + } + else + { + if (IFFUNC_CALLEESAVES (sym->type)) + { + int i; + + /* if any registers used */ + if (sym->regsUsed) + { + /* save the registers used */ + for (i = sym->regsUsed->size; i >= 0; i--) + { + if (bitVectBitValue (sym->regsUsed, i)) + emitpop (REG_WITH_INDEX (i)->dname); + } + } + } + + /* if debug then send end of function */ + if (options.debug && currFunc) + { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + emitcode ("ret", ""); + } + + if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep) + return; + + /* If this was an interrupt handler using bank 0 that called another */ + /* function, then all registers must be saved; nothing to optimize. */ + if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL (sym->type) && !FUNC_REGBANK (sym->type)) + return; + + /* There are no push/pops to optimize if not callee-saves or ISR */ + if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type))) + return; + + /* If there were stack parameters, we cannot optimize without also */ + /* fixing all of the stack offsets; this is too dificult to consider. */ + if (FUNC_HASSTACKPARM (sym->type)) + return; + + /* Compute the registers actually used */ + regsUsed = newBitVect (ds390_nRegs); + regsUsedPrologue = newBitVect (ds390_nRegs); + while (lnp) + { + if (lnp->ic && lnp->ic->op == FUNCTION) + regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten (lnp)); + else + regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten (lnp)); + + if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION) + break; + if (!lnp->prev) + break; + lnp = lnp->prev; + } + + if (bitVectBitValue (regsUsedPrologue, DPS_IDX) && !bitVectBitValue (regsUsed, DPS_IDX)) + { + bitVectUnSetBit (regsUsedPrologue, DPS_IDX); + } + + if (bitVectBitValue (regsUsedPrologue, CND_IDX) && !bitVectBitValue (regsUsed, CND_IDX)) + { + regsUsed = bitVectUnion (regsUsed, regsUsedPrologue); + if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type) && !sym->stack && !FUNC_ISCRITICAL (sym->type)) + bitVectUnSetBit (regsUsed, CND_IDX); + } + else + regsUsed = bitVectUnion (regsUsed, regsUsedPrologue); + + /* If this was an interrupt handler that called another function */ + /* function, then assume working registers may be modified by it. */ + if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL (sym->type)) + { + regsUsed = bitVectSetBit (regsUsed, AP_IDX); + regsUsed = bitVectSetBit (regsUsed, DPX1_IDX); + regsUsed = bitVectSetBit (regsUsed, DPL1_IDX); + regsUsed = bitVectSetBit (regsUsed, DPH1_IDX); + regsUsed = bitVectSetBit (regsUsed, DPX_IDX); + regsUsed = bitVectSetBit (regsUsed, DPL_IDX); + regsUsed = bitVectSetBit (regsUsed, DPH_IDX); + regsUsed = bitVectSetBit (regsUsed, DPS_IDX); + regsUsed = bitVectSetBit (regsUsed, B_IDX); + regsUsed = bitVectSetBit (regsUsed, A_IDX); + regsUsed = bitVectSetBit (regsUsed, CND_IDX); + } + + /* Remove the unneeded push/pops */ + regsUnneeded = newBitVect (ds390_nRegs); + while (lnp) + { + if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION)) + { + if (!strncmp (lnp->line, "push", 4)) + { + idx = bitVectFirstBit (port->peep.getRegsRead (lnp)); + if (idx >= 0 && !bitVectBitValue (regsUsed, idx)) + { + connectLine (lnp->prev, lnp->next); + regsUnneeded = bitVectSetBit (regsUnneeded, idx); + } + } + if (!strncmp (lnp->line, "pop", 3) || !strncmp (lnp->line, "mov", 3)) + { + idx = bitVectFirstBit (port->peep.getRegsWritten (lnp)); + if (idx >= 0 && !bitVectBitValue (regsUsed, idx)) + { + connectLine (lnp->prev, lnp->next); + regsUnneeded = bitVectSetBit (regsUnneeded, idx); + } + } + } + lnp = lnp->next; + } + + for (idx = 0; idx < regsUnneeded->size; idx++) + if (bitVectBitValue (regsUnneeded, idx)) + emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname); + + freeBitVect (regsUnneeded); + freeBitVect (regsUsed); + freeBitVect (regsUsedPrologue); +} + +/*-----------------------------------------------------------------*/ +/* genJavaNativeRet - generate code for return JavaNative */ +/*-----------------------------------------------------------------*/ +static void +genJavaNativeRet (iCode * ic) +{ + int i, size; + + aopOp (IC_LEFT (ic), ic, FALSE, IS_OP_RUONLY (IC_LEFT (ic)) ? FALSE : TRUE); + size = AOP_SIZE (IC_LEFT (ic)); + + assert (size <= 4); + + /* it is assigned to GPR0-R3 then push them */ + if (aopHasRegs (AOP (IC_LEFT (ic)), R0_IDX, R1_IDX) || aopHasRegs (AOP (IC_LEFT (ic)), R2_IDX, R3_IDX)) + { + for (i = 0; i < size; i++) + { + emitcode ("push", "%s", aopGet (IC_LEFT (ic), i, FALSE, TRUE, DP2_RESULT_REG)); + } + for (i = (size - 1); i >= 0; i--) + { + emitcode ("pop", "a%s", javaRet[i]); + } + } + else + { + for (i = 0; i < size; i++) + emitcode ("mov", "%s,%s", javaRet[i], aopGet (IC_LEFT (ic), i, FALSE, TRUE, DP2_RESULT_REG)); + } + for (i = size; i < 4; i++) + emitcode ("mov", "%s,#0", javaRet[i]); + return; +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void +genRet (iCode * ic) +{ + int size, offset = 0, pushed = 0; + bool pushedA = FALSE; + + D (emitcode (";", "genRet")); + + /* if we have no return value then + just generate the "ret" */ + if (!IC_LEFT (ic)) + goto jumpret; + + /* if this is a JavaNative function then return + value in different register */ + if (IFFUNC_ISJAVANATIVE (currFunc->type)) + { + genJavaNativeRet (ic); + goto jumpret; + } + /* we have something to return then + move the return value into place */ + aopOp (IC_LEFT (ic), ic, FALSE, (IS_OP_RUONLY (IC_LEFT (ic)) ? FALSE : TRUE)); + size = AOP_SIZE (IC_LEFT (ic)); + + _startLazyDPSEvaluation (); + + if (IS_BIT (_G.currentFunc->etype)) + { + if (!IS_OP_RUONLY (IC_LEFT (ic))) + toCarry (IC_LEFT (ic)); + _endLazyDPSEvaluation (); + } + else + { + while (size--) + { + if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR) + { + emitpush (aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL)); + pushed++; + } + else + { + const char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL); + if (!EQ (fReturn[offset], l)) + if (fReturn[offset][0] == 'r' && (AOP_TYPE (IC_LEFT (ic)) == AOP_REG || AOP_TYPE (IC_LEFT (ic)) == AOP_R0 || AOP_TYPE (IC_LEFT (ic)) == AOP_R1)) + emitcode ("mov", "a%s,%s", fReturn[offset], l); // use register's direct address instead of name + else + emitcode ("mov", "%s,%s", fReturn[offset], l); + if (size && !strcmp(fReturn[offset], "a") && aopGetUsesAcc (IC_LEFT (ic), offset+1)) + { + emitpush ("acc"); + pushedA = TRUE; + } + offset++; + } + } + _endLazyDPSEvaluation (); + + if (pushedA) + { + emitpop ("acc"); + } + + while (pushed) + { + pushed--; + if (!EQ (fReturn[pushed], "a")) + emitpop (fReturn[pushed]); + else + emitpop ("acc"); + } + } + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); + +jumpret: + /* generate a jump to the return label + if the next is not the return statement */ + if (!(ic->next && ic->next->op == LABEL && IC_LABEL (ic->next) == returnLabel)) + { + emitcode ("ljmp", "!tlabel", labelKey2num (returnLabel->key)); + } +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void +genLabel (iCode * ic) +{ + /* special case never generate */ + if (IC_LABEL (ic) == entryLabel) + return; + + D (emitcode (";", "genLabel")); + + emitLabel (IC_LABEL (ic)); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a ljmp */ +/*-----------------------------------------------------------------*/ +static void +genGoto (iCode * ic) +{ + D (emitcode (";", "genGoto")); + + emitcode ("ljmp", "!tlabel", labelKey2num (IC_LABEL (ic)->key)); +} + +/*-----------------------------------------------------------------*/ +/* findLabelBackwards: walks back through the iCode chain looking */ +/* for the given label. Returns number of iCode instructions */ +/* between that label and given ic. */ +/* Returns zero if label not found. */ +/*-----------------------------------------------------------------*/ +static int +findLabelBackwards (iCode * ic, int key) +{ + int count = 0; + + while (ic->prev) + { + ic = ic->prev; + count++; + + /* If we have any pushes or pops, we cannot predict the distance. + I don't like this at all, this should be dealt with in the + back-end */ + if (ic->op == IPUSH || ic->op == IPOP) + { + return 0; + } + + if (ic->op == LABEL && IC_LABEL (ic)->key == key) + { + /* printf("findLabelBackwards = %d\n", count); */ + return count; + } + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* genPlusIncr :- does addition with increment if possible */ +/*-----------------------------------------------------------------*/ +static bool +genPlusIncr (iCode *ic) +{ + unsigned long long icount; + unsigned int size = getDataSize (IC_RESULT (ic)), offset; + + /* will try to generate an increment */ + /* if the right side is not a literal + we cannot */ + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) + return FALSE; + + /* if the literal value of the right hand side + is greater than 4 then it is not worth it */ + if ((icount = ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4) + return FALSE; + + if (size == 1 && AOP (IC_LEFT (ic)) == AOP (IC_RESULT (ic)) && AOP_TYPE (IC_LEFT (ic)) == AOP_DIR) + { + while (icount--) + { + emitcode ("inc", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL)); + } + return TRUE; + } + /* if increment 16 bits in register */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && + AOP_TYPE (IC_RESULT (ic)) == AOP_REG && + sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && (icount == 1)) + { + symbol *tlbl; + int emitTlbl; + int labelRange; + const char *l; + + /* If the next instruction is a goto and the goto target + * is <= 5 instructions previous to this, we can generate + * jumps straight to that target. + */ + if (ic->next && ic->next->op == GOTO + && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0 && labelRange <= 5) + { + D (emitcode (";", "tail increment optimized (range %d)", labelRange)); + tlbl = IC_LABEL (ic->next); + emitTlbl = 0; + } + else + { + tlbl = newiTempLabel (NULL); + emitTlbl = 1; + } + l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL); + emitcode ("inc", "%s", l); + if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("cjne", "%s,%s,!tlabel", l, zero, labelKey2num (tlbl->key)); + } + else + { + emitcode ("clr", "a"); + emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key)); + } + + l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL); + emitcode ("inc", "%s", l); + for(offset = 2; size > 2; size--, offset++) + { + if (EQ (l, "acc")) + { + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + } + else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("cjne", "%s,%s,!tlabel", l, zero, labelKey2num (tlbl->key)); + } + else + { + emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key)); + } + + l = aopGet (IC_RESULT (ic), offset, FALSE, FALSE, NULL); + emitcode ("inc", "%s", l); + } + + if (emitTlbl) + { + emitLabel (tlbl); + } + return TRUE; + } + + if (AOP_TYPE (IC_RESULT (ic)) == AOP_STR && IS_ITEMP (IC_RESULT (ic)) && + !AOP_USESDPTR (IC_LEFT (ic)) && icount <= 5 && size <= 3 && options.model == MODEL_FLAT24) + { + if (AOP_SIZE (IC_RESULT (ic)) == 4) + { + emitcode ("mov", "b,%s", aopGet (IC_LEFT (ic), 3, FALSE, FALSE, NULL)); + } + switch (size) + { + case 3: + emitcode ("mov", "dpx,%s", aopGet (IC_LEFT (ic), 2, FALSE, FALSE, NULL)); + case 2: + emitcode ("mov", "dph,%s", aopGet (IC_LEFT (ic), 1, FALSE, FALSE, NULL)); + case 1: + emitcode ("mov", "dpl,%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL)); + break; + } + while (icount--) + emitcode ("inc", "dptr"); + + return TRUE; + } + + if (AOP_INDPTRn (IC_LEFT (ic)) && AOP_INDPTRn (IC_RESULT (ic)) && + AOP (IC_LEFT (ic))->aopu.dptr == AOP (IC_RESULT (ic))->aopu.dptr && icount <= 5) + { + emitcode ("mov", "dps,#!constbyte", AOP (IC_LEFT (ic))->aopu.dptr); + while (icount--) + emitcode ("inc", "dptr"); + emitcode ("mov", "dps,#0"); + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ + if (AOP_SIZE (IC_RESULT (ic)) > 1 || AOP_SIZE (IC_LEFT (ic)) > 1) + return FALSE; + + /* we can if the aops of the left & result match or + if they are in registers and the registers are the + same */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && + AOP_TYPE (IC_RESULT (ic)) == AOP_REG && sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + { + if (icount > 3) + { + MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL)); + emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff); + aopPut (IC_RESULT (ic), "a", 0); + } + else + { + _startLazyDPSEvaluation (); + while (icount--) + { + emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL)); + } + _endLazyDPSEvaluation (); + } + + return TRUE; + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* outBitAcc - output a bit in acc */ +/*-----------------------------------------------------------------*/ +static void +outBitAcc (operand * result) +{ + symbol *tlbl = newiTempLabel (NULL); + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) + { + aopPut (result, "a", 0); + } + else + { + emitcode ("jz", "!tlabel", labelKey2num (tlbl->key)); + emitcode ("mov", "a,%s", one); + emitLabel (tlbl); + outAcc (result); + } +} + +/*-----------------------------------------------------------------*/ +/* genPlusBits - generates code for addition of two bits */ +/*-----------------------------------------------------------------*/ +static void +genPlusBits (iCode * ic) +{ + D (emitcode (";", "genPlusBits")); + + emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir); + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) + { + symbol *lbl = newiTempLabel (NULL); + emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, labelKey2num (lbl->key)); + emitcode ("cpl", "c"); + emitLabel (lbl); + outBitC (IC_RESULT (ic)); + } + else + { + emitcode ("clr", "a"); + emitcode ("rlc", "a"); + emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir); + emitcode ("addc", "a,%s", zero); + outAcc (IC_RESULT (ic)); + } +} + +static void +adjustArithmeticResult (iCode * ic) +{ + if (opIsGptr (IC_RESULT (ic)) && opIsGptr (IC_LEFT (ic)) && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)))) + { + aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL), GPTRSIZE - 1); + } + + if (opIsGptr (IC_RESULT (ic)) && opIsGptr (IC_RIGHT (ic)) && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic)))) + { + aopPut (IC_RESULT (ic), aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL), GPTRSIZE - 1); + } + + if (opIsGptr (IC_RESULT (ic)) && + IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE && + IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE && + !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) && !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic)))) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "#%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL)); + aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1); + dbuf_destroy (&dbuf); + } +} + +// The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC, +// generates the result if possible. If result is generated, returns TRUE; otherwise +// returns false and caller must deal with fact that result isn't aopOp'd. +bool +aopOp3 (iCode * ic) +{ + bool dp1InUse, dp2InUse; + bool useDp2; + + // First, generate the right opcode. DPTR may be used if neither left nor result are + // of type AOP_STR. + +// D (emitcode(";", "aopOp3: IS_OP_RUONLY left: %s right: %s result: %s", +// IS_OP_RUONLY(IC_LEFT(ic)) ? "true" : "false", +// IS_OP_RUONLY(IC_RIGHT(ic)) ? "true" : "false", +// IS_OP_RUONLY(IC_RESULT(ic)) ? "true" : "false"); +// ); +// D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s", +// AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false", +// AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false", +// AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false"); +// ); + + // Right uses DPTR unless left or result is an AOP_STR; however, + // if right is an AOP_STR, it must use DPTR regardless. + if ((IS_OP_RUONLY (IC_LEFT (ic)) || IS_OP_RUONLY (IC_RESULT (ic))) && !IS_OP_RUONLY (IC_RIGHT (ic))) + { + useDp2 = TRUE; + } + else + { + useDp2 = FALSE; + } + + aopOp (IC_RIGHT (ic), ic, FALSE, useDp2); + + // if the right used DPTR, left MUST use DPTR2. + // if the right used DPTR2, left MUST use DPTR. + // if both are still available, we prefer to use DPTR. But if result is an AOP_STR + // and left is not an AOP_STR, then we will get better code if we use DP2 for left, + // enabling us to assign DPTR to result. + + if (AOP_USESDPTR (IC_RIGHT (ic))) + { + useDp2 = TRUE; + } + else if (AOP_USESDPTR2 (IC_RIGHT (ic))) + { + useDp2 = FALSE; + } + else + { + if (IS_OP_RUONLY (IC_RESULT (ic)) && !IS_OP_RUONLY (IC_LEFT (ic))) + { + useDp2 = TRUE; + } + else + { + useDp2 = FALSE; + } + } + + aopOp (IC_LEFT (ic), ic, FALSE, useDp2); + + + // We've op'd the left & right. So, if left or right are the same operand as result, + // we know aopOp will succeed, and we can just do it & bail. + if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic))) + { + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic))); + return TRUE; + } + if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic))) + { +// D (emitcode(";", "aopOp3: (left | right) & result equal")); + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic))); + return TRUE; + } + + // Operands may be equivalent (but not equal) if they share a spill location. If + // so, use the same DPTR or DPTR2. + if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic))) + { + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic))); + return TRUE; + } + if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic))) + { + aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic))); + return TRUE; + } + + // Note which dptrs are currently in use. + dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic)); + dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic)); + + // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot + // generate it. + if (dp1InUse && IS_OP_RUONLY (IC_RESULT (ic))) + { + return FALSE; + } + + // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it. + if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic))) + { + return FALSE; + } + + // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck + if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic))) + { + return FALSE; + } + + aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse); + + // Some sanity checking... + if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic))) + { + fprintf (stderr, "Internal error: got unexpected DPTR (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno); + emitcode (";", ">>> unexpected DPTR here."); + } + + if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic))) + { + fprintf (stderr, "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno); + emitcode (";", ">>> unexpected DPTR2 here."); + } + + return TRUE; +} + +// Macro to aopOp all three operands of an ic. If this cannot be done, +// the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter +// will be set TRUE. The caller must then handle the case specially, noting +// that the IC_RESULT operand is not aopOp'd. +// +#define AOP_OP_3_NOFATAL(ic, rc) \ + do { rc = !aopOp3(ic); } while (0) + +// aopOp the left & right operands of an ic. +#define AOP_OP_2(ic) \ + aopOp (IC_RIGHT (ic), ic, FALSE, IS_OP_RUONLY (IC_LEFT (ic))); \ + aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic))); + +// convienience macro. +#define AOP_SET_LOCALS(ic) \ + left = IC_LEFT(ic); \ + right = IC_RIGHT(ic); \ + result = IC_RESULT(ic); + + +// Given an integer value of pushedSize bytes on the stack, +// adjust it to be resultSize bytes, either by discarding +// the most significant bytes or by zero-padding. +// +// On exit from this macro, pushedSize will have been adjusted to +// equal resultSize, and ACC may be trashed. +#define ADJUST_PUSHED_RESULT(pushedSize, resultSize) \ + /* If the pushed data is bigger than the result, \ + * simply discard unused bytes. Icky, but works. \ + */ \ + while (pushedSize > resultSize) \ + { \ + D (emitcode (";", "discarding unused result byte.")); \ + emitcode ("pop", "acc"); \ + pushedSize--; \ + } \ + if (pushedSize < resultSize) \ + { \ + emitcode ("clr", "a"); \ + /* Conversly, we haven't pushed enough here. \ + * just zero-pad, and all is well. \ + */ \ + while (pushedSize < resultSize) \ + { \ + emitcode("push", "acc"); \ + pushedSize++; \ + } \ + } \ + assert(pushedSize == resultSize); + +/*-----------------------------------------------------------------*/ +/* genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void +genPlus (iCode * ic) +{ + int size, offset = 0; + bool pushResult; + int rSize; + bool swappedLR = FALSE; + + D (emitcode (";", "genPlus")); + + /* special cases :- */ + if (IS_OP_RUONLY (IC_LEFT (ic)) && isOperandLiteral (IC_RIGHT (ic)) && IS_OP_RUONLY (IC_RESULT (ic))) + { + aopOp (IC_RIGHT (ic), ic, TRUE, FALSE); + size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); + if (size <= 9) + { + while (size--) + emitcode ("inc", "dptr"); + } + else + { + emitcode ("mov", "a,dpl"); + emitcode ("add", "a,#!constbyte", size & 0xff); + emitcode ("mov", "dpl,a"); + emitcode ("mov", "a,dph"); + emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff); + emitcode ("mov", "dph,a"); + emitcode ("mov", "a,dpx"); + emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff); + emitcode ("mov", "dpx,a"); + } + freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE); + return; + } + if (IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->remat && isOperandInFarSpace (IC_RIGHT (ic))) + { + operand *op = IC_RIGHT (ic); + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = op; + } + + AOP_OP_3_NOFATAL (ic, pushResult); + + if (pushResult) + { + D (emitcode (";", "genPlus: must push result: 3 ops in far space")); + } + + if (!pushResult) + { + /* if literal, literal on the right or + if left requires ACC or right is already + in ACC */ + if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) || + ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC) + { + operand *t = IC_RIGHT (ic); + IC_RIGHT (ic) = IC_LEFT (ic); + IC_LEFT (ic) = t; + swappedLR = TRUE; + D (emitcode (";", "Swapped plus args.")); + } + + /* if both left & right are in bit space */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY) + { + genPlusBits (ic); + goto release; + } + + /* if left in bit space & right literal */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT) + { + emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir); + /* if result in bit space */ + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) + { + if (ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) + emitcode ("cpl", "c"); + outBitC (IC_RESULT (ic)); + } + else + { + size = getDataSize (IC_RESULT (ic)); + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + emitcode ("addc", "a,%s", zero); + aopPut (IC_RESULT (ic), "a", offset++); + } + _endLazyDPSEvaluation (); + } + goto release; + } + + /* if I can do an increment instead + of add then GOOD for ME */ + if (genPlusIncr (ic) == TRUE) + { + D (emitcode (";", "did genPlusIncr")); + goto release; + } + + } + size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic)); + + _startLazyDPSEvaluation (); + while (size--) + { + if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && !AOP_NEEDSACC (IC_RIGHT (ic))) + { + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + if (offset == 0) + emitcode ("add", "a,%s", aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + else + emitcode ("addc", "a,%s", aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + } + else + { + if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && (offset == 0)) + { + /* right is going to use ACC or we would have taken the + * above branch. + */ + assert (AOP_NEEDSACC (IC_RIGHT (ic))); + TR_AP ("#3"); + D (emitcode (";", "+ AOP_ACC special case.");); + emitcode ("xch", "a, %s", DP2_RESULT_REG); + } + MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + if (offset == 0) + { + if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC) + { + TR_AP ("#4"); + emitcode ("add", "a, %s", DP2_RESULT_REG); + } + else + { + emitcode ("add", "a,%s", aopGet (IC_LEFT (ic), offset, FALSE, FALSE, DP2_RESULT_REG)); + } + } + else + { + emitcode ("addc", "a,%s", aopGet (IC_LEFT (ic), offset, FALSE, FALSE, DP2_RESULT_REG)); + } + } + if (!pushResult) + { + aopPut (IC_RESULT (ic), "a", offset); + } + else + { + emitcode ("push", "acc"); + } + offset++; + } + _endLazyDPSEvaluation (); + + if (pushResult) + { + aopOp (IC_RESULT (ic), ic, TRUE, FALSE); + adjustArithmeticResult (ic); + + size = getDataSize (IC_LEFT (ic)); + rSize = getDataSize (IC_RESULT (ic)); + + ADJUST_PUSHED_RESULT (size, rSize); + + _startLazyDPSEvaluation (); + while (size--) + { + emitcode ("pop", "acc"); + aopPut (IC_RESULT (ic), "a", size); + } + _endLazyDPSEvaluation (); + } + else + adjustArithmeticResult (ic); + +release: + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + if (swappedLR) + swapOperands (&IC_LEFT (ic), &IC_RIGHT (ic)); + freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genMinusDec :- does subtraction with decrement if possible */ +/*-----------------------------------------------------------------*/ +static bool +genMinusDec (iCode * ic) +{ + unsigned long long icount; + unsigned int size = getDataSize (IC_RESULT (ic)); + + /* will try to generate a decrement */ + /* if the right side is not a literal + we cannot */ + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) + return FALSE; + + /* if the literal value of the right hand side + is greater than 4 then it is not worth it */ + if ((icount = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4) + return FALSE; + + if (size == 1 && AOP (IC_LEFT (ic)) == AOP (IC_RESULT (ic)) && AOP_TYPE (IC_LEFT (ic)) == AOP_DIR) + { + while (icount--) + { + emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL)); + } + return TRUE; + } + /* if decrement 16 bits in register */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && + AOP_TYPE (IC_RESULT (ic)) == AOP_REG && + sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && (size > 1) && (icount == 1)) + { + symbol *tlbl; + int emitTlbl; + int labelRange; + const char *l; + + /* If the next instruction is a goto and the goto target + * is <= 5 instructions previous to this, we can generate + * jumps straight to that target. + */ + if (ic->next && ic->next->op == GOTO + && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0 && labelRange <= 5) + { + D (emitcode (";", "tail decrement optimized (range %d)", labelRange)); + tlbl = IC_LABEL (ic->next); + emitTlbl = 0; + } + else + { + tlbl = newiTempLabel (NULL); + emitTlbl = 1; + } + + l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL); + emitcode ("dec", "%s", l); + + if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR || IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key)); + } + else + { + emitcode ("mov", "a,#!constbyte", 0xff); + emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key)); + } + l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL); + emitcode ("dec", "%s", l); + if (size > 2) + { + if (EQ (l, "acc")) + { + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + } + else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || + AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR || IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key)); + } + else + { + emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key)); + } + l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL); + emitcode ("dec", "%s", l); + } + if (size > 3) + { + if (EQ (l, "acc")) + { + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + } + else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG || + AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR || IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, labelKey2num (tlbl->key)); + } + else + { + emitcode ("cjne", "a,%s,!tlabel", l, labelKey2num (tlbl->key)); + } + emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL)); + } + if (emitTlbl) + { + emitLabel (tlbl); + } + return TRUE; + } + + /* if the sizes are greater than 1 then we cannot */ + if (AOP_SIZE (IC_RESULT (ic)) > 1 || AOP_SIZE (IC_LEFT (ic)) > 1) + return FALSE; + + /* we can if the aops of the left & result match or + if they are in registers and the registers are the + same */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && + AOP_TYPE (IC_RESULT (ic)) == AOP_REG && sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + { + const char *l; + + if (aopGetUsesAcc (IC_LEFT (ic), 0)) + { + MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL)); + l = "a"; + } + else + { + l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL); + } + + _startLazyDPSEvaluation (); + while (icount--) + { + emitcode ("dec", "%s", l); + } + _endLazyDPSEvaluation (); + + if (AOP_NEEDSACC (IC_RESULT (ic))) + aopPut (IC_RESULT (ic), "a", 0); + + return TRUE; + } + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* addSign - complete with sign */ +/*-----------------------------------------------------------------*/ +static void +addSign (operand * result, int offset, int sign) +{ + int size = (getDataSize (result) - offset); + if (size > 0) + { + _startLazyDPSEvaluation (); + if (sign) + { + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + while (size--) + { + aopPut (result, "a", offset++); + } + } + else + { + while (size--) + { + aopPut (result, zero, offset++); + } + } + _endLazyDPSEvaluation (); + } +} + +/*-----------------------------------------------------------------*/ +/* genMinusBits - generates code for subtraction of two bits */ +/*-----------------------------------------------------------------*/ +static void +genMinusBits (iCode * ic) +{ + symbol *lbl = newiTempLabel (NULL); + + D (emitcode (";", "genMinusBits")); + + if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir); + emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, labelKey2num (lbl->key)); + emitcode ("cpl", "c"); + emitLabel (lbl); + outBitC (IC_RESULT (ic)); + } + else + { + emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir); + emitcode ("subb", "a,acc"); + emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, labelKey2num ((lbl->key))); + emitcode ("inc", "a"); + emitLabel (lbl); + aopPut (IC_RESULT (ic), "a", 0); + addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic))))); + } +} + +/*-----------------------------------------------------------------*/ +/* genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static void +genMinus (iCode * ic) +{ + int size, offset = 0; + int rSize; + long long lit = 0L; + bool pushResult; + + D (emitcode (";", "genMinus")); + + AOP_OP_3_NOFATAL (ic, pushResult); + + if (!pushResult) + { + /* special cases :- */ + /* if both left & right are in bit space */ + if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY) + { + genMinusBits (ic); + goto release; + } + + /* if I can do a decrement instead + of subtract then GOOD for ME */ + if (genMinusDec (ic) == TRUE) + goto release; + + } + + size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic)); + + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) + { + CLRC; + } + else + { + lit = ullFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit); + lit = -lit; + } + + + /* if literal, add a,#-lit, else normal subb */ + _startLazyDPSEvaluation (); + while (size--) + { + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) + { + if (AOP_USESDPTR (IC_RIGHT (ic))) + { + emitcode ("mov", "b,%s", aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + emitcode ("subb", "a,b"); + } + else + { + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + emitcode ("subb", "a,%s", aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, DP2_RESULT_REG)); + } + } + else + { + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + /* first add without previous c */ + if (!offset) + { + if (!size && lit == -1) + { + emitcode ("dec", "a"); + } + else + { + emitcode ("add", "a,#!constbyte", (unsigned int) (lit & 0x0FFL)); + } + } + else + { + emitcode ("addc", "a,#!constbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL)); + } + } + + if (pushResult) + { + emitcode ("push", "acc"); + } + else + { + aopPut (IC_RESULT (ic), "a", offset); + } + offset++; + } + _endLazyDPSEvaluation (); + + if (pushResult) + { + aopOp (IC_RESULT (ic), ic, TRUE, FALSE); + adjustArithmeticResult (ic); + + size = getDataSize (IC_LEFT (ic)); + rSize = getDataSize (IC_RESULT (ic)); + + ADJUST_PUSHED_RESULT (size, rSize); + + _startLazyDPSEvaluation (); + while (size--) + { + emitcode ("pop", "acc"); + aopPut (IC_RESULT (ic), "a", size); + } + _endLazyDPSEvaluation (); + } + else + adjustArithmeticResult (ic); + +release: + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + + +/*-----------------------------------------------------------------*/ +/* genMultbits :- multiplication of bits */ +/*-----------------------------------------------------------------*/ +static void +genMultbits (operand * left, operand * right, operand * result, iCode * ic) +{ + D (emitcode (";", "genMultbits")); + + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir); + aopOp (result, ic, TRUE, FALSE); + outBitC (result); +} + +/*-----------------------------------------------------------------*/ +/* genMultOneByte : 8*8=8/16 bit multiplication */ +/*-----------------------------------------------------------------*/ +static void +genMultOneByte (operand * left, operand * right, operand * result, iCode * ic) +{ + symbol *lbl; + int size, offset = 0; + bool runtimeSign, compiletimeSign; + bool lUnsigned, rUnsigned, pushedB; + + /* (if two literals: the value is computed before) */ + /* if one literal, literal on the right */ + if (AOP_TYPE (left) == AOP_LIT) + { + operand *t = right; + right = left; + left = t; + /* emitcode (";", "swapped left and right"); */ + } + /* if no literal, unsigned on the right: shorter code */ + if (AOP_TYPE (right) != AOP_LIT && SPEC_USIGN (getSpec (operandType (left)))) + { + operand *t = right; + right = left; + left = t; + } + + lUnsigned = SPEC_USIGN (getSpec (operandType (left))); + rUnsigned = SPEC_USIGN (getSpec (operandType (right))); + + pushedB = pushB (); + + if ((lUnsigned && rUnsigned) + /* sorry, I don't know how to get size + without calling aopOp (result,...); + see Feature Request */ + /* || size == 1 */ ) + /* no, this is not a bug; with a 1 byte result there's + no need to take care about the signedness! */ + { + /* just an unsigned 8 * 8 = 8 multiply + or 8u * 8u = 16u */ + /* emitcode (";","unsigned"); */ + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mul", "ab"); + + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result); + + if (size < 1) + { + /* this should never happen */ + fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", size, __FILE__, lineno); + exit (EXIT_FAILURE); + } + + aopPut (result, "a", offset++); + _G.accInUse--; + if (size != 1) + aopPut (result, "b", offset++); + + while (size-- > 2) + aopPut (result, zero, offset++); + + popB (pushedB); + return; + } + + /* we have to do a signed multiply */ + /* emitcode (";", "signed"); */ + + /* now sign adjust for both left & right */ + + /* let's see what's needed: */ + /* apply negative sign during runtime */ + runtimeSign = FALSE; + /* negative sign from literals */ + compiletimeSign = FALSE; + + if (!lUnsigned) + { + if (AOP_TYPE (left) == AOP_LIT) + { + /* signed literal */ + signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit); + if (val < 0) + compiletimeSign = TRUE; + } + else + /* signed but not literal */ + runtimeSign = TRUE; + } + + if (!rUnsigned) + { + if (AOP_TYPE (right) == AOP_LIT) + { + /* signed literal */ + signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit); + if (val < 0) + compiletimeSign ^= TRUE; + } + else + /* signed but not literal */ + runtimeSign = TRUE; + } + + /* initialize F0, which stores the runtime sign */ + if (runtimeSign) + { + if (compiletimeSign) + emitcode ("setb", "F0"); /* set sign flag */ + else + emitcode ("clr", "F0"); /* reset sign flag */ + } + + /* save the signs of the operands */ + if (AOP_TYPE (right) == AOP_LIT) + { + signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit); + + if (!rUnsigned && val < 0) + emitcode ("mov", "b,#!constbyte", -val); + else + emitcode ("mov", "b,#!constbyte", (unsigned char) val); + } + else /* ! literal */ + { + if (rUnsigned) /* emitcode (";", "signed"); */ + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + else + { + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "F0"); /* complement sign flag */ + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + emitcode ("mov", "b,a"); + } + } + + if (AOP_TYPE (left) == AOP_LIT) + { + signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit); + + if (!lUnsigned && val < 0) + emitcode ("mov", "a,#!constbyte", -val); + else + emitcode ("mov", "a,#!constbyte", (unsigned char) val); + } + else /* ! literal */ + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + + if (!lUnsigned) /* emitcode (";", "signed"); */ + { + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "F0"); /* complement sign flag */ + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + } + } + + /* now the multiplication */ + emitcode ("mul", "ab"); + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result); + + if (size < 1) + { + /* this should never happen */ + fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", size, __FILE__, lineno); + exit (EXIT_FAILURE); + } + + if (runtimeSign || compiletimeSign) + { + lbl = newiTempLabel (NULL); + if (runtimeSign) + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); /* lsb 2's complement */ + if (size == 1) + emitcode ("inc", "a"); /* inc doesn't set carry flag */ + else + { + emitcode ("add", "a,#0x01"); /* this sets carry flag */ + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); /* msb 2's complement */ + emitcode ("addc", "a,#0x00"); + emitcode ("xch", "a,b"); + } + emitLabel (lbl); + } + aopPut (result, "a", offset++); + _G.accInUse--; + if (size != 1) + aopPut (result, "b", offset++); + + if (size > 2) + { + emitcode ("mov", "c,b.7"); + emitcode ("subb", "a,acc"); + _G.accInUse++; + while (size-- > 2) + aopPut (result, "a", offset++); + _G.accInUse--; + } + + popB (pushedB); +} + +/*-----------------------------------------------------------------*/ +/* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply */ +/*-----------------------------------------------------------------*/ +static void +genMultTwoByte (operand * left, operand * right, operand * result, iCode * ic) +{ + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (left)); + int umult = SPEC_USIGN (retype) | SPEC_USIGN (letype); + symbol *lbl; + + if (AOP_TYPE (left) == AOP_LIT) + { + operand *t = right; + right = left; + left = t; + } + /* save EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("setb", "F1"); + emitcode ("jbc", "EA,!tlabel", labelKey2num (lbl->key)); + emitcode ("clr", "F1"); + emitLabel (lbl); + + /* load up MB with right */ + if (!umult) + { + emitcode ("clr", "F0"); + if (AOP_TYPE (right) == AOP_LIT) + { + int val = (int) ulFromVal (AOP (right)->aopu.aop_lit); + if (val < 0) + { + emitcode ("setb", "F0"); + val = -val; + } + emitcode ("mov", "mb,#!constbyte", val & 0xff); + emitcode ("mov", "mb,#!constbyte", (val >> 8) & 0xff); + } + else + { + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitcode ("setb", "F0"); + emitLabel (lbl); + emitcode ("mov", "mb,b"); + emitcode ("mov", "mb,a"); + } + } + else + { + emitcode ("mov", "mb,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "mb,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + } + /* load up MA with left */ + if (!umult) + { + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitcode ("jbc", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "F0"); + emitLabel (lbl); + emitcode ("mov", "ma,b"); + emitcode ("mov", "ma,a"); + } + else + { + emitcode ("mov", "ma,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "ma,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + } + /* wait for multiplication to finish */ + lbl = newiTempLabel (NULL); + emitLabel (lbl); + emitcode ("mov", "a,mcnt1"); + emitcode ("anl", "a,#!constbyte", 0x80); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + aopOp (result, ic, TRUE, FALSE); + + /* if unsigned then simple */ + if (umult) + { + emitcode ("mov", "a,ma"); + if (AOP_SIZE (result) >= 4) + aopPut (result, "a", 3); + emitcode ("mov", "a,ma"); + if (AOP_SIZE (result) >= 3) + aopPut (result, "a", 2); + aopPut (result, "ma", 1); + aopPut (result, "ma", 0); + } + else + { + emitcode ("push", "ma"); + emitcode ("push", "ma"); + emitcode ("push", "ma"); + MOVA ("ma"); + /* negate result if needed */ + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitLabel (lbl); + if (AOP_TYPE (result) == AOP_ACC) + { + D (emitcode (";", "ACC special case.")); + /* We know result is the only live aop, and + * it's obviously not a DPTR2, so AP is available. + */ + emitcode ("mov", "%s,acc", DP2_RESULT_REG); + } + else + { + aopPut (result, "a", 0); + } + + emitcode ("pop", "acc"); + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("addc", "a,#0"); + emitLabel (lbl); + aopPut (result, "a", 1); + emitcode ("pop", "acc"); + if (AOP_SIZE (result) >= 3) + { + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("addc", "a,#0"); + emitLabel (lbl); + aopPut (result, "a", 2); + } + emitcode ("pop", "acc"); + if (AOP_SIZE (result) >= 4) + { + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("addc", "a,#0"); + emitLabel (lbl); + aopPut (result, "a", 3); + } + if (AOP_TYPE (result) == AOP_ACC) + { + /* We stashed the result away above. */ + emitcode ("mov", "acc,%s", DP2_RESULT_REG); + } + + } + freeAsmop (result, NULL, ic, TRUE); + + /* restore EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F1,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "EA"); + emitLabel (lbl); + return; +} + +/*-----------------------------------------------------------------*/ +/* genMult - generates code for multiplication */ +/*-----------------------------------------------------------------*/ +static void +genMult (iCode * ic) +{ + operand *left = IC_LEFT (ic); + operand *right = IC_RIGHT (ic); + operand *result = IC_RESULT (ic); + + D (emitcode (";", "genMult")); + + /* assign the asmops */ + AOP_OP_2 (ic); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + genMultbits (left, right, result, ic); + goto release; + } + + /* if both are of size == 1 */ + if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1) + { + genMultOneByte (left, right, result, ic); + goto release; + } + + if (AOP_SIZE (left) == 2 && AOP_SIZE (right) == 2) + { + /* use the ds390 ARITHMETIC accel UNIT */ + genMultTwoByte (left, right, result, ic); + return; + } + /* should have been converted to function call */ + assert (0); + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genDivbits :- division of bits */ +/*-----------------------------------------------------------------*/ +static void +genDivbits (operand * left, operand * right, operand * result, iCode * ic) +{ + bool pushedB; + + D (emitcode (";", "genDivbits")); + + pushedB = pushB (); + + /* the result must be bit */ + LOAD_AB_FOR_DIV (left, right); + emitcode ("div", "ab"); + emitcode ("rrc", "a"); + aopOp (result, ic, TRUE, FALSE); + + popB (pushedB); + + aopPut (result, "c", 0); +} + +/*-----------------------------------------------------------------*/ +/* genDivOneByte : 8 bit division */ +/*-----------------------------------------------------------------*/ +static void +genDivOneByte (operand * left, operand * right, operand * result, iCode * ic) +{ + bool lUnsigned, rUnsigned, pushedB; + bool runtimeSign, compiletimeSign; + symbol *lbl; + int size, offset; + + D (emitcode (";", "genDivOneByte")); + + offset = 1; + lUnsigned = SPEC_USIGN (getSpec (operandType (left))); + rUnsigned = SPEC_USIGN (getSpec (operandType (right))); + + pushedB = pushB (); + + /* signed or unsigned */ + if (lUnsigned && rUnsigned) + { + /* unsigned is easy */ + LOAD_AB_FOR_DIV (left, right); + emitcode ("div", "ab"); + + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + aopPut (result, "a", 0); + _G.accInUse--; + + size = AOP_SIZE (result) - 1; + + while (size--) + aopPut (result, zero, offset++); + + popB (pushedB); + return; + } + + /* signed is a little bit more difficult */ + + /* now sign adjust for both left & right */ + + /* let's see what's needed: */ + /* apply negative sign during runtime */ + runtimeSign = FALSE; + /* negative sign from literals */ + compiletimeSign = FALSE; + + if (!lUnsigned) + { + if (AOP_TYPE (left) == AOP_LIT) + { + /* signed literal */ + signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit); + if (val < 0) + compiletimeSign = TRUE; + } + else + /* signed but not literal */ + runtimeSign = TRUE; + } + + if (!rUnsigned) + { + if (AOP_TYPE (right) == AOP_LIT) + { + /* signed literal */ + signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit); + if (val < 0) + compiletimeSign ^= TRUE; + } + else + /* signed but not literal */ + runtimeSign = TRUE; + } + + /* initialize F0, which stores the runtime sign */ + if (runtimeSign) + { + if (compiletimeSign) + emitcode ("setb", "F0"); /* set sign flag */ + else + emitcode ("clr", "F0"); /* reset sign flag */ + } + + /* save the signs of the operands */ + if (AOP_TYPE (right) == AOP_LIT) + { + signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit); + + if (!rUnsigned && val < 0) + emitcode ("mov", "b,#0x%02x", -val); + else + emitcode ("mov", "b,#0x%02x", (unsigned char) val); + } + else /* ! literal */ + { + if (rUnsigned) + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + else + { + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "F0"); /* complement sign flag */ + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + emitcode ("mov", "b,a"); + } + } + + if (AOP_TYPE (left) == AOP_LIT) + { + signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit); + + if (!lUnsigned && val < 0) + emitcode ("mov", "a,#0x%02x", -val); + else + emitcode ("mov", "a,#0x%02x", (unsigned char) val); + } + else /* ! literal */ + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + + if (!lUnsigned) + { + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "F0"); /* complement sign flag */ + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + } + } + + /* now the division */ + emitcode ("nop", "; workaround for DS80C390 div bug."); + emitcode ("div", "ab"); + + if (runtimeSign || compiletimeSign) + { + lbl = newiTempLabel (NULL); + if (runtimeSign) + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); /* lsb 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result) - 1; + + if (size > 0) + { + /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1) + then the result will be in b, a */ + emitcode ("mov", "b,a"); /* 1 */ + /* msb is 0x00 or 0xff depending on the sign */ + if (runtimeSign) + { + emitcode ("mov", "c,F0"); + emitcode ("subb", "a,acc"); + emitcode ("xch", "a,b"); /* 2 */ + while (size--) + aopPut (result, "b", offset++); /* write msb's */ + } + else /* compiletimeSign */ + while (size--) + aopPut (result, "#0xff", offset++); /* write msb's */ + } + aopPut (result, "a", 0); /* 3: write lsb */ + } + else + { + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result) - 1; + + aopPut (result, "a", 0); + while (size--) + aopPut (result, zero, offset++); + } + _G.accInUse--; + popB (pushedB); +} + +/*-----------------------------------------------------------------*/ +/* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide */ +/*-----------------------------------------------------------------*/ +static void +genDivTwoByte (operand * left, operand * right, operand * result, iCode * ic) +{ + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (left)); + int umult = SPEC_USIGN (retype) | SPEC_USIGN (letype); + symbol *lbl; + + /* save EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("setb", "F1"); + emitcode ("jbc", "EA,!tlabel", labelKey2num (lbl->key)); + emitcode ("clr", "F1"); + emitLabel (lbl); + + /* load up MA with left */ + if (!umult) + { + emitcode ("clr", "F0"); + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitcode ("setb", "F0"); + emitLabel (lbl); + emitcode ("mov", "ma,b"); + emitcode ("mov", "ma,a"); + } + else + { + emitcode ("mov", "ma,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "ma,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + } + + /* load up MB with right */ + if (!umult) + { + if (AOP_TYPE (right) == AOP_LIT) + { + int val = (int) ulFromVal (AOP (right)->aopu.aop_lit); + if (val < 0) + { + lbl = newiTempLabel (NULL); + emitcode ("jbc", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "F0"); + emitLabel (lbl); + val = -val; + } + emitcode ("mov", "mb,#!constbyte", val & 0xff); + emitcode ("mov", "mb,#!constbyte", (val >> 8) & 0xff); + } + else + { + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitcode ("jbc", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "F0"); + emitLabel (lbl); + emitcode ("mov", "mb,b"); + emitcode ("mov", "mb,a"); + } + } + else + { + emitcode ("mov", "mb,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "mb,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + } + + /* wait for multiplication to finish */ + lbl = newiTempLabel (NULL); + emitLabel (lbl); + emitcode ("mov", "a,mcnt1"); + emitcode ("anl", "a,#!constbyte", 0x80); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + aopOp (result, ic, TRUE, FALSE); + + /* if unsigned then simple */ + if (umult) + { + aopPut (result, "ma", 1); + aopPut (result, "ma", 0); + } + else + { + emitcode ("push", "ma"); + MOVA ("ma"); + /* negate result if needed */ + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitLabel (lbl); + aopPut (result, "a", 0); + emitcode ("pop", "acc"); + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); + emitcode ("addc", "a,#0"); + emitLabel (lbl); + aopPut (result, "a", 1); + } + freeAsmop (result, NULL, ic, TRUE); + /* restore EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F1,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "EA"); + emitLabel (lbl); + return; +} + +/*-----------------------------------------------------------------*/ +/* genDiv - generates code for division */ +/*-----------------------------------------------------------------*/ +static void +genDiv (iCode * ic) +{ + operand *left = IC_LEFT (ic); + operand *right = IC_RIGHT (ic); + operand *result = IC_RESULT (ic); + + D (emitcode (";", "genDiv")); + + /* assign the asmops */ + AOP_OP_2 (ic); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + genDivbits (left, right, result, ic); + goto release; + } + + /* if both are of size == 1 */ + if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1) + { + genDivOneByte (left, right, result, ic); + goto release; + } + + if (AOP_SIZE (left) == 2 && AOP_SIZE (right) == 2) + { + /* use the ds390 ARITHMETIC accel UNIT */ + genDivTwoByte (left, right, result, ic); + return; + } + /* should have been converted to function call */ + assert (0); +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genModbits :- modulus of bits */ +/*-----------------------------------------------------------------*/ +static void +genModbits (operand * left, operand * right, operand * result, iCode * ic) +{ + bool pushedB; + + D (emitcode (";", "genModbits")); + + pushedB = pushB (); + + /* the result must be bit */ + LOAD_AB_FOR_DIV (left, right); + emitcode ("div", "ab"); + emitcode ("mov", "a,b"); + emitcode ("rrc", "a"); + aopOp (result, ic, TRUE, FALSE); + + popB (pushedB); + + aopPut (result, "c", 0); +} + +/*-----------------------------------------------------------------*/ +/* genModOneByte : 8 bit modulus */ +/*-----------------------------------------------------------------*/ +static void +genModOneByte (operand * left, operand * right, operand * result, iCode * ic) +{ + bool lUnsigned, rUnsigned, pushedB; + bool runtimeSign, compiletimeSign; + symbol *lbl; + int size, offset; + + D (emitcode (";", "genModOneByte")); + + offset = 1; + lUnsigned = SPEC_USIGN (getSpec (operandType (left))); + rUnsigned = SPEC_USIGN (getSpec (operandType (right))); + + pushedB = pushB (); + + /* signed or unsigned */ + if (lUnsigned && rUnsigned) + { + /* unsigned is easy */ + LOAD_AB_FOR_DIV (left, right); + emitcode ("div", "ab"); + aopOp (result, ic, TRUE, FALSE); + aopPut (result, "b", 0); + + for (size = AOP_SIZE (result) - 1; size--;) + aopPut (result, zero, offset++); + + popB (pushedB); + return; + } + + /* signed is a little bit more difficult */ + + /* now sign adjust for both left & right */ + + /* modulus: sign of the right operand has no influence on the result! */ + if (AOP_TYPE (right) == AOP_LIT) + { + signed char val = (signed char) operandLitValue (right); + + if (!rUnsigned && val < 0) + emitcode ("mov", "b,#0x%02x", -val); + else + emitcode ("mov", "b,#0x%02x", (unsigned char) val); + } + else /* not literal */ + { + if (rUnsigned) + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + else + { + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + emitcode ("mov", "b,a"); + } + } + + /* let's see what's needed: */ + /* apply negative sign during runtime */ + runtimeSign = FALSE; + /* negative sign from literals */ + compiletimeSign = FALSE; + + /* sign adjust left side */ + if (AOP_TYPE (left) == AOP_LIT) + { + signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit); + + if (!lUnsigned && val < 0) + { + compiletimeSign = TRUE; /* set sign flag */ + emitcode ("mov", "a,#0x%02x", -val); + } + else + emitcode ("mov", "a,#0x%02x", (unsigned char) val); + } + else /* ! literal */ + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + + if (!lUnsigned) + { + runtimeSign = TRUE; + emitcode ("clr", "F0"); /* clear sign flag */ + + lbl = newiTempLabel (NULL); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "F0"); /* set sign flag */ + emitcode ("cpl", "a"); /* 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + } + } + + /* now the modulus */ + emitcode ("nop", "; workaround for DS80C390 div bug."); + emitcode ("div", "ab"); + + if (runtimeSign || compiletimeSign) + { + emitcode ("mov", "a,b"); + lbl = newiTempLabel (NULL); + if (runtimeSign) + emitcode ("jnb", "F0,!tlabel", labelKey2num (lbl->key)); + emitcode ("cpl", "a"); /* lsb 2's complement */ + emitcode ("inc", "a"); + emitLabel (lbl); + + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result) - 1; + + if (size > 0) + { + /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1) + then the result will be in b, a */ + emitcode ("mov", "b,a"); /* 1 */ + /* msb is 0x00 or 0xff depending on the sign */ + if (runtimeSign) + { + emitcode ("mov", "c,F0"); + emitcode ("subb", "a,acc"); + emitcode ("xch", "a,b"); /* 2 */ + while (size--) + aopPut (result, "b", offset++); /* write msb's */ + } + else /* compiletimeSign */ + while (size--) + aopPut (result, "#0xff", offset++); /* write msb's */ + } + aopPut (result, "a", 0); /* 3: write lsb */ + } + else + { + _G.accInUse++; + aopOp (result, ic, TRUE, FALSE); + size = AOP_SIZE (result) - 1; + + aopPut (result, "b", 0); + while (size--) + aopPut (result, zero, offset++); + } + _G.accInUse--; + popB (pushedB); +} + +/*-----------------------------------------------------------------*/ +/* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus */ +/*-----------------------------------------------------------------*/ +static void +genModTwoByte (operand * left, operand * right, operand * result, iCode * ic) +{ + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (left)); + int umult = SPEC_USIGN (retype) | SPEC_USIGN (letype); + symbol *lbl; + + /* load up MA with left */ + /* save EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("setb", "F1"); + emitcode ("jbc", "EA,!tlabel", labelKey2num (lbl->key)); + emitcode ("clr", "F1"); + emitLabel (lbl); + + if (!umult) + { + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitLabel (lbl); + emitcode ("mov", "ma,b"); + emitcode ("mov", "ma,a"); + } + else + { + emitcode ("mov", "ma,%s", aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "ma,%s", aopGet (left, 1, FALSE, FALSE, NULL)); + } + + /* load up MB with right */ + if (!umult) + { + if (AOP_TYPE (right) == AOP_LIT) + { + int val = (int) ulFromVal (AOP (right)->aopu.aop_lit); + if (val < 0) + { + val = -val; + } + emitcode ("mov", "mb,#!constbyte", val & 0xff); + emitcode ("mov", "mb,#!constbyte", (val >> 8) & 0xff); + } + else + { + lbl = newiTempLabel (NULL); + emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "a,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + emitcode ("jnb", "acc[7],!tlabel", labelKey2num (lbl->key)); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); + emitcode ("add", "a,#1"); + emitcode ("xch", "a,b"); + emitcode ("cpl", "a"); // msb + emitcode ("addc", "a,#0"); + emitLabel (lbl); + emitcode ("mov", "mb,b"); + emitcode ("mov", "mb,a"); + } + } + else + { + emitcode ("mov", "mb,%s", aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "mb,%s", aopGet (right, 1, FALSE, FALSE, NULL)); + } + + /* wait for multiplication to finish */ + lbl = newiTempLabel (NULL); + emitLabel (lbl); + emitcode ("mov", "a,mcnt1"); + emitcode ("anl", "a,#!constbyte", 0x80); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + aopOp (result, ic, TRUE, FALSE); + + aopPut (result, "mb", 1); + aopPut (result, "mb", 0); + freeAsmop (result, NULL, ic, TRUE); + + /* restore EA bit in F1 */ + lbl = newiTempLabel (NULL); + emitcode ("jnb", "F1,!tlabel", labelKey2num (lbl->key)); + emitcode ("setb", "EA"); + emitLabel (lbl); +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void +genMod (iCode * ic) +{ + operand *left = IC_LEFT (ic); + operand *right = IC_RIGHT (ic); + operand *result = IC_RESULT (ic); + + D (emitcode (";", "genMod")); + + /* assign the asmops */ + AOP_OP_2 (ic); + + /* special cases first */ + /* both are bits */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + genModbits (left, right, result, ic); + goto release; + } + + /* if both are of size == 1 */ + if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1) + { + genModOneByte (left, right, result, ic); + goto release; + } + + if (AOP_SIZE (left) == 2 && AOP_SIZE (right) == 2) + { + /* use the ds390 ARITHMETIC accel UNIT */ + genModTwoByte (left, right, result, ic); + return; + } + + /* should have been converted to function call */ + assert (0); + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genIfxJump :- will create a jump depending on the ifx */ +/*-----------------------------------------------------------------*/ +static void +genIfxJump (iCode * ic, const char *jval, iCode * popIc) +{ + symbol *jlbl; + symbol *tlbl = newiTempLabel (NULL); + char *inst; + + /* if there is something to be popped then do it first */ + popForBranch (popIc, TRUE); + + D (emitcode (";", "genIfxJump")); + + /* if true label then we jump if condition + supplied is true */ + if (IC_TRUE (ic)) + { + jlbl = IC_TRUE (ic); + inst = ((EQ (jval, "a") ? "jz" : (EQ (jval, "c") ? "jnc" : "jnb"))); + } + else + { + /* false label is present */ + jlbl = IC_FALSE (ic); + inst = ((EQ (jval, "a") ? "jnz" : (EQ (jval, "c") ? "jc" : "jb"))); + } + if (EQ (inst, "jb") || EQ (inst, "jnb")) + emitcode (inst, "%s,!tlabel", jval, labelKey2num ((tlbl->key))); + else + emitcode (inst, "!tlabel", labelKey2num (tlbl->key)); + emitcode ("ljmp", "!tlabel", labelKey2num (jlbl->key)); + emitLabel (tlbl); + + /* mark the icode as generated */ + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* isHexChar :- check if a char is a digit or 'a-f' or 'A-F' */ +/*-----------------------------------------------------------------*/ +static int isHexChar (const char c) +{ + const char hc[] = "0123456789ABCDEFabcdef"; + size_t i; + for (i = 0; i < strlen (hc); i++) + if (c == hc[i]) + return 1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* genCmp :- greater or less than comparison */ +/*-----------------------------------------------------------------*/ +static void +genCmp (operand * left, operand * right, iCode * ic, iCode * ifx, int sign) +{ + int size, offset = 0; + unsigned long long lit = 0; + operand *result; + + D (emitcode (";", "genCmp")); + + result = IC_RESULT (ic); + + /* if left & right are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + /* generic pointers require special handling since all NULL pointers must compare equal */ + else if (opIsGptr (left) || opIsGptr (right)) + { + /* push right */ + while (offset < GPTRSIZE) + { + emitpush (aopGet (left, offset++, FALSE, TRUE, NULL)); + } + loadDptrFromOperand (right, TRUE); + emitcode ("lcall", "___gptr_cmp"); + for (offset = 0; offset < GPTRSIZE; offset++) + emitpop (NULL); + } + else + { + /* subtract right from left if at the + end the carry flag is set then we know that + left is greater than right */ + size = max (AOP_SIZE (left), AOP_SIZE (right)); + + /* if unsigned char cmp with lit, do cjne left,#right,zz */ + if (size == 1 && !sign && AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR) + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE, NULL)); + symbol *lbl = newiTempLabel (NULL); + if (AOP(left)->type != AOP_IMMD || ((AOP(right)->type != AOP_IMMD) && AOP(right)->type != AOP_LIT)) + emitcode ("cjne", "%s,%s,!tlabel", l, aopGet (right, offset, FALSE, FALSE, NULL), labelKey2num (lbl->key)); + else + { + const char *l0 = l; + const char *r0 = aopGet (right, offset, FALSE, FALSE, NULL); + long l1, r1; + while (!isHexChar (*l0)) + l0++; + while (!isHexChar (*r0)) + r0++; + assert (sscanf(l0, "0x%lx", &l1) == 1); + assert (sscanf(r0, "0x%lx", &r1) == 1); + if (l1 != r1) + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + } + Safe_free (l); + emitLabel (lbl); + } + else + { + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ullFromVal (AOP (right)->aopu.aop_lit); + /* optimize if(x < 0) or if(x >= 0) */ + if (lit == 0L) + { + if (!sign) + { + CLRC; + } + else + { + MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL)); + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + + if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx) + { + freeAsmop (result, NULL, ic, TRUE); + genIfxJump (ifx, "acc[7]", ic->next); + return; + } + else + { + emitcode ("rlc", "a"); + } + goto release_freedLR; + } + goto release; + } + } + CLRC; + while (size--) + { + // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset); + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + // emitcode (";", "genCmp #2"); + if (sign && (size == 0)) + { + // emitcode (";", "genCmp #3"); + emitcode ("xrl", "a,#!constbyte", 0x80); + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long long lit = ullFromVal (AOP (right)->aopu.aop_lit); + // emitcode (";", "genCmp #3.1"); + emitcode ("subb", "a,#!constbyte", 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL)); + } + else + { + // emitcode (";", "genCmp #3.2"); + saveAccWarn = 0; + MOVB (aopGet (right, offset++, FALSE, FALSE, "b")); + saveAccWarn = DEFAULT_ACC_WARNING; + emitcode ("xrl", "b,#!constbyte", 0x80); + emitcode ("subb", "a,b"); + } + } + else + { + const char *s; + + // emitcode (";", "genCmp #4"); + saveAccWarn = 0; + s = aopGet (right, offset++, FALSE, FALSE, "b"); + saveAccWarn = DEFAULT_ACC_WARNING; + + emitcode ("subb", "a,%s", s); + } + } + } + } + +release: + /* Don't need the left & right operands any more; do need the result. */ + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + +release_freedLR: + + if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) + { + outBitC (result); + } + else + { + /* if the result is used in the next + ifx conditional branch then generate + code a little differently */ + if (ifx) + { + genIfxJump (ifx, "c", ic->next); + } + else + { + outBitC (result); + } + /* leave the result in acc */ + } + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void +genCmpGt (iCode * ic, iCode * ifx) +{ + operand *left, *right; + sym_link *letype, *retype; + int sign = 0; + + D (emitcode (";", "genCmpGt")); + + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + + if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right))) + { + letype = getSpec (operandType (left)); + retype = getSpec (operandType (right)); + sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) || + (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype)))); + } + /* assign the left & right asmops */ + AOP_OP_2 (ic); + + genCmp (right, left, ic, ifx, sign); +} + +/*-----------------------------------------------------------------*/ +/* genCmpLt - less than comparisons */ +/*-----------------------------------------------------------------*/ +static void +genCmpLt (iCode * ic, iCode * ifx) +{ + operand *left, *right; + sym_link *letype, *retype; + int sign = 0; + + D (emitcode (";", "genCmpLt")); + + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + + if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right))) + { + letype = getSpec (operandType (left)); + retype = getSpec (operandType (right)); + sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) || + (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype)))); + } + /* assign the left & right asmops */ + AOP_OP_2 (ic); + + genCmp (left, right, ic, ifx, sign); +} + +/*-----------------------------------------------------------------*/ +/* gencjneshort - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void +gencjneshort (operand * left, operand * right, symbol * lbl) +{ + int size = max (AOP_SIZE (left), AOP_SIZE (right)); + int offset = 0; + unsigned long long lit = 0; + + D (emitcode (";", "gencjneshort")); + + /* if the left side is a literal or + if the right is in a pointer register and left is not */ + if ((AOP_TYPE (left) == AOP_LIT) || + (AOP_TYPE (left) == AOP_IMMD) || (AOP_TYPE (left) == AOP_DIR) || (IS_AOP_PREG (right) && !IS_AOP_PREG (left))) + { + operand *t = right; + right = left; + left = t; + } + + if (AOP_TYPE (right) == AOP_LIT) + lit = ullFromVal (AOP (right)->aopu.aop_lit); + + /* generic pointers require special handling since all NULL pointers must compare equal */ + if (opIsGptr (left) || opIsGptr (right)) + { + /* push left */ + while (offset < size) + { + emitpush (aopGet (left, offset++, FALSE, TRUE, NULL)); + } + loadDptrFromOperand (right, TRUE); + emitcode ("lcall", "___gptr_cmp"); + for (offset = 0; offset < GPTRSIZE; offset++) + emitpop (NULL); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + } + + /* if the right side is a literal then anything goes */ + else if (AOP_TYPE (right) == AOP_LIT && + AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_IMMD && + AOP_TYPE (left) != AOP_STR && AOP_TYPE (left) != AOP_DPTRn) + { + while (size--) + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("cjne", "%s,%s,!tlabel", l, aopGet (right, offset, FALSE, FALSE, NULL), labelKey2num (lbl->key)); + Safe_free (l); + offset++; + } + } + + /* if the right side is in a register or in direct space or + if the left is a pointer register & right is not */ + else if (AOP_TYPE (right) == AOP_REG || + AOP_TYPE (right) == AOP_DIR || + AOP_TYPE (right) == AOP_LIT || + AOP_TYPE (right) == AOP_IMMD || + (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) || (IS_AOP_PREG (left) && !IS_AOP_PREG (right))) + { + while (size--) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) && + ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)) + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + else + emitcode ("cjne", "a,%s,!tlabel", aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG), labelKey2num (lbl->key)); + offset++; + } + } + else + { + /* right is a pointer reg need both a & b */ + while (size--) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("cjne", "a,b,!tlabel", labelKey2num (lbl->key)); + offset++; + } + } +} + +/*-----------------------------------------------------------------*/ +/* gencjne - compare and jump if not equal */ +/*-----------------------------------------------------------------*/ +static void +gencjne (operand * left, operand * right, symbol * lbl) +{ + symbol *tlbl = newiTempLabel (NULL); + + D (emitcode (";", "gencjne")); + + gencjneshort (left, right, lbl); + + MOVA (one); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl->key)); + emitLabel (lbl); + MOVA (zero); + emitLabel (tlbl); +} + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpEq (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + iCode *popIc = ic->next; + + D (emitcode (";", "genCmpEq")); + + AOP_OP_2 (ic); + AOP_SET_LOCALS (ic); + + /* if literal, literal on the right or + if the right is in a pointer register and left + is not */ + if ((AOP_TYPE (left) == AOP_LIT) || (IS_AOP_PREG (right) && !IS_AOP_PREG (left))) + { + swapOperands (&left, &right); + } + + if (ifx && /* !AOP_SIZE(result) */ + OP_SYMBOL (result) && OP_SYMBOL (result)->regType == REG_CND) + { + symbol *tlbl; + /* if they are both bit variables */ + if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) + { + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long long lit = ullFromVal (AOP (right)->aopu.aop_lit); + if (lit == 0L) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("cpl", "c"); + } + else if (lit == 1L) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + emitcode ("clr", "c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } + else + { + symbol *lbl = newiTempLabel (NULL); + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, labelKey2num (lbl->key)); + emitcode ("cpl", "c"); + emitLabel (lbl); + } + /* if true label then we jump if condition + supplied is true */ + tlbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) + { + emitcode ("jnc", "!tlabel", labelKey2num (tlbl->key)); + popForBranch (popIc, FALSE); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key)); + } + else + { + emitcode ("jc", "!tlabel", labelKey2num (tlbl->key)); + popForBranch (popIc, FALSE); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ifx)->key)); + } + emitLabel (tlbl); + } + else + { + tlbl = newiTempLabel (NULL); + gencjneshort (left, right, tlbl); + if (IC_TRUE (ifx)) + { + popForBranch (popIc, FALSE); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key)); + emitLabel (tlbl); + } + else + { + symbol *lbl = newiTempLabel (NULL); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (tlbl); + popForBranch (popIc, FALSE); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ifx)->key)); + emitLabel (lbl); + } + } + /* mark the icode as generated */ + ifx->generated = 1; + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + return; + } + + /* if they are both bit variables */ + if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT))) + { + if (AOP_TYPE (right) == AOP_LIT) + { + unsigned long long lit = ullFromVal (AOP (right)->aopu.aop_lit); + if (lit == 0L) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("cpl", "c"); + } + else if (lit == 1L) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + emitcode ("clr", "c"); + } + /* AOP_TYPE(right) == AOP_CRY */ + } + else + { + symbol *lbl = newiTempLabel (NULL); + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, labelKey2num (lbl->key)); + emitcode ("cpl", "c"); + emitLabel (lbl); + } + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, TRUE, FALSE); + + /* c = 1 if egal */ + if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) + { + outBitC (result); + goto release; + } + if (ifx) + { + genIfxJump (ifx, "c", popIc); + goto release; + } + /* if the result is used in an arithmetic operation + then put the result in place */ + outBitC (result); + } + else + { + gencjne (left, right, newiTempLabel (NULL)); + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, TRUE, FALSE); + + if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) + { + aopPut (result, "a", 0); + goto release; + } + if (ifx) + { + genIfxJump (ifx, "a", popIc); + goto release; + } + /* if the result is used in an arithmetic operation + then put the result in place */ + if (AOP_TYPE (result) != AOP_CRY) + outAcc (result); + /* leave the result in acc */ + } + +release: + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* hasInc - operand is incremented before any other use */ +/*-----------------------------------------------------------------*/ +static iCode * +hasInc (operand * op, iCode * ic, int osize) +{ + sym_link *type = operandType (op); + sym_link *retype = getSpec (type); + iCode *lic = ic->next; + int isize; + + /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */ + if (!IS_SYMOP (op)) + return NULL; + + if (IS_BITVAR (retype) || !IS_PTR (type)) + return NULL; + if (IS_AGGREGATE (type->next)) + return NULL; + if (osize != (isize = getSize (type->next))) + return NULL; + + while (lic) + { + /* if operand of the form op = op + <sizeof *op> */ + if (lic->op == '+' && isOperandEqual (IC_LEFT (lic), op) && + isOperandEqual (IC_RESULT (lic), op) && + isOperandLiteral (IC_RIGHT (lic)) && operandLitValue (IC_RIGHT (lic)) == isize) + { + return lic; + } + /* if the operand used or deffed */ + if (bitVectBitValue (OP_USES (op), lic->key) || lic->defKey == op->key) + { + return NULL; + } + /* if GOTO or IFX */ + if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) + break; + lic = lic->next; + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void +genAndOp (iCode * ic) +{ + operand *left, *right, *result; + symbol *tlbl; + + D (emitcode (";", "genAndOp")); + + /* note here that && operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + AOP_OP_2 (ic); + AOP_SET_LOCALS (ic); + + /* if both are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + outBitC (result); + } + else + { + tlbl = newiTempLabel (NULL); + toBoolean (left); + emitcode ("jz", "!tlabel", labelKey2num (tlbl->key)); + toBoolean (right); + emitLabel (tlbl); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + outBitAcc (result); + } + + freeAsmop (result, NULL, ic, TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genOrOp - for || operation */ +/*-----------------------------------------------------------------*/ +static void +genOrOp (iCode * ic) +{ + operand *left, *right, *result; + symbol *tlbl; + + D (emitcode (";", "genOrOp")); + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + AOP_OP_2 (ic); + AOP_SET_LOCALS (ic); + + /* if both are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + + outBitC (result); + } + else + { + tlbl = newiTempLabel (NULL); + toBoolean (left); + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + toBoolean (right); + emitLabel (tlbl); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + + aopOp (result, ic, FALSE, FALSE); + + outBitAcc (result); + } + + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* isLiteralBit - test if lit == 2^n */ +/*-----------------------------------------------------------------*/ +static int +isLiteralBit (unsigned long lit) +{ + unsigned long pw[32] = { 1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L, + 0x100L, 0x200L, 0x400L, 0x800L, + 0x1000L, 0x2000L, 0x4000L, 0x8000L, + 0x10000L, 0x20000L, 0x40000L, 0x80000L, + 0x100000L, 0x200000L, 0x400000L, 0x800000L, + 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L, + 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L + }; + int idx; + + for (idx = 0; idx < 32; idx++) + if (lit == pw[idx]) + return idx + 1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* continueIfTrue - */ +/*-----------------------------------------------------------------*/ +static void +continueIfTrue (iCode * ic) +{ + if (IC_TRUE (ic)) + { + emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ic)->key)); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpIfTrue - */ +/*-----------------------------------------------------------------*/ +static void +jumpIfTrue (iCode * ic) +{ + if (!IC_TRUE (ic)) + { + emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ic)->key)); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* jmpTrueOrFalse - */ +/*-----------------------------------------------------------------*/ +static void +jmpTrueOrFalse (iCode * ic, symbol * tlbl) +{ + // ugly but optimized by peephole + if (IC_TRUE (ic)) + { + symbol *nlbl = newiTempLabel (NULL); + emitcode ("sjmp", "!tlabel", labelKey2num (nlbl->key)); + emitLabel (tlbl); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ic)->key)); + emitLabel (nlbl); + } + else + { + emitcode ("ljmp", "!tlabel", labelKey2num (IC_FALSE (ic)->key)); + emitLabel (tlbl); + } + ic->generated = 1; +} + +// Generate code to perform a bit-wise logic operation +// on two operands in far space (assumed to already have been +// aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result +// in far space. This requires pushing the result on the stack +// then popping it into the result. +static void +genFarFarLogicOp (iCode * ic, char *logicOp) +{ + int size, resultSize, compSize; + int offset = 0; + + TR_AP ("#5"); + D (emitcode (";", "%s special case for 3 far operands.", logicOp);); + compSize = AOP_SIZE (IC_LEFT (ic)) < AOP_SIZE (IC_RIGHT (ic)) ? AOP_SIZE (IC_LEFT (ic)) : AOP_SIZE (IC_RIGHT (ic)); + + _startLazyDPSEvaluation (); + for (size = compSize; (size--); offset++) + { + MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL)); + emitcode ("mov", "%s, acc", DP2_RESULT_REG); + MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL)); + + emitcode (logicOp, "a,%s", DP2_RESULT_REG); + emitcode ("push", "acc"); + } + _endLazyDPSEvaluation (); + + freeAsmop (IC_LEFT (ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE); + freeAsmop (IC_RIGHT (ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE); + aopOp (IC_RESULT (ic), ic, TRUE, FALSE); + + resultSize = AOP_SIZE (IC_RESULT (ic)); + + ADJUST_PUSHED_RESULT (compSize, resultSize); + + _startLazyDPSEvaluation (); + while (compSize--) + { + emitcode ("pop", "acc"); + aopPut (IC_RESULT (ic), "a", compSize); + } + _endLazyDPSEvaluation (); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void +genAnd (iCode * ic, iCode * ifx) +{ + operand *left, *right, *result; + int size, offset = 0; + unsigned long long lit = 0L; + int bytelit = 0; + bool pushResult; + + D (emitcode (";", "genAnd")); + + AOP_OP_3_NOFATAL (ic, pushResult); + AOP_SET_LOCALS (ic); + + if (pushResult) + { + genFarFarLogicOp (ic, "anl"); + return; + } + +#ifdef DEBUG_TYPE + emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); + emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) +#ifdef LOGIC_OPS_BROKEN + || AOP_NEEDSACC (left) +#endif + ) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if result = right then exchange left and right */ + if (sameRegs (AOP (result), AOP (right))) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY) + { + operand *tmp = right; + right = left; + left = tmp; + } + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ullFromVal (AOP (right)->aopu.aop_lit); + } + + size = AOP_SIZE (result); + + // if(bit & yy) + // result = bit & yy; + if (AOP_TYPE (left) == AOP_CRY) + { + if (AOP_TYPE (right) == AOP_LIT) + { + // c = bit & literal; + if (lit & 1) + { + if (size && sameRegs (AOP (result), AOP (left))) + // no change + goto release; + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // bit(result) = 0; + if (size && (AOP_TYPE (result) == AOP_CRY)) + { + emitcode ("clr", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jumpIfTrue (ifx); + goto release; + } + emitcode ("clr", "c"); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit & bit; + if (IS_OP_ACCUSE (left)) + { + emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir); + } + else if (IS_OP_ACCUSE (right)) + { + emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + } + else if (AOP_TYPE (right) == AOP_DIR && IS_BOOL (operandType (right)) && AOP_TYPE (left) == AOP_CRY) + { + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("anl", "c,acc.0"); + } + else + { + // c = bit & val; + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + // c = lsb + emitcode ("rrc", "a"); + emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir); + } + } + // bit = c + // val = c + if (size) + outBitC (result); + // if(bit & ...) + else if ((AOP_TYPE (result) == AOP_CRY) && ifx) + genIfxJump (ifx, "c", ic->next); + goto release; + } + + // if(val & 0xZZ) - size = 0, ifx != FALSE - + // bit = val & 0xZZ - size = 1, ifx = FALSE - + if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY)) + { + int posbit = isLiteralBit (lit); + /* left & 2^n */ + if (posbit) + { + posbit--; + MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL)); + // bit = left & 2^n + if (size) + { + switch (posbit & 0x07) + { + case 0: + emitcode ("rrc", "a"); + break; + case 7: + emitcode ("rlc", "a"); + break; + default: + emitcode ("mov", "c,acc[%d]", posbit & 0x07); + break; + } + } + // if(left & 2^n) + else + { + if (ifx) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "acc[%d]", posbit & 0x07); + genIfxJump (ifx, dbuf_c_str (&dbuf), ic->next); + dbuf_destroy (&dbuf); + } + else + { + emitcode ("anl", "a,#!constbyte", 1 << (posbit & 0x07)); + } + goto release; + } + } + else + { + symbol *tlbl = newiTempLabel (NULL); + int sizel = AOP_SIZE (left); + if (size) + emitcode ("setb", "c"); + while (sizel--) + { + if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + // byte == 2^n ? + if ((posbit = isLiteralBit (bytelit)) != 0) + emitcode ("jb", "acc[%d],!tlabel", (posbit - 1) & 0x07, labelKey2num (tlbl->key)); + else + { + if (bytelit != 0x0FFL) + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + } + } + offset++; + } + // bit = left & literal + if (size) + { + emitcode ("clr", "c"); + emitLabel (tlbl); + } + // if(left & literal) + else + { + if (ifx) + jmpTrueOrFalse (ifx, tlbl); + else + emitLabel (tlbl); + goto release; + } + } + outBitC (result); + goto release; + } + + /* if left is same as result */ + if (sameRegs (AOP (result), AOP (left))) + { + for (; size--; offset++) + { + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0x0FF) + { + /* dummy read of volatile operand */ + if (isOperandVolatile (left, FALSE)) + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + else + continue; + } + else if (bytelit == 0) + { + aopPut (result, zero, offset); + } + else if (IS_AOP_PREG (result)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE, NULL)); + emitcode ("anl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE, NULL)); + Safe_free (l); + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + if (offset) + emitcode ("mov", "b,a"); + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("anl", "a,b"); + aopPut (result, "a", offset); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + if (IS_AOP_PREG (result)) + { + emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + } + } + } + } + } + else + { + // left & result in different registers + if (AOP_TYPE (result) == AOP_CRY) + { + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left & right) + symbol *tlbl = newiTempLabel (NULL); + int sizer = min (AOP_SIZE (left), AOP_SIZE (right)); + if (size) + emitcode ("setb", "c"); + while (sizer--) + { + if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR) + && AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL)); + } + else if (AOP_TYPE (left) == AOP_ACC) + { + if (!offset) + { + //B contains high byte of left + emitpush ("b"); + emitcode ("mov", "b,a"); + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,b"); + emitpop ("b"); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,b"); + } + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("anl", "a,b"); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + emitLabel (tlbl); + outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + else + emitLabel (tlbl); + } + else + { + for (; (size--); offset++) + { + // normal case + // result = left & right + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0x0FF) + { + aopPut (result, aopGet (left, offset, FALSE, FALSE, NULL), offset); + continue; + } + else if (bytelit == 0) + { + /* dummy read of volatile operand */ + if (isOperandVolatile (left, FALSE)) + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + aopPut (result, zero, offset); + continue; + } + else if (AOP_TYPE (left) == AOP_ACC) + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE, NULL)); + aopPut (result, l, offset); + Safe_free (l); + continue; + } + } + // faster than result <- left, anl result,right + // and better if result is SFR + if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR) + && AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL)); + } + else if (AOP_TYPE (left) == AOP_ACC) + { + if (!offset) + { + //B contains high byte of left + emitpush ("b"); + emitcode ("mov", "b,a"); + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,b"); + emitpop ("b"); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,b"); + } + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("anl", "a,b"); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + aopPut (result, "a", offset); + } + } + } + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genOr - code for or */ +/*-----------------------------------------------------------------*/ +static void +genOr (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset = 0; + unsigned long long lit = 0; + int bytelit = 0; + bool pushResult; + + D (emitcode (";", "genOr")); + + AOP_OP_3_NOFATAL (ic, pushResult); + AOP_SET_LOCALS (ic); + + if (pushResult) + { + genFarFarLogicOp (ic, "orl"); + return; + } + + +#ifdef DEBUG_TYPE + emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); + emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); +#endif + + /* if left is a literal & right is not then exchange them */ + if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) +#ifdef LOGIC_OPS_BROKEN + || AOP_NEEDSACC (left) // I think this is a net loss now. +#endif + ) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if result = right then exchange left and right */ + if (sameRegs (AOP (result), AOP (right))) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY) + { + operand *tmp = right; + right = left; + left = tmp; + } + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ullFromVal (AOP (right)->aopu.aop_lit); + } + + size = AOP_SIZE (result); + + // if(bit | yy) + // xx = bit | yy; + if (AOP_TYPE (left) == AOP_CRY) + { + if (AOP_TYPE (right) == AOP_LIT) + { + // c = bit | literal; + if (lit) + { + // lit != 0 => result = 1 + if (AOP_TYPE (result) == AOP_CRY) + { + if (size) + emitcode ("setb", "%s", AOP (result)->aopu.aop_dir); + else if (ifx) + continueIfTrue (ifx); + goto release; + } + emitcode ("setb", "c"); + } + else + { + // lit == 0 => result = left + if (size && sameRegs (AOP (result), AOP (left))) + goto release; + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + } + else + { + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit | bit; + if (IS_OP_ACCUSE (left)) + { + emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir); + } + else if (IS_OP_ACCUSE (right)) + { + emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir); + } + } + else + { + // c = bit | val; + symbol *tlbl = newiTempLabel (NULL); + if (!((AOP_TYPE (result) == AOP_CRY) && ifx)) + emitcode ("setb", "c"); + emitcode ("jb", "%s,!tlabel", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key)); + toBoolean (right); + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + if ((AOP_TYPE (result) == AOP_CRY) && ifx) + { + jmpTrueOrFalse (ifx, tlbl); + goto release; + } + else + { + CLRC; + emitLabel (tlbl); + } + } + } + // bit = c + // val = c + if (size) + outBitC (result); + // if(bit | ...) + else if ((AOP_TYPE (result) == AOP_CRY) && ifx) + genIfxJump (ifx, "c", ic->next); + goto release; + } + + // if(val | 0xZZ) - size = 0, ifx != FALSE - + // bit = val | 0xZZ - size = 1, ifx = FALSE - + if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY)) + { + if (lit) + { + // result = 1 + if (size) + emitcode ("setb", "%s", AOP (result)->aopu.aop_dir); + else if (ifx) + continueIfTrue (ifx); + goto release; + } + else + { + // lit = 0, result = boolean(left) + if (size) + SETC; + toBoolean (left); + if (size) + { + symbol *tlbl = newiTempLabel (NULL); + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + CLRC; + emitLabel (tlbl); + } + else + { + /* FIXME, thats pretty fishy, check for ifx!=0, testcase .. */ + assert (ifx); + genIfxJump (ifx, "a", ic->next); + goto release; + } + } + outBitC (result); + goto release; + } + + /* if left is same as result */ + if (sameRegs (AOP (result), AOP (left))) + { + for (; size--; offset++) + { + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0) + { + /* dummy read of volatile operand */ + if (isOperandVolatile (left, FALSE)) + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + else + continue; + } + else if (bytelit == 0x0FF) + { + aopPut (result, "#0xff", offset); + } + else if (IS_AOP_PREG (left)) + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE, NULL)); + emitcode ("orl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + Safe_free (l); + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + if (offset) + emitcode ("mov", "b,a"); + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + aopPut (result, "a", offset); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + if (IS_AOP_PREG (left)) + { + emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + } + } + } + } + } + else + { + // left & result in different registers + if (AOP_TYPE (result) == AOP_CRY) + { + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left | right) + symbol *tlbl = newiTempLabel (NULL); + int sizer = max (AOP_SIZE (left), AOP_SIZE (right)); + if (size) + emitcode ("setb", "c"); + while (sizer--) + { + if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR) + && AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else if (AOP_TYPE (left) == AOP_ACC) + { + if (!offset) + { + //B contains high byte of left + emitpush ("b"); + emitcode ("mov", "b,a"); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + emitpop ("b"); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + emitLabel (tlbl); + outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + else + emitLabel (tlbl); + } + else + { + _startLazyDPSEvaluation (); + for (; (size--); offset++) + { + // normal case + // result = left | right + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0) + { + aopPut (result, aopGet (left, offset, FALSE, FALSE, NULL), offset); + continue; + } + else if (bytelit == 0x0FF) + { + /* dummy read of volatile operand */ + if (isOperandVolatile (left, FALSE)) + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + aopPut (result, "#0xff", offset); + continue; + } + } + // faster than result <- left, orl result,right + // and better if result is SFR + if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR) + && AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else if (AOP_TYPE (left) == AOP_ACC) + { + if (!offset) + { + //B contains high byte of left + emitpush ("b"); + emitcode ("mov", "b,a"); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + emitpop ("b"); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + aopPut (result, "a", offset); + } + _endLazyDPSEvaluation (); + } + } + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void +genXor (iCode *ic, iCode *ifx) +{ + operand *left, *right, *result; + int size, offset = 0; + unsigned long long lit = 0; + int bytelit = 0; + bool pushResult; + + D (emitcode (";", "genXor")); + + AOP_OP_3_NOFATAL (ic, pushResult); + AOP_SET_LOCALS (ic); + + if (pushResult) + { + genFarFarLogicOp (ic, "xrl"); + return; + } + +#ifdef DEBUG_TYPE + emitcode (";", "Type res[%d] = l[%d]&r[%d]", AOP_TYPE (result), AOP_TYPE (left), AOP_TYPE (right)); + emitcode (";", "Size res[%d] = l[%d]&r[%d]", AOP_SIZE (result), AOP_SIZE (left), AOP_SIZE (right)); +#endif + + /* if left is a literal & right is not || + if left needs acc & right does not */ + if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) +#ifdef LOGIC_OPS_BROKEN + || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)) +#endif + ) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if result = right then exchange left and right */ + if (sameRegs (AOP (result), AOP (right))) + { + operand *tmp = right; + right = left; + left = tmp; + } + + /* if right is bit then exchange them */ + if (AOP_TYPE (right) == AOP_CRY && AOP_TYPE (left) != AOP_CRY) + { + operand *tmp = right; + right = left; + left = tmp; + } + if (AOP_TYPE (right) == AOP_LIT) + { + lit = ullFromVal (AOP (right)->aopu.aop_lit); + } + + size = AOP_SIZE (result); + + // if(bit ^ yy) + // xx = bit ^ yy; + if (AOP_TYPE (left) == AOP_CRY) + { + if (AOP_TYPE (right) == AOP_LIT) + { + // c = bit ^ literal; + if (lit >> 1) + { + // lit>>1 != 0 => result = 1 + if (AOP_TYPE (result) == AOP_CRY) + { + if (size) + emitcode ("setb", "%s", AOP (result)->aopu.aop_dir); + else if (ifx) + continueIfTrue (ifx); + goto release; + } + emitcode ("setb", "c"); + } + else + { + // lit == (0 or 1) + if (lit == 0) + { + // lit == 0, result = left + if (size && sameRegs (AOP (result), AOP (left))) + goto release; + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + } + else + { + // lit == 1, result = not(left) + if (size && sameRegs (AOP (result), AOP (left))) + { + emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir); + goto release; + } + else + { + emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir); + emitcode ("cpl", "c"); + } + } + } + } + else + { + // right != literal + symbol *tlbl = newiTempLabel (NULL); + if (AOP_TYPE (right) == AOP_CRY) + { + // c = bit ^ bit; + if (IS_OP_ACCUSE (left)) + { + // left already is in the carry + operand *tmp = right; + right = left; + left = tmp; + } + else + { + toCarry (right); + } + } + else + { + // c = bit ^ val + toCarry (right); + } + emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, labelKey2num (tlbl->key)); + emitcode ("cpl", "c"); + emitLabel (tlbl); + } + // bit = c + // val = c + if (size) + outBitC (result); + // if(bit ^ ...) + else if ((AOP_TYPE (result) == AOP_CRY) && ifx) + genIfxJump (ifx, "c", ic->next); + goto release; + } + + /* if left is same as result */ + if (sameRegs (AOP (result), AOP (left))) + { + for (; size--; offset++) + { + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0) + { + /* dummy read of volatile operand */ + if (isOperandVolatile (left, FALSE)) + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + else + continue; + } + else if (IS_AOP_PREG (left)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + char *l = Safe_strdup (aopGet (left, offset, FALSE, TRUE, NULL)); + emitcode ("xrl", "%s,%s", l, aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + Safe_free (l); + } + } + else + { + if (AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + if (offset) + emitcode ("mov", "b,a"); + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("xrl", "a,b"); + aopPut (result, "a", offset); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + if (IS_AOP_PREG (left)) + { + emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + aopPut (result, "a", offset); + } + else + { + emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + } + } + } + } + } + else + { + // left & result in different registers + if (AOP_TYPE (result) == AOP_CRY) + { + // result = bit + // if(size), result in bit + // if(!size && ifx), conditional oper: if(left ^ right) + symbol *tlbl = newiTempLabel (NULL); + int sizer = max (AOP_SIZE (left), AOP_SIZE (right)); + + if (size) + emitcode ("setb", "c"); + while (sizer--) + { + if ((AOP_TYPE (right) == AOP_LIT) && (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + } + else if ((AOP_TYPE (right) == AOP_REG || IS_AOP_PREG (right) || AOP_TYPE (right) == AOP_DIR) + && AOP_TYPE (left) == AOP_ACC) + { + if (offset) + emitcode ("mov", "a,b"); + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else if (AOP_TYPE (left) == AOP_ACC) + { + if (!offset) + { + //B contains high byte of left + emitpush ("b"); + emitcode ("mov", "b,a"); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("xrl", "a,b"); + emitpop ("b"); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("xrl", "a,b"); + } + } + else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset)) + { + MOVB (aopGet (left, offset, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("xrl", "a,b"); + } + else if (aopGetUsesAcc (left, offset)) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + MOVA (aopGet (right, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG)); + } + + emitcode ("jnz", "!tlabel", labelKey2num (tlbl->key)); + offset++; + } + if (size) + { + CLRC; + emitLabel (tlbl); + outBitC (result); + } + else if (ifx) + jmpTrueOrFalse (ifx, tlbl); + else // need a target here + emitLabel (tlbl); + } + else + { + for (; (size--); offset++) + { + // normal case + // result = left ^ right + if (AOP_TYPE (right) == AOP_LIT) + { + bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL); + if (bytelit == 0) + { + aopPut (result, aopGet (left, offset, FALSE, FALSE, NULL), offset); + continue; + } + D (emitcode (";", "better literal XOR.")); + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a, %s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + // faster than result <- left, anl result,right + // and better if result is SFR + if (AOP_TYPE (left) == AOP_ACC) + { + emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + const char *rOp = aopGet (right, offset, FALSE, FALSE, NULL); + if (!strcmp (rOp, "a") || !strcmp (rOp, "acc")) + { + emitcode ("mov", "b,a"); + rOp = "b"; + } + + rOp = Safe_strdup (rOp); + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("xrl", "a,%s", rOp); + Safe_free ((void *) rOp); + } + } + aopPut (result, "a", offset); + } + } + } + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void +genRRC (iCode * ic) +{ + operand *left, *result; + int size, offset; + + D (emitcode (";", "genRRC")); + + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* move it to the result */ + size = AOP_SIZE (result); + offset = size - 1; + _startLazyDPSEvaluation (); + /* no need to clear carry, bit7 will be written later */ + while (size--) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("rrc", "a"); + if (AOP_SIZE (result) > 1) + aopPut (result, "a", offset--); + } + _endLazyDPSEvaluation (); + + /* now we need to put the carry into the + highest order byte of the result */ + if (AOP_SIZE (result) > 1) + { + MOVA (aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL)); + } + emitcode ("mov", "acc[7],c"); + aopPut (result, "a", AOP_SIZE (result) - 1); + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRLC - generate code for rotate left with carry */ +/*-----------------------------------------------------------------*/ +static void +genRLC (iCode * ic) +{ + operand *left, *result; + int size, offset; + + D (emitcode (";", "genRLC")); + + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* move it to the result */ + size = AOP_SIZE (result); + offset = 0; + if (size--) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); /* bit0 will be written later */ + if (AOP_SIZE (result) > 1) + { + aopPut (result, "a", offset++); + } + + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); + if (AOP_SIZE (result) > 1) + aopPut (result, "a", offset++); + } + _endLazyDPSEvaluation (); + } + /* now we need to put the carry into the + highest order byte of the result */ + if (AOP_SIZE (result) > 1) + { + MOVA (aopGet (result, 0, FALSE, FALSE, NULL)); + } + emitcode ("mov", "acc[0],c"); + aopPut (result, "a", 0); + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void +genGetHbit (iCode * ic) +{ + operand *left, *result; + + D (emitcode (";", "genGetHbit")); + + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* get the highest order byte into a */ + MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL)); + if (AOP_TYPE (result) == AOP_CRY) + { + emitcode ("rlc", "a"); + outBitC (result); + } + else + { + emitcode ("rl", "a"); + emitcode ("anl", "a,#0x01"); + outAcc (result); + } + + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genSwap - generates code to swap nibbles or bytes */ +/*-----------------------------------------------------------------*/ +static void +genSwap (iCode * ic) +{ + operand *left, *result; + + D (emitcode (";", "genSwap")); + + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + _startLazyDPSEvaluation (); + switch (AOP_SIZE (left)) + { + case 1: /* swap nibbles in byte */ + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("swap", "a"); + aopPut (result, "a", 0); + break; + case 2: /* swap bytes in word */ + if (AOP_TYPE (left) == AOP_REG && sameRegs (AOP (left), AOP (result))) + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0); + aopPut (result, "a", 1); + } + else if (operandsEqu (left, result)) + { + char *reg = "a"; + bool pushedB = FALSE, leftInB = FALSE; + + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + if (aopGetUsesAcc (left, 1) || aopGetUsesAcc (result, 0)) + { + pushedB = pushB (); + emitcode ("mov", "b,a"); + reg = "b"; + leftInB = TRUE; + } + aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0); + aopPut (result, reg, 1); + + if (leftInB) + popB (pushedB); + } + else + { + aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0); + aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1); + } + break; + default: + wassertl (FALSE, "unsupported SWAP operand size"); + } + _endLazyDPSEvaluation (); + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* AccRol - rotate left accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccRol (int shCount) +{ + shCount &= 0x0007; // shCount : 0..7 + + switch (shCount) + { + case 0: + break; + case 1: + emitcode ("rl", "a"); + break; + case 2: + emitcode ("rl", "a"); + emitcode ("rl", "a"); + break; + case 3: + emitcode ("swap", "a"); + emitcode ("rr", "a"); + break; + case 4: + emitcode ("swap", "a"); + break; + case 5: + emitcode ("swap", "a"); + emitcode ("rl", "a"); + break; + case 6: + emitcode ("rr", "a"); + emitcode ("rr", "a"); + break; + case 7: + emitcode ("rr", "a"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccLsh - left shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccLsh (int shCount) +{ + if (shCount != 0) + { + if (shCount == 1) + emitcode ("add", "a,acc"); + else if (shCount == 2) + { + emitcode ("add", "a,acc"); + emitcode ("add", "a,acc"); + } + else + { + /* rotate left accumulator */ + AccRol (shCount); + /* and kill the lower order bits */ + emitcode ("anl", "a,#!constbyte", SLMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccRsh - right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccRsh (int shCount) +{ + if (shCount != 0) + { + if (shCount == 1) + { + CLRC; + emitcode ("rrc", "a"); + } + else + { + /* rotate right accumulator */ + AccRol (8 - shCount); + /* and kill the higher order bits */ + emitcode ("anl", "a,#!constbyte", SRMask[shCount]); + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccSRsh - signed right shift accumulator by known count */ +/*-----------------------------------------------------------------*/ +static void +AccSRsh (int shCount) +{ + symbol *tlbl; + if (shCount != 0) + { + if (shCount == 1) + { + emitcode ("mov", "c,acc[7]"); + emitcode ("rrc", "a"); + } + else if (shCount == 2) + { + emitcode ("mov", "c,acc[7]"); + emitcode ("rrc", "a"); + emitcode ("mov", "c,acc[7]"); + emitcode ("rrc", "a"); + } + else + { + tlbl = newiTempLabel (NULL); + /* rotate right accumulator */ + AccRol (8 - shCount); + /* and kill the higher order bits */ + emitcode ("anl", "a,#!constbyte", SRMask[shCount]); + emitcode ("jnb", "acc[%d],!tlabel", 7 - shCount, labelKey2num (tlbl->key)); + emitcode ("orl", "a,#!constbyte", (unsigned char) ~SRMask[shCount]); + emitLabel (tlbl); + } + } +} + +/*-----------------------------------------------------------------*/ +/* shiftR1Left2Result - shift right one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftR1Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign) +{ + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + /* shift right accumulator */ + if (sign) + AccSRsh (shCount); + else + AccRsh (shCount); + aopPut (result, "a", offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftL1Left2Result - shift left one byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftL1Left2Result (operand * left, int offl, operand * result, int offr, int shCount) +{ + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + /* shift left accumulator */ + AccLsh (shCount); + aopPut (result, "a", offr); +} + +/*-----------------------------------------------------------------*/ +/* movLeft2Result - move byte from left to result */ +/*-----------------------------------------------------------------*/ +static void +movLeft2Result (operand * left, int offl, operand * result, int offr, int sign) +{ + const char *l; + if (!sameRegs (AOP (left), AOP (result)) || (offl != offr)) + { + l = aopGet (left, offl, FALSE, FALSE, NULL); + + if (*l == '@' && (IS_AOP_PREG (result))) + { + emitcode ("mov", "a,%s", l); + aopPut (result, "a", offr); + } + else + { + if (!sign) + { + aopPut (result, l, offr); + } + else + { + /* MSB sign in acc.7 ! */ + if (getDataSize (left) == offl + 1) + { + MOVA (l); + aopPut (result, "a", offr); + } + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRrl1 - right rotate c->a:x->c by 1 */ +/*-----------------------------------------------------------------*/ +static void +AccAXRrl1 (const char *x) +{ + emitcode ("rrc", "a"); + emitcode ("xch", "a,%s", x); + emitcode ("rrc", "a"); + emitcode ("xch", "a,%s", x); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLrl1 - left rotate c<-a:x<-c by 1 */ +/*-----------------------------------------------------------------*/ +static void +AccAXLrl1 (const char *x) +{ + emitcode ("xch", "a,%s", x); + emitcode ("rlc", "a"); + emitcode ("xch", "a,%s", x); + emitcode ("rlc", "a"); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLsh1 - left shift a:x<-0 by 1 */ +/*-----------------------------------------------------------------*/ +static void +AccAXLsh1 (const char *x) +{ + emitcode ("xch", "a,%s", x); + emitcode ("add", "a,acc"); + emitcode ("xch", "a,%s", x); + emitcode ("rlc", "a"); +} + +/*-----------------------------------------------------------------*/ +/* AccAXLsh - left shift a:x by known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void +AccAXLsh (const char *x, int shCount) +{ + unsigned char mask; + + switch (shCount) + { + case 0: + break; + case 1: + AccAXLsh1 (x); + break; + case 2: + AccAXLsh1 (x); + AccAXLsh1 (x); + break; + case 3: + case 4: + case 5: // AAAAABBB:CCCCCDDD + mask = SLMask[shCount]; + AccRol (shCount); // BBBAAAAA:CCCCCDDD + emitcode ("anl", "a,#!constbyte", mask); // BBB00000:CCCCCDDD + emitcode ("xch", "a,%s", x); // CCCCCDDD:BBB00000 + AccRol (shCount); // DDDCCCCC:BBB00000 + emitcode ("xch", "a,%s", x); // BBB00000:DDDCCCCC + emitcode ("xrl", "a,%s", x); // (BBB^DDD)CCCCC:DDDCCCCC + emitcode ("xch", "a,%s", x); // DDDCCCCC:(BBB^DDD)CCCCC + emitcode ("anl", "a,#!constbyte", mask); // DDD00000:(BBB^DDD)CCCCC + emitcode ("xch", "a,%s", x); // (BBB^DDD)CCCCC:DDD00000 + emitcode ("xrl", "a,%s", x); // BBBCCCCC:DDD00000 + break; + case 6: // AAAAAABB:CCCCCCDD + mask = SRMask[shCount]; + emitcode ("anl", "a,#!constbyte", mask); // 000000BB:CCCCCCDD + emitcode ("mov", "c,acc[0]"); // c = B + emitcode ("xch", "a,%s", x); // CCCCCCDD:000000BB + emitcode ("rrc", "a"); + emitcode ("xch", "a,%s", x); + emitcode ("rrc", "a"); + emitcode ("mov", "c,acc[0]"); //<< get correct bit + emitcode ("xch", "a,%s", x); + emitcode ("rrc", "a"); + emitcode ("xch", "a,%s", x); + emitcode ("rrc", "a"); + emitcode ("xch", "a,%s", x); + break; + case 7: // a:x <<= 7 + mask = SRMask[shCount]; + emitcode ("anl", "a,#!constbyte", mask); // 0000000B:CCCCCCCD + emitcode ("mov", "c,acc[0]"); // c = B + emitcode ("xch", "a,%s", x); // CCCCCCCD:0000000B + AccAXRrl1 (x); // BCCCCCCC:D0000000 + break; + default: + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRsh - right shift a:x known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void +AccAXRsh (const char *x, int shCount) +{ + unsigned char mask = SRMask[shCount]; + + switch (shCount) + { + case 0: + break; + case 1: + CLRC; + AccAXRrl1 (x); // 0->a:x + break; + case 2: + CLRC; + AccAXRrl1 (x); // 0->a:x + CLRC; + AccAXRrl1 (x); // 0->a:x + break; + case 3: + case 4: + case 5: // AAAAABBB:CCCCCDDD = a:x + AccRol (8 - shCount); // BBBAAAAA:DDDCCCCC + emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA + AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA + emitcode ("anl", "a,#!constbyte", mask); // 000CCCCC:BBBAAAAA + emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA + emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA) + emitcode ("anl", "a,#!constbyte", mask); // 000AAAAA:BBB(CCCCC^AAAAA) + emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA + emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA + emitcode ("xch", "a,%s", x); // 000AAAAA:BBBCCCCC + break; + case 6: // AABBBBBB:CCDDDDDD + emitcode ("mov", "c,acc[7]"); + AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA + emitcode ("mov", "c,acc[7]"); + AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA + emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC + emitcode ("anl", "a,#!constbyte", mask); // 000000AA:BBBBBBCC + break; + case 7: // ABBBBBBB:CDDDDDDD + emitcode ("mov", "c,acc[7]"); // c = A + AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA + emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC + emitcode ("anl", "a,#!constbyte", mask); // 0000000A:BBBBBBBC + break; + default: + break; + } +} + +/*-----------------------------------------------------------------*/ +/* AccAXRshS - right shift signed a:x known count (0..7) */ +/*-----------------------------------------------------------------*/ +static void +AccAXRshS (const char *x, int shCount) +{ + symbol *tlbl; + unsigned char mask = SRMask[shCount]; + + switch (shCount) + { + case 0: + break; + case 1: + emitcode ("mov", "c,acc[7]"); + AccAXRrl1 (x); // s->a:x + break; + case 2: + emitcode ("mov", "c,acc[7]"); + AccAXRrl1 (x); // s->a:x + emitcode ("mov", "c,acc[7]"); + AccAXRrl1 (x); // s->a:x + break; + case 3: + case 4: + case 5: // AAAAABBB:CCCCCDDD = a:x + tlbl = newiTempLabel (NULL); + AccRol (8 - shCount); // BBBAAAAA:CCCCCDDD + emitcode ("xch", "a,%s", x); // CCCCCDDD:BBBAAAAA + AccRol (8 - shCount); // DDDCCCCC:BBBAAAAA + emitcode ("anl", "a,#!constbyte", mask); // 000CCCCC:BBBAAAAA + emitcode ("xrl", "a,%s", x); // BBB(CCCCC^AAAAA):BBBAAAAA + emitcode ("xch", "a,%s", x); // BBBAAAAA:BBB(CCCCC^AAAAA) + emitcode ("anl", "a,#!constbyte", mask); // 000AAAAA:BBB(CCCCC^AAAAA) + emitcode ("xch", "a,%s", x); // BBB(CCCCC^AAAAA):000AAAAA + emitcode ("xrl", "a,%s", x); // BBBCCCCC:000AAAAA + emitcode ("xch", "a,%s", x); // 000SAAAA:BBBCCCCC + emitcode ("jnb", "acc[%d],!tlabel", 7 - shCount, labelKey2num (tlbl->key)); + mask = ~SRMask[shCount]; + emitcode ("orl", "a,#!constbyte", mask); // 111AAAAA:BBBCCCCC + emitLabel (tlbl); + break; // SSSSAAAA:BBBCCCCC + case 6: // AABBBBBB:CCDDDDDD + tlbl = newiTempLabel (NULL); + emitcode ("mov", "c,acc[7]"); + AccAXLrl1 (x); // ABBBBBBC:CDDDDDDA + emitcode ("mov", "c,acc[7]"); + AccAXLrl1 (x); // BBBBBBCC:DDDDDDAA + emitcode ("xch", "a,%s", x); // DDDDDDAA:BBBBBBCC + emitcode ("anl", "a,#!constbyte", mask); // 000000AA:BBBBBBCC + emitcode ("jnb", "acc[%d],!tlabel", 7 - shCount, labelKey2num (tlbl->key)); + mask = ~SRMask[shCount]; + emitcode ("orl", "a,#!constbyte", mask); // 111111AA:BBBBBBCC + emitLabel (tlbl); + break; + case 7: // ABBBBBBB:CDDDDDDD + tlbl = newiTempLabel (NULL); + emitcode ("mov", "c,acc[7]"); // c = A + AccAXLrl1 (x); // BBBBBBBC:DDDDDDDA + emitcode ("xch", "a,%s", x); // DDDDDDDA:BBBBBBCC + emitcode ("anl", "a,#!constbyte", mask); // 0000000A:BBBBBBBC + emitcode ("jnb", "acc[%d],!tlabel", 7 - shCount, labelKey2num (tlbl->key)); + mask = ~SRMask[shCount]; + emitcode ("orl", "a,#!constbyte", mask); // 1111111A:BBBBBBBC + emitLabel (tlbl); + break; + default: + break; + } +} + +static void +_loadLeftIntoAx (const char **lsb, operand * left, operand * result, int offl, int offr) +{ + // Get the initial value from left into a pair of registers. + // MSB must be in A, LSB can be any register. + // + // If the result is held in registers, it is an optimization + // if the LSB can be held in the register which will hold the, + // result LSB since this saves us from having to copy it into + // the result following AccAXLsh. + // + // If the result is addressed indirectly, this is not a gain. + if (AOP_NEEDSACC (result)) + { + _startLazyDPSEvaluation (); + if (AOP_TYPE (left) == AOP_DPTR2) + { + // Get MSB in A. + MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL)); + // get LSB in DP2_RESULT_REG. + assert (!strcmp (aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG), DP2_RESULT_REG)); + } + else + { + const char *leftByte; + + // get LSB into DP2_RESULT_REG + leftByte = aopGet (left, offl, FALSE, FALSE, NULL); + if (strcmp (leftByte, DP2_RESULT_REG)) + { + TR_AP ("#7"); + emitcode ("mov", "%s,%s", DP2_RESULT_REG, leftByte); + } + // And MSB in A. + leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL); + assert (strcmp (leftByte, DP2_RESULT_REG)); + MOVA (leftByte); + } + _endLazyDPSEvaluation (); + *lsb = DP2_RESULT_REG; + } + else + { + if (sameRegs (AOP (result), AOP (left)) && ((offl + MSB16) == offr)) + { + /* don't crash result[offr] */ + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG)); + } + else + { + movLeft2Result (left, offl, result, offr, 0); + MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL)); + } + *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG); + assert (strcmp (*lsb, "a")); + } +} + +static void +_storeAxResults (const char *lsb, operand * result, int offr) +{ + _startLazyDPSEvaluation (); + if (AOP_NEEDSACC (result)) + { + /* We have to explicitly update the result LSB. + */ + emitcode ("xch", "a,%s", lsb); + aopPut (result, "a", offr); + emitcode ("mov", "a,%s", lsb); + } + if (getDataSize (result) > 1) + { + aopPut (result, "a", offr + MSB16); + } + _endLazyDPSEvaluation (); +} + +/*-----------------------------------------------------------------*/ +/* shiftL2Left2Result - shift left two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftL2Left2Result (operand * left, int offl, operand * result, int offr, int shCount) +{ + const char *lsb; + + _loadLeftIntoAx (&lsb, left, result, offl, offr); + + AccAXLsh (lsb, shCount); + + _storeAxResults (lsb, result, offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftR2Left2Result - shift right two bytes from left to result */ +/*-----------------------------------------------------------------*/ +static void +shiftR2Left2Result (operand * left, int offl, operand * result, int offr, int shCount, int sign) +{ + const char *lsb; + + _loadLeftIntoAx (&lsb, left, result, offl, offr); + + /* a:x >> shCount (x = lsb(result)) */ + if (sign) + AccAXRshS (lsb, shCount); + else + AccAXRsh (lsb, shCount); + + + _storeAxResults (lsb, result, offr); +} + +/*------------------------------------------------------------------*/ +/* shiftLLeftOrResult - shift left one byte from left, or to result */ +/*------------------------------------------------------------------*/ +static void +shiftLLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount) +{ + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + /* shift left accumulator */ + AccLsh (shCount); + /* or with result */ + if (aopGetUsesAcc (result, offr)) + { + emitcode ("xch", "a,b"); + MOVA (aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + else + { + emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG)); + } + /* back to result */ + aopPut (result, "a", offr); +} + +/*-----------------------------------------------------------------*/ +/* shiftRLeftOrResult - shift right one byte from left,or to result */ +/*-----------------------------------------------------------------*/ +static void +shiftRLeftOrResult (operand * left, int offl, operand * result, int offr, int shCount) +{ + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + /* shift right accumulator */ + AccRsh (shCount); + /* or with result */ + if (aopGetUsesAcc (result, offr)) + { + emitcode ("xch", "a,b"); + MOVA (aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("orl", "a,b"); + } + else + { + emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG)); + } + /* back to result */ + aopPut (result, "a", offr); +} + +/*-----------------------------------------------------------------*/ +/* genlshTwo - left shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genlshTwo (operand * result, operand * left, int shCount) +{ + int size; + + D (emitcode (";", "genlshTwo")); + + size = getDataSize (result); + + /* if shCount >= 8 */ + if (shCount >= 8) + { + shCount -= 8; + + if (size > 1) + { + if (shCount) + { + _startLazyDPSEvaluation (); + _endLazyDPSEvaluation (); + shiftL1Left2Result (left, LSB, result, MSB16, shCount); + aopPut (result, zero, LSB); + } + else + { + _startLazyDPSEvaluation (); + movLeft2Result (left, LSB, result, MSB16, 0); + aopPut (result, zero, LSB); + _endLazyDPSEvaluation (); + } + } + else + { + _startLazyDPSEvaluation (); + aopPut (result, zero, LSB); + _endLazyDPSEvaluation (); + } + } + + /* 1 <= shCount <= 7 */ + else + { + if (size == 1) + shiftL1Left2Result (left, LSB, result, LSB, shCount); + else + shiftL2Left2Result (left, LSB, result, LSB, shCount); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftLLong - shift left one long from left to result */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void +shiftLLong (operand * left, operand * result, int offr) +{ + int offl = LSB; + int size = AOP_SIZE (result); + int useXch = (sameRegs (AOP (left), AOP (result)) && size >= MSB16 + offr && offr != LSB); + + if (size > offl + offr) + { + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + emitcode ("add", "a,acc"); + if (useXch) + xch_a_aopGet (left, offl + offr, FALSE, FALSE, NULL); + else + aopPut (result, "a", offl + offr); + } + + for (offl = LSB + 1; offl < LSB + 8; offl++) + { + if (size > offl + offr) + { + if (!useXch) + MOVA (aopGet (left, offl, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); + if (useXch) + xch_a_aopGet (left, offl + offr, FALSE, FALSE, NULL); + else + aopPut (result, "a", offl + offr); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genlshFixed - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genlshFixed (operand *result, operand *left, int shCount) +{ + int size, b; + int full_bytes; + + D (emitcode (";", "genlshFixed")); + + size = AOP_SIZE (result); + + full_bytes = shCount / 8; + shCount -= full_bytes * 8; + if (shCount == 0) + { + for (b = size - 1; b > full_bytes - 1; b--) + movLeft2Result (left, b - full_bytes, result, b, 0); + } + else if ((shCount == 1) && (full_bytes < 2)) + { + shiftLLong (left, result, full_bytes); + } + else if ((shCount == 2) && (full_bytes == 0)) + { + shiftLLong (left, result, full_bytes); + shiftLLong (result, result, full_bytes); + } + else + { + int off; + for (off = size - 2; off - full_bytes >= 0; off -= 2) + { + shiftL2Left2Result (left, off - full_bytes, result, off, shCount); + if (off - full_bytes - 1 >= 0) + shiftRLeftOrResult (left, off - full_bytes - 1, result, off, 8 - shCount); + } + if (off - full_bytes == -1) + { + shiftL1Left2Result (left, LSB, result, full_bytes, shCount); + } + } + for (b = LSB; b < full_bytes; b++) + aopPut (result, zero, b); + return; +} + +/*-----------------------------------------------------------------*/ +/* genLeftShiftLiteral - left shifting by known count */ +/*-----------------------------------------------------------------*/ +static void +genLeftShiftLiteral (operand * left, operand * right, operand * result, iCode * ic) +{ + int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + int size; + + size = getSize (operandType (result)); + + D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size)); + + freeAsmop (right, NULL, ic, TRUE); + + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + +#if VIEW_SIZE + emitcode ("; shift left ", "result %d, left %d", size, AOP_SIZE (left)); +#endif + + /* I suppose that the left size >= result size */ + if (shCount == 0) + { + _startLazyDPSEvaluation (); + while (size--) + { + movLeft2Result (left, size, result, size, 0); + } + _endLazyDPSEvaluation (); + } + else if (shCount >= (size * 8)) + { + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, zero, size); + } + _endLazyDPSEvaluation (); + } + else + { + switch (size) + { + case 2: + genlshTwo (result, left, shCount); + break; + + case 1: + case 4: + case 8: + genlshFixed (result, left, shCount); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "*** ack! mystery literal shift!\n"); + break; + } + } + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void +genLeftShift (iCode * ic) +{ + operand *left, *right, *result; + int size, offset; + symbol *tlbl, *tlbl1; + bool pushedB; + + D (emitcode (";", "genLeftShift")); + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (right, ic, FALSE, FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE (right) == AOP_LIT) + { + genLeftShiftLiteral (left, right, result, ic); + return; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits makes no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + pushedB = pushB (); + if (AOP_TYPE (right) == AOP_LIT) + { + /* Really should be handled by genLeftShiftLiteral, + * but since I'm too lazy to fix that today, at least we can make + * some small improvement. + */ + emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1); + } + else + { + MOVB (aopGet (right, 0, FALSE, FALSE, "b")); + emitcode ("inc", "b"); + } + freeAsmop (right, NULL, ic, TRUE); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* now move the left to the result if they are not the same */ + if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1) + { + size = AOP_SIZE (result); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + const char *l = aopGet (left, offset, FALSE, TRUE, NULL); + if (*l == '@' && (IS_AOP_PREG (result))) + { + + emitcode ("mov", "a,%s", l); + aopPut (result, "a", offset); + } + else + aopPut (result, l, offset); + offset++; + } + _endLazyDPSEvaluation (); + } + + tlbl = newiTempLabel (NULL); + size = AOP_SIZE (result); + offset = 0; + tlbl1 = newiTempLabel (NULL); + + /* if it is only one byte then */ + if (size == 1) + { + symbol *tlbl1 = newiTempLabel (NULL); + + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + emitcode ("add", "a,acc"); + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); + aopPut (result, "a", 0); + goto release; + } + + reAdjustPreg (AOP (result)); + + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + MOVA (aopGet (result, offset, FALSE, FALSE, NULL)); + emitcode ("add", "a,acc"); + aopPut (result, "a", offset++); + _startLazyDPSEvaluation (); + while (--size) + { + MOVA (aopGet (result, offset, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); + aopPut (result, "a", offset++); + } + _endLazyDPSEvaluation (); + reAdjustPreg (AOP (result)); + + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genrshOne - right shift a one byte quantity by known count */ +/*-----------------------------------------------------------------*/ +static void +genrshOne (operand * result, operand * left, int shCount, int sign) +{ + D (emitcode (";", "genrshOne")); + + shiftR1Left2Result (left, LSB, result, LSB, shCount, sign); +} + +/*-----------------------------------------------------------------*/ +/* genrshTwo - right shift two bytes by known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genrshTwo (operand * result, operand * left, int shCount, int sign) +{ + D (emitcode (";", "genrshTwo")); + + /* if shCount >= 8 */ + if (shCount >= 8) + { + shCount -= 8; + _startLazyDPSEvaluation (); + if (shCount) + shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign); + else + movLeft2Result (left, MSB16, result, LSB, sign); + addSign (result, MSB16, sign); + _endLazyDPSEvaluation (); + } + + /* 1 <= shCount <= 7 */ + else + { + shiftR2Left2Result (left, LSB, result, LSB, shCount, sign); + } +} + +/*-----------------------------------------------------------------*/ +/* shiftRLong - shift right one long from left to result */ +/* offl = LSB or MSB16 */ +/*-----------------------------------------------------------------*/ +static void +shiftRLong (operand * left, int offl, operand * result, int sign) +{ + bool overlapping = regsInCommon (left, result) || operandsEqu (left, result); + + if (overlapping && offl > 1) + { + // we are in big trouble, but this shouldn't happen + werror (E_INTERNAL_ERROR, __FILE__, __LINE__); + } + + MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL)); + + if (offl == MSB16) + { + // shift is > 8 + if (sign) + { + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32)) + { + xch_a_aopGet (left, MSB32, FALSE, FALSE, DP2_RESULT_REG); + } + else + { + aopPut (result, "a", MSB32); + MOVA (aopGet (left, MSB32, FALSE, FALSE, DP2_RESULT_REG)); + } + } + else + { + if (aopPutUsesAcc (result, zero, MSB32)) + { + emitcode ("xch", "a,b"); + aopPut (result, zero, MSB32); + emitcode ("xch", "a,b"); + } + else + { + aopPut (result, zero, MSB32); + } + } + } + + if (!sign) + { + emitcode ("clr", "c"); + } + else + { + emitcode ("mov", "c,acc[7]"); + } + + emitcode ("rrc", "a"); + + if (overlapping && offl == MSB16 && sameByte (AOP (left), MSB24, AOP (result), MSB32 - offl)) + { + xch_a_aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG); + } + else + { + aopPut (result, "a", MSB32 - offl); + MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL)); + } + + emitcode ("rrc", "a"); + if (overlapping && offl == MSB16 && sameByte (AOP (left), MSB16, AOP (result), MSB24 - offl)) + { + xch_a_aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG); + } + else + { + aopPut (result, "a", MSB24 - offl); + MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL)); + } + + emitcode ("rrc", "a"); + if (offl != LSB) + { + aopPut (result, "a", MSB16 - offl); + } + else + { + if (overlapping && sameByte (AOP (left), LSB, AOP (result), MSB16 - offl)) + { + xch_a_aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG); + } + else + { + aopPut (result, "a", MSB16 - offl); + MOVA (aopGet (left, LSB, FALSE, FALSE, NULL)); + } + emitcode ("rrc", "a"); + aopPut (result, "a", LSB); + } +} + +/*-----------------------------------------------------------------*/ +/* genrshFour - shift four byte by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genrshFour (operand * result, operand * left, int shCount, int sign) +{ + D (emitcode (";", "genrshFour")); + + /* if shifting more that 3 bytes */ + if (shCount >= 24) + { + shCount -= 24; + _startLazyDPSEvaluation (); + if (shCount) + shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign); + else + movLeft2Result (left, MSB32, result, LSB, sign); + addSign (result, MSB16, sign); + _endLazyDPSEvaluation (); + } + else if (shCount >= 16) + { + shCount -= 16; + _startLazyDPSEvaluation (); + if (shCount) + shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign); + else + { + movLeft2Result (left, MSB24, result, LSB, 0); + movLeft2Result (left, MSB32, result, MSB16, sign); + } + addSign (result, MSB24, sign); + _endLazyDPSEvaluation (); + } + else if (shCount >= 8) + { + shCount -= 8; + _startLazyDPSEvaluation (); + if (shCount == 1) + { + shiftRLong (left, MSB16, result, sign); + } + else if (shCount == 0) + { + movLeft2Result (left, MSB16, result, LSB, 0); + movLeft2Result (left, MSB24, result, MSB16, 0); + movLeft2Result (left, MSB32, result, MSB24, sign); + addSign (result, MSB32, sign); + } + else + { + shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0); + shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount); + /* the last shift is signed */ + shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign); + addSign (result, MSB32, sign); + } + _endLazyDPSEvaluation (); + } + else + { + /* 1 <= shCount <= 7 */ + if (shCount <= 2) + { + shiftRLong (left, LSB, result, sign); + if (shCount == 2) + shiftRLong (result, LSB, result, sign); + } + else + { + shiftR2Left2Result (left, LSB, result, LSB, shCount, 0); + shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount); + shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genrshAny - shift any number of bytes by a known amount != 0 */ +/*-----------------------------------------------------------------*/ +static void +genrshAny (operand *result, operand *left, int shCount, int sign) +{ + int size, size2, offset; + + D (emitcode (";", "genrshAny")); + + size = AOP_SIZE (result); + + if (!operandsEqu (result, left)) + for (size2 = size, offset = 0; size2 > 0; size2--, offset++) + aopPut (result, aopGet (left, offset, FALSE, FALSE, NULL), offset); + + while (shCount--) + { + MOVA (aopGet (result, size - 1, FALSE, FALSE, NULL)); + if (!sign) + emitcode ("clr", "c"); + else + emitcode ("mov", "c,acc.7"); + emitcode ("rrc", "a"); + aopPut (result, "a", size - 1); + + for(size2 = size - 1, offset = size - 2; size2 > 0; size2--, offset--) + { + + MOVA (aopGet (result, offset, FALSE, FALSE, NULL)); + emitcode ("rrc", "a"); + aopPut (result, "a", offset); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genRightShiftLiteral - right shifting by known count */ +/*-----------------------------------------------------------------*/ +static void +genRightShiftLiteral (operand * left, operand * right, operand * result, iCode * ic, int sign) +{ + int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + int size; + + size = getSize (operandType (result)); + + D (emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size)); + + freeAsmop (right, NULL, ic, TRUE); + + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + +#if VIEW_SIZE + emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result), AOP_SIZE (left)); +#endif + + /* test the LEFT size !!! */ + + /* I suppose that the left size >= result size */ + if (shCount == 0) + { + size = getDataSize (result); + _startLazyDPSEvaluation (); + while (size--) + movLeft2Result (left, size, result, size, 0); + _endLazyDPSEvaluation (); + } + else if (shCount >= (size * 8)) + { + if (sign) + { + /* get sign in acc.7 */ + MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL)); + } + addSign (result, LSB, sign); + } + else + { + switch (size) + { + case 1: + genrshOne (result, left, shCount, sign); + break; + + case 2: + genrshTwo (result, left, shCount, sign); + break; + + case 4: + genrshFour (result, left, shCount, sign); + break; + + default: + genrshAny (result, left, shCount, sign); + break; + } + } + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genSignedRightShift - right shift of signed number */ +/*-----------------------------------------------------------------*/ +static void +genSignedRightShift (iCode * ic) +{ + operand *right, *left, *result; + int size, offset; + symbol *tlbl, *tlbl1; + bool pushedB; + + D (emitcode (";", "genSignedRightShift")); + + /* we do it the hard way put the shift count in b + and loop thru preserving the sign */ + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (right, ic, FALSE, FALSE); + + if (AOP_TYPE (right) == AOP_LIT) + { + genRightShiftLiteral (left, right, result, ic, 1); + return; + } + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + pushedB = pushB (); + if (AOP_TYPE (right) == AOP_LIT) + { + /* Really should be handled by genRightShiftLiteral, + * but since I'm too lazy to fix that today, at least we can make + * some small improvement. + */ + emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1); + } + else + { + MOVB (aopGet (right, 0, FALSE, FALSE, "b")); + emitcode ("inc", "b"); + } + freeAsmop (right, NULL, ic, TRUE); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* now move the left to the result if they are not the + same */ + if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1) + { + + size = AOP_SIZE (result); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + const char *l = aopGet (left, offset, FALSE, TRUE, NULL); + if (*l == '@' && IS_AOP_PREG (result)) + { + + emitcode ("mov", "a,%s", l); + aopPut (result, "a", offset); + } + else + aopPut (result, l, offset); + offset++; + } + _endLazyDPSEvaluation (); + } + + /* mov the highest order bit to OVR */ + tlbl = newiTempLabel (NULL); + tlbl1 = newiTempLabel (NULL); + + size = AOP_SIZE (result); + offset = size - 1; + MOVA (aopGet (left, offset, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); + emitcode ("mov", "ov,c"); + /* if it is only one byte then */ + if (size == 1) + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + emitcode ("mov", "c,ov"); + emitcode ("rrc", "a"); + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); + aopPut (result, "a", 0); + goto release; + } + + reAdjustPreg (AOP (result)); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + emitcode ("mov", "c,ov"); + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (result, offset, FALSE, FALSE, NULL)); + emitcode ("rrc", "a"); + aopPut (result, "a", offset--); + } + _endLazyDPSEvaluation (); + reAdjustPreg (AOP (result)); + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void +genRightShift (iCode * ic) +{ + operand *right, *left, *result; + sym_link *letype; + int size, offset; + symbol *tlbl, *tlbl1; + bool pushedB; + + D (emitcode (";", "genRightShift")); + + /* if signed then we do it the hard way preserve the + sign bit moving it inwards */ + letype = getSpec (operandType (IC_LEFT (ic))); + + if (!SPEC_USIGN (letype)) + { + genSignedRightShift (ic); + return; + } + + /* signed & unsigned types are treated the same : i.e. the + signed is NOT propagated inwards : quoting from the + ANSI - standard : "for E1 >> E2, is equivalent to division + by 2**E2 if unsigned or if it has a non-negative value, + otherwise the result is implementation defined ", MY definition + is that the sign does not get propagated */ + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (right, ic, FALSE, FALSE); + + /* if the shift count is known then do it + as efficiently as possible */ + if (AOP_TYPE (right) == AOP_LIT) + { + genRightShiftLiteral (left, right, result, ic, 0); + return; + } + + /* shift count is unknown then we have to form + a loop get the loop count in B : Note: we take + only the lower order byte since shifting + more that 32 bits make no sense anyway, ( the + largest size of an object can be only 32 bits ) */ + + pushedB = pushB (); + if (AOP_TYPE (right) == AOP_LIT) + { + /* Really should be handled by genRightShiftLiteral, + * but since I'm too lazy to fix that today, at least we can make + * some small improvement. + */ + emitcode ("mov", "b,#!constbyte", ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1); + } + else + { + MOVB (aopGet (right, 0, FALSE, FALSE, "b")); + emitcode ("inc", "b"); + } + freeAsmop (right, NULL, ic, TRUE); + aopOp (left, ic, FALSE, FALSE); + aopOp (result, ic, FALSE, AOP_USESDPTR (left)); + + /* now move the left to the result if they are not the + same */ + if (!sameRegs (AOP (left), AOP (result)) && AOP_SIZE (result) > 1) + { + size = AOP_SIZE (result); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + const char *l = aopGet (left, offset, FALSE, TRUE, NULL); + if (*l == '@' && IS_AOP_PREG (result)) + { + + emitcode ("mov", "a,%s", l); + aopPut (result, "a", offset); + } + else + aopPut (result, l, offset); + offset++; + } + _endLazyDPSEvaluation (); + } + + tlbl = newiTempLabel (NULL); + tlbl1 = newiTempLabel (NULL); + size = AOP_SIZE (result); + offset = size - 1; + + /* if it is only one byte then */ + if (size == 1) + { + MOVA (aopGet (left, 0, FALSE, FALSE, NULL)); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + CLRC; + emitcode ("rrc", "a"); + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); + aopPut (result, "a", 0); + goto release; + } + + reAdjustPreg (AOP (result)); + emitcode ("sjmp", "!tlabel", labelKey2num (tlbl1->key)); + emitLabel (tlbl); + CLRC; + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (result, offset, FALSE, FALSE, NULL)); + emitcode ("rrc", "a"); + aopPut (result, "a", offset--); + } + _endLazyDPSEvaluation (); + reAdjustPreg (AOP (result)); + + emitLabel (tlbl1); + emitcode ("djnz", "b,!tlabel", labelKey2num (tlbl->key)); + popB (pushedB); + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* emitPtrByteGet - emits code to get a byte into A through a */ +/* pointer register (R0, R1, or DPTR). The */ +/* original value of A can be preserved in B. */ +/*-----------------------------------------------------------------*/ +static void +emitPtrByteGet (const char *rname, int p_type, bool preserveAinB) +{ + switch (p_type) + { + case IPOINTER: + case POINTER: + if (preserveAinB) + emitcode ("mov", "b,a"); + emitcode ("mov", "a,@%s", rname); + break; + + case PPOINTER: + if (preserveAinB) + emitcode ("mov", "b,a"); + emitcode ("movx", "a,@%s", rname); + break; + + case FPOINTER: + if (preserveAinB) + emitcode ("mov", "b,a"); + emitcode ("movx", "a,@dptr"); + break; + + case CPOINTER: + if (preserveAinB) + emitcode ("mov", "b,a"); + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + break; + + case GPOINTER: + if (preserveAinB) + { + emitpush ("b"); + emitpush ("acc"); + } + emitcode ("lcall", "__gptrget"); + if (preserveAinB) + emitpop ("b"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* emitPtrByteSet - emits code to set a byte from src through a */ +/* pointer register (R0, R1, or DPTR). */ +/*-----------------------------------------------------------------*/ +static void +emitPtrByteSet (const char *rname, int p_type, const char *src) +{ + switch (p_type) + { + case IPOINTER: + case POINTER: + if (*src == '@') + { + MOVA (src); + emitcode ("mov", "@%s,a", rname); + } + else + emitcode ("mov", "@%s,%s", rname, src); + break; + + case PPOINTER: + MOVA (src); + emitcode ("movx", "@%s,a", rname); + break; + + case FPOINTER: + MOVA (src); + emitcode ("movx", "@dptr,a"); + break; + + case GPOINTER: + MOVA (src); + emitcode ("lcall", "__gptrput"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, const char *rname, int ptype) +{ + int offset = 0; /* result byte offset */ + int rsize; /* result size */ + int rlen = 0; /* remaining bitfield length */ + sym_link *etype; /* bitfield type information */ + unsigned blen; /* bitfield length */ + unsigned bstr; /* bitfield starting bit within byte */ + + D (emitcode (";", "genUnpackBits")); + + etype = getSpec (operandType (result)); + rsize = getSize (operandType (result)); + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + emitPtrByteGet (rname, ptype, FALSE); + AccRol (8 - bstr); + emitcode ("anl", "a,#!constbyte", ((unsigned char) - 1) >> (8 - blen)); + if (!SPEC_USIGN (etype)) + { + /* signed bitfield */ + symbol *tlbl = newiTempLabel (NULL); + + emitcode ("jnb", "acc[%d],!tlabel", blen - 1, labelKey2num (tlbl->key)); + emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen)); + emitLabel (tlbl); + } + aopPut (result, "a", offset++); + goto finish; + } + + /* Bit field did not fit in a byte. Copy all + but the partial byte at the end. */ + for (rlen = blen; rlen >= 8; rlen -= 8) + { + emitPtrByteGet (rname, ptype, FALSE); + aopPut (result, "a", offset++); + if (rlen > 8) + emitcode ("inc", "%s", rname); + } + + /* Handle the partial byte at the end */ + if (rlen) + { + emitPtrByteGet (rname, ptype, FALSE); + emitcode ("anl", "a,#!constbyte", ((unsigned char) - 1) >> (8 - rlen)); + if (!SPEC_USIGN (etype)) + { + /* signed bitfield */ + symbol *tlbl = newiTempLabel (NULL); + + emitcode ("jnb", "acc[%d],!tlabel", rlen - 1, labelKey2num (tlbl->key)); + emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen)); + emitLabel (tlbl); + } + aopPut (result, "a", offset++); + } + +finish: + if (offset < rsize) + { + char *source; + + if (SPEC_USIGN (etype)) + source = zero; + else + { + /* signed bitfield: sign extension with 0x00 or 0xff */ + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + + source = "a"; + } + rsize -= offset; + while (rsize--) + aopPut (result, source, offset++); + } +} + + +/*-----------------------------------------------------------------*/ +/* genDataPointerGet - generates code when ptr offset is known */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerGet (operand * left, operand * result, iCode * ic) +{ + const char *l; + int size, offset = 0; + + D (emitcode (";", "genDataPointerGet")); + + aopOp (result, ic, TRUE, FALSE); + + /* get the string representation of the name */ + l = aopGet (left, 0, FALSE, TRUE, NULL) + 1; // remove # + size = AOP_SIZE (result); + _startLazyDPSEvaluation (); + while (size--) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + if (offset) + { + dbuf_printf (&dbuf, "(%s + %d)", l, offset); + } + else + { + dbuf_append_str (&dbuf, l); + } + aopPut (result, dbuf_c_str (&dbuf), offset++); + dbuf_destroy (&dbuf); + } + _endLazyDPSEvaluation (); + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerGet (operand * left, operand * result, iCode * ic, iCode * pi) +{ + asmop *aop = NULL; + reg_info *preg = NULL; + const char *rname; + sym_link *rtype, *retype, *letype; + sym_link *ltype = operandType (left); + + D (emitcode (";", "genNearPointerGet")); + + rtype = operandType (result); + retype = getSpec (rtype); + letype = getSpec (ltype); + + aopOp (left, ic, FALSE, FALSE); + + /* if left is rematerialisable and + result is not bitfield variable type and + the left is pointer to data space i.e + lower 128 bytes of space */ + if (AOP_TYPE (left) == AOP_IMMD && !IS_BITFIELD (retype) && !IS_BITFIELD (letype) && DCL_TYPE (ltype) == POINTER) + { + genDataPointerGet (left, result, ic); + return; + } + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG (AOP (left))) + { + /* otherwise get a free pointer register */ + aop = newAsmop (0); + preg = getFreePtr (ic, &aop, FALSE); + emitcode ("mov", "%s,%s", preg->name, aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG)); + rname = preg->name; + } + else + rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG); + + freeAsmop (left, NULL, ic, TRUE); + aopOp (result, ic, FALSE, FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + genUnpackBits (result, rname, POINTER); + else + { + /* we can just get the values */ + int size = AOP_SIZE (result); + int offset = 0; + + while (size--) + { + if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK) + { + + emitcode ("mov", "a,@%s", rname); + aopPut (result, "a", offset); + } + else + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "@%s", rname); + aopPut (result, dbuf_c_str (&dbuf), offset); + dbuf_destroy (&dbuf); + } + offset++; + if (size || pi) + emitcode ("inc", "%s", rname); + } + } + + /* now some housekeeping stuff */ + if (aop) /* we had to allocate for this iCode */ + { + if (pi) + { + /* post increment present */ + aopPut (left, rname, 0); + } + freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth) && !pi) + { + int size = AOP_SIZE (result) - 1; + while (size--) + emitcode ("dec", "%s", rname); + } + } + + /* done */ + freeAsmop (result, NULL, ic, TRUE); + if (pi) + pi->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerGet - emitcode for paged pointer fetch */ +/*-----------------------------------------------------------------*/ +static void +genPagedPointerGet (operand * left, operand * result, iCode * ic, iCode * pi) +{ + asmop *aop = NULL; + reg_info *preg = NULL; + const char *rname; + sym_link *rtype, *retype, *letype; + + D (emitcode (";", "genPagedPointerGet")); + + rtype = operandType (result); + retype = getSpec (rtype); + letype = getSpec (operandType (left)); + aopOp (left, ic, FALSE, FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG (AOP (left))) + { + /* otherwise get a free pointer register */ + aop = newAsmop (0); + preg = getFreePtr (ic, &aop, FALSE); + emitcode ("mov", "%s,%s", preg->name, aopGet (left, 0, FALSE, TRUE, NULL)); + rname = preg->name; + } + else + rname = aopGet (left, 0, FALSE, FALSE, NULL); + + freeAsmop (left, NULL, ic, TRUE); + aopOp (result, ic, FALSE, FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + genUnpackBits (result, rname, PPOINTER); + else + { + /* we have can just get the values */ + int size = AOP_SIZE (result); + int offset = 0; + + while (size--) + { + + emitcode ("movx", "a,@%s", rname); + aopPut (result, "a", offset); + + offset++; + + if (size || pi) + emitcode ("inc", "%s", rname); + } + } + + /* now some housekeeping stuff */ + if (aop) /* we had to allocate for this iCode */ + { + if (pi) + aopPut (left, rname, 0); + freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE (result) > 1 && !OP_SYMBOL (left)->remat && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth) && !pi) + { + int size = AOP_SIZE (result) - 1; + while (size--) + emitcode ("dec", "%s", rname); + } + } + + /* done */ + freeAsmop (result, NULL, ic, TRUE); + if (pi) + pi->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerGet - get value from far space */ +/*-----------------------------------------------------------------*/ +static void +genFarPointerGet (operand * left, operand * result, iCode * ic, iCode * pi) +{ + int size, offset, dopi; + sym_link *retype = getSpec (operandType (result)); + sym_link *letype = getSpec (operandType (left)); + + D (emitcode (";", "genFarPointerGet")); + + aopOp (left, ic, FALSE, FALSE); + dopi = loadDptrFromOperand (left, FALSE); + + /* so dptr now contains the address */ + aopOp (result, ic, FALSE, (AOP_INDPTRn (left) ? FALSE : TRUE)); + + /* if bit then unpack */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + { + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + genUnpackBits (result, "dptr", FPOINTER); + if (AOP_INDPTRn (left)) + { + genSetDPTR (0); + } + } + else + { + size = AOP_SIZE (result); + offset = 0; + + if (AOP_INDPTRn (left) && AOP_USESDPTR (result)) + { + while (size--) + { + genSetDPTR (AOP (left)->aopu.dptr); + emitcode ("movx", "a,@dptr"); + if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD)) + emitcode ("inc", "dptr"); + genSetDPTR (0); + aopPut (result, "a", offset++); + } + } + else + { + _startLazyDPSEvaluation (); + while (size--) + { + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + else + { + genSetDPTR (0); + } + _flushLazyDPS (); + + emitcode ("movx", "a,@dptr"); + if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD)) + emitcode ("inc", "dptr"); + + aopPut (result, "a", offset++); + } + _endLazyDPSEvaluation (); + } + } + if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) + { + if (!AOP_INDPTRn (left)) + { + _startLazyDPSEvaluation (); + aopPut (left, "dpl", 0); + aopPut (left, "dph", 1); + if (options.model == MODEL_FLAT24) + aopPut (left, "dpx", 2); + _endLazyDPSEvaluation (); + } + pi->generated = 1; + } + else if ((IS_OP_RUONLY (left) || AOP_INDPTRn (left)) && + AOP_SIZE (result) > 1 && IS_SYMOP (left) && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) + { + size = AOP_SIZE (result) - 1; + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + while (size--) + emitcode ("lcall", "__decdptr"); + if (AOP_INDPTRn (left)) + { + genSetDPTR (0); + } + } + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCodePointerGet - get value from code space */ +/*-----------------------------------------------------------------*/ +static void +genCodePointerGet (operand * left, operand * result, iCode * ic, iCode * pi) +{ + int size, offset, dopi; + sym_link *retype = getSpec (operandType (result)); + + D (emitcode (";", "genCodePointerGet")); + + aopOp (left, ic, FALSE, FALSE); + dopi = loadDptrFromOperand (left, FALSE); + + /* so dptr now contains the address */ + aopOp (result, ic, FALSE, (AOP_INDPTRn (left) ? FALSE : TRUE)); + + /* if bit then unpack */ + if (IS_BITFIELD (retype)) + { + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + genUnpackBits (result, "dptr", CPOINTER); + if (AOP_INDPTRn (left)) + { + genSetDPTR (0); + } + } + else + { + size = AOP_SIZE (result); + offset = 0; + if (AOP_INDPTRn (left) && AOP_USESDPTR (result)) + { + while (size--) + { + genSetDPTR (AOP (left)->aopu.dptr); + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD)) + emitcode ("inc", "dptr"); + genSetDPTR (0); + aopPut (result, "a", offset++); + } + } + else + { + _startLazyDPSEvaluation (); + while (size--) + { + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + else + { + genSetDPTR (0); + } + _flushLazyDPS (); + + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD)) + emitcode ("inc", "dptr"); + aopPut (result, "a", offset++); + } + _endLazyDPSEvaluation (); + } + } + if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) + { + if (!AOP_INDPTRn (left)) + { + _startLazyDPSEvaluation (); + + aopPut (left, "dpl", 0); + aopPut (left, "dph", 1); + if (options.model == MODEL_FLAT24) + aopPut (left, "dpx", 2); + + _endLazyDPSEvaluation (); + } + pi->generated = 1; + } + else if (IS_SYMOP (left) && + (IS_OP_RUONLY (left) || AOP_INDPTRn (left)) && + AOP_SIZE (result) > 1 && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) + { + size = AOP_SIZE (result) - 1; + if (AOP_INDPTRn (left)) + { + genSetDPTR (AOP (left)->aopu.dptr); + } + while (size--) + emitcode ("lcall", "__decdptr"); + if (AOP_INDPTRn (left)) + { + genSetDPTR (0); + } + } + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - get value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerGet (operand * left, operand * result, iCode * ic, iCode * pi) +{ + int size, offset, dopi; + bool pushedB; + sym_link *retype = getSpec (operandType (result)); + sym_link *letype = getSpec (operandType (left)); + + D (emitcode (";", "genGenPointerGet")); + + aopOp (left, ic, FALSE, FALSE); + + pushedB = pushB (); + dopi = loadDptrFromOperand (left, TRUE); + + /* so dptr-b now contains the address */ + aopOp (result, ic, FALSE, (AOP_INDPTRn (left) ? FALSE : TRUE)); + + /* if bit then unpack */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + { + genUnpackBits (result, "dptr", GPOINTER); + } + else + { + size = AOP_SIZE (result); + offset = 0; + + while (size--) + { + if (size) + { + // Get two bytes at a time, results in _AP & A. + // dptr will be incremented ONCE by __gptrgetWord. + // + // Note: any change here must be coordinated + // with the implementation of __gptrgetWord + // in device/lib/_gptrget.c + emitcode ("lcall", "__gptrgetWord"); + aopPut (result, "a", offset++); + aopPut (result, DP2_RESULT_REG, offset++); + size--; + } + else + { + // Only one byte to get. + emitcode ("lcall", "__gptrget"); + aopPut (result, "a", offset++); + } + + if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD)) + { + emitcode ("inc", "dptr"); + } + } + } + + if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) + { + _startLazyDPSEvaluation (); + + aopPut (left, "dpl", 0); + aopPut (left, "dph", 1); + if (options.model == MODEL_FLAT24) + { + aopPut (left, "dpx", 2); + aopPut (left, "b", 3); + } + else + aopPut (left, "b", 2); + + _endLazyDPSEvaluation (); + + pi->generated = 1; + } + else if (IS_OP_RUONLY (left) && AOP_SIZE (result) > 1 && (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) + { + size = AOP_SIZE (result) - 1; + while (size--) + emitcode ("lcall", "__decdptr"); + } + popB (pushedB); + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (left, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPointerGet - generate code for pointer get */ +/*-----------------------------------------------------------------*/ +static void +genPointerGet (iCode * ic, iCode * pi) +{ + operand *left, *result; + sym_link *type, *etype; + int p_type; + + D (emitcode (";", "genPointerGet")); + + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType (left); + etype = getSpec (type); + /* if left is of type of pointer then it is simple */ + if (IS_PTR (type) && !IS_FUNC (type->next)) + { + p_type = DCL_TYPE (type); + } + else + { + /* we have to go by the storage class */ + p_type = PTR_TYPE (SPEC_OCLS (etype)); + } + + /* special case when cast remat */ + if (p_type == GPOINTER && IS_SYMOP (left) && OP_SYMBOL (left)->remat && IS_CAST_ICODE (OP_SYMBOL (left)->rematiCode)) + { + left = IC_RIGHT (OP_SYMBOL (left)->rematiCode); + type = operandType (left); + p_type = DCL_TYPE (type); + } + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) + { + case POINTER: + case IPOINTER: + genNearPointerGet (left, result, ic, pi); + break; + + case PPOINTER: + genPagedPointerGet (left, result, ic, pi); + break; + + case FPOINTER: + genFarPointerGet (left, result, ic, pi); + break; + + case CPOINTER: + genCodePointerGet (left, result, ic, pi); + break; + + case GPOINTER: + genGenPointerGet (left, result, ic, pi); + break; + } +} + + +/*-----------------------------------------------------------------*/ +/* genPackBits - generates code for packed bit storage */ +/*-----------------------------------------------------------------*/ +static void +genPackBits (sym_link * etype, operand * right, const char *rname, int p_type) +{ + int offset = 0; /* source byte offset */ + int rlen = 0; /* remaining bitfield length */ + unsigned blen; /* bitfield length */ + unsigned bstr; /* bitfield starting bit within byte */ + int litval; /* source literal value (if AOP_LIT) */ + unsigned char mask; /* bitmask within current byte */ + + D (emitcode (";", "genPackBits")); + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + /* If the bitfield length is less than a byte */ + if (blen < 8) + { + mask = ((unsigned char) (0xFF << (blen + bstr)) | (unsigned char) (0xFF >> (8 - bstr))); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with a bitfield length <8 and literal source + */ + litval = (int) ulFromVal (AOP (right)->aopu.aop_lit); + litval <<= bstr; + litval &= (~mask) & 0xff; + emitPtrByteGet (rname, p_type, FALSE); + if ((mask | litval) != 0xff) + emitcode ("anl", "a,#!constbyte", mask); + if (litval) + emitcode ("orl", "a,#!constbyte", litval); + } + else + { + if ((blen == 1) && (p_type != GPOINTER)) + { + /* Case with a bitfield length == 1 and no generic pointer + */ + if (AOP_TYPE (right) == AOP_CRY) + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + else + { + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + emitcode ("rrc", "a"); + } + emitPtrByteGet (rname, p_type, FALSE); + emitcode ("mov", "acc[%d],c", bstr); + } + else + { + bool pushedB; + /* Case with a bitfield length < 8 and arbitrary source + */ + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + /* shift and mask source value */ + AccLsh (bstr); + emitcode ("anl", "a,#!constbyte", (~mask) & 0xff); + + pushedB = pushB (); + /* transfer A to B and get next byte */ + emitPtrByteGet (rname, p_type, TRUE); + + emitcode ("anl", "a,#!constbyte", mask); + emitcode ("orl", "a,b"); + if (p_type == GPOINTER) + emitpop ("b"); + + popB (pushedB); + } + } + + emitPtrByteSet (rname, p_type, "a"); + return; + } + + /* Bit length is greater than 7 bits. In this case, copy */ + /* all except the partial byte at the end */ + for (rlen = blen; rlen >= 8; rlen -= 8) + { + emitPtrByteSet (rname, p_type, aopGet (right, offset++, FALSE, TRUE, NULL)); + if (rlen > 8) + emitcode ("inc", "%s", rname); + } + + /* If there was a partial byte at the end */ + if (rlen) + { + mask = (((unsigned char) - 1 << rlen) & 0xff); + + if (AOP_TYPE (right) == AOP_LIT) + { + /* Case with partial byte and literal source + */ + litval = (int) ulFromVal (AOP (right)->aopu.aop_lit); + litval >>= (blen - rlen); + litval &= (~mask) & 0xff; + emitPtrByteGet (rname, p_type, FALSE); + if ((mask | litval) != 0xff) + emitcode ("anl", "a,#!constbyte", mask); + if (litval) + emitcode ("orl", "a,#!constbyte", litval); + } + else + { + bool pushedB; + /* Case with partial byte and arbitrary source + */ + MOVA (aopGet (right, offset++, FALSE, FALSE, NULL)); + emitcode ("anl", "a,#!constbyte", (~mask) & 0xff); + + pushedB = pushB (); + /* transfer A to B and get next byte */ + emitPtrByteGet (rname, p_type, TRUE); + + emitcode ("anl", "a,#!constbyte", mask); + emitcode ("orl", "a,b"); + if (p_type == GPOINTER) + emitpop ("b"); + + popB (pushedB); + } + emitPtrByteSet (rname, p_type, "a"); + } +} + + +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerSet (operand * right, operand * result, iCode * ic) +{ + int size, offset; + char *l; + + D (emitcode (";", "genDataPointerSet")); + + aopOp (right, ic, FALSE, FALSE); + + size = max (AOP_SIZE (right), AOP_SIZE (result)); + //remove # + l = Safe_strdup (aopGet (result, 0, FALSE, TRUE, NULL) + 1); + for (offset = 0; offset < size; offset++) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + if (offset) + dbuf_printf (&dbuf, "(%s + %d)", l, offset); + else + dbuf_append_str (&dbuf, l); + emitcode ("mov", "%s,%s", dbuf_c_str (&dbuf), aopGet (right, offset, FALSE, FALSE, NULL)); + dbuf_destroy (&dbuf); + } + Safe_free (l); + + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void +genNearPointerSet (operand * right, operand * result, iCode * ic, iCode * pi) +{ + asmop *aop = NULL; + reg_info *preg = NULL; + const char *rname; + sym_link *retype, *letype; + sym_link *ptype = operandType (result); + + D (emitcode (";", "genNearPointerSet")); + + retype = getSpec (operandType (right)); + letype = getSpec (ptype); + + aopOp (result, ic, FALSE, FALSE); + + /* if the result is rematerializable & + in data space & not a bit variable */ + if (AOP_TYPE (result) == AOP_IMMD && DCL_TYPE (ptype) == POINTER && !IS_BITVAR (retype) && !IS_BITVAR (letype)) + { + genDataPointerSet (right, result, ic); + return; + } + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG (AOP (result))) + { + /* otherwise get a free pointer register */ + + aop = newAsmop (0); + preg = getFreePtr (ic, &aop, FALSE); + emitcode ("mov", "%s,%s", preg->name, aopGet (result, 0, FALSE, TRUE, NULL)); + rname = preg->name; + } + else + { + rname = aopGet (result, 0, FALSE, FALSE, NULL); + } + + aopOp (right, ic, FALSE, FALSE); + + rname = Safe_strdup (rname); + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER); + else + { + /* we can just get the values */ + int size = AOP_SIZE (right); + int offset = 0; + + while (size--) + { + const char *l = aopGet (right, offset, FALSE, TRUE, NULL); + if ((*l == '@') || (EQ (l, "acc"))) + { + MOVA (l); + emitcode ("mov", "@%s,a", rname); + } + else + emitcode ("mov", "@%s,%s", rname, l); + if (size || pi) + emitcode ("inc", "%s", rname); + offset++; + } + } + + /* now some housekeeping stuff */ + if (aop) /* we had to allocate for this iCode */ + { + if (pi) + aopPut (result, rname, 0); + freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if ((AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) && !pi) + { + int size = AOP_SIZE (right) - 1; + while (size--) + emitcode ("dec", "%s", rname); + } + } + Safe_free ((void *) rname); + + /* done */ + if (pi) + pi->generated = 1; + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPagedPointerSet - emitcode for Paged pointer put */ +/*-----------------------------------------------------------------*/ +static void +genPagedPointerSet (operand * right, operand * result, iCode * ic, iCode * pi) +{ + asmop *aop = NULL; + reg_info *preg = NULL; + const char *rname; + sym_link *retype, *letype; + + D (emitcode (";", "genPagedPointerSet")); + + retype = getSpec (operandType (right)); + letype = getSpec (operandType (result)); + + aopOp (result, ic, FALSE, FALSE); + + /* if the value is already in a pointer register + then don't need anything more */ + if (!AOP_INPREG (AOP (result))) + { + /* otherwise get a free pointer register */ + + aop = newAsmop (0); + preg = getFreePtr (ic, &aop, FALSE); + emitcode ("mov", "%s,%s", preg->name, aopGet (result, 0, FALSE, TRUE, NULL)); + rname = preg->name; + } + else + { + rname = aopGet (result, 0, FALSE, FALSE, NULL); + } + + aopOp (right, ic, FALSE, FALSE); + + rname = Safe_strdup (rname); + /* if bitfield then unpack the bits */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER); + else + { + /* we can just get the values */ + int size = AOP_SIZE (right); + int offset = 0; + + while (size--) + { + MOVA (aopGet (right, offset, FALSE, TRUE, NULL)); + emitcode ("movx", "@%s,a", rname); + if (size || pi) + emitcode ("inc", "%s", rname); + offset++; + } + } + + /* now some housekeeping stuff */ + if (aop) /* we had to allocate for this iCode */ + { + if (pi) + aopPut (result, rname, 0); + freeAsmop (NULL, aop, ic, TRUE); + } + else + { + /* we did not allocate which means left + already in a pointer register, then + if size > 0 && this could be used again + we have to point it back to where it + belongs */ + if (AOP_SIZE (right) > 1 && !OP_SYMBOL (result)->remat && (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) && !pi) + { + int size = AOP_SIZE (right) - 1; + while (size--) + emitcode ("dec", "%s", rname); + } + } + Safe_free ((void *) rname); + + /* done */ + if (pi) + pi->generated = 1; + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genFarPointerSet - set value from far space */ +/*-----------------------------------------------------------------*/ +static void +genFarPointerSet (operand * right, operand * result, iCode * ic, iCode * pi) +{ + int size, offset, dopi; + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (result)); + + D (emitcode (";", "genFarPointerSet")); + + aopOp (result, ic, FALSE, FALSE); + dopi = loadDptrFromOperand (result, FALSE); + + /* so dptr now contains the address */ + aopOp (right, ic, FALSE, (AOP_INDPTRn (result) ? FALSE : TRUE)); + + /* if bit then unpack */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + { + if (AOP_INDPTRn (result)) + { + genSetDPTR (AOP (result)->aopu.dptr); + } + genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER); + if (AOP_INDPTRn (result)) + { + genSetDPTR (0); + } + } + else + { + size = AOP_SIZE (right); + offset = 0; + if (AOP_INDPTRn (result) && AOP_USESDPTR (right)) + { + while (size--) + { + MOVA (aopGet (right, offset++, FALSE, FALSE, NULL)); + + genSetDPTR (AOP (result)->aopu.dptr); + emitcode ("movx", "@dptr,a"); + if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD)) + emitcode ("inc", "dptr"); + genSetDPTR (0); + } + } + else if (AOP_USESDPTR (result) && AOP_USESDPTR (right)) + { + int i; + _startLazyDPSEvaluation (); + for (i = size - 1; i > 0; i--) + emitcode ("push", aopGet (right, i, FALSE, FALSE, NULL)); + while (size--) + { + if (offset++) + emitcode ("pop", "acc"); + else + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + genSetDPTR (0); + _flushLazyDPS (); + emitcode ("movx", "@dptr,a"); + if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD)) + emitcode ("inc", "dptr"); + } + _endLazyDPSEvaluation (); + } + else + { + _startLazyDPSEvaluation (); + while (size--) + { + MOVA (aopGet (right, offset++, FALSE, FALSE, NULL)); + + if (AOP_INDPTRn (result)) + { + genSetDPTR (AOP (result)->aopu.dptr); + } + else + { + genSetDPTR (0); + } + _flushLazyDPS (); + + emitcode ("movx", "@dptr,a"); + if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD)) + emitcode ("inc", "dptr"); + } + _endLazyDPSEvaluation (); + } + } + + if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) + { + if (!AOP_INDPTRn (result)) + { + _startLazyDPSEvaluation (); + + aopPut (result, "dpl", 0); + aopPut (result, "dph", 1); + if (options.model == MODEL_FLAT24) + aopPut (result, "dpx", 2); + + _endLazyDPSEvaluation (); + } + pi->generated = 1; + } + else if (IS_SYMOP (result) && + (IS_OP_RUONLY (result) || AOP_INDPTRn (result)) && + (AOP_SIZE (right) > 1) && + (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) + { + size = AOP_SIZE (right) - 1; + if (AOP_INDPTRn (result)) + { + genSetDPTR (AOP (result)->aopu.dptr); + } + while (size--) + emitcode ("lcall", "__decdptr"); + if (AOP_INDPTRn (result)) + { + genSetDPTR (0); + } + } + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerSet - set value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerSet (operand * right, operand * result, iCode * ic, iCode * pi) +{ + int size, offset, dopi; + bool pushedB; + sym_link *retype = getSpec (operandType (right)); + sym_link *letype = getSpec (operandType (result)); + + D (emitcode (";", "genGenPointerSet")); + + aopOp (result, ic, FALSE, FALSE); + pushedB = pushB (); + dopi = loadDptrFromOperand (result, TRUE); + + /* so dptr-b now contains the address */ + aopOp (right, ic, FALSE, (AOP_INDPTRn (result) ? FALSE : TRUE)); + + /* if bit then unpack */ + if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) + { + genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER); + } + else + { + size = AOP_SIZE (right); + offset = 0; + + _startLazyDPSEvaluation (); + while (size--) + { + if (size) + { + // Set two bytes at a time, passed in AP & A. + // dptr will be incremented ONCE by __gptrputWord. + // + // Note: any change here must be coordinated + // with the implementation of __gptrputWord + // in device/lib/_gptrput.c + emitcode ("mov", "acc1, %s", aopGet (right, offset++, FALSE, FALSE, NULL)); + MOVA (aopGet (right, offset++, FALSE, FALSE, NULL)); + + genSetDPTR (0); + _flushLazyDPS (); + emitcode ("lcall", "__gptrputWord"); + size--; + } + else + { + // Only one byte to put. + MOVA (aopGet (right, offset++, FALSE, FALSE, NULL)); + + genSetDPTR (0); + _flushLazyDPS (); + emitcode ("lcall", "__gptrput"); + } + + if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD)) + { + emitcode ("inc", "dptr"); + } + } + _endLazyDPSEvaluation (); + } + + if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) + { + _startLazyDPSEvaluation (); + + aopPut (result, "dpl", 0); + aopPut (result, "dph", 1); + if (options.model == MODEL_FLAT24) + { + aopPut (result, "dpx", 2); + aopPut (result, "b", 3); + } + else + { + aopPut (result, "b", 2); + } + _endLazyDPSEvaluation (); + + pi->generated = 1; + } + else if (IS_SYMOP (result) && IS_OP_RUONLY (result) && AOP_SIZE (right) > 1 && + (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) + { + size = AOP_SIZE (right) - 1; + while (size--) + emitcode ("lcall", "__decdptr"); + } + popB (pushedB); + + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genPointerSet - stores the value into a pointer location */ +/*-----------------------------------------------------------------*/ +static void +genPointerSet (iCode * ic, iCode * pi) +{ + operand *right, *result; + sym_link *type, *etype; + int p_type; + + D (emitcode (";", "genPointerSet")); + + right = IC_RIGHT (ic); + result = IC_RESULT (ic); + + /* depending on the type of pointer we need to + move it to the correct pointer register */ + type = operandType (result); + etype = getSpec (type); + /* if left is of type of pointer then it is simple */ + if (IS_PTR (type) && !IS_FUNC (type->next)) + { + p_type = DCL_TYPE (type); + } + else + { + /* we have to go by the storage class */ + p_type = PTR_TYPE (SPEC_OCLS (etype)); + } + + /* special case when cast remat */ + if (p_type == GPOINTER && IS_SYMOP (result) && OP_SYMBOL (result)->remat && IS_CAST_ICODE (OP_SYMBOL (result)->rematiCode)) + { + result = IC_RIGHT (OP_SYMBOL (result)->rematiCode); + type = operandType (result); + p_type = DCL_TYPE (type); + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) + { + case POINTER: + case IPOINTER: + genNearPointerSet (right, result, ic, pi); + break; + + case PPOINTER: + genPagedPointerSet (right, result, ic, pi); + break; + + case FPOINTER: + genFarPointerSet (right, result, ic, pi); + break; + + case GPOINTER: + genGenPointerSet (right, result, ic, pi); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genPointerSet: illegal pointer type"); + } +} + +/*-----------------------------------------------------------------*/ +/* genIfx - generate code for Ifx statement */ +/*-----------------------------------------------------------------*/ +static void +genIfx (iCode * ic, iCode * popIc) +{ + operand *cond = IC_COND (ic); + int isbit = 0; + char *dup = NULL; + + D (emitcode (";", "genIfx")); + + aopOp (cond, ic, FALSE, FALSE); + + /* get the value into acc */ + if (AOP_TYPE (cond) != AOP_CRY) + { + toBoolean (cond); + } + else + { + isbit = 1; + if (AOP (cond)->aopu.aop_dir) + /* TODO: borutr: is really necessary to strdup it? */ + dup = Safe_strdup (AOP (cond)->aopu.aop_dir); + } + + /* the result is now in the accumulator or a directly addressable bit */ + freeAsmop (cond, NULL, ic, TRUE); + + /* if the condition is a bit variable */ + if (isbit && dup) + genIfxJump (ic, dup, popIc); + else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond)) + genIfxJump (ic, SPIL_LOC (cond)->rname, popIc); + else if (isbit && !IS_ITEMP (cond)) + genIfxJump (ic, OP_SYMBOL (cond)->rname, popIc); + else + genIfxJump (ic, "a", popIc); + + if (dup) + Safe_free (dup); + + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void +genAddrOf (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + int size, offset; + bool pushedA = FALSE; + + D (emitcode (";", "genAddrOf")); + + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + + /* if the operand is on the stack then we + need to get the stack offset of this + variable */ + if (sym->onStack) + { + /* if 10 bit stack */ + if (options.stack10bit) + { + struct dbuf_s dbuf; + int offset; + + dbuf_init (&dbuf, 128); + dbuf_tprintf (&dbuf, "#!constbyte", (options.stack_loc >> 16) & 0xff); + /* if it has an offset then we need to compute it */ + /* emitcode ("subb", "a,#!constbyte", */ + /* -((sym->stack < 0) ? */ + /* ((short) (sym->stack - _G.nRegsSaved)) : */ + /* ((short) sym->stack)) & 0xff); */ + /* emitcode ("mov","b,a"); */ + /* emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */ + /* ((short) (sym->stack - _G.nRegsSaved)) : */ + /* ((short) sym->stack)) >> 8) & 0xff); */ + if (sym->stack) + { + emitcode ("mov", "a,_bpx"); + emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ? + ((char) (sym->stack - _G.nRegsSaved)) : ((char) sym->stack)) & 0xff); + emitcode ("mov", "b,a"); + emitcode ("mov", "a,_bpx+1"); + + offset = (((sym->stack < 0) ? ((short) (sym->stack - _G.nRegsSaved)) : ((short) sym->stack)) >> 8) & 0xff; + + emitcode ("addc", "a,#!constbyte", offset); + + if (aopPutUsesAcc (IC_RESULT (ic), "b", 0)) + { + emitpush ("acc"); + pushedA = TRUE; + } + aopPut (IC_RESULT (ic), "b", 0); + if (pushedA) + emitpop ("acc"); + aopPut (IC_RESULT (ic), "a", 1); + aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), 2); + } + else + { + /* we can just move _bp */ + aopPut (IC_RESULT (ic), "_bpx", 0); + aopPut (IC_RESULT (ic), "_bpx+1", 1); + aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), 2); + } + dbuf_destroy (&dbuf); + } + else + { + /* if it has an offset then we need to compute it */ + if (sym->stack) + { + emitcode ("mov", "a,_bp"); + emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff)); + aopPut (IC_RESULT (ic), "a", 0); + } + else + { + /* we can just move _bp */ + aopPut (IC_RESULT (ic), "_bp", 0); + } + /* fill the result with zero */ + size = AOP_SIZE (IC_RESULT (ic)) - 1; + + + if (options.stack10bit && size < (FARPTRSIZE - 1)) + { + fprintf (stderr, "*** warning: pointer to stack var truncated.\n"); + } + + offset = 1; + while (size--) + { + aopPut (IC_RESULT (ic), zero, offset++); + } + } + goto release; + } + + /* object not on stack then we need the name */ + size = getDataSize (IC_RESULT (ic)); + offset = 0; + + while (size--) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + if (offset) + { + switch (offset) + { + case 1: + dbuf_tprintf (&dbuf, "#!his", sym->rname); + break; + case 2: + dbuf_tprintf (&dbuf, "#!hihis", sym->rname); + break; + case 3: + dbuf_tprintf (&dbuf, "#!hihihis", sym->rname); + break; + default: /* should not need this (just in case) */ + dbuf_printf (&dbuf, "#(%s >> %d)", sym->rname, offset * 8); + } + } + else + { + dbuf_printf (&dbuf, "#%s", sym->rname); + } + aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), offset++); + dbuf_destroy (&dbuf); + } + if (opIsGptr (IC_RESULT (ic))) + { + struct dbuf_s dbuf; + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL)); + aopPut (IC_RESULT (ic), dbuf_c_str (&dbuf), GPTRSIZE - 1); + dbuf_destroy (&dbuf); + } + +release: + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genFarFarAssign - assignment when both are in far space */ +/*-----------------------------------------------------------------*/ +static void +genFarFarAssign (operand * result, operand * right, iCode * ic) +{ + int size = AOP_SIZE (right); + int offset = 0; + symbol *rSym = NULL; + + if (size == 1) + { + /* quick & easy case. */ + D (emitcode (";", "genFarFarAssign (1 byte case)")); + MOVA (aopGet (right, 0, FALSE, FALSE, NULL)); + freeAsmop (right, NULL, ic, FALSE); + /* now assign DPTR to result */ + _G.accInUse++; + aopOp (result, ic, FALSE, FALSE); + _G.accInUse--; + aopPut (result, "a", 0); + freeAsmop (result, NULL, ic, FALSE); + return; + } + + /* See if we've got an underlying symbol to abuse. */ + if (IS_SYMOP (result) && OP_SYMBOL (result)) + { + if (IS_TRUE_SYMOP (result)) + { + rSym = OP_SYMBOL (result); + } + else if (IS_ITEMP (result) && OP_SYMBOL (result)->isspilt && OP_SYMBOL (result)->usl.spillLoc) + { + rSym = OP_SYMBOL (result)->usl.spillLoc; + } + } + + if (size > 1 && rSym && rSym->rname && !rSym->onStack && !IS_OP_RUONLY (right)) + { + /* We can use the '390 auto-toggle feature to good effect here. */ + + D (emitcode (";", "genFarFarAssign (390 auto-toggle fun)")); + emitcode ("mov", "dps,#!constbyte", 0x21); /* Select DPTR2 & auto-toggle. */ + emitcode ("mov", "dptr,#%s", rSym->rname); + /* DP2 = result, DP1 = right, DP1 is current. */ + while (size) + { + if (AOP (right)->code) + { + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + } + else + { + emitcode ("movx", "a,@dptr"); + } + emitcode ("movx", "@dptr,a"); + if (--size) + { + emitcode ("inc", "dptr"); + emitcode ("inc", "dptr"); + } + } + emitcode ("mov", "dps,#0"); + freeAsmop (right, NULL, ic, FALSE); +#if 0 + some alternative code for processors without auto - toggle + no time to test now, so later well put in ... kpb D (emitcode (";", "genFarFarAssign (dual-dptr fun)")); + emitcode ("mov", "dps,#1"); /* Select DPTR2. */ + emitcode ("mov", "dptr,#%s", rSym->rname); + /* DP2 = result, DP1 = right, DP1 is current. */ + while (size) + { + --size; + emitcode ("movx", "a,@dptr"); + if (size) + emitcode ("inc", "dptr"); + emitcode ("inc", "dps"); + emitcode ("movx", "@dptr,a"); + if (size) + emitcode ("inc", "dptr"); + emitcode ("inc", "dps"); + } + emitcode ("mov", "dps,#0"); + freeAsmop (right, NULL, ic, FALSE); +#endif + } + else + { + D (emitcode (";", "genFarFarAssign")); + aopOp (result, ic, TRUE, TRUE); + + _startLazyDPSEvaluation (); + + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + freeAsmop (result, NULL, ic, FALSE); + freeAsmop (right, NULL, ic, FALSE); + } +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void +genAssign (iCode * ic) +{ + operand *result, *right; + int size, offset; + unsigned long long lit = 0ull; + + D (emitcode (";", "genAssign")); + + result = IC_RESULT (ic); + right = IC_RIGHT (ic); + + /* if they are the same */ + if (operandsEqu (result, right) && !isOperandVolatile (result, FALSE) && !isOperandVolatile (right, FALSE)) + return; + + /* if both are ruonly */ + if (IS_OP_RUONLY (right) && IS_OP_RUONLY (result)) + return; + + aopOp (right, ic, FALSE, IS_OP_RUONLY (result)); + + emitcode (";", "genAssign: resultIsFar = %s", isOperandInFarSpace (result) ? "TRUE" : "FALSE"); + + /* special case both in far space */ + if ((AOP_TYPE (right) == AOP_DPTR || AOP_TYPE (right) == AOP_DPTR2 || IS_OP_RUONLY (right)) && + /* IS_TRUE_SYMOP(result) && */ + isOperandInFarSpace (result)) + { + genFarFarAssign (result, right, ic); + return; + } + + aopOp (result, ic, TRUE, FALSE); + + /* if they are the same registers */ + if (sameRegs (AOP (right), AOP (result)) && !isOperandVolatile (result, FALSE) && !isOperandVolatile (right, FALSE)) + goto release; + + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */ + { + /* if the right size is a literal then + we know what the value is */ + if (AOP_TYPE (right) == AOP_LIT) + { + if (((int) operandLitValue (right))) + aopPut (result, one, 0); + else + aopPut (result, zero, 0); + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE (right) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + aopPut (result, "c", 0); + goto release; + } + + /* we need to or */ + toBoolean (right); + aopPut (result, "a", 0); + goto release; + } + + /* bit variables done */ + /* general case */ + if (AOP_TYPE (right) == AOP_LIT) + { + if (!IS_FLOAT (operandType (right))) + { + lit = ullFromVal (AOP (right)->aopu.aop_lit); + } + else + { + union + { + float f; + unsigned char c[4]; + } fl; + + fl.f = (float) floatFromVal (AOP (right)->aopu.aop_lit); +#ifdef WORDS_BIGENDIAN + lit = (fl.c[3] << 0) | (fl.c[2] << 8) | (fl.c[1] << 16) | (fl.c[0] << 24); +#else + lit = (fl.c[0] << 0) | (fl.c[1] << 8) | (fl.c[2] << 16) | (fl.c[3] << 24); +#endif + } + } + + size = getDataSize (result); + offset = 0; + + if ((size > 1) && (AOP_TYPE (result) != AOP_REG) && (AOP_TYPE (right) == AOP_LIT)) + { + _startLazyDPSEvaluation (); + while (size && ((unsigned long long) (lit >> (offset * 8)) != 0)) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + size--; + } + /* And now fill the rest with zeros. */ + if (size) + { + emitcode ("clr", "a"); + } + while (size--) + { + aopPut (result, "a", offset++); + } + _endLazyDPSEvaluation (); + } + else + { + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + } + adjustArithmeticResult (ic); + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - generates code for jump table */ +/*-----------------------------------------------------------------*/ +static void +genJumpTab (iCode * ic) +{ + symbol *jtab; + + D (emitcode (";", "genJumpTab")); + + aopOp (IC_JTCOND (ic), ic, FALSE, FALSE); + /* get the condition into accumulator */ + MOVA (aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL)); + /* multiply by four! */ + emitcode ("add", "a,acc"); + emitcode ("add", "a,acc"); + freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE); + + jtab = newiTempLabel (NULL); + emitcode ("mov", "dptr,#!tlabel", labelKey2num (jtab->key)); + emitcode ("jmp", "@a+dptr"); + emitLabel (jtab); + /* now generate the jump labels */ + for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic))) + emitcode ("ljmp", "!tlabel", labelKey2num (jtab->key)); +} + +/*-----------------------------------------------------------------*/ +/* genCast - gen code for casting */ +/*-----------------------------------------------------------------*/ +static void +genCast (iCode * ic) +{ + operand *result = IC_RESULT (ic); + sym_link *ctype = operandType (IC_LEFT (ic)); + sym_link *rtype = operandType (IC_RIGHT (ic)); + operand *right = IC_RIGHT (ic); + int size, offset; + + D (emitcode (";", "genCast")); + + /* if they are equivalent then do nothing */ + if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) + return; + + /* if casting to <= size and both ruonly then do nothing */ + if (IS_OP_RUONLY (right) && IS_OP_RUONLY (result)) + return; + + aopOp (right, ic, FALSE, IS_OP_RUONLY (result)); + aopOp (result, ic, FALSE, (AOP_TYPE (right) == AOP_DPTR)); + + /* if the result is a bit (and not a bitfield) */ + if (IS_BOOLEAN (OP_SYMBOL (result)->type)) + { + /* if the right size is a literal then + we know what the value is */ + if (AOP_TYPE (right) == AOP_LIT) + { + if (((int) operandLitValue (right))) + aopPut (result, one, 0); + else + aopPut (result, zero, 0); + + goto release; + } + + /* the right is also a bit variable */ + if (AOP_TYPE (right) == AOP_CRY) + { + emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir); + aopPut (result, "c", 0); + goto release; + } + + /* we need to or */ + toCarry (right); + outBitC (result); + goto release; + } + + /* if they are the same size : or less */ + if (AOP_SIZE (result) <= AOP_SIZE (right) && !IS_BOOLEAN (operandType (result))) + { + /* if they are in the same place */ + if (sameRegs (AOP (right), AOP (result))) + goto release; + + /* if they in different places then copy */ + size = AOP_SIZE (result); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + goto release; + } + + /* if the result is of type pointer */ + if (IS_PTR (ctype) && !IS_INTEGRAL (rtype)) + { + int p_type; + sym_link *type = operandType (right); + + /* pointer to generic pointer */ + if (IS_GENPTR (ctype)) + { + if (IS_PTR (type) || IS_FUNC (type)) + { + p_type = DCL_TYPE (type); + } + else + { +#if OLD_CAST_BEHAVIOR + /* KV: we are converting a non-pointer type to + * a generic pointer. This (ifdef'd out) code + * says that the resulting generic pointer + * should have the same class as the storage + * location of the non-pointer variable. + * + * For example, converting an int (which happens + * to be stored in DATA space) to a pointer results + * in a DATA generic pointer; if the original int + * in XDATA space, so will be the resulting pointer. + * + * I don't like that behavior, and thus this change: + * all such conversions will be forced to XDATA and + * throw a warning. If you want some non-XDATA + * type, or you want to suppress the warning, you + * must go through an intermediate cast, like so: + * + * char _generic *gp = (char _xdata *)(intVar); + */ + sym_link *etype = getSpec (type); + + /* we have to go by the storage class */ + if (SPEC_OCLS (etype) != generic) + { + p_type = PTR_TYPE (SPEC_OCLS (etype)); + } + else +#endif + { + /* Converting unknown class (i.e. register variable) + * to generic pointer. This is not good, but + * we'll make a guess (and throw a warning). + */ + p_type = FPOINTER; + werror (W_INT_TO_GEN_PTR_CAST); + } + } + + /* the first two bytes are known */ + size = GPTRSIZE - 1; + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + + /* the last byte depending on type */ + { + int gpVal = pointerTypeToGPByte (p_type, NULL, NULL); + char gpValStr[10]; + + if (gpVal == -1) + { + // pointerTypeToGPByte will have warned, just copy. + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + } + else + { + SNPRINTF (gpValStr, sizeof (gpValStr), "#0x%02x", gpVal); + aopPut (result, gpValStr, GPTRSIZE - 1); + } + } + goto release; + } + + /* just copy the pointers */ + size = AOP_SIZE (result); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + goto release; + } + + /* so we now know that the size of destination is greater + than the size of the source */ + /* we move to result for the size of source */ + size = AOP_SIZE (right); + offset = 0; + _startLazyDPSEvaluation (); + while (size--) + { + aopPut (result, aopGet (right, offset, FALSE, FALSE, NULL), offset); + offset++; + } + _endLazyDPSEvaluation (); + + /* now depending on the sign of the source && destination */ + size = AOP_SIZE (result) - AOP_SIZE (right); + /* if unsigned or not an integral type */ + /* also, if the source is a bit, we don't need to sign extend, because + * it can't possibly have set the sign bit. + */ + if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY) + { + while (size--) + { + aopPut (result, zero, offset++); + } + } + else + { + /* we need to extend the sign :{ */ + MOVA (aopGet (right, AOP_SIZE (right) - 1, FALSE, FALSE, NULL)); + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + while (size--) + aopPut (result, "a", offset++); + } + + /* we are done hurray !!!! */ + +release: + freeAsmop (result, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genMemcpyX2X - gen code for memcpy xdata to xdata */ +/*-----------------------------------------------------------------*/ +static void +genMemcpyX2X (iCode * ic, int nparms, operand ** parms, int fromc) +{ + operand *from, *to, *count; + symbol *lbl; + bitVect *rsave; + int i; + + /* we know it has to be 3 parameters */ + assert (nparms == 3); + + rsave = newBitVect (16); + /* save DPTR if it needs to be saved */ + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectIntersect (rsave, bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + savermask (rsave); + + to = parms[0]; + from = parms[1]; + count = parms[2]; + + aopOp (from, ic->next, FALSE, FALSE); + + /* get from into DPTR1 */ + emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL)); + } + + freeAsmop (from, NULL, ic, FALSE); + aopOp (to, ic, FALSE, FALSE); + /* get "to" into DPTR */ + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (to) != AOP_STR) + { + /* if already in DPTR then we need to push */ + if (AOP_TYPE (to) == AOP_DPTR) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + emitcode ("pop", "dph"); + emitcode ("pop", "dpl"); + } + else + { + _startLazyDPSEvaluation (); + /* if this is remateriazable */ + if (AOP_TYPE (to) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL)); + } + else + { + /* we need to get it byte by byte */ + emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); + } + } + freeAsmop (to, NULL, ic, FALSE); + _G.dptrInUse = _G.dptr1InUse = 1; + aopOp (count, ic->next->next, FALSE, FALSE); + lbl = newiTempLabel (NULL); + + /* now for the actual copy */ + if (AOP_TYPE (count) == AOP_LIT && (int) ulFromVal (AOP (count)->aopu.aop_lit) <= 256) + { + emitcode ("mov", "b,%s", aopGet (count, 0, FALSE, FALSE, NULL)); + if (fromc) + { + emitcode ("lcall", "__bi_memcpyc2x_s"); + } + else + { + emitcode ("lcall", "__bi_memcpyx2x_s"); + } + freeAsmop (count, NULL, ic, FALSE); + } + else + { + symbol *lbl1 = newiTempLabel (NULL); + + emitcode (";", " Auto increment but no djnz"); + emitcode ("mov", "acc1,%s", aopGet (count, 0, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 1, FALSE, TRUE, NULL)); + freeAsmop (count, NULL, ic, FALSE); + emitcode ("mov", "dps,#!constbyte", 0x21); /* Select DPTR2 & auto-toggle. */ + emitLabel (lbl); + if (fromc) + { + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + } + else + emitcode ("movx", "a,@dptr"); + emitcode ("movx", "@dptr,a"); + emitcode ("inc", "dptr"); + emitcode ("inc", "dptr"); + emitcode ("mov", "a,b"); + emitcode ("orl", "a,acc1"); + emitcode ("jz", "!tlabel", labelKey2num (lbl1->key)); + emitcode ("mov", "a,acc1"); + emitcode ("add", "a,#!constbyte", 0xFF); + emitcode ("mov", "acc1,a"); + emitcode ("mov", "a,b"); + emitcode ("addc", "a,#!constbyte", 0xFF); + emitcode ("mov", "b,a"); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (lbl1); + } + emitcode ("mov", "dps,#0"); + _G.dptrInUse = _G.dptr1InUse = 0; + unsavermask (rsave); + +} + +/*-----------------------------------------------------------------*/ +/* genMemcmpX2X - gen code for memcmp xdata to xdata */ +/*-----------------------------------------------------------------*/ +static void +genMemcmpX2X (iCode * ic, int nparms, operand ** parms, int fromc) +{ + operand *from, *to, *count; + symbol *lbl, *lbl2; + bitVect *rsave; + int i; + + /* we know it has to be 3 parameters */ + assert (nparms == 3); + + rsave = newBitVect (16); + /* save DPTR if it needs to be saved */ + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectIntersect (rsave, bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + savermask (rsave); + + to = parms[0]; + from = parms[1]; + count = parms[2]; + + aopOp (from, ic->next, FALSE, FALSE); + + /* get from into DPTR1 */ + emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL)); + } + + freeAsmop (from, NULL, ic, FALSE); + aopOp (to, ic, FALSE, FALSE); + /* get "to" into DPTR */ + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (to) != AOP_STR) + { + /* if already in DPTR then we need to push */ + if (AOP_TYPE (to) == AOP_DPTR) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + emitcode ("pop", "dph"); + emitcode ("pop", "dpl"); + } + else + { + _startLazyDPSEvaluation (); + /* if this is remateriazable */ + if (AOP_TYPE (to) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL)); + } + else + { + /* we need to get it byte by byte */ + emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); + } + } + freeAsmop (to, NULL, ic, FALSE); + _G.dptrInUse = _G.dptr1InUse = 1; + aopOp (count, ic->next->next, FALSE, FALSE); + lbl = newiTempLabel (NULL); + lbl2 = newiTempLabel (NULL); + + /* now for the actual compare */ + if (AOP_TYPE (count) == AOP_LIT && (int) ulFromVal (AOP (count)->aopu.aop_lit) <= 256) + { + emitcode ("mov", "b,%s", aopGet (count, 0, FALSE, FALSE, NULL)); + if (fromc) + emitcode ("lcall", "__bi_memcmpc2x_s"); + else + emitcode ("lcall", "__bi_memcmpx2x_s"); + freeAsmop (count, NULL, ic, FALSE); + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + else + { + symbol *lbl1 = newiTempLabel (NULL); + + emitcode ("push", "ar0"); + emitcode (";", " Auto increment but no djnz"); + emitcode ("mov", "acc1,%s", aopGet (count, 0, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 1, FALSE, TRUE, NULL)); + freeAsmop (count, NULL, ic, FALSE); + emitcode ("mov", "dps,#!constbyte", 0x21); /* Select DPTR2 & auto-toggle. */ + emitLabel (lbl); + if (fromc) + { + emitcode ("clr", "a"); + emitcode ("movc", "a,@a+dptr"); + } + else + emitcode ("movx", "a,@dptr"); + emitcode ("mov", "r0,a"); + emitcode ("movx", "a,@dptr"); + emitcode ("clr", "c"); + emitcode ("subb", "a,r0"); + emitcode ("jnz", "!tlabel", labelKey2num (lbl2->key)); + emitcode ("inc", "dptr"); + emitcode ("inc", "dptr"); + emitcode ("mov", "a,b"); + emitcode ("orl", "a,acc1"); + emitcode ("jz", "!tlabel", labelKey2num (lbl1->key)); + emitcode ("mov", "a,acc1"); + emitcode ("add", "a,#!constbyte", 0xFF); + emitcode ("mov", "acc1,a"); + emitcode ("mov", "a,b"); + emitcode ("addc", "a,#!constbyte", 0xFF); + emitcode ("mov", "b,a"); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (lbl1); + emitcode ("clr", "a"); + emitLabel (lbl2); + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + emitcode ("pop", "ar0"); + emitcode ("mov", "dps,#0"); + } + _G.dptrInUse = _G.dptr1InUse = 0; + unsavermask (rsave); + +} + +/*-----------------------------------------------------------------*/ +/* genInp - gen code for __builtin_inp read data from a mem mapped */ +/* port, first parameter output area second parameter pointer to */ +/* port third parameter count */ +/*-----------------------------------------------------------------*/ +static void +genInp (iCode * ic, int nparms, operand ** parms) +{ + operand *from, *to, *count; + symbol *lbl; + bitVect *rsave; + int i; + + /* we know it has to be 3 parameters */ + assert (nparms == 3); + + rsave = newBitVect (16); + /* save DPTR if it needs to be saved */ + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectIntersect (rsave, bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + savermask (rsave); + + to = parms[0]; + from = parms[1]; + count = parms[2]; + + aopOp (from, ic->next, FALSE, FALSE); + + /* get from into DPTR1 */ + emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL)); + } + + freeAsmop (from, NULL, ic, FALSE); + aopOp (to, ic, FALSE, FALSE); + /* get "to" into DPTR */ + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (to) != AOP_STR) + { + /* if already in DPTR then we need to push */ + if (AOP_TYPE (to) == AOP_DPTR) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + emitcode ("pop", "dph"); + emitcode ("pop", "dpl"); + } + else + { + _startLazyDPSEvaluation (); + /* if this is remateriazable */ + if (AOP_TYPE (to) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL)); + } + else + { + /* we need to get it byte by byte */ + emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); + } + } + freeAsmop (to, NULL, ic, FALSE); + + _G.dptrInUse = _G.dptr1InUse = 1; + aopOp (count, ic->next->next, FALSE, FALSE); + lbl = newiTempLabel (NULL); + + /* now for the actual copy */ + if (AOP_TYPE (count) == AOP_LIT && (int) ulFromVal (AOP (count)->aopu.aop_lit) <= 256) + { + emitcode (";", "OH JOY auto increment with djnz (very fast)"); + emitcode ("mov", "dps,#!constbyte", 0x1); /* Select DPTR2 */ + emitcode ("mov", "b,%s", aopGet (count, 0, FALSE, FALSE, NULL)); + freeAsmop (count, NULL, ic, FALSE); + emitLabel (lbl); + emitcode ("movx", "a,@dptr"); /* read data from port */ + emitcode ("dec", "dps"); /* switch to DPTR */ + emitcode ("movx", "@dptr,a"); /* save into location */ + emitcode ("inc", "dptr"); /* point to next area */ + emitcode ("inc", "dps"); /* switch to DPTR2 */ + emitcode ("djnz", "b,!tlabel", labelKey2num (lbl->key)); + } + else + { + symbol *lbl1 = newiTempLabel (NULL); + + emitcode (";", " Auto increment but no djnz"); + emitcode ("mov", "acc1,%s", aopGet (count, 0, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 1, FALSE, TRUE, NULL)); + freeAsmop (count, NULL, ic, FALSE); + emitcode ("mov", "dps,#!constbyte", 0x1); /* Select DPTR2 */ + emitLabel (lbl); + emitcode ("movx", "a,@dptr"); + emitcode ("dec", "dps"); /* switch to DPTR */ + emitcode ("movx", "@dptr,a"); + emitcode ("inc", "dptr"); + emitcode ("inc", "dps"); /* switch to DPTR2 */ + /* emitcode ("djnz","b,!tlabel",lbl->key+100); */ + /* emitcode ("djnz","acc1,!tlabel",lbl->key+100); */ + emitcode ("mov", "a,b"); + emitcode ("orl", "a,acc1"); + emitcode ("jz", "!tlabel", labelKey2num (lbl1->key)); + emitcode ("mov", "a,acc1"); + emitcode ("add", "a,#!constbyte", 0xFF); + emitcode ("mov", "acc1,a"); + emitcode ("mov", "a,b"); + emitcode ("addc", "a,#!constbyte", 0xFF); + emitcode ("mov", "b,a"); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (lbl1); + } + emitcode ("mov", "dps,#0"); + _G.dptrInUse = _G.dptr1InUse = 0; + unsavermask (rsave); + +} + +/*-----------------------------------------------------------------*/ +/* genOutp - gen code for __builtin_inp write data to a mem mapped */ +/* port, first parameter output area second parameter pointer to */ +/* port third parameter count */ +/*-----------------------------------------------------------------*/ +static void +genOutp (iCode * ic, int nparms, operand ** parms) +{ + operand *from, *to, *count; + symbol *lbl; + bitVect *rsave; + int i; + + /* we know it has to be 3 parameters */ + assert (nparms == 3); + + rsave = newBitVect (16); + /* save DPTR if it needs to be saved */ + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectIntersect (rsave, bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + savermask (rsave); + + to = parms[0]; + from = parms[1]; + count = parms[2]; + + aopOp (from, ic->next, FALSE, FALSE); + + /* get from into DPTR1 */ + emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL)); + } + + freeAsmop (from, NULL, ic, FALSE); + aopOp (to, ic, FALSE, FALSE); + /* get "to" into DPTR */ + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (to) != AOP_STR) + { + /* if already in DPTR then we need to push */ + if (AOP_TYPE (to) == AOP_DPTR) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + emitcode ("pop", "dph"); + emitcode ("pop", "dpl"); + } + else + { + _startLazyDPSEvaluation (); + /* if this is remateriazable */ + if (AOP_TYPE (to) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL)); + } + else + { + /* we need to get it byte by byte */ + emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); + } + } + freeAsmop (to, NULL, ic, FALSE); + + _G.dptrInUse = _G.dptr1InUse = 1; + aopOp (count, ic->next->next, FALSE, FALSE); + lbl = newiTempLabel (NULL); + + /* now for the actual copy */ + if (AOP_TYPE (count) == AOP_LIT && (int) ulFromVal (AOP (count)->aopu.aop_lit) <= 256) + { + emitcode (";", "OH JOY auto increment with djnz (very fast)"); + emitcode ("mov", "dps,#!constbyte", 0x0); /* Select DPTR */ + emitcode ("mov", "b,%s", aopGet (count, 0, FALSE, FALSE, NULL)); + emitLabel (lbl); + emitcode ("movx", "a,@dptr"); /* read data from port */ + emitcode ("inc", "dps"); /* switch to DPTR2 */ + emitcode ("movx", "@dptr,a"); /* save into location */ + emitcode ("inc", "dptr"); /* point to next area */ + emitcode ("dec", "dps"); /* switch to DPTR */ + emitcode ("djnz", "b,!tlabel", labelKey2num (lbl->key)); + freeAsmop (count, NULL, ic, FALSE); + } + else + { + symbol *lbl1 = newiTempLabel (NULL); + + emitcode (";", " Auto increment but no djnz"); + emitcode ("mov", "acc1,%s", aopGet (count, 0, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 1, FALSE, TRUE, NULL)); + freeAsmop (count, NULL, ic, FALSE); + emitcode ("mov", "dps,#!constbyte", 0x0); /* Select DPTR */ + emitLabel (lbl); + emitcode ("movx", "a,@dptr"); + emitcode ("inc", "dptr"); + emitcode ("inc", "dps"); /* switch to DPTR2 */ + emitcode ("movx", "@dptr,a"); + emitcode ("dec", "dps"); /* switch to DPTR */ + emitcode ("mov", "a,b"); + emitcode ("orl", "a,acc1"); + emitcode ("jz", "!tlabel", labelKey2num (lbl1->key)); + emitcode ("mov", "a,acc1"); + emitcode ("add", "a,#!constbyte", 0xFF); + emitcode ("mov", "acc1,a"); + emitcode ("mov", "a,b"); + emitcode ("addc", "a,#!constbyte", 0xFF); + emitcode ("mov", "b,a"); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (lbl1); + } + emitcode ("mov", "dps,#0"); + _G.dptrInUse = _G.dptr1InUse = 0; + unsavermask (rsave); + +} + +/*-----------------------------------------------------------------*/ +/* genSwapW - swap lower & high order bytes */ +/*-----------------------------------------------------------------*/ +static void +genSwapW (iCode * ic, int nparms, operand ** parms) +{ + operand *dest; + operand *src; + assert (nparms == 1); + + src = parms[0]; + dest = IC_RESULT (ic); + + assert (getSize (operandType (src)) == 2); + + aopOp (src, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (src, 0, FALSE, FALSE, NULL)); + _G.accInUse++; + MOVB (aopGet (src, 1, FALSE, FALSE, "b")); + _G.accInUse--; + freeAsmop (src, NULL, ic, FALSE); + + aopOp (dest, ic, FALSE, FALSE); + aopPut (dest, "b", 0); + aopPut (dest, "a", 1); + freeAsmop (dest, NULL, ic, FALSE); +} + +/*-----------------------------------------------------------------*/ +/* genMemsetX - gencode for memSetX data */ +/*-----------------------------------------------------------------*/ +static void +genMemsetX (iCode * ic, int nparms, operand ** parms) +{ + operand *to, *val, *count; + symbol *lbl; + int i; + bitVect *rsave; + + /* we know it has to be 3 parameters */ + assert (nparms == 3); + + to = parms[0]; + val = parms[1]; + count = parms[2]; + + /* save DPTR if it needs to be saved */ + rsave = newBitVect (16); + for (i = DPL_IDX; i <= B_IDX; i++) + { + if (bitVectBitValue (ic->rMask, i)) + rsave = bitVectSetBit (rsave, i); + } + rsave = bitVectIntersect (rsave, bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + savermask (rsave); + + aopOp (to, ic, FALSE, FALSE); + /* get "to" into DPTR */ + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_TYPE (to) != AOP_STR) + { + /* if already in DPTR then we need to push */ + if (AOP_TYPE (to) == AOP_DPTR) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL)); + if (options.model == MODEL_FLAT24) + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + emitcode ("pop", "dph"); + emitcode ("pop", "dpl"); + } + else + { + _startLazyDPSEvaluation (); + /* if this is remateriazable */ + if (AOP_TYPE (to) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL)); + } + else + { + /* we need to get it byte by byte */ + emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL)); + if (options.model == MODEL_FLAT24) + { + emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL)); + } + } + _endLazyDPSEvaluation (); + } + } + freeAsmop (to, NULL, ic, FALSE); + + aopOp (val, ic->next->next, FALSE, FALSE); + aopOp (count, ic->next->next, FALSE, FALSE); + lbl = newiTempLabel (NULL); + /* now for the actual copy */ + if (AOP_TYPE (count) == AOP_LIT && (int) ulFromVal (AOP (count)->aopu.aop_lit) <= 256) + { + char *l = Safe_strdup (aopGet (val, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 0, FALSE, FALSE, NULL)); + MOVA (l); + Safe_free (l); + emitLabel (lbl); + emitcode ("movx", "@dptr,a"); + emitcode ("inc", "dptr"); + emitcode ("djnz", "b,!tlabel", labelKey2num (lbl->key)); + } + else + { + symbol *lbl1 = newiTempLabel (NULL); + + emitcode ("mov", "acc1,%s", aopGet (count, 0, FALSE, TRUE, NULL)); + emitcode ("mov", "b,%s", aopGet (count, 1, FALSE, TRUE, NULL)); + emitLabel (lbl); + MOVA (aopGet (val, 0, FALSE, FALSE, NULL)); + emitcode ("movx", "@dptr,a"); + emitcode ("inc", "dptr"); + emitcode ("mov", "a,b"); + emitcode ("orl", "a,acc1"); + emitcode ("jz", "!tlabel", labelKey2num (lbl1->key)); + emitcode ("mov", "a,acc1"); + emitcode ("add", "a,#!constbyte", 0xFF); + emitcode ("mov", "acc1,a"); + emitcode ("mov", "a,b"); + emitcode ("addc", "a,#!constbyte", 0xFF); + emitcode ("mov", "b,a"); + emitcode ("sjmp", "!tlabel", labelKey2num (lbl->key)); + emitLabel (lbl1); + } + freeAsmop (count, NULL, ic, FALSE); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genNatLibLoadPrimitive - calls TINI api function to load primitive */ +/*-----------------------------------------------------------------*/ +static void +genNatLibLoadPrimitive (iCode * ic, int nparms, operand ** parms, int size) +{ + bitVect *rsave; + operand *pnum, *result; + int i; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + pnum = parms[0]; + aopOp (pnum, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (pnum, 0, FALSE, FALSE, DP2_RESULT_REG)); + freeAsmop (pnum, NULL, ic, FALSE); + emitcode ("lcall", "NatLib_LoadPrimitive"); + aopOp (result = IC_RESULT (ic), ic, FALSE, FALSE); + if (aopHasRegs (AOP (result), R0_IDX, R1_IDX) || aopHasRegs (AOP (result), R2_IDX, R3_IDX)) + { + for (i = (size - 1); i >= 0; i--) + { + emitcode ("push", "a%s", javaRet[i]); + } + for (i = 0; i < size; i++) + { + emitcode ("pop", "a%s", aopGet (result, i, FALSE, FALSE, DP2_RESULT_REG)); + } + } + else + { + for (i = 0; i < size; i++) + { + aopPut (result, javaRet[i], i); + } + } + freeAsmop (result, NULL, ic, FALSE); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genNatLibLoadPointer - calls TINI api function to load pointer */ +/*-----------------------------------------------------------------*/ +static void +genNatLibLoadPointer (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *pnum, *result; + int size = 3; + int i; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + pnum = parms[0]; + aopOp (pnum, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (pnum, 0, FALSE, FALSE, DP2_RESULT_REG)); + freeAsmop (pnum, NULL, ic, FALSE); + emitcode ("lcall", "NatLib_LoadPointer"); + aopOp (result = IC_RESULT (ic), ic, FALSE, FALSE); + if (AOP_TYPE (result) != AOP_STR) + { + for (i = 0; i < size; i++) + { + aopPut (result, fReturn[i], i); + } + } + freeAsmop (result, NULL, ic, FALSE); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genNatLibInstallStateBlock - */ +/*-----------------------------------------------------------------*/ +static void +genNatLibInstallStateBlock (iCode * ic, int nparms, operand ** parms, const char *name) +{ + bitVect *rsave; + operand *psb, *handle; + assert (nparms == 2); + + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + psb = parms[0]; + handle = parms[1]; + + /* put pointer to state block into DPTR1 */ + aopOp (psb, ic, FALSE, FALSE); + if (AOP_TYPE (psb) == AOP_IMMD) + { + emitcode ("mov", "dps,#1"); + emitcode ("mov", "dptr,%s", aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dps,#0"); + } + else + { + emitcode ("mov", "dpl1,%s", aopGet (psb, 0, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dph1,%s", aopGet (psb, 1, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dpx1,%s", aopGet (psb, 2, FALSE, FALSE, DP2_RESULT_REG)); + } + freeAsmop (psb, NULL, ic, FALSE); + + /* put libraryID into DPTR */ + emitcode ("mov", "dptr,#LibraryID"); + + /* put handle into r3:r2 */ + aopOp (handle, ic, FALSE, FALSE); + if (aopHasRegs (AOP (handle), R2_IDX, R3_IDX)) + { + emitcode ("push", "%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + } + else + { + emitcode ("mov", "r2,%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + } + freeAsmop (psb, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "NatLib_Install%sStateBlock", name); + + /* put return value into place */ + _G.accInUse++; + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + _G.accInUse--; + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genNatLibRemoveStateBlock - */ +/*-----------------------------------------------------------------*/ +static void +genNatLibRemoveStateBlock (iCode * ic, int nparms, const char *name) +{ + bitVect *rsave; + + assert (nparms == 0); + + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + /* put libraryID into DPTR */ + emitcode ("mov", "dptr,#LibraryID"); + /* make the call */ + emitcode ("lcall", "NatLib_Remove%sStateBlock", name); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genNatLibGetStateBlock - */ +/*-----------------------------------------------------------------*/ +static void +genNatLibGetStateBlock (iCode * ic, int nparms, operand ** parms, const char *name) +{ + bitVect *rsave; + symbol *lbl = newiTempLabel (NULL); + + assert (nparms == 0); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + /* put libraryID into DPTR */ + emitcode ("mov", "dptr,#LibraryID"); + /* make the call */ + emitcode ("lcall", "NatLib_Remove%sStateBlock", name); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + + /* put return value into place */ + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + if (aopHasRegs (AOP (IC_RESULT (ic)), R2_IDX, R3_IDX)) + { + emitcode ("push", "ar3"); + emitcode ("push", "ar2"); + emitcode ("pop", "%s", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "%s", aopGet (IC_RESULT (ic), 1, FALSE, TRUE, DP2_RESULT_REG)); + } + else + { + aopPut (IC_RESULT (ic), "r2", 0); + aopPut (IC_RESULT (ic), "r3", 1); + } + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + emitLabel (lbl); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genMMMalloc - */ +/*-----------------------------------------------------------------*/ +static void +genMMMalloc (iCode * ic, int nparms, operand ** parms, int size, const char *name) +{ + bitVect *rsave; + operand *bsize; + symbol *rsym; + symbol *lbl = newiTempLabel (NULL); + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + bsize = parms[0]; + aopOp (bsize, ic, FALSE, FALSE); + + /* put the size in R4-R2 */ + if (aopHasRegs (AOP (bsize), R2_IDX, (size == 3 ? R4_IDX : R3_IDX))) + { + emitcode ("push", "%s", aopGet (bsize, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (bsize, 1, FALSE, TRUE, DP2_RESULT_REG)); + if (size == 3) + { + emitcode ("push", "%s", aopGet (bsize, 2, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar4"); + } + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + } + else + { + emitcode ("mov", "r2,%s", aopGet (bsize, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (bsize, 1, FALSE, TRUE, DP2_RESULT_REG)); + if (size == 3) + { + emitcode ("mov", "r4,%s", aopGet (bsize, 2, FALSE, TRUE, DP2_RESULT_REG)); + } + } + freeAsmop (bsize, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "MM_%s", name); + emitcode ("jz", "!tlabel", labelKey2num (lbl->key)); + emitcode ("mov", "r2,#!constbyte", 0xff); + emitcode ("mov", "r3,#!constbyte", 0xff); + emitLabel (lbl); + /* we don't care about the pointer : we just save the handle */ + rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + if (aopHasRegs (AOP (IC_RESULT (ic)), R2_IDX, R3_IDX)) + { + emitcode ("push", "ar3"); + emitcode ("push", "ar2"); + emitcode ("pop", "%s", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "%s", aopGet (IC_RESULT (ic), 1, FALSE, TRUE, DP2_RESULT_REG)); + } + else + { + aopPut (IC_RESULT (ic), "r2", 0); + aopPut (IC_RESULT (ic), "r3", 1); + } + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genMMDeref - */ +/*-----------------------------------------------------------------*/ +static void +genMMDeref (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *handle; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + handle = parms[0]; + aopOp (handle, ic, FALSE, FALSE); + + /* put the size in R4-R2 */ + if (aopHasRegs (AOP (handle), R2_IDX, R3_IDX)) + { + emitcode ("push", "%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + } + else + { + emitcode ("mov", "r2,%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + } + freeAsmop (handle, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "MM_Deref"); + + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + if (AOP_TYPE (IC_RESULT (ic)) != AOP_STR) + { + _startLazyDPSEvaluation (); + + aopPut (IC_RESULT (ic), "dpl", 0); + aopPut (IC_RESULT (ic), "dph", 1); + aopPut (IC_RESULT (ic), "dpx", 2); + + _endLazyDPSEvaluation (); + + } + } + } + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genMMUnrestrictedPersist - */ +/*-----------------------------------------------------------------*/ +static void +genMMUnrestrictedPersist (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *handle; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + handle = parms[0]; + aopOp (handle, ic, FALSE, FALSE); + + /* put the size in R3-R2 */ + if (aopHasRegs (AOP (handle), R2_IDX, R3_IDX)) + { + emitcode ("push", "%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + } + else + { + emitcode ("mov", "r2,%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + } + freeAsmop (handle, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "MM_UnrestrictedPersist"); + + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + } + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemExecJavaProcess - */ +/*-----------------------------------------------------------------*/ +static void +genSystemExecJavaProcess (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *handle, *pp; + + assert (nparms == 2); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + pp = parms[0]; + handle = parms[1]; + + /* put the handle in R3-R2 */ + aopOp (handle, ic, FALSE, FALSE); + if (aopHasRegs (AOP (handle), R2_IDX, R3_IDX)) + { + emitcode ("push", "%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + } + else + { + emitcode ("mov", "r2,%s", aopGet (handle, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (handle, 1, FALSE, TRUE, DP2_RESULT_REG)); + } + freeAsmop (handle, NULL, ic, FALSE); + + /* put pointer in DPTR */ + aopOp (pp, ic, FALSE, FALSE); + if (AOP_TYPE (pp) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (pp, 0, TRUE, FALSE, NULL)); + } + else if (AOP_TYPE (pp) != AOP_STR) + { + /* not already in dptr */ + emitcode ("mov", "dpl,%s", aopGet (pp, 0, FALSE, FALSE, NULL)); + emitcode ("mov", "dph,%s", aopGet (pp, 1, FALSE, FALSE, NULL)); + emitcode ("mov", "dpx,%s", aopGet (pp, 2, FALSE, FALSE, NULL)); + } + freeAsmop (handle, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "System_ExecJavaProcess"); + + /* put result in place */ + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + } + + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemRTCRegisters - */ +/*-----------------------------------------------------------------*/ +static void +genSystemRTCRegisters (iCode * ic, int nparms, operand ** parms, char *name) +{ + bitVect *rsave; + operand *pp; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + pp = parms[0]; + /* put pointer in DPTR */ + aopOp (pp, ic, FALSE, FALSE); + if (AOP_TYPE (pp) == AOP_IMMD) + { + emitcode ("mov", "dps,#1"); + emitcode ("mov", "dptr,%s", aopGet (pp, 0, TRUE, FALSE, NULL)); + emitcode ("mov", "dps,#0"); + } + else + { + emitcode ("mov", "dpl1,%s", aopGet (pp, 0, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dph1,%s", aopGet (pp, 1, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dpx1,%s", aopGet (pp, 2, FALSE, FALSE, DP2_RESULT_REG)); + } + freeAsmop (pp, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "System_%sRTCRegisters", name); + + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemThreadSleep - */ +/*-----------------------------------------------------------------*/ +static void +genSystemThreadSleep (iCode * ic, int nparms, operand ** parms, char *name) +{ + bitVect *rsave; + operand *to, *s; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + to = parms[0]; + aopOp (to, ic, FALSE, FALSE); + if (aopHasRegs (AOP (to), R2_IDX, R3_IDX) || aopHasRegs (AOP (to), R0_IDX, R1_IDX)) + { + emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (to, 2, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("push", "%s", aopGet (to, 3, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("pop", "ar3"); + emitcode ("pop", "ar2"); + emitcode ("pop", "ar1"); + emitcode ("pop", "ar0"); + } + else + { + emitcode ("mov", "r0,%s", aopGet (to, 0, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r1,%s", aopGet (to, 1, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r2,%s", aopGet (to, 2, FALSE, TRUE, DP2_RESULT_REG)); + emitcode ("mov", "r3,%s", aopGet (to, 3, FALSE, TRUE, DP2_RESULT_REG)); + } + freeAsmop (to, NULL, ic, FALSE); + + /* suspend in acc */ + s = parms[1]; + aopOp (s, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (s, 0, FALSE, TRUE, NULL)); + freeAsmop (s, NULL, ic, FALSE); + + /* make the call */ + emitcode ("lcall", "System_%s", name); + + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemThreadResume - */ +/*-----------------------------------------------------------------*/ +static void +genSystemThreadResume (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *tid, *pid; + + assert (nparms == 2); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + tid = parms[0]; + pid = parms[1]; + + /* PID in R0 */ + aopOp (pid, ic, FALSE, FALSE); + emitcode ("mov", "r0,%s", aopGet (pid, 0, FALSE, TRUE, DP2_RESULT_REG)); + freeAsmop (pid, NULL, ic, FALSE); + + /* tid into ACC */ + aopOp (tid, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (tid, 0, FALSE, TRUE, DP2_RESULT_REG)); + freeAsmop (tid, NULL, ic, FALSE); + + emitcode ("lcall", "System_ThreadResume"); + + /* put result into place */ + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + } + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemProcessResume - */ +/*-----------------------------------------------------------------*/ +static void +genSystemProcessResume (iCode * ic, int nparms, operand ** parms) +{ + bitVect *rsave; + operand *pid; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + pid = parms[0]; + + /* pid into ACC */ + aopOp (pid, ic, FALSE, FALSE); + emitcode ("mov", "a,%s", aopGet (pid, 0, FALSE, TRUE, DP2_RESULT_REG)); + freeAsmop (pid, NULL, ic, FALSE); + + emitcode ("lcall", "System_ProcessResume"); + + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystem - */ +/*-----------------------------------------------------------------*/ +static void +genSystem (iCode * ic, int nparms, char *name) +{ + assert (nparms == 0); + + emitcode ("lcall", "System_%s", name); +} + +/*-----------------------------------------------------------------*/ +/* genSystemPoll - */ +/*-----------------------------------------------------------------*/ +static void +genSystemPoll (iCode * ic, int nparms, operand ** parms, char *name) +{ + bitVect *rsave; + operand *fp; + + assert (nparms == 1); + /* save registers that need to be saved */ + savermask (rsave = bitVectCplAnd (bitVectCopy (ic->rMask), ds390_rUmaskForOp (IC_RESULT (ic)))); + + fp = parms[0]; + aopOp (fp, ic, FALSE, FALSE); + if (AOP_TYPE (fp) == AOP_IMMD) + { + emitcode ("mov", "dptr,%s", aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG)); + } + else if (AOP_TYPE (fp) != AOP_STR) + { + /* not already in dptr */ + emitcode ("mov", "dpl,%s", aopGet (fp, 0, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dph,%s", aopGet (fp, 1, FALSE, FALSE, DP2_RESULT_REG)); + emitcode ("mov", "dpx,%s", aopGet (fp, 2, FALSE, FALSE, DP2_RESULT_REG)); + } + freeAsmop (fp, NULL, ic, FALSE); + + emitcode ("lcall", "System_%sPoll", name); + + /* put result into place */ + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + } + unsavermask (rsave); +} + +/*-----------------------------------------------------------------*/ +/* genSystemGetCurrentID - */ +/*-----------------------------------------------------------------*/ +static void +genSystemGetCurrentID (iCode * ic, int nparms, operand ** parms, char *name) +{ + assert (nparms == 0); + + emitcode ("lcall", "System_GetCurrent%sId", name); + /* put result into place */ + { + symbol *rsym = OP_SYMBOL (IC_RESULT (ic)); + if (rsym->liveFrom != rsym->liveTo) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + aopPut (IC_RESULT (ic), "a", 0); + freeAsmop (IC_RESULT (ic), NULL, ic, FALSE); + } + } +} + +/*-----------------------------------------------------------------*/ +/* genDjnz - generate decrement & jump if not zero instruction */ +/*-----------------------------------------------------------------*/ +static int +genDjnz (iCode * ic, iCode * ifx) +{ + symbol *lbl, *lbl1; + if (!ifx) + return 0; + + /* if the if condition has a false label + then we cannot save */ + if (IC_FALSE (ifx)) + return 0; + + /* if the minus is not of the form a = a - 1 */ + if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) || !IS_OP_LITERAL (IC_RIGHT (ic))) + return 0; + + if (operandLitValue (IC_RIGHT (ic)) != 1) + return 0; + + /* if the size of this greater than one then no saving */ + if (getSize (operandType (IC_RESULT (ic))) > 1) + return 0; + + /* otherwise we can save BIG */ + + popForBranch (ic->next, TRUE); + + D (emitcode (";", "genDjnz")); + + lbl = newiTempLabel (NULL); + lbl1 = newiTempLabel (NULL); + + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + + if (AOP_NEEDSACC (IC_RESULT (ic))) + { + /* If the result is accessed indirectly via + * the accumulator, we must explicitly write + * it back after the decrement. + */ + const char *rByte = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL); + + if (!EQ (rByte, "a")) + { + /* Something is hopelessly wrong */ + fprintf (stderr, "*** warning: internal error at %s:%d\n", __FILE__, __LINE__); + /* We can just give up; the generated code will be inefficient, + * but what the hey. + */ + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + return 0; + } + emitcode ("dec", "%s", rByte); + aopPut (IC_RESULT (ic), rByte, 0); + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + } + else if (IS_AOP_PREG (IC_RESULT (ic))) + { + emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL)); + MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + ifx->generated = 1; + emitcode ("jnz", "!tlabel", labelKey2num (lbl->key)); + } + else + { + emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL), labelKey2num (lbl->key)); + } + emitcode ("sjmp", "!tlabel", labelKey2num (lbl1->key)); + emitLabel (lbl); + emitcode ("ljmp", "!tlabel", labelKey2num (IC_TRUE (ifx)->key)); + emitLabel (lbl1); + + if (!ifx->generated) + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + ifx->generated = 1; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void +genReceive (iCode * ic) +{ + int size = getSize (operandType (IC_RESULT (ic))); + int offset = 0; + int rb1off; + + D (emitcode (";", "genReceive")); + + if (ic->argreg == 1) + { + /* first parameter */ + if (IS_OP_RUONLY (IC_RESULT (ic))) + { + /* Nothing to do: it's already in the proper place. */ + return; + } + else + { + bool useDp2; + + useDp2 = isOperandInFarSpace (IC_RESULT (ic)) && + (OP_SYMBOL (IC_RESULT (ic))->isspilt || IS_TRUE_SYMOP (IC_RESULT (ic))); + + _G.accInUse++; + aopOp (IC_RESULT (ic), ic, FALSE, useDp2); + _G.accInUse--; + + /* Sanity checking... */ + if (AOP_USESDPTR (IC_RESULT (ic))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "genReceive got unexpected DPTR."); + } + assignResultValue (IC_RESULT (ic), NULL); + } + } + else if (ic->argreg > 12) + { + /* bit parameters */ + reg_info *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0]; + + if (!reg || reg->rIdx != ic->argreg - 5) + { + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + emitcode ("mov", "c,%s", rb1regs[ic->argreg - 5]); + outBitC (IC_RESULT (ic)); + } + } + else + { + /* second receive onwards */ + /* this gets a little tricky since unused receives will be + eliminated, we have saved the reg in the type field . and + we use that to figure out which register to use */ + aopOp (IC_RESULT (ic), ic, FALSE, FALSE); + rb1off = ic->argreg; + while (size--) + { + aopPut (IC_RESULT (ic), rb1regs[rb1off++ - 5], offset++); + } + } + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + operand *op; + int size, offset; + + D (emitcode (";", "genDummyRead")); + + op = IC_RIGHT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* if the result is a bit */ + if (AOP_TYPE (op) == AOP_CRY) + emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir); + else + { + /* bit variables done */ + /* general case */ + size = AOP_SIZE (op); + offset = 0; + while (size--) + { + MOVA (aopGet (op, offset, FALSE, FALSE, FALSE)); + offset++; + } + } + + freeAsmop (op, NULL, ic, TRUE); + } + + op = IC_LEFT (ic); + if (op && IS_SYMOP (op)) + { + aopOp (op, ic, FALSE, FALSE); + + /* if the result is a bit */ + if (AOP_TYPE (op) == AOP_CRY) + emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir); + else + { + /* bit variables done */ + /* general case */ + size = AOP_SIZE (op); + offset = 0; + while (size--) + { + MOVA (aopGet (op, offset, FALSE, FALSE, FALSE)); + offset++; + } + } + + freeAsmop (op, NULL, ic, TRUE); + } +} + +/*-----------------------------------------------------------------*/ +/* genCritical - generate code for start of a critical sequence */ +/*-----------------------------------------------------------------*/ +static void +genCritical (iCode * ic) +{ + symbol *tlbl = newiTempLabel (NULL); + + D (emitcode (";", "genCritical")); + + if (IC_RESULT (ic)) + { + aopOp (IC_RESULT (ic), ic, TRUE, FALSE); + aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */ + emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */ + aopPut (IC_RESULT (ic), zero, 0); + emitLabel (tlbl); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + else + { + emitcode ("setb", "c"); + emitcode ("jbc", "ea,!tlabel", labelKey2num (tlbl->key)); /* atomic test & clear */ + emitcode ("clr", "c"); + emitLabel (tlbl); + emitpush ("psw"); /* save old ea via c in psw on top of stack */ + } +} + +/*-----------------------------------------------------------------*/ +/* genEndCritical - generate code for end of a critical sequence */ +/*-----------------------------------------------------------------*/ +static void +genEndCritical (iCode * ic) +{ + D (emitcode (";", "genEndCritical")); + + if (IC_RIGHT (ic)) + { + aopOp (IC_RIGHT (ic), ic, FALSE, FALSE); + if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY) + { + emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir); + emitcode ("mov", "ea,c"); + } + else + { + MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE)); + emitcode ("rrc", "a"); + emitcode ("mov", "ea,c"); + } + freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE); + } + else + { + emitpop ("psw"); /* restore ea via c in psw on top of stack */ + emitcode ("mov", "ea,c"); + } +} + + + +/*-----------------------------------------------------------------*/ +/* genBuiltIn - calls the appropriate function to generating code */ +/* for a built in function */ +/*-----------------------------------------------------------------*/ +static void +genBuiltIn (iCode * ic) +{ + operand *bi_parms[MAX_BUILTIN_ARGS]; + int nbi_parms; + iCode *bi_iCode; + symbol *bif; + + /* get all the arguments for a built in function */ + bi_iCode = getBuiltinParms (ic, &nbi_parms, bi_parms); + + /* which function is it */ + bif = OP_SYMBOL (IC_LEFT (bi_iCode)); + if (strcmp (bif->name, "__builtin_memcpy_x2x") == 0) + { + genMemcpyX2X (bi_iCode, nbi_parms, bi_parms, 0); + } + else if (strcmp (bif->name, "__builtin_memcpy_c2x") == 0) + { + genMemcpyX2X (bi_iCode, nbi_parms, bi_parms, 1); + } + else if (strcmp (bif->name, "__builtin_memcmp_x2x") == 0) + { + genMemcmpX2X (bi_iCode, nbi_parms, bi_parms, 0); + } + else if (strcmp (bif->name, "__builtin_memcmp_c2x") == 0) + { + genMemcmpX2X (bi_iCode, nbi_parms, bi_parms, 1); + } + else if (strcmp (bif->name, "__builtin_memset_x") == 0) + { + genMemsetX (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "__builtin_inp") == 0) + { + genInp (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "__builtin_outp") == 0) + { + genOutp (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "__builtin_swapw") == 0) + { + genSwapW (bi_iCode, nbi_parms, bi_parms); + /* JavaNative builtIns */ + } + else if (strcmp (bif->name, "NatLib_LoadByte") == 0) + { + genNatLibLoadPrimitive (bi_iCode, nbi_parms, bi_parms, 1); + } + else if (strcmp (bif->name, "NatLib_LoadShort") == 0) + { + genNatLibLoadPrimitive (bi_iCode, nbi_parms, bi_parms, 2); + } + else if (strcmp (bif->name, "NatLib_LoadInt") == 0) + { + genNatLibLoadPrimitive (bi_iCode, nbi_parms, bi_parms, 4); + } + else if (strcmp (bif->name, "NatLib_LoadPointer") == 0) + { + genNatLibLoadPointer (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "NatLib_InstallImmutableStateBlock") == 0) + { + genNatLibInstallStateBlock (bi_iCode, nbi_parms, bi_parms, "Immutable"); + } + else if (strcmp (bif->name, "NatLib_InstallEphemeralStateBlock") == 0) + { + genNatLibInstallStateBlock (bi_iCode, nbi_parms, bi_parms, "Ephemeral"); + } + else if (strcmp (bif->name, "NatLib_RemoveImmutableStateBlock") == 0) + { + genNatLibRemoveStateBlock (bi_iCode, nbi_parms, "Immutable"); + } + else if (strcmp (bif->name, "NatLib_RemoveEphemeralStateBlock") == 0) + { + genNatLibRemoveStateBlock (bi_iCode, nbi_parms, "Ephemeral"); + } + else if (strcmp (bif->name, "NatLib_GetImmutableStateBlock") == 0) + { + genNatLibGetStateBlock (bi_iCode, nbi_parms, bi_parms, "Immutable"); + } + else if (strcmp (bif->name, "NatLib_GetEphemeralStateBlock") == 0) + { + genNatLibGetStateBlock (bi_iCode, nbi_parms, bi_parms, "Ephemeral"); + } + else if (strcmp (bif->name, "MM_XMalloc") == 0) + { + genMMMalloc (bi_iCode, nbi_parms, bi_parms, 3, "XMalloc"); + } + else if (strcmp (bif->name, "MM_Malloc") == 0) + { + genMMMalloc (bi_iCode, nbi_parms, bi_parms, 2, "Malloc"); + } + else if (strcmp (bif->name, "MM_ApplicationMalloc") == 0) + { + genMMMalloc (bi_iCode, nbi_parms, bi_parms, 2, "ApplicationMalloc"); + } + else if (strcmp (bif->name, "MM_Free") == 0) + { + genMMMalloc (bi_iCode, nbi_parms, bi_parms, 2, "Free"); + } + else if (strcmp (bif->name, "MM_Deref") == 0) + { + genMMDeref (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "MM_UnrestrictedPersist") == 0) + { + genMMUnrestrictedPersist (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_ExecJavaProcess") == 0) + { + genSystemExecJavaProcess (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_GetRTCRegisters") == 0) + { + genSystemRTCRegisters (bi_iCode, nbi_parms, bi_parms, "Get"); + } + else if (strcmp (bif->name, "System_SetRTCRegisters") == 0) + { + genSystemRTCRegisters (bi_iCode, nbi_parms, bi_parms, "Set"); + } + else if (strcmp (bif->name, "System_ThreadSleep") == 0) + { + genSystemThreadSleep (bi_iCode, nbi_parms, bi_parms, "ThreadSleep"); + } + else if (strcmp (bif->name, "System_ThreadSleep_ExitCriticalSection") == 0) + { + genSystemThreadSleep (bi_iCode, nbi_parms, bi_parms, "ThreadSleep_ExitCriticalSection"); + } + else if (strcmp (bif->name, "System_ProcessSleep") == 0) + { + genSystemThreadSleep (bi_iCode, nbi_parms, bi_parms, "ProcessSleep"); + } + else if (strcmp (bif->name, "System_ProcessSleep_ExitCriticalSection") == 0) + { + genSystemThreadSleep (bi_iCode, nbi_parms, bi_parms, "ProcessSleep_ExitCriticalSection"); + } + else if (strcmp (bif->name, "System_ThreadResume") == 0) + { + genSystemThreadResume (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_SaveThread") == 0) + { + genSystemThreadResume (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_ThreadResume") == 0) + { + genSystemThreadResume (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_ProcessResume") == 0) + { + genSystemProcessResume (bi_iCode, nbi_parms, bi_parms); + } + else if (strcmp (bif->name, "System_SaveJavaThreadState") == 0) + { + genSystem (bi_iCode, nbi_parms, "SaveJavaThreadState"); + } + else if (strcmp (bif->name, "System_RestoreJavaThreadState") == 0) + { + genSystem (bi_iCode, nbi_parms, "RestoreJavaThreadState"); + } + else if (strcmp (bif->name, "System_ProcessYield") == 0) + { + genSystem (bi_iCode, nbi_parms, "ProcessYield"); + } + else if (strcmp (bif->name, "System_ProcessSuspend") == 0) + { + genSystem (bi_iCode, nbi_parms, "ProcessSuspend"); + } + else if (strcmp (bif->name, "System_RegisterPoll") == 0) + { + genSystemPoll (bi_iCode, nbi_parms, bi_parms, "Register"); + } + else if (strcmp (bif->name, "System_RemovePoll") == 0) + { + genSystemPoll (bi_iCode, nbi_parms, bi_parms, "Remove"); + } + else if (strcmp (bif->name, "System_GetCurrentThreadId") == 0) + { + genSystemGetCurrentID (bi_iCode, nbi_parms, bi_parms, "Thread"); + } + else if (strcmp (bif->name, "System_GetCurrentProcessId") == 0) + { + genSystemGetCurrentID (bi_iCode, nbi_parms, bi_parms, "Process"); + } + else + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "unknown builtin function encountered\n"); + return; + } + return; +} + +/*-----------------------------------------------------------------*/ +/* gen390Code - generate code for Dallas 390 based controllers */ +/*-----------------------------------------------------------------*/ +void +gen390Code (iCode * lic) +{ + iCode *ic; + int cln = 0; + + _G.currentFunc = NULL; + + dptrn[1][0] = "dpl1"; + dptrn[1][1] = "dph1"; + dptrn[1][2] = "dpx1"; + + if (options.model == MODEL_FLAT24) + { + fReturnSizeDS390 = 5; + fReturn = fReturn24; + } + else + { + fReturnSizeDS390 = 4; + fReturn = fReturn16; + options.stack10bit = 0; + } + /* print the allocation information */ + if (allocInfo && currFunc) + printAllocInfo (currFunc, codeOutBuf); + /* if debug information required */ + if (options.debug && currFunc) + { + debugFile->writeFunction (currFunc, lic); + } + /* stack pointer name */ + if (options.useXstack) + spname = "_spx"; + else + spname = "sp"; + + for (ic = lic; ic; ic = ic->next) + { + initGenLineElement (); + + genLine.lineElement.ic = ic; + + if (ic->lineno && cln != ic->lineno) + { + if (options.debug) + { + debugFile->writeCLine (ic); + } + if (!options.noCcodeInAsm) + { + emitcode (";", "%s:%d: %s", ic->filename, ic->lineno, printCLine (ic->filename, ic->lineno)); + } + cln = ic->lineno; + } + if (options.iCodeInAsm) + { + const char *iLine; + iLine = printILine (ic); + emitcode (";", "ic:%d: %s", ic->key, iLine); + dbuf_free (iLine); + } + /* if the result is marked as + spilt and rematerializable or code for + this has already been generated then + do nothing */ + if (resultRemat (ic) || ic->generated) + continue; + + /* depending on the operation */ + switch (ic->op) + { + case '!': + genNot (ic); + break; + + case '~': + genCpl (ic); + break; + + case UNARYMINUS: + genUminus (ic); + break; + + case IPUSH: + genIpush (ic); + break; + + case IPOP: + { + iCode *ifxIc, *popIc; + bool CommonRegs = FALSE; + + /* IPOP happens only when trying to restore a + spilt live range, if there is an ifx statement + following this pop (or several) then the if statement might + be using some of the registers being popped which + would destroy the contents of the register so + we need to check for this condition and handle it */ + for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next); + for (popIc = ic; popIc && popIc->op == IPOP; popIc = popIc->next) + CommonRegs |= (ifxIc && ifxIc->op == IFX && !ifxIc->generated && regsInCommon (IC_LEFT (popIc), IC_COND (ifxIc))); + if (CommonRegs) + genIfx (ifxIc, ic); + else + genIpop (ic); + } + break; + + case CALL: + genCall (ic); + break; + + case PCALL: + genPcall (ic); + break; + + case FUNCTION: + genFunction (ic); + break; + + case ENDFUNCTION: + genEndFunction (ic); + break; + + case RETURN: + genRet (ic); + break; + + case LABEL: + genLabel (ic); + break; + + case GOTO: + genGoto (ic); + break; + + case '+': + genPlus (ic); + break; + + case '-': + if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic))) + genMinus (ic); + break; + + case '*': + genMult (ic); + break; + + case '/': + genDiv (ic); + break; + + case '%': + genMod (ic); + break; + + case '>': + genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case '<': + genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case LE_OP: + case GE_OP: + case NE_OP: + + /* note these two are xlated by algebraic equivalence + in decorateType() in SDCCast.c */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got '>=' or '<=' shouldn't have come here"); + break; + + case EQ_OP: + genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case AND_OP: + genAndOp (ic); + break; + + case OR_OP: + genOrOp (ic); + break; + + case '^': + genXor (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case '|': + genOr (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case BITWISEAND: + genAnd (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case INLINEASM: + genInline (ic); + break; + + case RRC: + genRRC (ic); + break; + + case RLC: + genRLC (ic); + break; + + case GETHBIT: + genGetHbit (ic); + break; + + case LEFT_OP: + genLeftShift (ic); + break; + + case RIGHT_OP: + genRightShift (ic); + break; + + case GET_VALUE_AT_ADDRESS: + genPointerGet (ic, hasInc (IC_LEFT (ic), ic, getSize (operandType (IC_RESULT (ic))))); + break; + + case '=': + if (POINTER_SET (ic)) + genPointerSet (ic, hasInc (IC_RESULT (ic), ic, getSize (operandType (IC_RIGHT (ic))))); + else + genAssign (ic); + break; + + case IFX: + genIfx (ic, NULL); + break; + + case ADDRESS_OF: + genAddrOf (ic); + break; + + case JUMPTABLE: + genJumpTab (ic); + break; + + case CAST: + genCast (ic); + break; + + case RECEIVE: + genReceive (ic); + break; + + case SEND: + if (ic->builtinSEND) + genBuiltIn (ic); + else + addSet (&_G.sendSet, ic); + break; + + case DUMMY_READ_VOLATILE: + genDummyRead (ic); + break; + + case CRITICAL: + genCritical (ic); + break; + + case ENDCRITICAL: + genEndCritical (ic); + break; + + case SWAP: + genSwap (ic); + break; + + default: + /* This should never happen, right? */ + fprintf (stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n", ic->op, ic->op, __FILE__, __LINE__); + ic = ic; + } + } + + /* now we are ready to call the + peep hole optimizer */ + if (!options.nopeep) + peepHole (&genLine.lineHead); + + /* now do the actual printing */ + printLine (genLine.lineHead, codeOutBuf); + + /* destroy the line list */ + destroy_line_list (); +} diff --git a/src/ds390/gen.h b/src/ds390/gen.h new file mode 100644 index 0000000..c680715 --- /dev/null +++ b/src/ds390/gen.h @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------- + gen.h - header file for code generation for DS80C390 + + Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +#ifndef SDCCGEN390_H +#define SDCCGEN390_H + +enum +{ + AOP_LIT = 1, + AOP_REG, AOP_DIR, + AOP_DPTR, AOP_DPTR2, AOP_R0, AOP_R1, + AOP_STK, AOP_IMMD, AOP_STR, + AOP_CRY, AOP_ACC, AOP_DPTRn, AOP_DUMMY +}; + +/* type asmop : a homogenised type for + all the different spaces an operand can be + in */ +typedef struct asmop +{ + + short type; /* can have values + AOP_LIT - operand is a literal value + AOP_REG - is in registers + AOP_DIR - direct just a name + AOP_DPTR - dptr contains address of operand + AOP_DPTR2 - dptr2 contains address of operand (DS80C390 only). + AOP_R0/R1 - r0/r1 contains address of operand + AOP_STK - should be pushed on stack this + can happen only for the result + AOP_IMMD - immediate value for eg. remateriazable + AOP_CRY - carry contains the value of this + AOP_STR - array of strings + AOP_ACC - result is in the acc:b pair + AOP_DPTRn - is in dptr(n) + AOP_DUMMY - read as 0, discard writes + */ + short coff; /* current offset */ + short size; /* total size */ + unsigned code:1; /* is in Code space */ + unsigned paged:1; /* in paged memory */ + unsigned short allocated; /* number of times allocated */ + union + { + short dptr; /* if AOP_DPTRn */ + value *aop_lit; /* if literal */ + reg_info *aop_reg[8]; /* array of registers */ + char *aop_dir; /* if direct */ + reg_info *aop_ptr; /* either -> to r0 or r1 */ + struct + { + int from_cast_remat; /* cast remat created this : immd2 field used for highest order */ + char *aop_immd1; /* if immediate others are implied */ + char *aop_immd2; /* cast remat will generate this */ + } aop_immd; + int aop_stk; /* stack offset when AOP_STK */ + char *aop_str[5]; /* just a string array containing the location */ + } + aopu; +} +asmop; + +void gen390Code (iCode *); +void ds390_emitDebuggerSymbol (const char *); + +#endif diff --git a/src/ds390/main.c b/src/ds390/main.c new file mode 100644 index 0000000..2d7708b --- /dev/null +++ b/src/ds390/main.c @@ -0,0 +1,1710 @@ +/*------------------------------------------------------------------------- + main.h - ds390 specific general functions + + Copyright (C) 2000, Kevin Vigor + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ +/* + Note that mlh prepended _ds390_ on the static functions. Makes + it easier to set a breakpoint using the debugger. +*/ + +#include "common.h" +#include "main.h" +#include "ralloc.h" +#include "gen.h" +#include "dbuf_string.h" + +static char _defaultRules[] = +{ +#include "peeph.rul" +}; + +#define OPTION_STACK_8BIT "--stack-8bit" +#define OPTION_FLAT24_MODEL "--model-flat24" +#define OPTION_STACK_SIZE "--stack-size" + +static OPTION _ds390_options[] = + { + { 0, OPTION_FLAT24_MODEL, NULL, "use the flat24 model for the ds390 (default)" }, + { 0, OPTION_STACK_8BIT, NULL, "use the 8bit stack for the ds390 (not supported yet)" }, + { 0, OPTION_STACK_SIZE, &options.stack_size, "Tells the linker to allocate this space for stack", CLAT_INTEGER }, + { 0, "--pack-iram", NULL, "Tells the linker to pack variables in internal ram (default)"}, + { 0, "--no-pack-iram", &options.no_pack_iram, "Deprecated: Tells the linker not to pack variables in internal ram"}, + { 0, "--stack-10bit", &options.stack10bit, "use the 10bit stack for ds390 (default)" }, + { 0, "--use-accelerator", &options.useAccelerator, "generate code for ds390 arithmetic accelerator"}, + { 0, "--protect-sp-update", &options.protect_sp_update, "will disable interrupts during ESP:SP updates"}, + { 0, "--parms-in-bank1", &options.parms_in_bank1, "use Bank1 for parameter passing"}, + { 0, NULL } + }; + + +/* list of key words used by msc51 */ +static char *_ds390_keywords[] = +{ + "at", + "bit", + "code", + "critical", + "data", + "far", + "idata", + "interrupt", + "near", + "pdata", + "reentrant", + "sfr", + "sfr16", + "sfr32", + "sbit", + "using", + "xdata", + "_data", + "_code", + "_generic", + "_near", + "_xdata", + "_pdata", + "_idata", + "_naked", + NULL +}; + +static builtins __ds390_builtins[] = { + { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */ + { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code char *,int) */ + { "__builtin_memset_x","v",3,{"cx*","c","i"}}, /* void __builtin_memset (xdata char *,char,int) */ + /* __builtin_inp - used to read from a memory mapped port, increment first pointer */ + { "__builtin_inp","v",3,{"cx*","cx*","i"}}, /* void __builtin_inp (xdata char *,xdata char *,int) */ + /* __builtin_inp - used to write to a memory mapped port, increment first pointer */ + { "__builtin_outp","v",3,{"cx*","cx*","i"}}, /* void __builtin_outp (xdata char *,xdata char *,int) */ + { "__builtin_swapw","Us",1,{"Us"}}, /* unsigned short __builtin_swapw (unsigned short) */ + { "__builtin_memcmp_x2x","c",3,{"cx*","cx*","i"}}, /* void __builtin_memcmp_x2x (xdata char *,xdata char *,int) */ + { "__builtin_memcmp_c2x","c",3,{"cx*","cp*","i"}}, /* void __builtin_memcmp_c2x (xdata char *,code char *,int) */ + { NULL , NULL,0, {NULL}} /* mark end of table */ +}; +void ds390_assignRegisters (ebbIndex * ebbi); + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void +_ds390_init (void) +{ + asm_addTree (&asm_asxxxx_mapping); +} + +static void +_ds390_reset_regparm (struct sym_link *funcType) +{ + regParmFlg = 0; +} + +static int +_ds390_regparm (sym_link * l, bool reentrant) +{ + if (IS_SPEC(l) && (SPEC_NOUN(l) == V_BIT)) + return 0; + if (options.parms_in_bank1 == 0) { + /* simple can pass only the first parameter in a register */ + if (regParmFlg) + return 0; + + regParmFlg = 1; + return 1; + } else { + int size = getSize(l); + int remain ; + + /* first one goes the usual way to DPTR */ + if (regParmFlg == 0) { + regParmFlg += 4 ; + return 1; + } + /* second one onwards goes to RB1_0 thru RB1_7 */ + remain = regParmFlg - 4; + if (size > (8 - remain)) { + regParmFlg = 12 ; + return 0; + } + regParmFlg += size ; + return regParmFlg - size + 1; + } +} + +static bool +_ds390_parseOptions (int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + if (!strcmp (argv[*i], OPTION_STACK_8BIT)) + { + options.stack10bit = 0; + return TRUE; + } + else if (!strcmp (argv[*i], OPTION_FLAT24_MODEL)) + { + options.model = MODEL_FLAT24; + return TRUE; + } + return FALSE; +} + +static void +_ds390_finaliseOptions (void) +{ + if (options.noXinitOpt) + { + port->genXINIT=0; + } + + /* Hack-o-matic: if we are using the flat24 model, + * adjust pointer sizes. + */ + if (options.model != MODEL_FLAT24) + { + fprintf (stderr, + "*** warning: ds390 port small and large model experimental.\n"); + if (options.model == MODEL_LARGE) + { + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + } + else + { + port->mem.default_local_map = data; + port->mem.default_globl_map = data; + } + } + else + { + port->s.far_ptr_size = 3; + port->s.funcptr_size = 3; + port->s.ptr_size = 4; + + port->stack.isr_overhead += 2; /* Will save dpx on ISR entry. */ + + port->stack.call_overhead += 2; /* This acounts for the extra byte + * of return addres on the stack. + * but is ugly. There must be a + * better way. + */ + + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + + if (!options.stack10bit) + { + fprintf (stderr, + "*** error: ds390 port only supports the 10 bit stack mode.\n"); + } + else + { + if (!options.stack_loc) options.stack_loc = 0x400008; + } + + /* Fixup the memory map for the stack; it is now in + * far space and requires an FPOINTER to access it. + */ + istack->fmap = 1; + istack->ptrType = FPOINTER; + + } /* MODEL_FLAT24 */ +} + +static void +_ds390_setDefaultOptions (void) +{ + options.model=MODEL_FLAT24; + options.stack10bit=1; +} + +static const char * +_ds390_getRegName (const struct reg_info *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +extern char * iComments2; + +static void +_ds390_genAssemblerPreamble (FILE * of) +{ + fputs (iComments2, of); + fputs ("; CPU specific extensions\n",of); + fputs (iComments2, of); + + fputs ("\t.DS80C390\n", of); + + if (options.model == MODEL_FLAT24) + fputs ("\t.amode\t2\t; 24 bit flat addressing\n", of); + + fputs ("dpl\t=\t0x82\n", of); + fputs ("dph\t=\t0x83\n", of); + fputs ("dpl1\t=\t0x84\n", of); + fputs ("dph1\t=\t0x85\n", of); + fputs ("dps\t=\t0x86\n", of); + fputs ("dpx\t=\t0x93\n", of); + fputs ("dpx1\t=\t0x95\n", of); + fputs ("esp\t=\t0x9B\n", of); + fputs ("ap\t=\t0x9C\n", of); + fputs ("acc1\t=\t0x9C\n", of); + fputs ("mcnt0\t=\t0xD1\n", of); + fputs ("mcnt1\t=\t0xD2\n", of); + fputs ("ma\t=\t0xD3\n", of); + fputs ("mb\t=\t0xD4\n", of); + fputs ("mc\t=\t0xD5\n", of); + fputs ("acon\t=\t0x9D\n", of); + fputs ("mcon\t=\t0xC6\n", of); + fputs ("F1\t=\t0xD1\t; user flag\n", of); + if (options.parms_in_bank1) + { + int i ; + for (i=0; i < 8 ; i++ ) + fprintf (of,"b1_%d\t=\t0x%02X\n",i,8+i); + } +} + +/* Generate interrupt vector table. */ +static int +_ds390_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts) +{ + int i; + + if (options.model != MODEL_FLAT24) + { + dbuf_printf (oBuf, "\tljmp\t__sdcc_gsinit_startup\n"); + + /* now for the other interrupts */ + for (i = 0; i < maxInterrupts; i++) + { + if (interrupts[i]) + { + dbuf_printf (oBuf, "\tljmp\t%s\n", interrupts[i]->rname); + if ( i != maxInterrupts - 1 ) + dbuf_printf (oBuf, "\t.ds\t5\n"); + } + else + { + dbuf_printf (oBuf, "\treti\n"); + if ( i != maxInterrupts - 1 ) + dbuf_printf (oBuf, "\t.ds\t7\n"); + } + } + } + else + { + dbuf_printf (oBuf, "\t.amode\t0\t; 16 bit addressing\n"); + dbuf_printf (oBuf, "\tljmp\t__reset_vect\n"); + dbuf_printf (oBuf, "\t.amode\t2\t; 24 bit flat addressing\n"); + + /* now for the other interrupts */ + for (i = 0; i < maxInterrupts; i++) + { + if (interrupts[i]) + { + dbuf_printf (oBuf, "\tljmp\t%s\n\t.ds\t4\n", interrupts[i]->rname); + } + else + { + dbuf_printf (oBuf, "\treti\n\t.ds\t7\n"); + } + } + + dbuf_printf (oBuf, "__reset_vect:\n"); + if (options.stack10bit) + { + dbuf_printf (oBuf, "\tmov _TA,#0xAA\n"); + dbuf_printf (oBuf, "\tmov _TA,#0x55\n"); + dbuf_printf (oBuf, "\tmov acon,#0x06\t;24 bit addresses, 10 bit stack\n"); + dbuf_printf (oBuf, "\tmov _TA,#0xAA\n"); + dbuf_printf (oBuf, "\tmov _TA,#0x55\n"); + dbuf_printf (oBuf, "\tmov mcon,#0x90\t;10 bit stack at 0x400000\n"); + dbuf_printf (oBuf, "\tmov _ESP,#0x00\t; reinitialize the stack\n"); + dbuf_printf (oBuf, "\tmov _SP,#0x00\n"); + } + else + { + dbuf_printf (oBuf, "\tmov _TA,#0xAA\n"); + dbuf_printf (oBuf, "\tmov _TA,#0x55\n"); + dbuf_printf (oBuf, "\tmov acon,#0x02\t;24 bit addresses, default 8 bit stack\n"); + } + dbuf_printf (oBuf, "\tljmp\t__sdcc_gsinit_startup\n"); + } + return TRUE; +} + +static void +_ds390_genInitStartup (FILE *of) +{ + fprintf (of, "__sdcc_gsinit_startup:\n"); + /* if external stack is specified then the + higher order byte of the xdata location is + going into P2 and the lower order going into + spx */ + if (options.useXstack) + { + fprintf (of, "\tmov\tP2,#0x%02x\n", + (((unsigned int) options.xdata_loc) >> 8) & 0xff); + fprintf (of, "\tmov\t_spx,#0x%02x\n", + (unsigned int) options.xdata_loc & 0xff); + } + + // This should probably be a port option, but I'm being lazy. + // on the 400, the firmware boot loader gives us a valid stack + // (see '400 data sheet pg. 85 (TINI400 ROM Initialization code) + if (!TARGET_IS_DS400 && !options.stack10bit) + { + /* initialise the stack pointer. JCF: sdld takes care of the location */ + fprintf (of, "\tmov\tsp,#__start__stack - 1\n"); /* MOF */ + } + + fprintf (of, "\tlcall\t__sdcc_external_startup\n"); + fprintf (of, "\tmov\ta,dpl\n"); + fprintf (of, "\tjz\t__sdcc_init_data\n"); + fprintf (of, "\tljmp\t__sdcc_program_startup\n"); + fprintf (of, "__sdcc_init_data:\n"); + + // if the port can copy the XINIT segment to XISEG + if (port->genXINIT) + { + port->genXINIT(of); + } +} + +/* Generate code to copy XINIT to XISEG */ +static void _ds390_genXINIT (FILE * of) +{ + fprintf (of, "; _ds390_genXINIT() start\n"); + fprintf (of, " mov a,#l_XINIT\n"); + fprintf (of, " orl a,#l_XINIT>>8\n"); + fprintf (of, " jz 00003$\n"); + fprintf (of, " mov a,#s_XINIT\n"); + fprintf (of, " add a,#l_XINIT\n"); + fprintf (of, " mov r1,a\n"); + fprintf (of, " mov a,#s_XINIT>>8\n"); + fprintf (of, " addc a,#l_XINIT>>8\n"); + fprintf (of, " mov r2,a\n"); + fprintf (of, " mov dptr,#s_XINIT\n"); + fprintf (of, " mov dps,#0x21\n"); + fprintf (of, " mov dptr,#s_XISEG\n"); + fprintf (of, "00001$: clr a\n"); + fprintf (of, " movc a,@a+dptr\n"); + fprintf (of, " movx @dptr,a\n"); + fprintf (of, " inc dptr\n"); + fprintf (of, " inc dptr\n"); + fprintf (of, "00002$: mov a,dpl\n"); + fprintf (of, " cjne a,ar1,00001$\n"); + fprintf (of, " mov a,dph\n"); + fprintf (of, " cjne a,ar2,00001$\n"); + fprintf (of, " mov dps,#0\n"); + fprintf (of, "00003$:\n"); + fprintf (of, "; _ds390_genXINIT() end\n"); + + fprintf (of, "; _ds390_genXRAMCLEAR() start\n"); + fprintf (of, " mov r0,#l_PSEG\n"); + fprintf (of, " mov a,r0\n"); + fprintf (of, " orl a,#(l_PSEG >> 8)\n"); + fprintf (of, " jz 00006$\n"); + fprintf (of, " mov r1,#s_PSEG\n"); + fprintf (of, " mov _P2,#(s_PSEG >> 8)\n"); + fprintf (of, " clr a\n"); + fprintf (of, "00005$: movx @r1,a\n"); + fprintf (of, " inc r1\n"); + fprintf (of, " djnz r0,00005$\n"); + fprintf (of, "00006$: mov r0,#l_XSEG\n"); + fprintf (of, " mov a,r0\n"); + fprintf (of, " orl a,#(l_XSEG >> 8)\n"); + fprintf (of, " jz 00008$\n"); + fprintf (of, " mov r1,#((l_XSEG + 255) >> 8)\n"); + fprintf (of, " mov dptr,#s_XSEG\n"); + fprintf (of, " clr a\n"); + fprintf (of, "00007$: movx @dptr,a\n"); + fprintf (of, " inc dptr\n"); + fprintf (of, " djnz r0,00007$\n"); + fprintf (of, " djnz r1,00007$\n"); + fprintf (of, "00008$:\n"); + fprintf (of, "; _ds390_genXRAMCLEAR() end\n"); +} + +/* Do CSE estimation */ +static bool cseCostEstimation (iCode *ic, iCode *pdic) +{ + operand *result = IC_RESULT(ic); + //operand *right = IC_RIGHT(ic); + //operand *left = IC_LEFT(ic); + sym_link *result_type = operandType(result); + //sym_link *right_type = (right ? operandType(right) : 0); + //sym_link *left_type = (left ? operandType(left) : 0); + + /* if it is a pointer then return ok for now */ + if (IC_RESULT(ic) && IS_PTR(result_type)) return 1; + + /* if bitwise | add & subtract then no since mcs51 is pretty good at it + so we will cse only if they are local (i.e. both ic & pdic belong to + the same basic block */ + if (IS_BITWISE_OP(ic) || ic->op == '+' || ic->op == '-') { + /* then if they are the same Basic block then ok */ + if (ic->eBBlockNum == pdic->eBBlockNum) return 1; + else return 0; + } + + /* for others it is cheaper to do the cse */ + return 1; +} + +bool _ds390_nativeMulCheck(iCode *ic, sym_link *left, sym_link *right) +{ + return + getSize (left) == 1 && getSize (right) == 1 || + options.useAccelerator && getSize (left) == 2 && getSize (right) == 2; +} + +/* Indicate which extended bit operations this port supports */ +static bool +hasExtBitOp (int op, int size) +{ + if (op == RRC + || op == RLC + || op == GETHBIT + || (op == SWAP && size <= 2) + ) + return TRUE; + else + return FALSE; +} + +/* Indicate the expense of an access to an output storage class */ +static int +oclsExpense (struct memmap *oclass) +{ + if (IN_FARSPACE(oclass)) + return 1; + + return 0; +} + +static int +instructionSize(char *inst, char *op1, char *op2) +{ + int isflat24 = (options.model == MODEL_FLAT24); + + #define ISINST(s) (strncmp(inst, (s), sizeof(s)-1) == 0) + #define IS_A(s) (*(s) == 'a' && *(s+1) == '\0') + #define IS_C(s) (*(s) == 'c' && *(s+1) == '\0') + #define IS_Rn(s) (*(s) == 'r' && *(s+1) >= '0' && *(s+1) <= '7') + #define IS_atRi(s) (*(s) == '@' && *(s+1) == 'r') + + /* Based on the current (2003-08-22) code generation for the + small library, the top instruction probability is: + + 57% mov/movx/movc + 6% push + 6% pop + 4% inc + 4% lcall + 4% add + 3% clr + 2% subb + */ + /* mov, push, & pop are the 69% of the cases. Check them first! */ + if (ISINST ("mov")) + { + if (*(inst+3)=='x') return 1; /* movx */ + if (*(inst+3)=='c') return 1; /* movc */ + if (IS_C (op1) || IS_C (op2)) return 2; + if (IS_A (op1)) + { + if (IS_Rn (op2) || IS_atRi (op2)) return 1; + return 2; + } + if (IS_Rn(op1) || IS_atRi(op1)) + { + if (IS_A(op2)) return 1; + return 2; + } + if (strcmp (op1, "dptr") == 0) return 3+isflat24; + if (IS_A (op2) || IS_Rn (op2) || IS_atRi (op2)) return 2; + return 3; + } + + if (ISINST ("push")) return 2; + if (ISINST ("pop")) return 2; + + if (ISINST ("lcall")) return 3+isflat24; + if (ISINST ("ret")) return 1; + if (ISINST ("ljmp")) return 3+isflat24; + if (ISINST ("sjmp")) return 2; + if (ISINST ("rlc")) return 1; + if (ISINST ("rrc")) return 1; + if (ISINST ("rl")) return 1; + if (ISINST ("rr")) return 1; + if (ISINST ("swap")) return 1; + if (ISINST ("jc")) return 2; + if (ISINST ("jnc")) return 2; + if (ISINST ("jb")) return 3; + if (ISINST ("jnb")) return 3; + if (ISINST ("jbc")) return 3; + if (ISINST ("jmp")) return 1; // always jmp @a+dptr + if (ISINST ("jz")) return 2; + if (ISINST ("jnz")) return 2; + if (ISINST ("cjne")) return 3; + if (ISINST ("mul")) return 1; + if (ISINST ("div")) return 1; + if (ISINST ("da")) return 1; + if (ISINST ("xchd")) return 1; + if (ISINST ("reti")) return 1; + if (ISINST ("nop")) return 1; + if (ISINST ("acall")) return 2+isflat24; + if (ISINST ("ajmp")) return 2+isflat24; + + + if (ISINST ("add") || ISINST ("addc") || ISINST ("subb") || ISINST ("xch")) + { + if (IS_Rn(op2) || IS_atRi(op2)) return 1; + return 2; + } + if (ISINST ("inc") || ISINST ("dec")) + { + if (IS_A(op1) || IS_Rn(op1) || IS_atRi(op1)) return 1; + if (strcmp(op1, "dptr") == 0) return 1; + return 2; + } + if (ISINST ("anl") || ISINST ("orl") || ISINST ("xrl")) + { + if (IS_C(op1)) return 2; + if (IS_A(op1)) + { + if (IS_Rn(op2) || IS_atRi(op2)) return 1; + return 2; + } + else + { + if (IS_A(op2)) return 2; + return 3; + } + } + if (ISINST ("clr") || ISINST ("setb") || ISINST ("cpl")) + { + if (IS_A(op1) || IS_C(op1)) return 1; + return 2; + } + if (ISINST ("djnz")) + { + if (IS_Rn(op1)) return 2; + return 3; + } + + /* If the instruction is unrecognized, we shouldn't try to optimize. */ + /* Return a large value to discourage optimization. */ + return 999; +} + +asmLineNode * +ds390newAsmLineNode (int currentDPS) +{ + asmLineNode *aln; + + aln = Safe_alloc ( sizeof (asmLineNode)); + aln->size = 0; + aln->regsRead = NULL; + aln->regsWritten = NULL; + aln->initialized = 0; + aln->currentDPS = currentDPS; + + return aln; +} + + +typedef struct ds390operanddata + { + char name[6]; + int regIdx1; + int regIdx2; + } +ds390operanddata; + +static ds390operanddata ds390operandDataTable[] = + { + {"acc1", AP_IDX, -1}, + {"a", A_IDX, -1}, + {"ab", A_IDX, B_IDX}, + {"ac", CND_IDX, -1}, + {"ap", AP_IDX, -1}, + {"acc", A_IDX, -1}, + {"ar0", R0_IDX, -1}, + {"ar1", R1_IDX, -1}, + {"ar2", R2_IDX, -1}, + {"ar3", R3_IDX, -1}, + {"ar4", R4_IDX, -1}, + {"ar5", R5_IDX, -1}, + {"ar6", R6_IDX, -1}, + {"ar7", R7_IDX, -1}, + {"b", B_IDX, -1}, + {"c", CND_IDX, -1}, + {"cy", CND_IDX, -1}, + {"dph", DPH_IDX, -1}, + {"dph0", DPH_IDX, -1}, + {"dph1", DPH1_IDX, -1}, + {"dpl", DPL_IDX, -1}, + {"dpl0", DPL_IDX, -1}, + {"dpl1", DPL1_IDX, -1}, +/* {"dptr", DPL_IDX, DPH_IDX}, */ /* dptr is special, based on currentDPS */ + {"dps", DPS_IDX, -1}, + {"dpx", DPX_IDX, -1}, + {"dpx0", DPX_IDX, -1}, + {"dpx1", DPX1_IDX, -1}, + {"f0", CND_IDX, -1}, + {"f1", CND_IDX, -1}, + {"ov", CND_IDX, -1}, + {"p", CND_IDX, -1}, + {"psw", CND_IDX, -1}, + {"r0", R0_IDX, -1}, + {"r1", R1_IDX, -1}, + {"r2", R2_IDX, -1}, + {"r3", R3_IDX, -1}, + {"r4", R4_IDX, -1}, + {"r5", R5_IDX, -1}, + {"r6", R6_IDX, -1}, + {"r7", R7_IDX, -1}, + }; + +static int +ds390operandCompare (const void *key, const void *member) +{ + return strcmp((const char *)key, ((ds390operanddata *)member)->name); +} + +static void +updateOpRW (asmLineNode *aln, char *op, char *optype, int currentDPS) +{ + ds390operanddata *opdat; + char *dot; + int regIdx1 = -1; + int regIdx2 = -1; + int regIdx3 = -1; + + dot = strchr(op, '.'); + if (dot) + *dot = '\0'; + + opdat = bsearch (op, ds390operandDataTable, + sizeof(ds390operandDataTable)/sizeof(ds390operanddata), + sizeof(ds390operanddata), ds390operandCompare); + + if (opdat) + { + regIdx1 = opdat->regIdx1; + regIdx2 = opdat->regIdx2; + } + if (!strcmp(op, "dptr")) + { + if (!currentDPS) + { + regIdx1 = DPL_IDX; + regIdx2 = DPH_IDX; + regIdx3 = DPX_IDX; + } + else + { + regIdx1 = DPL1_IDX; + regIdx2 = DPH1_IDX; + regIdx3 = DPX1_IDX; + } + } + + if (strchr(optype,'r')) + { + if (regIdx1 >= 0) + aln->regsRead = bitVectSetBit (aln->regsRead, regIdx1); + if (regIdx2 >= 0) + aln->regsRead = bitVectSetBit (aln->regsRead, regIdx2); + if (regIdx3 >= 0) + aln->regsRead = bitVectSetBit (aln->regsRead, regIdx3); + } + if (strchr(optype,'w')) + { + if (regIdx1 >= 0) + aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx1); + if (regIdx2 >= 0) + aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx2); + if (regIdx3 >= 0) + aln->regsWritten = bitVectSetBit (aln->regsWritten, regIdx3); + } + if (op[0] == '@') + { + if (!strcmp(op, "@r0")) + aln->regsRead = bitVectSetBit (aln->regsRead, R0_IDX); + if (!strcmp(op, "@r1")) + aln->regsRead = bitVectSetBit (aln->regsRead, R1_IDX); + if (strstr(op, "dptr")) + { + if (!currentDPS) + { + aln->regsRead = bitVectSetBit (aln->regsRead, DPL_IDX); + aln->regsRead = bitVectSetBit (aln->regsRead, DPH_IDX); + aln->regsRead = bitVectSetBit (aln->regsRead, DPX_IDX); + } + else + { + aln->regsRead = bitVectSetBit (aln->regsRead, DPL1_IDX); + aln->regsRead = bitVectSetBit (aln->regsRead, DPH1_IDX); + aln->regsRead = bitVectSetBit (aln->regsRead, DPX1_IDX); + } + } + if (strstr(op, "a+")) + aln->regsRead = bitVectSetBit (aln->regsRead, A_IDX); + } +} + +typedef struct ds390opcodedata + { + char name[6]; + char class[3]; + char pswtype[3]; + char op1type[3]; + char op2type[3]; + } +ds390opcodedata; + +static ds390opcodedata ds390opcodeDataTable[] = + { + {"acall","j", "", "", ""}, + {"add", "", "w", "rw", "r"}, + {"addc", "", "rw", "rw", "r"}, + {"ajmp", "j", "", "", ""}, + {"anl", "", "", "rw", "r"}, + {"cjne", "j", "w", "r", "r"}, + {"clr", "", "", "w", ""}, + {"cpl", "", "", "rw", ""}, + {"da", "", "rw", "rw", ""}, + {"dec", "", "", "rw", ""}, + {"div", "", "w", "rw", ""}, + {"djnz", "j", "", "rw", ""}, + {"inc", "", "", "rw", ""}, + {"jb", "j", "", "r", ""}, + {"jbc", "j", "", "rw", ""}, + {"jc", "j", "", "", ""}, + {"jmp", "j", "", "", ""}, + {"jnb", "j", "", "r", ""}, + {"jnc", "j", "", "", ""}, + {"jnz", "j", "", "", ""}, + {"jz", "j", "", "", ""}, + {"lcall","j", "", "", ""}, + {"ljmp", "j", "", "", ""}, + {"mov", "", "", "w", "r"}, + {"movc", "", "", "w", "r"}, + {"movx", "", "", "w", "r"}, + {"mul", "", "w", "rw", ""}, + {"nop", "", "", "", ""}, + {"orl", "", "", "rw", "r"}, + {"pop", "", "", "w", ""}, + {"push", "", "", "r", ""}, + {"ret", "j", "", "", ""}, + {"reti", "j", "", "", ""}, + {"rl", "", "", "rw", ""}, + {"rlc", "", "rw", "rw", ""}, + {"rr", "", "", "rw", ""}, + {"rrc", "", "rw", "rw", ""}, + {"setb", "", "", "w", ""}, + {"sjmp", "j", "", "", ""}, + {"subb", "", "rw", "rw", "r"}, + {"swap", "", "", "rw", ""}, + {"xch", "", "", "rw", "rw"}, + {"xchd", "", "", "rw", "rw"}, + {"xrl", "", "", "rw", "r"}, + }; + +static int +ds390opcodeCompare (const void *key, const void *member) +{ + return strcmp((const char *)key, ((ds390opcodedata *)member)->name); +} + +static asmLineNode * +asmLineNodeFromLineNode (lineNode *ln, int currentDPS) +{ + asmLineNode *aln = ds390newAsmLineNode(currentDPS); + char *op, op1[256], op2[256]; + int opsize; + const char *p; + char inst[8]; + ds390opcodedata *opdat; + + aln->initialized = 1; + + p = ln->line; + + while (*p && isspace(*p)) p++; + for (op = inst, opsize=1; *p; p++) + { + if (isspace(*p) || *p == ';' || *p == ':' || *p == '=') + break; + else + if (opsize < sizeof(inst)) + *op++ = tolower(*p), opsize++; + } + *op = '\0'; + + if (*p == ';' || *p == ':' || *p == '=') + return aln; + + while (*p && isspace(*p)) p++; + if (*p == '=') + return aln; + + for (op = op1, opsize=1; *p && *p != ','; p++) + { + if (!isspace(*p) && opsize < sizeof(op1)) + *op++ = tolower(*p), opsize++; + } + *op = '\0'; + + if (*p == ',') p++; + for (op = op2, opsize=1; *p && *p != ','; p++) + { + if (!isspace(*p) && opsize < sizeof(op2)) + *op++ = tolower(*p), opsize++; + } + *op = '\0'; + + aln->size = instructionSize(inst, op1, op2); + + aln->regsRead = newBitVect (END_IDX); + aln->regsWritten = newBitVect (END_IDX); + + opdat = bsearch (inst, ds390opcodeDataTable, + sizeof(ds390opcodeDataTable)/sizeof(ds390opcodedata), + sizeof(ds390opcodedata), ds390opcodeCompare); + + if (opdat) + { + updateOpRW (aln, op1, opdat->op1type, currentDPS); + updateOpRW (aln, op2, opdat->op2type, currentDPS); + if (strchr(opdat->pswtype,'r')) + aln->regsRead = bitVectSetBit (aln->regsRead, CND_IDX); + if (strchr(opdat->pswtype,'w')) + aln->regsWritten = bitVectSetBit (aln->regsWritten, CND_IDX); + } + + return aln; +} + +static void +initializeAsmLineNode (lineNode *line) +{ + if (!line->aln) + line->aln = (asmLineNodeBase *) asmLineNodeFromLineNode (line, 0); + else if (line->aln && !((asmLineNode *)line->aln)->initialized) + { + int currentDPS = ((asmLineNode *)line->aln)->currentDPS; + free(line->aln); + line->aln = (asmLineNodeBase *) asmLineNodeFromLineNode (line, currentDPS); + } +} + +static int +getInstructionSize (lineNode *line) +{ + initializeAsmLineNode (line); + return line->aln->size; +} + +static bitVect * +getRegsRead (lineNode *line) +{ + initializeAsmLineNode (line); + return line->aln->regsRead; +} + +static bitVect * +getRegsWritten (lineNode *line) +{ + initializeAsmLineNode (line); + return line->aln->regsWritten; +} + +static const char * +get_model (void) +{ + switch (options.model) + { + case MODEL_SMALL: + if (options.stackAuto) + return "small-stack-auto"; + else + return "small"; + + case MODEL_LARGE: + if (options.stackAuto) + return "large-stack-auto"; + else + return "large"; + + case MODEL_FLAT24: + return port->target; + + default: + werror (W_UNKNOWN_MODEL, __FILE__, __LINE__); + return "unknown"; + } +} + +/** $1 is always the basename. + $2 is always the output file. + $3 varies + $l is the list of extra options that should be there somewhere... + MUST be terminated with a NULL. +*/ +static const char *_linkCmd[] = +{ + "sdld", "-nf", "$1", NULL +}; + +/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */ +static const char *_asmCmd[] = +{ + "sdas390", "$l", "$3", "$2", "$1.asm", NULL +}; + +static const char * const _libs_ds390[] = { STD_DS390_LIB, NULL, }; + +/* Globals */ +PORT ds390_port = +{ + TARGET_ID_DS390, + "ds390", + "DS80C390", /* Target name */ + NULL, + { + glue, + TRUE, /* Emit glue around main */ + MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24, + MODEL_SMALL, + get_model, + }, + { + _asmCmd, + NULL, + "-plosgffwy", /* Options with debug */ + "-plosgffw", /* Options without debug */ + 0, + ".asm", + NULL /* no do_assemble function */ + }, + { /* Linker */ + _linkCmd, + NULL, + NULL, + ".rel", + 1, + NULL, /* crt */ + _libs_ds390, /* libs */ + }, + { + _defaultRules, + getInstructionSize, + getRegsRead, + getRegsWritten, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + /* Sizes: char, short, int, long, long long, near ptr, far ptr, gptr, bit, float */ + { 1, 2, 2, 4, 8, 1, 2, 3, 2, 3, 1, 4 }, + + /* tags for generic pointers */ + { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */ + + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "PSEG (PAG,XDATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + "XISEG (XDATA)", // initialized xdata + "XINIT (CODE)", // a code copy of xiseg + "CONST (CODE)", // const_name - const data (code or not) + "CABS (ABS,CODE)", // cabs_name - const absolute data (code or not) + "XABS (ABS,XDATA)", // xabs_name - absolute xdata/pdata + "IABS (ABS,DATA)", // iabs_name - absolute idata/data + NULL, // name of segment for initialized variables + NULL, // name of segment for copies of initialized variables in code space + NULL, + NULL, + 1, + 1 // No fancy alignments supported. + }, + { NULL, NULL }, + { +1, 1, 4, 1, 1, 0, 0 }, + /* ds390 has an 16 bit mul & div */ + { -1, FALSE }, + { ds390_emitDebuggerSymbol }, + { + 255/4, /* maxCount */ + 4, /* sizeofElement */ + {8,12,20}, /* sizeofMatchJump[] */ + {10,14,22}, /* sizeofRangeCompare[] */ + 4, /* sizeofSubtract */ + 7, /* sizeofDispatch */ + }, + "_", + _ds390_init, + _ds390_parseOptions, + _ds390_options, + NULL, + _ds390_finaliseOptions, + _ds390_setDefaultOptions, + ds390_assignRegisters, + _ds390_getRegName, + 0, + NULL, + _ds390_keywords, + _ds390_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _ds390_genIVT, + _ds390_genXINIT, + _ds390_genInitStartup, + _ds390_reset_regparm, + _ds390_regparm, + NULL, + NULL, + _ds390_nativeMulCheck, + hasExtBitOp, /* hasExtBitOp */ + oclsExpense, /* oclsExpense */ + FALSE, + TRUE, /* little endian */ + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + cseCostEstimation, + __ds390_builtins, /* table of builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + 0, /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */ + PORT_MAGIC +}; + +/*---------------------------------------------------------------------------------*/ +/* TININative specific */ +/*---------------------------------------------------------------------------------*/ + +#define OPTION_TINI_LIBID "--tini-libid" + +static OPTION _tininative_options[] = + { + { 0, OPTION_FLAT24_MODEL, NULL, "use the flat24 model for the ds390 (default)" }, + { 0, OPTION_STACK_8BIT, NULL, "use the 8bit stack for the ds390 (not supported yet)" }, + { 0, OPTION_STACK_SIZE, &options.stack_size, "Tells the linker to allocate this space for stack", CLAT_INTEGER }, + { 0, "--pack-iram", NULL, "Tells the linker to pack variables in internal ram (default)"}, + { 0, "--no-pack-iram", &options.no_pack_iram, "Deprecated: Tells the linker not to pack variables in internal ram"}, + { 0, "--stack-10bit", &options.stack10bit, "use the 10bit stack for ds390 (default)" }, + { 0, "--use-accelerator", &options.useAccelerator, "generate code for ds390 arithmetic accelerator"}, + { 0, "--protect-sp-update", &options.protect_sp_update, "will disable interrupts during ESP:SP updates"}, + { 0, "--parms-in-bank1", &options.parms_in_bank1, "use Bank1 for parameter passing"}, + { 0, OPTION_TINI_LIBID, &options.tini_libid, "<nnnn> LibraryID used in -mTININative", CLAT_INTEGER }, + { 0, NULL } + }; + +static void _tininative_init (void) +{ + asm_addTree (&asm_a390_mapping); +} + +static void _tininative_setDefaultOptions (void) +{ + options.model=MODEL_FLAT24; + options.stack10bit=1; + options.stackAuto = 1; +} + +static void _tininative_finaliseOptions (void) +{ + /* Hack-o-matic: if we are using the flat24 model, + * adjust pointer sizes. + */ + if (options.model != MODEL_FLAT24) { + options.model = MODEL_FLAT24 ; + fprintf(stderr,"TININative supports only MODEL FLAT24\n"); + } + port->s.far_ptr_size = 3; + port->s.funcptr_size = 3; + port->s.ptr_size = 4; + + port->stack.isr_overhead += 2; /* Will save dpx on ISR entry. */ + + port->stack.call_overhead += 2; /* This acounts for the extra byte + * of return address on the stack. + * but is ugly. There must be a + * better way. + */ + + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + + if (!options.stack10bit) { + options.stack10bit = 1; + fprintf(stderr,"TININative supports only stack10bit \n"); + } + + if (!options.stack_loc) options.stack_loc = 0x400008; + + /* Fixup the memory map for the stack; it is now in + * far space and requires a FPOINTER to access it. + */ + istack->fmap = 1; + istack->ptrType = FPOINTER; + options.cc_only =1; +} + +static int _tininative_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts) +{ + return TRUE; +} + +static void _tininative_genAssemblerPreamble (FILE * of) +{ + fputs("$include(tini.inc)\n", of); + fputs("$include(ds80c390.inc)\n", of); + fputs("$include(tinimacro.inc)\n", of); + fputs("$include(apiequ.inc)\n", of); + fputs("_bpx EQU 01Eh \t\t; _bpx (frame pointer) mapped to R7_B3:R6_B3\n", of); + fputs("acc1 EQU 01Dh \t\t; acc1 mapped to R5_B3\n", of); + /* Must be first and return 0 */ + fputs("Lib_Native_Init:\n",of); + fputs("\tclr\ta\n",of); + fputs("\tret\n",of); + fputs("LibraryID:\n",of); + fputs("\tdb \"DS\"\n",of); + if (options.tini_libid) { + fprintf(of,"\tdb 0,0,0%02xh,0%02xh,0%02xh,0%02xh\n", + (options.tini_libid>>24 & 0xff), + (options.tini_libid>>16 & 0xff), + (options.tini_libid>>8 & 0xff), + (options.tini_libid & 0xff)); + } else { + fprintf(of,"\tdb 0,0,0,0,0,1\n"); + } + +} +static void _tininative_genAssemblerEnd (FILE * of) +{ + fputs("\tend\n",of); +} +/* tininative assembler , calls "macro", if it succeeds calls "a390" */ +static void _tininative_do_assemble (set *asmOptions) +{ + char *buf; + static const char *macroCmd[] = { + "macro","$1.a51",NULL + }; + static const char *a390Cmd[] = { + "a390","$1.mpp",NULL + }; + + buf = buildCmdLine(macroCmd, dstFileName, NULL, NULL, NULL); + if (sdcc_system(buf)) { + Safe_free (buf); + exit(1); + } + Safe_free (buf); + buf = buildCmdLine(a390Cmd, dstFileName, NULL, NULL, asmOptions); + if (sdcc_system(buf)) { + Safe_free (buf); + exit(1); + } + Safe_free (buf); +} + +/* list of key words used by TININative */ +static char *_tininative_keywords[] = +{ + "at", + "bit", + "code", + "critical", + "data", + "far", + "idata", + "interrupt", + "near", + "pdata", + "reentrant", + "sfr", + "sbit", + "using", + "xdata", + "_data", + "_code", + "_generic", + "_near", + "_xdata", + "_pdata", + "_idata", + "_naked", + "_JavaNative", + NULL +}; + +static builtins __tininative_builtins[] = { + { "__builtin_memcpy_x2x","v",3,{"cx*","cx*","i"}}, /* void __builtin_memcpy_x2x (xdata char *,xdata char *,int) */ + { "__builtin_memcpy_c2x","v",3,{"cx*","cp*","i"}}, /* void __builtin_memcpy_c2x (xdata char *,code char *,int) */ + { "__builtin_memset_x","v",3,{"cx*","c","i"}}, /* void __builtin_memset (xdata char *,char,int) */ + /* TINI NatLib */ + { "NatLib_LoadByte","c",1,{"c"}}, /* char Natlib_LoadByte (0 based parameter number) */ + { "NatLib_LoadShort","s",1,{"c"}}, /* short Natlib_LoadShort (0 based parameter number) */ + { "NatLib_LoadInt","l",1,{"c"}}, /* long Natlib_LoadLong (0 based parameter number) */ + { "NatLib_LoadPointer","cx*",1,{"c"}}, /* long Natlib_LoadPointer (0 based parameter number) */ + /* TINI StateBlock related */ + { "NatLib_InstallImmutableStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallImmutableStateBlock(state block *,int handle) */ + { "NatLib_InstallEphemeralStateBlock","c",2,{"vx*","us"}},/* char NatLib_InstallEphemeralStateBlock(state block *,int handle) */ + { "NatLib_RemoveImmutableStateBlock","v",0,{NULL}},/* void NatLib_RemoveImmutableStateBlock() */ + { "NatLib_RemoveEphemeralStateBlock","v",0,{NULL}},/* void NatLib_RemoveEphemeralStateBlock() */ + { "NatLib_GetImmutableStateBlock","i",0,{NULL}}, /* int NatLib_GetImmutableStateBlock () */ + { "NatLib_GetEphemeralStateBlock","i",0,{NULL}}, /* int NatLib_GetEphemeralStateBlock () */ + /* Memory manager */ + { "MM_XMalloc","i",1,{"l"}}, /* int MM_XMalloc (long) */ + { "MM_Malloc","i",1,{"i"}}, /* int MM_Malloc (int) */ + { "MM_ApplicationMalloc","i",1,{"i"}}, /* int MM_ApplicationMalloc (int) */ + { "MM_Free","i",1,{"i"}}, /* int MM_Free (int) */ + { "MM_Deref","cx*",1,{"i"}}, /* char *MM_Free (int) */ + { "MM_UnrestrictedPersist","c",1,{"i"}}, /* char MM_UnrestrictedPersist (int) */ + /* System functions */ + { "System_ExecJavaProcess","c",2,{"cx*","i"}}, /* char System_ExecJavaProcess (char *,int) */ + { "System_GetRTCRegisters","v",1,{"cx*"}}, /* void System_GetRTCRegisters (char *) */ + { "System_SetRTCRegisters","v",1,{"cx*"}}, /* void System_SetRTCRegisters (char *) */ + { "System_ThreadSleep","v",2,{"l","c"}}, /* void System_ThreadSleep (long,char) */ + { "System_ThreadSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ThreadSleep_ExitCriticalSection (long,char) */ + { "System_ProcessSleep","v",2,{"l","c"}}, /* void System_ProcessSleep (long,char) */ + { "System_ProcessSleep_ExitCriticalSection","v",2,{"l","c"}},/* void System_ProcessSleep_ExitCriticalSection (long,char) */ + { "System_ThreadResume","c",2,{"c","c"}}, /* char System_ThreadResume(char,char) */ + { "System_SaveJavaThreadState","v",0,{NULL}}, /* void System_SaveJavaThreadState() */ + { "System_RestoreJavaThreadState","v",0,{NULL}}, /* void System_RestoreJavaThreadState() */ + { "System_ProcessYield","v",0,{NULL}}, /* void System_ProcessYield() */ + { "System_ProcessSuspend","v",0,{NULL}}, /* void System_ProcessSuspend() */ + { "System_ProcessResume","v",1,{"c"}}, /* void System_ProcessResume(char) */ + { "System_RegisterPoll","c",1,{"vF*"}}, /* char System_RegisterPoll ((void *func pointer)()) */ + { "System_RemovePoll","c",1,{"vF*"}}, /* char System_RemovePoll ((void *func pointer)()) */ + { "System_GetCurrentProcessId","c",0,{NULL}}, /* char System_GetCurrentProcessId() */ + { "System_GetCurrentThreadId","c",0,{NULL}}, /* char System_GetCurrentThreadId() */ + { NULL , NULL,0, {NULL}} /* mark end of table */ +}; + +static const char *_a390Cmd[] = +{ + "macro", "$l", "$3", "$1.a51", NULL +}; + +PORT tininative_port = +{ + TARGET_ID_DS390, + "TININative", + "DS80C390", /* Target name */ + NULL, /* processor */ + { + glue, + FALSE, /* Emit glue around main */ + MODEL_FLAT24, + MODEL_FLAT24, + get_model, + }, + { + _a390Cmd, + NULL, + "-l", /* Options with debug */ + "-l", /* Options without debug */ + 0, + ".a51", + _tininative_do_assemble + }, + { /* Linker */ + NULL, + NULL, + NULL, + ".tlib", + 1, + NULL, /* crt */ + _libs_ds390, /* libs */ + }, + { + _defaultRules, + getInstructionSize, + getRegsRead, + getRegsWritten, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + /* Sizes: char, short, int, long, long long, near ptr, far ptr, gptr, func ptr, banked func ptr, bit, float */ + { 1, 2, 2, 4, 8, 1, 3, 3, 3, 3, 1, 4 }, + /* tags for generic pointers */ + { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */ + + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "PSEG (PAG,XDATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + NULL, + NULL, + "CONST (CODE)", // const_name - const data (code or not) + "CABS (ABS,CODE)", // cabs_name - const absolute data (code or not) + "XABS (ABS,XDATA)", // xabs_name - absolute xdata/pdata + "IABS (ABS,DATA)", // iabs_name - absolute idata/data + NULL, // name of segment for initialized variables + NULL, // name of segment for copies of initialized variables in code space + NULL, + NULL, + 1, + 1 // No fancy alignments supported. + }, + { NULL, NULL }, + { +1, 1, 4, 1, 1, 0, 0 }, + /* ds390 has an 16 bit mul & div */ + { -1, FALSE }, + { ds390_emitDebuggerSymbol }, + { + 255/4, /* maxCount */ + 4, /* sizeofElement */ + {8,12,20}, /* sizeofMatchJump[] */ + {10,14,22}, /* sizeofRangeCompare[] */ + 4, /* sizeofSubtract */ + 7, /* sizeofDispatch */ + }, + "", + _tininative_init, + _ds390_parseOptions, + _tininative_options, + NULL, + _tininative_finaliseOptions, + _tininative_setDefaultOptions, + ds390_assignRegisters, + _ds390_getRegName, + 0, + NULL, + _tininative_keywords, + _tininative_genAssemblerPreamble, + _tininative_genAssemblerEnd, + _tininative_genIVT, + NULL, + _ds390_genInitStartup, + _ds390_reset_regparm, + _ds390_regparm, + NULL, + NULL, + _ds390_nativeMulCheck, + hasExtBitOp, /* hasExtBitOp */ + oclsExpense, /* oclsExpense */ + FALSE, + TRUE, /* little endian */ + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + cseCostEstimation, + __tininative_builtins, /* table of builtin functions */ + FPOINTER, /* treat unqualified pointers as far pointers */ + 0, /* DONOT reset labelKey */ + 0, /* globals & local static NOT allowed */ + 0, /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */ + PORT_MAGIC +}; + +static int +_ds400_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts) +{ + /* We can't generate a static IVT, since the boot rom creates one + * for us in rom_init. + * + * we must patch it as part of the C startup. + */ + dbuf_printf (oBuf, ";\tDS80C400 IVT must be generated at runtime.\n"); + dbuf_printf (oBuf, "\tsjmp\t__sdcc_400boot\n"); + dbuf_printf (oBuf, "\t.ascii\t'TINI'\t; required signature for 400 boot loader.\n"); + dbuf_printf (oBuf, "\t.db\t0\t; selected bank: zero *should* work...\n"); + dbuf_printf (oBuf, "\t__sdcc_400boot:\tljmp\t__sdcc_gsinit_startup\n"); + + return TRUE; +} + + +/*---------------------------------------------------------------------------------*/ +/* _ds400 specific */ +/*---------------------------------------------------------------------------------*/ + +static OPTION _ds400_options[] = + { + { 0, OPTION_FLAT24_MODEL, NULL, "use the flat24 model for the ds400 (default)" }, + { 0, OPTION_STACK_8BIT, NULL, "use the 8bit stack for the ds400 (not supported yet)" }, + { 0, OPTION_STACK_SIZE, &options.stack_size, "Tells the linker to allocate this space for stack", CLAT_INTEGER }, + { 0, "--pack-iram", NULL, "Tells the linker to pack variables in internal ram (default)"}, + { 0, "--no-pack-iram", &options.no_pack_iram, "Deprecated: Tells the linker not to pack variables in internal ram"}, + { 0, "--stack-10bit", &options.stack10bit, "use the 10bit stack for ds400 (default)" }, + { 0, "--use-accelerator", &options.useAccelerator, "generate code for ds400 arithmetic accelerator"}, + { 0, "--protect-sp-update", &options.protect_sp_update, "will disable interrupts during ESP:SP updates"}, + { 0, "--parms-in-bank1", &options.parms_in_bank1, "use Bank1 for parameter passing"}, + { 0, NULL } + }; + +static void +_ds400_finaliseOptions (void) +{ + if (options.noXinitOpt) + { + port->genXINIT=0; + } + + // hackhack: we're a superset of the 390. + addSet(&preArgvSet, Safe_strdup("-D__SDCC_ds390")); + addSet(&preArgvSet, Safe_strdup("-D__ds390")); + + /* Hack-o-matic: if we are using the flat24 model, + * adjust pointer sizes. + */ + if (options.model != MODEL_FLAT24) + { + fprintf (stderr, + "*** warning: ds400 port small and large model experimental.\n"); + if (options.model == MODEL_LARGE) + { + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + } + else + { + port->mem.default_local_map = data; + port->mem.default_globl_map = data; + } + } + else + { + port->s.far_ptr_size = 3; + port->s.funcptr_size = 3; + port->s.ptr_size = 4; + + port->stack.isr_overhead += 2; /* Will save dpx on ISR entry. */ + + port->stack.call_overhead += 2; /* This acounts for the extra byte + * of return addres on the stack. + * but is ugly. There must be a + * better way. + */ + + port->mem.default_local_map = xdata; + port->mem.default_globl_map = xdata; + + if (!options.stack10bit) + { + fprintf (stderr, + "*** error: ds400 port only supports the 10 bit stack mode.\n"); + } + else + { + if (!options.stack_loc) + options.stack_loc = 0xffdc00; + // assumes IDM1:0 = 1:0, CMA = 1. + } + + /* Fixup the memory map for the stack; it is now in + * far space and requires a FPOINTER to access it. + */ + istack->fmap = 1; + istack->ptrType = FPOINTER; + + // the DS400 rom calling interface uses register bank 3. + RegBankUsed[3] = 1; + + } /* MODEL_FLAT24 */ +} + +static void _ds400_generateRomDataArea(FILE *fp, bool isMain) +{ + /* Only do this for the file containing main() */ + if (isMain) + { + fprintf(fp, "%s", iComments2); + fprintf(fp, "; the direct data area used by the DS80c400 ROM code.\n"); + fprintf(fp, "%s", iComments2); + fprintf(fp, ".area ROMSEG (ABS,CON,DATA)\n\n"); + fprintf(fp, ".ds 24 ; 24 bytes of directs used starting at 0x68\n\n"); + } +} + +static void _ds400_linkRomDataArea(FILE *fp) +{ + fprintf(fp, "-b ROMSEG = 0x0068\n"); +} + +static const char * const _libs_ds400[] = { STD_DS400_LIB, NULL, }; + +PORT ds400_port = +{ + TARGET_ID_DS400, + "ds400", + "DS80C400", /* Target name */ + NULL, + { + glue, + TRUE, /* Emit glue around main */ + MODEL_SMALL | MODEL_LARGE | MODEL_FLAT24, + MODEL_SMALL, + get_model, + }, + { + _asmCmd, + NULL, + "-plosgffwy", /* Options with debug */ + "-plosgffw", /* Options without debug */ + 0, + ".asm", + NULL /* no do_assemble function */ + }, + { /* Linker */ + _linkCmd, + NULL, + NULL, + ".rel", + 1, + NULL, /* crt */ + _libs_ds400, /* libs */ + }, + { /* Peephole optimizer */ + _defaultRules, + getInstructionSize, + getRegsRead, + getRegsWritten, + NULL, + NULL, + NULL, + NULL, + NULL, + }, + /* Sizes: char, short, int, long, long long, near ptr, far ptr, gptr, func ptr, banked func ptr, bit, float */ + { 1, 2, 2, 4, 8, 1, 2, 3, 2, 3, 1, 4 }, + + /* tags for generic pointers */ + { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */ + + { + "XSEG (XDATA)", + "STACK (DATA)", + "CSEG (CODE)", + "DSEG (DATA)", + "ISEG (DATA)", + "PSEG (PAG,XDATA)", + "XSEG (XDATA)", + "BSEG (BIT)", + "RSEG (DATA)", + "GSINIT (CODE)", + "OSEG (OVR,DATA)", + "GSFINAL (CODE)", + "HOME (CODE)", + "XISEG (XDATA)", // initialized xdata + "XINIT (CODE)", // a code copy of xiseg + "CONST (CODE)", // const_name - const data (code or not) + "CABS (ABS,CODE)", // cabs_name - const absolute data (code or not) + "XABS (ABS,XDATA)", // xabs_name - absolute xdata/pdata + "IABS (ABS,DATA)", // iabs_name - absolute idata/data + NULL, // name of segment for initialized variables + NULL, // name of segment for copies of initialized variables in code space + NULL, + NULL, + 1 + }, + { _ds400_generateRomDataArea, _ds400_linkRomDataArea }, + { +1, 1, 4, 1, 1, 0, 0 }, + { -1, FALSE }, + { ds390_emitDebuggerSymbol }, + { + 255/4, /* maxCount */ + 4, /* sizeofElement */ + {8,12,20}, /* sizeofMatchJump[] */ + {10,14,22}, /* sizeofRangeCompare[] */ + 4, /* sizeofSubtract */ + 7, /* sizeofDispatch */ + }, + "_", + _ds390_init, + _ds390_parseOptions, + _ds400_options, + NULL, + _ds400_finaliseOptions, + _ds390_setDefaultOptions, + ds390_assignRegisters, + _ds390_getRegName, + 0, + NULL, + _ds390_keywords, + _ds390_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _ds400_genIVT, + _ds390_genXINIT, + _ds390_genInitStartup, + _ds390_reset_regparm, + _ds390_regparm, + NULL, + NULL, + _ds390_nativeMulCheck, + hasExtBitOp, /* hasExtBitOp */ + oclsExpense, /* oclsExpense */ + FALSE, + TRUE, /* little endian */ + 0, /* leave lt */ + 0, /* leave gt */ + 1, /* transform <= to ! > */ + 1, /* transform >= to ! < */ + 1, /* transform != to !(a == b) */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + cseCostEstimation, + __ds390_builtins, /* table of builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + 0, /* Number of registers handled in the tree-decomposition-based register allocator in SDCCralloc.hpp */ + PORT_MAGIC +}; diff --git a/src/ds390/main.h b/src/ds390/main.h new file mode 100644 index 0000000..839c055 --- /dev/null +++ b/src/ds390/main.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- + main.h - ds390 specific general header file + + Copyright (C) 2000, Kevin Vigor + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------*/ + +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +#include "SDCCgen.h" + +typedef struct asmLineNode + { +#ifdef UNNAMED_STRUCT_TAG + struct asmLineNodeBase; +#else + /* exactly the same members as of struct asmLineNodeBase from SDCCgen.h */ + int size; + bitVect *regsRead; + bitVect *regsWritten; +#endif + int currentDPS; + unsigned initialized:1; + } +asmLineNode; + +bool x_parseOptions (char **argv, int *pargc); +void x_setDefaultOptions (void); +void x_finaliseOptions (void); +asmLineNode * ds390newAsmLineNode (int currentDPS); + +#endif diff --git a/src/ds390/peeph.def b/src/ds390/peeph.def new file mode 100644 index 0000000..2159286 --- /dev/null +++ b/src/ds390/peeph.def @@ -0,0 +1,2856 @@ +//replace restart { +// pop %1 +// push %1 +//} by { +// ; Peephole 1 removed pop %1 push %1 (not push pop) +//} + +//replace restart { +// pop %1 +// mov %2,%3 +// push %1 +//} by { +// ; Peephole 2 removed pop %1 push %1 (not push pop) +// mov %2,%3 +//} + +// +// added by Jean Louis VERN for +// his shift stuff +replace restart { + xch a,%1 + xch a,%1 +} by { + ; Peephole 2.a removed redundant xch xch +} + +replace restart { +// saving 2 byte + mov %1,#0x00 + mov a,#0x00 +} by { + ; Peephole 3.a changed mov to clr + clr a + mov %1,a +} + +replace restart { +// saving 1 byte + mov %1,#0x00 + clr a +} by { + ; Peephole 3.b changed mov to clr + clr a + mov %1,a +} + +replace restart { +// saving 1 byte, loosing 1 cycle but maybe allowing peephole 3.b to start + mov %1,#0x00 + mov %2,#0x00 + mov a,%3 +} by { + ; Peephole 3.c changed mov to clr + clr a + mov %1,a + mov %2,a + mov a,%3 +} + +replace restart { + mov a,#0 +} by { + ; Peephole 3.d changed mov to clr + clr a +} + +replace { + mov %1,a + mov dptr,#%2 + mov a,%1 + movx @dptr,a +} by { + ; Peephole 100 removed redundant mov + mov %1,a + mov dptr,#%2 + movx @dptr,a +} + +replace { + mov a,acc +} by { + ; Peephole 100.a removed redundant mov +} + +replace { + mov a,%1 + movx @dptr,a + inc dptr + mov a,%1 + movx @dptr,a +} by { + ; Peephole 101 removed redundant mov + mov a,%1 + movx @dptr,a + inc dptr + movx @dptr,a +} + +replace { + mov %1,%2 + ljmp %3 +%4: + mov %1,%5 +%3: + mov dpl,%1 +%7: + mov sp,bp + pop bp +} by { + ; Peephole 102 removed redundant mov + mov dpl,%2 + ljmp %3 +%4: + mov dpl,%5 +%3: +%7: + mov sp,bp + pop bp +} + +replace { + mov %1,%2 + ljmp %3 +%4: + mov a%1,%5 +%3: + mov dpl,%1 +%7: + mov sp,bp + pop bp +} by { + ; Peephole 103 removed redundant mov + mov dpl,%2 + ljmp %3 +%4: + mov dpl,%5 +%3: +%7: + mov sp,bp + pop bp +} + +replace { + mov a,bp + clr c + add a,#0x01 + mov r%1,a +} by { + ; Peephole 104 optimized increment (acc not set to r%1, flags undefined) + mov r%1,bp + inc r%1 +} + +replace { + mov %1,a + mov a,%1 +} by { + ; Peephole 105 removed redundant mov + mov %1,a +} + +replace { + mov %1,a + clr c + mov a,%1 +} by { + ; Peephole 106 removed redundant mov + mov %1,a + clr c +} + +replace { + ljmp %1 +%1: +} by { + ; Peephole 107 removed redundant ljmp +%1: +} + +replace { + jc %1 + ljmp %5 +%1: +} by { + ; Peephole 108 removed ljmp by inverse jump logic + jnc %5 +%1: +} if labelInRange(%5) + +replace { + jz %1 + ljmp %5 +%1: +} by { + ; Peephole 109 removed ljmp by inverse jump logic + jnz %5 +%1: +} if labelInRange(%5) + +replace { + jnz %1 + ljmp %5 +%1: +} by { + ; Peephole 110 removed ljmp by inverse jump logic + jz %5 +%1: +} if labelInRange(%5) + +replace { + jb %1,%2 + ljmp %5 +%2: +} by { + ; Peephole 111 removed ljmp by inverse jump logic + jnb %1,%5 +%2: +} if labelInRange(%5) + +replace { + jnb %1,%2 + ljmp %5 +%2: +} by { + ; Peephole 112 removed ljmp by inverse jump logic + jb %1,%5 +%2: +} if labelInRange(%5) + +replace { + ljmp %5 +%1: +} by { + ; Peephole 132 changed ljmp to sjmp + sjmp %5 +%1: +} if labelInRange(%5) + + +replace { + clr a + cjne %1,%2,%3 + cpl a +%3: + rrc a + mov %4,c +} by { + ; Peephole 113 optimized misc sequence + clr %4 + cjne %1,%2,%3 + setb %4 +%3: +} if labelRefCount %3 1 + +replace { + clr a + cjne %1,%2,%3 + cjne %10,%11,%3 + cpl a +%3: + rrc a + mov %4,c +} by { + ; Peephole 114 optimized misc sequence + clr %4 + cjne %1,%2,%3 + cjne %10,%11,%3 + setb %4 +%3: +} if labelRefCount %3 2 + +replace { + clr a + cjne %1,%2,%3 + cpl a +%3: + jnz %4 +} by { + ; Peephole 115 jump optimization + cjne %1,%2,%3 + sjmp %4 +%3: +} if labelRefCount %3 1 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cpl a +%3: + jnz %4 +} by { + ; Peephole 116 jump optimization + cjne %1,%2,%3 + cjne %9,%10,%3 + sjmp %4 +%3: +} if labelRefCount %3 2 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + cpl a +%3: + jnz %4 +} by { + ; Peephole 117 jump optimization + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + sjmp %4 +%3: +} if labelRefCount %3 3 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + cjne %13,%14,%3 + cpl a +%3: + jnz %4 +} by { + ; Peephole 118 jump optimization + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + cjne %13,%14,%3 + sjmp %4 +%3: +} if labelRefCount %3 4 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + clr a +%3: + jnz %4 +} by { + ; Peephole 119 jump optimization + cjne %1,%2,%4 +%3: +} if labelRefCount %3 1 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + clr a +%3: + jnz %4 +} by { + ; Peephole 120 jump optimization + cjne %1,%2,%4 + cjne %10,%11,%4 +%3: +} if labelRefCount %3 2 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + clr a +%3: + jnz %4 +} by { + ; Peephole 121 jump optimization + cjne %1,%2,%4 + cjne %10,%11,%4 + cjne %12,%13,%4 +%3: +} if labelRefCount %3 3 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + cjne %14,%15,%3 + clr a +%3: + jnz %4 +} by { + ; Peephole 122 jump optimization + cjne %1,%2,%4 + cjne %10,%11,%4 + cjne %12,%13,%4 + cjne %14,%15,%4 +%3: +} if labelRefCount %3 4 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + clr a +%3: + jz %4 +} by { + ; Peephole 123 jump optimization + cjne %1,%2,%3 + smp %4 +%3: +} if labelRefCount %3 1 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + clr a +%3: + jz %4 +} by { + ; Peephole 124 jump optimization + cjne %1,%2,%3 + cjne %10,%11,%3 + sjmp %4 +%3: +} if labelRefCount %3 2 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + clr a +%3: + jz %4 +} by { + ; Peephole 125 jump optimization + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + sjmp %4 +%3: +} if labelRefCount %3 3 + +replace { + mov a,#0x01 + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + cjne %14,%15,%3 + clr a +%3: + jz %4 +} by { + ; Peephole 126 jump optimization + cjne %1,%2,%3 + cjne %10,%11,%3 + cjne %12,%13,%3 + cjne %14,%15,%3 + sjmp %4 +%3: +} if labelRefCount %3 4 + +replace { + push psw + mov psw,%1 + push bp + mov bp,%2 +%3: + mov %2,bp + pop bp + pop psw + ret +} by { + ; Peephole 127 removed misc sequence + ret +} if labelRefCount %3 0 + +replace { + clr a + rlc a + jz %1 +} by { + ; Peephole 128 jump optimization + jnc %1 +} + +replace { + clr a + rlc a + jnz %1 +} by { + ; Peephole 129 jump optimization + jc %1 +} + +replace { + mov r%1,@r%2 +} by { + ; Peephole 130 changed target address mode r%1 to ar%1 + mov ar%1,@r%2 +} + +replace { + mov a,%1 + subb a,#0x01 + mov %2,a + mov %1,%2 +} by { + ; Peephole 131 optimized decrement (not caring for c) + dec %1 + mov %2,%1 +} + +replace { + mov r%1,%2 + mov ar%3,@r%1 + inc r%3 + mov r%4,%2 + mov @r%4,ar%3 +} by { + ; Peephole 133 removed redundant moves + mov r%1,%2 + inc @r%1 + mov ar%3,@r%1 +} + +replace { + mov r%1,%2 + mov ar%3,@r%1 + dec r%3 + mov r%4,%2 + mov @r%4,ar%3 +} by { + ; Peephole 134 removed redundant moves + mov r%1,%2 + dec @r%1 + mov ar%3,@r%1 +} + +replace { + mov r%1,a + mov a,r%2 + orl a,r%1 +} by { + ; Peephole 135 removed redundant mov + mov r%1,a + orl a,r%2 +} + +replace { + mov %1,a + mov dpl,%2 + mov dph,%3 + mov dpx,%4 + mov a,%1 +} by { + ; Peephole 136a removed redundant moves + mov %1,a + mov dpl,%2 + mov dph,%3 + mov dpx,%4 +} if 24bitMode + +replace { + mov %1,a + mov dpl,%2 + mov dph,%3 + mov a,%1 +} by { + ; Peephole 136 removed redundant moves + mov %1,a + mov dpl,%2 + mov dph,%3 +} + +// WTF? Doesn't look sensible to me... +//replace { +// mov b,#0x00 +// mov a,%1 +// cjne %2,%3,%4 +// mov b,#0x01 +//%4: +// mov a,b +// jz %5 +//} by { +// ; Peephole 137 optimized misc jump sequence +// mov a,%1 +// cjne %2,%3,%5 +//%4: +//} if labelRefCount %4 1 +// +//replace { +// mov b,#0x00 +// mov a,%1 +// cjne %2,%3,%4 +// mov b,#0x01 +//%4: +// mov a,b +// jnz %5 +//} by { +// ; Peephole 138 optimized misc jump sequence +// mov a,%1 +// cjne %2,%3,%4 +// sjmp %5 +//%4: +//} if labelRefCount %4 1 + +replace { + mov r%1,a + anl ar%1,%2 + mov a,r%1 +} by { + ; Peephole 139 removed redundant mov + anl a,%2 + mov r%1,a +} + +replace { + mov r%1,a + orl ar%1,%2 + mov a,r%1 +} by { + ; Peephole 140 removed redundant mov + orl a,%2 + mov r%1,a } + +replace { + mov r%1,a + xrl ar%1,%2 + mov a,r%1 +} by { + ; Peephole 141 removed redundant mov + xrl a,%2 + mov r%1,a +} + +replace { + mov r%1,a + mov r%2,ar%1 + mov ar%1,@r%2 +} by { + ; Peephole 142 removed redundant moves + mov r%2,a + mov ar%1,@r%2 +} + +replace { + rlc a + mov acc.0,c +} by { + ; Peephole 143 converted rlc to rl + rl a +} + +replace { + rrc a + mov acc.7,c +} by { + ; Peephole 144 converted rrc to rc + rr a +} + +replace { + clr c + addc a,%1 +} by { + ; Peephole 145 changed to add without carry + add a,%1 +} + +replace { + clr c + mov a,%1 + addc a,%2 +} by { + ; Peephole 146 changed to add without carry + mov a,%1 + add a,%2 +} + +replace { + orl r%1,a +} by { + ; Peephole 147 changed target address mode r%1 to ar%1 + orl ar%1,a +} + +replace { + anl r%1,a +} by { + ; Peephole 148 changed target address mode r%1 to ar%1 + anl ar%1,a +} + +replace { + xrl r%1,a +} by { + ; Peephole 149 changed target address mode r%1 to ar%1 + xrl ar%1,a +} + +replace { + mov %1,dpl + mov dpl,%1 +%9: + ret +} by { + ; Peephole 150 removed misc moves via dpl before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov dpl,%1 + mov dph,%2 +%9: + ret +} by { + ; Peephole 151 removed misc moves via dph, dpl before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov dpl,%1 +%9: + ret +} by { + ; Peephole 152 removed misc moves via dph, dpl before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov dpl,%1 + mov dph,%2 + mov b,%3 +%9: + ret +} by { + ; Peephole 153 removed misc moves via dph, dpl, b before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov dpl,%1 +%9: + ret +} by { + ; Peephole 154 removed misc moves via dph, dpl, b before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov dpl,%1 + mov dph,%2 +%9: + ret +} by { + ; Peephole 155 removed misc moves via dph, dpl, b before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov %4,a + mov dpl,%1 + mov dph,%2 + mov b,%3 + mov a,%4 +%9: + ret +} by { + ; Peephole 156 removed misc moves via dph, dpl, b, a before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov %4,a + mov dpl,%1 + mov dph,%2 +%9: + ret +} by { + ; Peephole 157 removed misc moves via dph, dpl, b, a before return +%9: + ret +} + +replace { + mov %1,dpl + mov %2,dph + mov %3,b + mov %4,a + mov dpl,%1 +%9: + ret } by { + ; Peephole 158 removed misc moves via dph, dpl, b, a before return +%9: + ret } + +replace { + mov %1,#%2 + xrl %1,#0x80 +} by { + ; Peephole 159 avoided xrl during execution + mov %1,#(%2 ^ 0x80) +} + +replace { + jnc %1 + sjmp %2 +%1: +} by { + ; Peephole 160 removed sjmp by inverse jump logic + jc %2 +%1:} + +replace { + jc %1 + sjmp %2 +%1: +} by { + ; Peephole 161 removed sjmp by inverse jump logic + jnc %2 +%1:} + +replace { + jnz %1 + sjmp %2 +%1: +} by { + ; Peephole 162 removed sjmp by inverse jump logic + jz %2 +%1:} + +replace { + jz %1 + sjmp %2 +%1: +} by { + ; Peephole 163 removed sjmp by inverse jump logic + jnz %2 +%1:} + +replace { + jnb %3,%1 + sjmp %2 +%1: +} by { + ; Peephole 164 removed sjmp by inverse jump logic + jb %3,%2 +%1: +} + +replace { + jb %3,%1 + sjmp %2 +%1: +} by { + ; Peephole 165 removed sjmp by inverse jump logic + jnb %3,%2 +%1: +} + +replace { + mov %1,%2 + mov %3,%1 + mov %2,%1 +} by { + ; Peephole 166 removed redundant mov + mov %1,%2 + mov %3,%1 } + +replace { + mov c,%1 + cpl c + mov %1,c +} by { + ; Peephole 167 removed redundant bit moves (c not set to %1) + cpl %1 } + +replace { + jnb %1,%2 + sjmp %3 +%2:} by { + ; Peephole 168 jump optimization + jb %1,%3 +%2:} + +replace { + jb %1,%2 + sjmp %3 +%2:} by { + ; Peephole 169 jump optimization + jnb %1,%3 +%2:} + +replace { + clr a + cjne %1,%2,%3 + cpl a +%3: + jz %4 +} by { + ; Peephole 170 jump optimization + cjne %1,%2,%4 +%3: +} if labelRefCount %3 1 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cpl a +%3: + jz %4 +} by { + ; Peephole 171 jump optimization + cjne %1,%2,%4 + cjne %9,%10,%4 +%3: +} if labelRefCount %3 2 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + cpl a +%3: + jz %4 +} by { + ; Peephole 172 jump optimization + cjne %1,%2,%4 + cjne %9,%10,%4 + cjne %11,%12,%4 +%3: +} if labelRefCount %3 3 + +replace { + clr a + cjne %1,%2,%3 + cjne %9,%10,%3 + cjne %11,%12,%3 + cjne %13,%14,%3 + cpl a +%3: + jz %4 +} by { + ; Peephole 173 jump optimization + cjne %1,%2,%4 + cjne %9,%10,%4 + cjne %11,%12,%4 + cjne %13,%14,%4 +%3: +} if labelRefCount %3 4 + +replace { + mov r%1,%2 + clr c + mov a,r%1 + subb a,#0x01 + mov %2,a +} by { + ; Peephole 174 optimized decrement (acc not set to %2, flags undefined) + mov r%1,%2 + dec %2 +} + + +replace { + mov r%1,%2 + mov a,r%1 + add a,#0x01 + mov %2,a +} by { + ; Peephole 175 optimized increment (acc not set to %2, flags undefined) + mov r%1,%2 + inc %2 +} + +replace { + mov %1,@r%2 + inc %1 + mov @r%2,%1 +} by { + ; Peephole 176 optimized increment, removed redundant mov + inc @r%2 + mov %1,@r%2 +} + +// this one will screw assignes to volatile/sfr's +//replace { +// mov %1,%2 +// mov %2,%1 +//} by { +// ; Peephole 177 removed redundant mov +// mov %1,%2 +//} + +replace { + mov a,%1 + mov b,a + mov a,%2 +} by { + ; Peephole 178 removed redundant mov + mov b,%1 + mov a,%2 +} + +// rules 179-182 provided by : Frieder <fe@lake.iup.uni-heidelberg.de> +// saving 2 byte, 1 cycle +replace { + mov b,#0x00 + mov a,#0x00 +} by { + ; Peephole 179 changed mov to clr + clr a + mov b,a +} + +// saving 1 byte, 0 cycles +replace { + mov a,#0x00 +} by { + ; Peephole 180 changed mov to clr + clr a +} + +replace { + mov dpl,#0x00 + mov dph,#0x00 + mov dpx,#0x00 +} by { + ; Peephole 181a used 24 bit load of dptr + mov dptr,#0x0000 +} if 24bitMode + +// saving 3 byte, 2 cycles, return(NULL) profits here +replace { + mov dpl,#0x00 + mov dph,#0x00 +} by { + ; Peephole 181 used 16 bit load of dptr + mov dptr,#0x0000 +} + +replace { + mov dpl,#%1 + mov dph,#(%1 >> 8) + mov dpx,#(%1 >> 16) +} by { + ; Peephole 182b used 24 bit load of DPTR + mov dptr,#%1 +} + +// saves 2 bytes, ?? cycles. +replace { + mov dpl,#0x%1 + mov dph,#0x%2 + mov dpx,#0x%3 +} by { + ; Peephole 182a used 24 bit load of dptr + mov dptr,#0x%3%2%1 +} if 24bitMode(), portIsDS390 + +// saves 2 bytes, ?? cycles. +replace { + mov dpl,#%1 + mov dph,#%2 + mov dpx,#%3 +} by { + ; Peephole 182b used 24 bit load of dptr + mov dptr,#((%3 << 16) + (%2 << 8) + %1) +} if 24bitMode(), portIsDS390 + +// saving 3 byte, 2 cycles, return(float_constant) profits here +replace { + mov dpl,#0x%1 + mov dph,#0x%2 +} by { + ; Peephole 182c used 16 bit load of dptr + mov dptr,#0x%2%1 +} + +// saving 3 byte, 2 cycles, return(float_constant) profits here +replace { + mov dpl,#%1 + mov dph,#%2 +} by { + ; Peephole 182 used 16 bit load of dptr + mov dptr,#(((%2)<<8) + %1) +} + +replace { + anl %1,#%2 + anl %1,#%3 +} by { + ; Peephole 183 avoided anl during execution + anl %1,#(%2 & %3) +} + +replace { + mov %1,a + cpl a + mov %1,a +} by { + ; Peephole 184 removed redundant mov + cpl a + mov %1,a +} + +replace { +// acc being incremented might cause problems + mov %1,a + inc %1 +} by { + ; Peephole 185 changed order of increment (acc incremented also!) + inc a + mov %1,a +} + +// char indexed access to: long code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + movc a,@a+dptr + mov %2,a + inc dptr + clr a + movc a,@a+dptr + mov %3,a + inc dptr + clr a + movc a,@a+dptr + mov %4,a + inc dptr + clr a + movc a,@a+dptr +} by { + ; Peephole 186.a optimized movc sequence + mov b,a + mov dptr,#%1 + movc a,@a+dptr + mov %2,a + inc dptr + mov a,b + movc a,@a+dptr + mov %3,a + inc dptr + mov a,b + movc a,@a+dptr + mov %4,a + inc dptr + mov a,b + movc a,@a+dptr +} + +// char indexed access to: void* code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + movc a,@a+dptr + mov %2,a + inc dptr + clr a + movc a,@a+dptr + mov %3,a + inc dptr + clr a + movc a,@a+dptr +} by { + ; Peephole 186.b optimized movc sequence + mov b,a + mov dptr,#%1 + movc a,@a+dptr + mov %2,a + inc dptr + mov a,b + movc a,@a+dptr + mov %3,a + inc dptr + mov a,b + movc a,@a+dptr +} + +// char indexed access to: int code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + movc a,@a+dptr + mov %2,a + inc dptr + clr a + movc a,@a+dptr +} by { + ; Peephole 186.c optimized movc sequence + mov %2,a + mov dptr,#%1 + movc a,@a+dptr + xch a,%2 + inc dptr + movc a,@a+dptr +} + +// char indexed access to: char code table[] = {4,3,2,1}; +replace { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + movc a,@a+dptr +} by { + ; Peephole 186.d optimized movc sequence + mov dptr,#%1 + movc a,@a+dptr +} + +replace { + mov r%1,%2 + anl ar%1,#%3 + mov a,r%1 +} by { + ; Peephole 187 used a instead of ar%1 for anl + mov a,%2 + anl a,#%3 + mov r%1,a +} + +replace { + mov %1,a + mov dptr,%2 + movc a,@a+dptr + mov %1,a +} by { + ; Peephole 188 removed redundant mov + mov dptr,%2 + movc a,@a+dptr + mov %1,a +} + +replace { + anl a,#0x0f + mov %1,a + mov a,#0x0f + anl a,%1 +} by { + ; Peephole 189 removed redundant mov and anl + anl a,#0x0f + mov %1,a +} + +// rules 190 & 191 need to be in order +replace { + mov a,%1 + lcall __gptrput + mov a,%1 +} by { + ; Peephole 190 removed redundant mov + mov a,%1 + lcall __gptrput +} + +replace { + mov %1,a + mov dpl,%2 + mov dph,%3 + mov b,%4 + mov a,%1 +} by { + ; Peephole 191 removed redundant mov + mov %1,a + mov dpl,%2 + mov dph,%3 + mov b,%4 +} + +replace { + mov r%1,a + mov @r%2,ar%1 +} by { + ; Peephole 192 used a instead of ar%1 as source + mov r%1,a + mov @r%2,a +} + +replace { + jnz %3 + mov a,%4 + jnz %3 + mov a,%9 + jnz %3 + mov a,%12 + cjne %13,%14,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 193.a optimized misc jump sequence + jnz %8 + mov a,%4 + jnz %8 + mov a,%9 + jnz %8 + mov a,%12 + cjne %13,%14,%8 + sjmp %7 +;%3: +} if labelRefCount %3 4 + +replace { + cjne %1,%2,%3 + mov a,%4 + cjne %5,%6,%3 + mov a,%9 + cjne %10,%11,%3 + mov a,%12 + cjne %13,%14,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 193 optimized misc jump sequence + cjne %1,%2,%8 + mov a,%4 + cjne %5,%6,%8 + mov a,%9 + cjne %10,%11,%8 + mov a,%12 + cjne %13,%14,%8 + sjmp %7 +;%3: +} if labelRefCount %3 4 + +replace { + cjne @%1,%2,%3 + inc %1 + cjne @%1,%6,%3 + inc %1 + cjne @%1,%11,%3 + inc %1 + cjne @%1,%14,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 193.a optimized misc jump sequence + cjne @%1,%2,%8 + inc %1 + cjne @%1,%6,%8 + inc %1 + cjne @%1,%11,%8 + inc %1 + cjne @%1,%14,%8 + sjmp %7 +;%3: +} if labelRefCount %3 4 + +replace { + cjne %1,%2,%3 + cjne %5,%6,%3 + cjne %10,%11,%3 + cjne %13,%14,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 194 optimized misc jump sequence + cjne %1,%2,%8 + cjne %5,%6,%8 + cjne %10,%11,%8 + cjne %13,%14,%8 + sjmp %7 +;%3: +} if labelRefCount %3 4 + +replace { + jnz %3 + mov a,%4 + jnz %3 + mov a,%9 + cjne %10,%11,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 195.a optimized misc jump sequence + jnz %8 + mov a,%4 + jnz %8 + mov a,%9 + cjne %10,%11,%8 + sjmp %7 +;%3: +} if labelRefCount %3 3 + +replace { + cjne %1,%2,%3 + mov a,%4 + cjne %5,%6,%3 + mov a,%9 + cjne %10,%11,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 195 optimized misc jump sequence + cjne %1,%2,%8 + mov a,%4 + cjne %5,%6,%8 + mov a,%9 + cjne %10,%11,%8 + sjmp %7 +;%3: +} if labelRefCount %3 3 + +replace { + cjne @%1,%2,%3 + inc %1 + cjne @%1,%6,%3 + inc %1 + cjne @%1,%11,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 195.a optimized misc jump sequence + cjne @%1,%2,%8 + inc %1 + cjne @%1,%6,%8 + inc %1 + cjne @%1,%11,%8 + sjmp %7 +;%3: +} if labelRefCount %3 3 + +replace { + cjne %1,%2,%3 + cjne %5,%6,%3 + cjne %10,%11,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 196 optimized misc jump sequence + cjne %1,%2,%8 + cjne %5,%6,%8 + cjne %10,%11,%8 + sjmp %7 +;%3: +} if labelRefCount %3 3 + +replace { + jnz %3 + mov a,%4 + cjne %5,%6,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 197.a optimized misc jump sequence + jnz %8 + mov a,%4 + cjne %5,%6,%8 + sjmp %7 +;%3: +} if labelRefCount %3 2 + +replace { + cjne %1,%2,%3 + mov a,%4 + cjne %5,%6,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 197 optimized misc jump sequence + cjne %1,%2,%8 + mov a,%4 + cjne %5,%6,%8 + sjmp %7 +;%3: +} if labelRefCount %3 2 + +replace { + cjne @%1,%2,%3 + inc %1 + cjne @%1,%6,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 197.a optimized misc jump sequence + cjne @%1,%2,%8 + inc %1 + cjne @%1,%6,%8 + sjmp %7 +;%3: +} if labelRefCount %3 2 + +replace { + cjne %1,%2,%3 + cjne %5,%6,%3 + sjmp %7 +%3: + sjmp %8 +} by { + ; Peephole 198 optimized misc jump sequence + cjne %1,%2,%8 + cjne %5,%6,%8 + sjmp %7 +;%3: +} if labelRefCount %3 2 + +replace { + cjne %1,%2,%3 + sjmp %4 +%3: + sjmp %5 +} by { + ; Peephole 199 optimized misc jump sequence + cjne %1,%2,%5 + sjmp %4 +;%3: +} if labelRefCount %3 1 + +replace { + sjmp %1 +%1: +} by { + ; Peephole 200 removed redundant sjmp +%1: +} + +replace { + sjmp %1 +%2: +%1: +} by { + ; Peephole 201 removed redundant sjmp +%2: +%1: +} + +replace { + push acc + mov dptr,%1 + pop acc +} by { + ; Peephole 202 removed redundant push pop + mov dptr,%1 +} + +replace { + push acc + pop acc +} by { + ; Peephole 202b removed redundant push pop +} + +replace { + mov r%1,_spx + lcall %2 + mov r%1,_spx +} by { + ; Peephole 203 removed mov r%1,_spx + lcall %2 +} + +replace { + mov %1,a + add a,acc + mov %1,a +} by { + ; Peephole 204 removed redundant mov + add a,acc + mov %1,a +} + +replace { + djnz %1,%2 + sjmp %3 +%2: + sjmp %4 +%3: +} by { + ; Peephole 205 optimized misc jump sequence + djnz %1,%4 +%2: +%3: +} if labelRefCount %2 1 + +replace { + mov %1,%1 +} by { + ; Peephole 206 removed redundant mov %1,%1 +} + +replace { + mov a,_bp + add a,#0x00 + mov %1,a +} by { + ; Peephole 207 removed zero add (acc not set to %1, flags undefined) + mov %1,_bp +} + +replace { + push acc + mov r%1,_bp + pop acc +} by { + ; Peephole 208 removed redundant push pop + mov r%1,_bp +} + +replace { + mov a,_bp + add a,#0x00 + inc a + mov %1,a +} by { + ; Peephole 209 optimized increment (acc not set to %1, flags undefined) + mov %1,_bp + inc %1 +} + +replace { + mov dptr,#((((%1 >> 16)) <<16) + (((%1 >> 8)) <<8) + %1) +} by { + ; Peephole 210a simplified expression + mov dptr,#%1 +} if 24bitMode + +replace { + mov dptr,#((((%1 >> 8)) <<8) + %1) +} by { + ; Peephole 210 simplified expression + mov dptr,#%1 +} + +replace restart { + push ar%1 + pop ar%1 +} by { + ; Peephole 211 removed redundant push r%1 pop r%1 +} + +replace { + mov a,_bp + add a,#0x01 + mov r%1,a +} by { + ; Peephole 212 reduced add sequence to inc + mov r%1,_bp + inc r%1 +} + +replace { + mov %1,#(( %2 >> 8 ) ^ 0x80) +} by { + ; Peephole 213.a inserted fix + mov %1,#(%2 >> 8) + xrl %1,#0x80 +} if portIsDS390 + +replace { + mov %1,#(( %2 >> 16 ) ^ 0x80) +} by { + ; Peephole 213.b inserted fix + mov %1,#(%2 >> 16) + xrl %1,#0x80 +} if portIsDS390 + +replace { + mov %1,#(( %2 + %3 >> 8 ) ^ 0x80) +} by { + ; Peephole 213.c inserted fix + mov %1,#((%2 + %3) >> 8) + xrl %1,#0x80 +} if portIsDS390 + +replace { + mov %1,a + mov a,%2 + add a,%1 +} by { + ; Peephole 214 reduced some extra movs + mov %1,a + add a,%2 +} if notSame(%1 %2) + +replace { + mov %1,a + add a,%2 + mov %1,a +} by { + ; Peephole 215 removed some movs + add a,%2 + mov %1,a +} if notSame(%1 %2) + +replace { + mov r%1,%2 + clr a + inc r%1 + mov @r%1,a + dec r%1 + mov @r%1,a +} by { + ; Peephole 216 simplified clear (2bytes) + mov r%1,%2 + clr a + mov @r%1,a + inc r%1 + mov @r%1,a +} + +replace { + mov r%1,%2 + clr a + inc r%1 + inc r%1 + mov @r%1,a + dec r%1 + mov @r%1,a + dec r%1 + mov @r%1,a +} by { + ; Peephole 217 simplified clear (3bytes) + mov r%1,%2 + clr a + mov @r%1,a + inc r%1 + mov @r%1,a + inc r%1 + mov @r%1,a +} + +replace { + mov r%1,%2 + clr a + inc r%1 + inc r%1 + inc r%1 + mov @r%1,a + dec r%1 + mov @r%1,a + dec r%1 + mov @r%1,a + dec r%1 + mov @r%1,a +} by { + ; Peephole 218 simplified clear (4bytes) + mov r%1,%2 + clr a + mov @r%1,a + inc r%1 + mov @r%1,a + inc r%1 + mov @r%1,a + inc r%1 + mov @r%1,a +} + +replace { + clr a + movx @dptr,a + mov dptr,%1 + clr a + movx @dptr,a +} by { + ; Peephole 219 removed redundant clear + clr a + movx @dptr,a + mov dptr,%1 + movx @dptr,a +} + +replace { + clr a + movx @dptr,a + mov dptr,%1 + movx @dptr,a + mov dptr,%2 + clr a + movx @dptr,a +} by { + ; Peephole 219a removed redundant clear + clr a + movx @dptr,a + mov dptr,%1 + movx @dptr,a + mov dptr,%2 + movx @dptr,a +} + +replace { + mov dps, #0 + mov dps, #1 +} by { + ; Peephole 220a removed bogus DPS set + mov dps, #1 +} + +replace { + mov dps, #1 + mov dps, #0 +} by { + ; Peephole 220b removed bogus DPS set + mov dps, #0 +} + +replace { + mov dps, #0 + mov dps, #0x01 +} by { + ; Peephole 220c removed bogus DPS set +} + +replace { + mov dps,#1 + inc dptr + mov dps,#1 +} by { + ; Peephole 220d removed bogus DPS set + mov dps,#1 + inc dptr +} + +replace { + mov %1 + %2,(%2 + %1) +} by { + ; Peephole 221a remove redundant move +} + +replace { + mov (%1 + %2 + %3),((%2 + %1) + %3) +} by { + ; Peephole 221b remove redundant move +} + +replace { + dec r%1 + inc r%1 +} by { + ; removed dec/inc pair +} + +replace { + mov dps, #0 + mov %1,a + mov dps, #1 +} by { + ; Peephole 222 removed DPS abuse. + mov %1,a + mov dps, #1 +} + +replace { + mov dps, #0 + xch a, ap + mov %1, ap + mov dps, #1 +} by { + ; Peephole 222a removed DPS abuse. + xch a, ap + mov %1, ap + mov dps, #1 +} + +replace { + mov dps, #%1 + inc dptr + movx a,@dptr + mov %2,a + mov dps, #%1 +} by { + mov dps, #%1 + inc dptr + movx a,@dptr + mov %2,a +; Peephole 223: yet more DPS abuse removed. +} + +replace { + mov dps, #0 + inc dps +} by { + mov dps, #1 +} + +replace { + mov dps, #%1 + mov dptr, %2 + mov dps, #%1 +} by { + mov dps, #%1 + mov dptr, %2 +} + +replace { + mov dps, #1 + mov dptr, %1 + mov dps, #0 + mov dptr, %2 + inc dps +} by { + mov dps, #0 + mov dptr, %2 + inc dps + mov dptr, %1 +; Peephole 224a: DPS usage re-arranged. +} + +replace { + mov dps, #%1 + mov dptr, %2 + mov dps, #%3 + mov dptr, %4 + mov dps, #%1 +} by { + mov dps, #%3 + mov dptr, %4 + mov dps, #%1 + mov dptr, %2 +; Peephole 224: DPS usage re-arranged. +} + +replace { + mov dps, #1 + mov dptr, %1 + mov dps, #0 +} by { + mov dps, #1 + mov dptr, %1 + dec dps +} + +replace { + xch a, ap + add a, ap +} by { + add a, ap +} + +replace { + xch a, ap + addc a, ap +} by { + addc a, ap +} + +replace { + inc dps + mov dps, #%1 +} by { + mov dps, #%1 +} + +replace { + dec dps + mov dps, #%1 +} by { + mov dps, #%1 +} + + +// char indexed access to: long code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + addc a,#(%1 >> 16) + mov dpx,a + clr a + movc a,@a+dptr + inc dptr + mov %2,a + clr a + movc a,@a+dptr + inc dptr + mov %3,a + clr a + movc a,@a+dptr + inc dptr + mov %4,a + clr a + movc a,@a+dptr +} by { + ; Peephole 227.a movc optimize + mov b,a + mov dptr,#%1 + movc a,@a+dptr + inc dptr + mov %2,a + mov a,b + movc a,@a+dptr + inc dptr + mov %3,a + mov a,b + movc a,@a+dptr + inc dptr + mov %4,a + mov a,b + movc a,@a+dptr +} + +// char indexed access to: void* code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + addc a,#(%1 >> 16) + mov dpx,a + clr a + movc a,@a+dptr + inc dptr + mov %2,a + clr a + movc a,@a+dptr + inc dptr + mov %3,a + clr a + movc a,@a+dptr +} by { + ; Peephole 227.b movc optimize + mov b,a + mov dptr,#%1 + movc a,@a+dptr + inc dptr + mov %2,a + mov a,b + movc a,@a+dptr + inc dptr + mov %3,a + mov a,b + movc a,@a+dptr +} + +// char indexed access to: int code table[] = {4,3,2,1}; +replace restart { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + addc a,#(%1 >> 16) + mov dpx,a + clr a + movc a,@a+dptr + inc dptr + mov %2,a + clr a + movc a,@a+dptr +} by { + ; Peephole 227.c movc optimize + mov %2,a + mov dptr,#%1 + movc a,@a+dptr + inc dptr + xch a,%2 + movc a,@a+dptr +} + +// char indexed access to: char code table[] = {4,3,2,1}; +replace { + add a,#%1 + mov dpl,a + clr a + addc a,#(%1 >> 8) + mov dph,a + clr a + addc a,#(%1 >> 16) + mov dpx,a + clr a + movc a,@a+dptr +} by { + ; Peephole 227.d movc optimize + mov dptr,#%1 + movc a,@a+dptr +} + +replace { + mov r%1,%2 + mov ar%1,%3 +} by { + ; Peephole 228 redundant move + mov ar%1,%3 +} + +replace { + mov r%1,a + dec r%1 + mov a,r%1 +} by { + ; Peephole 229.a redundant move + dec a + mov r%1,a +} + +replace { + mov r%1,a + mov r%2,b + mov a,r%1 +} by { + ; Peephole 229.b redundant move + mov r%1,a + mov r%2,b +} + +replace { + mov r%1,a + mov r%2,b + add a,#%3 + mov r%1,a + mov a,r%2 + addc a,#(%3 >> 8) + mov r%2,a +} by { + ; Peephole 229.c redundant move + add a,#%3 + mov r%1,a + mov a,b + addc a,#(%3 >> 8) + mov r%2,a +} + +replace { + mov a,%1 + mov b,a + movx a,%2 +} by { + ; Peephole 229.d redundant move + mov b,%1 + movx a,%2 +} + +replace { + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + mov r%4,a + add a,#0x01 + mov r%5,a + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx @dptr,a +} by { + ; Peephole 230.a save reload dptr + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + mov r%4,a + add a,#0x01 + mov r%5,a + movx @dptr,a +} + +replace { + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + mov r%4,a + dec r%4 + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + mov a,r%4 + movx @dptr,a +} by { + ; Peephole 230.b save reload dptr + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + dec a + mov r%4,a + movx @dptr,a +} + +replace { + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + inc a + mov r%4,a + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + mov a,r%4 + movx @dptr,a +} by { + ; Peephole 230.c save reload dptr + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + inc a + mov r%4,a + movx @dptr,a +} + +replace { + mov r%1,dpl + mov r%2,dph + mov r%3,dpx + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 +} by { + ; Peephole 230.d save reload dptr + mov r%1,dpl + mov r%2,dph + mov r%3,dpx +} + +replace { + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + mov r%4,a + orl ar%4,#%5 + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + mov a,r1 + movx @dptr,a +} by { + ; Peephole 230.e save reload dptr + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + orl a,#%5 + mov r%4,a + movx @dptr,a +} + +replace { + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + mov r%4,a + anl ar%4,#%5 + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + mov a,r1 + movx @dptr,a +} by { + ; Peephole 230.e save reload dptr + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 + movx a,@dptr + anl a,#%5 + mov r%4,a + movx @dptr,a +} + +replace { + mov r%1,dpl + mov r%2,dph + mov r%3,dpx + mov a,r%4 + inc dps + movx @dptr,a + inc dptr + mov dps,#0 + mov dpl,r%1 + mov dph,r%2 + mov dpx,r%3 +} by { + ; Peephole 230.f save reload dptr + mov r%1,dpl + mov r%2,dph + mov r%3,dpx + mov a,r%4 + inc dps + movx @dptr,a + inc dptr + mov dps,#0 +} + +replace { + mov ar%1,r%2 + mov ar%3,r%1 + mov r%1,#0x00 + mov ar%2,r%4 + mov r3,#0x00 +} by { + ; Peephole 231.a simplified moves + mov ar%3,r%2 + mov ar%2,r%4 + mov r%4,#0 + mov r%1,#0 +} + +replace { + mov r%1,#0 + mov r%2,#0 + mov a,r%2 + orl a,r%3 + mov %4,a + mov a,r%5 + orl a,r%1 + mov %6,a +} by { + ; Peephole 231.b simplified or + mov r%1,#0 + mov r%2,#0 + mov a,r%3 + mov %4,a + mov a,r%5 + mov %6,a +} + +replace { + mov a,r%1 + mov b,r%2 + mov r%1,b + mov r%2,a +} by { + ; Peehole 232.a simplified xch + mov a,r%1 + xch a,r%2 + mov r%1,a +} + +replace { + mov a,#%1 + mov b,#%2 + mov r%3,b + mov r%4,a +} by { + ; Peehole 232.b simplified xch + mov r%3,#%2 + mov r%4,#%1 +} + +replace { + mov dpl1,#%1 + mov dph1,#(%1 >> 8) + mov dpx1,#(%1 >> 16) +} by { + ; Peephole 233 24 bit load of dptr1 + inc dps + mov dptr,#%1 + dec dps +} + +// 14 rules by Fiorenzo D. Ramaglia <fd.ramaglia@tin.it> + +replace { + add a,ar%1 +} by { + ; Peephole 236a + add a,r%1 +} + +replace { + addc a,ar%1 +} by { + ; Peephole 236b + addc a,r%1 +} + +replace { + anl a,ar%1 +} by { + ; Peephole 236c + anl a,r%1 +} + +replace { + dec ar%1 +} by { + ; Peephole 236d + dec r%1 +} + +replace { + djnz ar%1,%2 +} by { + ; Peephole 236e + djnz r%1,%2 +} + +replace { + inc ar%1 +} by { + ; Peephole 236f + inc r%1 +} + +replace { + mov a,ar%1 +} by { + ; Peephole 236g + mov a,r%1 +} + +replace { + mov ar%1,#%2 +} by { + ; Peephole 236h + mov r%1,#%2 +} + +replace { + mov ar%1,a +} by { + ; Peephole 236i + mov r%1,a +} + +replace { + mov ar%1,ar%2 +} by { + ; Peephole 236j + mov r%1,ar%2 +} + +replace { + orl a,ar%1 +} by { + ; Peephole 236k + orl a,r%1 +} + +replace { + subb a,ar%1 +} by { + ; Peephole 236l + subb a,r%1 +} + +replace { + xch a,ar%1 +} by { + ; Peephole 236m + xch a,r%1 +} + +replace { + xrl a,ar%1 +} by { + ; Peephole 236n + xrl a,r%1 +} + +replace { + sjmp %1 +%2: + mov %3,%4 +%1: + ret +} by { + ; Peephole 237a removed sjmp to ret + ret +%2: + mov %3,%4 +%1: + ret +} + +replace { + sjmp %1 +%2: + mov %3,%4 + mov dpl,%5 + mov dph,%6 +%1: + ret +} by { + ; Peephole 237b removed sjmp to ret + ret +%2: + mov %3,%4 + mov dpl,%5 + mov dph,%6 +%1: + ret +} + +// applies to f.e. device/lib/log10f.c +replace { + mov %1,%9 + mov %2,%10 + mov %3,%11 + mov %4,%12 + + mov %5,%13 + mov %6,%14 + mov %7,%15 + mov %8,%16 + + mov %9,%1 + mov %10,%2 + mov %11,%3 + mov %12,%4 +} by { + mov %1,%9 + mov %2,%10 + mov %3,%11 + mov %4,%12 + + mov %5,%13 + mov %6,%14 + mov %7,%15 + mov %8,%16 + ; Peephole 238.a removed 4 redundant moves +} if notSame(%1 %2 %3 %4 %5 %6 %7 %8) + +// applies to device/lib/log10f.c +replace { + mov %1,%5 + mov %2,%6 + mov %3,%7 + mov %4,%8 + + mov %5,%1 + mov %6,%2 + mov %7,%3 +} by { + mov %1,%5 + mov %2,%6 + mov %3,%7 + mov %4,%8 + ; Peephole 238.b removed 3 redundant moves +} if notSame(%1 %2 %3 %4 %5 %6 %7) + +// applies to f.e. device/lib/time.c +replace { + mov %1,%5 + mov %2,%6 + + mov %3,%7 + mov %4,%8 + + mov %5,%1 + mov %6,%2 +} by { + mov %1,%5 + mov %2,%6 + + mov %3,%7 + mov %4,%8 + ; Peephole 238.c removed 2 redundant moves +} if notSame(%1 %2 %3 %4) + +// applies to f.e. support/regression/tests/bug-524209.c +replace { + mov %1,%4 + mov %2,%5 + mov %3,%6 + + mov %4,%1 + mov %5,%2 + mov %6,%3 +} by { + mov %1,%4 + mov %2,%5 + mov %3,%6 + ; Peephole 238.d removed 3 redundant moves +} if notSame(%1 %2 %3 %4 %5 %6) + +// applies to f.e. ser_ir.asm +replace { + mov r%1,acc +} by { + ; Peephole 239 used a instead of acc + mov r%1,a +} + +replace restart { + mov a,%1 + addc a,#0x00 +} by { + ; Peephole 240 use clr instead of addc a,#0 + clr a + addc a,%1 +} + +// peepholes 241.a to 241.c and 241.d to 241.f need to be in order +replace { + cjne r%1,#%2,%3 + cjne r%4,#%5,%3 + cjne r%6,#%7,%3 + cjne r%8,#%9,%3 + mov a,#0x01 + sjmp %10 +%3: + clr a +%10: +} by { + ; Peephole 241.a optimized compare + clr a + cjne r%1,#%2,%3 + cjne r%4,#%5,%3 + cjne r%6,#%7,%3 + cjne r%8,#%9,%3 + inc a +%3: +%10: +} + +// applies to f.e. time.c +replace { + cjne r%1,#%2,%3 + cjne r%4,#%5,%3 + mov a,#0x01 + sjmp %6 +%3: + clr a +%6: +} by { + ; Peephole 241.b optimized compare + clr a + cjne r%1,#%2,%3 + cjne r%4,#%5,%3 + inc a +%3: +%6: +} + +// applies to f.e. malloc.c +replace { + cjne r%1,#%2,%3 + mov a,#0x01 + sjmp %4 +%3: + clr a +%4: +} by { + ; Peephole 241.c optimized compare + clr a + cjne r%1,#%2,%3 + inc a +%3: +%4: +} + +// applies to f.e. j = (k!=0x1000); +// with volatile idata long k; +replace { + cjne @r%1,#%2,%3 + inc r%1 + cjne @r%1,#%4,%3 + inc r%1 + cjne @r%1,#%5,%3 + inc r%1 + cjne @r%1,#%6,%3 + mov a,#0x01 + sjmp %7 +%3: + clr a +%7: +} by { + ; Peephole 241.d optimized compare + clr a + cjne @r%1,#%2,%3 + inc r%1 + cjne @r%1,#%4,%3 + inc r%1 + cjne @r%1,#%5,%3 + inc r%1 + cjne @r%1,#%6,%3 + inc a +%3: +%7: +} + +// applies to f.e. j = (k!=0x1000); +// with volatile idata int k; +replace { + cjne @r%1,#%2,%3 + inc r%1 + cjne @r%1,#%4,%3 + mov a,#0x01 + sjmp %7 +%3: + clr a +%7: +} by { + ; Peephole 241.e optimized compare + clr a + cjne @r%1,#%2,%3 + inc r%1 + cjne @r%1,#%4,%3 + inc a +%3: +%7: +} + +// applies to f.e. vprintf.asm (--stack-auto) +replace { + cjne @r%1,#%2,%3 + mov a,#0x01 + sjmp %7 +%3: + clr a +%7: +} by { + ; Peephole 241.f optimized compare + clr a + cjne @r%1,#%2,%3 + inc a +%3: +%7: +} + +// applies to f.e. scott-bool1.c +replace { + jnz %1 + mov %2,%3 +%1: + jz %4 +} by { + ; Peephole 242.a avoided branch jnz to jz + jnz %1 + mov %2,%3 + jz %4 +%1: +} if labelRefCount %1 1 + +// applies to f.e. scott-bool1.c +replace { + jnz %1 + mov %2,%3 + orl a,%5 +%1: + jz %4 +} by { + ; Peephole 242.b avoided branch jnz to jz + jnz %1 + mov %2,%3 + orl a,%5 + jz %4 +%1: +} if labelRefCount %1 1 + +// applies to f.e. logic.c +replace { + jnz %1 + mov %2,%3 + orl a,%5 + orl a,%6 + orl a,%7 +%1: + jz %4 +} by { + ; Peephole 242.c avoided branch jnz to jz + jnz %1 + mov %2,%3 + orl a,%5 + orl a,%6 + orl a,%7 + jz %4 +%1: +} if labelRefCount %1 1 + +replace { + jnz %1 +%1: +} by { + ; Peephole 243a jump optimization +} if labelRefCount %1 1 + +replace { + jz %1 +%1: +} by { + ; Peephole 243b jump optimization +} if labelRefCount %1 1 + + +// This allows non-interrupt and interrupt code to safely compete +// for a resource without the non-interrupt code having to disable +// interrupts: +// volatile bit resource_is_free; +// if( resource_is_free ) { +// resource_is_free=0; do_something; resource_is_free=1; +// } +replace { + jnb %1,%2 +%3: + clr %1 +} by { + ; Peephole 244.a using atomic test and clear + jbc %1,%3 + sjmp %2 +%3: +} if labelRefCount %3 0 + +replace { + jb %1,%2 + ljmp %3 +%2: + clr %1 +} by { + ; Peephole 244.b using atomic test and clear + jbc %1,%2 + ljmp %3 +%2: +} if labelRefCount %2 1 + diff --git a/src/ds390/ralloc.c b/src/ds390/ralloc.c new file mode 100644 index 0000000..77bbc5a --- /dev/null +++ b/src/ds390/ralloc.c @@ -0,0 +1,3501 @@ +/*------------------------------------------------------------------------ + + SDCCralloc.c - source file for register allocation. (DS80C390) specific + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "ralloc.h" +#include "gen.h" +#include "dbuf_string.h" + +/*-----------------------------------------------------------------*/ +/* At this point we start getting processor specific although */ +/* some routines are non-processor specific & can be reused when */ +/* targetting other processors. The decision for this will have */ +/* to be made on a routine by routine basis */ +/* routines used to pack registers are most definitely not reusable */ +/* since the pack the registers depending strictly on the MCU */ +/*-----------------------------------------------------------------*/ + +#define D(x) + +extern char **fReturnDS390; + +/* Global data */ +static struct +{ + bitVect *spiltSet; + set *stackSpil; + bitVect *regAssigned; + bitVect *totRegAssigned; /* final set of LRs that got into registers */ + short blockSpil; + int slocNum; + bitVect *funcrUsed; /* registers used in a function */ + int stackExtend; + int dataExtend; + bitVect *allBitregs; /* all bit registers */ +} +_G; + +/* Shared with gen.c */ +int ds390_ptrRegReq; /* one byte pointer register required */ + +/* 8051 registers */ +reg_info regs390[] = { + + {REG_GPR, R2_IDX, REG_GPR, "r2", "ar2", "0", 2, 1, 1}, + {REG_GPR, R3_IDX, REG_GPR, "r3", "ar3", "0", 3, 1, 1}, + {REG_GPR, R4_IDX, REG_GPR, "r4", "ar4", "0", 4, 1, 1}, + {REG_GPR, R5_IDX, REG_GPR, "r5", "ar5", "0", 5, 1, 1}, + {REG_GPR, R6_IDX, REG_GPR, "r6", "ar6", "0", 6, 1, 1}, + {REG_GPR, R7_IDX, REG_GPR, "r7", "ar7", "0", 7, 1, 1}, + {REG_PTR, R0_IDX, REG_PTR, "r0", "ar0", "0", 0, 1, 1}, + {REG_PTR, R1_IDX, REG_PTR, "r1", "ar1", "0", 1, 1, 1}, + {REG_GPR, DPL_IDX, REG_GPR, "dpl", "dpl", "dpl", 0, 0, 0}, + {REG_GPR, DPH_IDX, REG_GPR, "dph", "dph", "dph", 0, 0, 0}, + {REG_GPR, DPX_IDX, REG_GPR, "dpx", "dpx", "dpx", 0, 0, 0}, + {REG_GPR, B_IDX, REG_GPR, "b", "b", "b", 0, 0, 0}, + {REG_BIT, B0_IDX, REG_BIT, "b0", "b0", "bits", 0, 1, 0}, + {REG_BIT, B1_IDX, REG_BIT, "b1", "b1", "bits", 1, 1, 0}, + {REG_BIT, B2_IDX, REG_BIT, "b2", "b2", "bits", 2, 1, 0}, + {REG_BIT, B3_IDX, REG_BIT, "b3", "b3", "bits", 3, 1, 0}, + {REG_BIT, B4_IDX, REG_BIT, "b4", "b4", "bits", 4, 1, 0}, + {REG_BIT, B5_IDX, REG_BIT, "b5", "b5", "bits", 5, 1, 0}, + {REG_BIT, B6_IDX, REG_BIT, "b6", "b6", "bits", 6, 1, 0}, + {REG_BIT, B7_IDX, REG_BIT, "b7", "b7", "bits", 7, 1, 0}, + {REG_GPR, X8_IDX, REG_GPR, "x8", "x8", "xreg", 0, 0, 0}, + {REG_GPR, X9_IDX, REG_GPR, "x9", "x9", "xreg", 1, 0, 0}, + {REG_GPR, X10_IDX, REG_GPR, "x10", "x10", "xreg", 2, 0, 0}, + {REG_GPR, X11_IDX, REG_GPR, "x11", "x11", "xreg", 3, 0, 0}, + {REG_GPR, X12_IDX, REG_GPR, "x12", "x12", "xreg", 4, 0, 0}, + {REG_CND, CND_IDX, REG_GPR, "C", "psw", "xreg", 0, 0, 0}, + {0, DPL1_IDX, 0, "dpl1", "dpl1", "dpl1", 0, 0, 0}, + {0, DPH1_IDX, 0, "dph1", "dph1", "dph1", 0, 0, 0}, + {0, DPX1_IDX, 0, "dpx1", "dpx1", "dpx1", 0, 0, 0}, + {0, DPS_IDX, 0, "dps", "dps", "dps", 0, 0, 0}, + {0, A_IDX, 0, "a", "acc", "acc", 0, 0, 0}, + {0, AP_IDX, 0, "ap", "ap", "ap", 0, 0, 0}, +}; + +int ds390_nRegs = 13; +int ds390_nBitRegs = 0; + +static void spillThis (symbol *); +static void freeAllRegs (); +static iCode *packRegsDPTRuse (operand *); +static int packRegsDPTRnuse (operand *, unsigned); + + + +/*-----------------------------------------------------------------*/ +/* allocReg - allocates register of given type */ +/*-----------------------------------------------------------------*/ +static reg_info * +allocReg (short type) +{ + int i; + + for (i = 0; i < ds390_nRegs; i++) + { + + /* if type is given as 0 then any + free register will do */ + if (!type && regs390[i].isFree) + { + regs390[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, i); + return ®s390[i]; + } + /* otherwise look for specific type of register */ + if (regs390[i].isFree && regs390[i].type == type) + { + regs390[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, i); + return ®s390[i]; + } + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* ds390_regWithIdx - returns pointer to register with index number*/ +/*-----------------------------------------------------------------*/ +reg_info * +ds390_regWithIdx (int idx) +{ + int i; + + for (i = 0; i < sizeof (regs390) / sizeof (reg_info); i++) + if (regs390[i].rIdx == idx) + return ®s390[i]; + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "regWithIdx not found"); + exit (1); +} + +/*-----------------------------------------------------------------*/ +/* freeReg - frees a register */ +/*-----------------------------------------------------------------*/ +static void +freeReg (reg_info *reg) +{ + if (!reg) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "freeReg - Freeing NULL register"); + exit (1); + } + + reg->isFree = 1; +} + +/*-----------------------------------------------------------------*/ +/* useReg - marks a register as used */ +/*-----------------------------------------------------------------*/ +static void +useReg (reg_info *reg) +{ + reg->isFree = 0; +} + +/*-----------------------------------------------------------------*/ +/* nFreeRegs - returns number of free registers */ +/*-----------------------------------------------------------------*/ +static int +nFreeRegs (int type) +{ + int i; + int nfr = 0; + + for (i = 0; i < ds390_nRegs; i++) + if (regs390[i].isFree && regs390[i].type == type) + nfr++; + return nfr; +} + +/*-----------------------------------------------------------------*/ +/* nfreeRegsType - free registers with type */ +/*-----------------------------------------------------------------*/ +static int +nfreeRegsType (int type) +{ + int nfr; + if (type == REG_PTR) + { + if ((nfr = nFreeRegs (type)) == 0) + return nFreeRegs (REG_GPR); + } + + return nFreeRegs (type); +} + +/*-----------------------------------------------------------------*/ +/* isOperandInReg - returns true if operand is currently in regs */ +/*-----------------------------------------------------------------*/ +static int +isOperandInReg (operand * op) +{ + if (!IS_SYMOP (op)) + return 0; + if (OP_SYMBOL (op)->ruonly) + return 1; + if (OP_SYMBOL (op)->accuse) + return 1; + if (OP_SYMBOL (op)->dptr) + return 1; + return bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (op)->key); +} + +/* When the spill locations aren't fully initialized, the usual + * isOperandInFarSpace() function may return false for a spilled + * operand that will ultimately end up in far space, but is not + * quite there yet. This function returns TRUE if the operand + * is either currently in far space or will be by the time code + * generation begins */ +static bool +isOperandInFarSpace2 (operand * op) +{ + symbol * opsym; + + if (isOperandInFarSpace (op)) + return TRUE; + + if (!IS_ITEMP (op)) + return FALSE; + + opsym = OP_SYMBOL (op); + if (isOperandInReg (op)) + return FALSE; + + if ((currFunc && IFFUNC_ISREENT (currFunc->type)) || options.stackAuto) + return FALSE; /* Will spill to internal stack */ + + if (options.model == MODEL_SMALL) + return FALSE; /* Will spill to internal data memory */ + + return TRUE; /* No other option; must spill to external data memory */ +} + +/*-----------------------------------------------------------------*/ +/* computeSpillable - given a point find the spillable live ranges */ +/*-----------------------------------------------------------------*/ +static bitVect * +computeSpillable (iCode * ic) +{ + bitVect *spillable; + + /* spillable live ranges are those that are live at this + point . the following categories need to be subtracted + from this set. + a) - those that are already spilt + b) - if being used by this one + c) - defined by this one */ + + spillable = bitVectCopy (ic->rlive); + spillable = bitVectCplAnd (spillable, _G.spiltSet); /* those already spilt */ + spillable = bitVectCplAnd (spillable, ic->uses); /* used in this one */ + bitVectUnSetBit (spillable, ic->defKey); + spillable = bitVectIntersect (spillable, _G.regAssigned); + return spillable; + +} + +/*-----------------------------------------------------------------*/ +/* bitType - will return 1 if the symbol has type REG_BIT */ +/*-----------------------------------------------------------------*/ +static int +bitType (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (sym->regType == REG_BIT ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* noSpilLoc - return true if a variable has no spil location */ +/*-----------------------------------------------------------------*/ +static int +noSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (sym->usl.spillLoc ? 0 : 1); +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLoc - will return 1 if the symbol has spil location */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return (sym->usl.spillLoc ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* directSpilLoc - will return 1 if the spillocation is in direct */ +/*-----------------------------------------------------------------*/ +static int +directSpilLoc (symbol * sym, eBBlock * ebp, iCode * ic) +{ + if (sym->usl.spillLoc && (IN_DIRSPACE (SPEC_OCLS (sym->usl.spillLoc->etype)))) + return 1; + else + return 0; +} + +/*-----------------------------------------------------------------*/ +/* hasSpilLocnoUptr - will return 1 if the symbol has spil location */ +/* but is not used as a pointer */ +/*-----------------------------------------------------------------*/ +static int +hasSpilLocnoUptr (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return ((sym->usl.spillLoc && !sym->uptr) ? 1 : 0); +} + +/*-----------------------------------------------------------------*/ +/* rematable - will return 1 if the remat flag is set */ +/*-----------------------------------------------------------------*/ +static int +rematable (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return sym->remat; +} + +/*-----------------------------------------------------------------*/ +/* notUsedInRemaining - not used or defined in remain of the block */ +/*-----------------------------------------------------------------*/ +static int +notUsedInRemaining (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return ((usedInRemaining (operandFromSymbol (sym), ic) ? 0 : 1) && allDefsOutOfRange (sym->defs, ebp->fSeq, ebp->lSeq)); +} + +/*-----------------------------------------------------------------*/ +/* allLRs - return true for all */ +/*-----------------------------------------------------------------*/ +static int +allLRs (symbol * sym, eBBlock * ebp, iCode * ic) +{ + return 1; +} + +/*-----------------------------------------------------------------*/ +/* liveRangesWith - applies function to a given set of live range */ +/*-----------------------------------------------------------------*/ +static set * +liveRangesWith (bitVect * lrs, int (func) (symbol *, eBBlock *, iCode *), eBBlock * ebp, iCode * ic) +{ + set *rset = NULL; + int i; + + if (!lrs || !lrs->size) + return NULL; + + for (i = 1; i < lrs->size; i++) + { + symbol *sym; + if (!bitVectBitValue (lrs, i)) + continue; + + /* if we don't find it in the live range + hash table we are in serious trouble */ + if (!(sym = hTabItemWithKey (liveRanges, i))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "liveRangesWith could not find liveRange"); + exit (1); + } + + if (func (sym, ebp, ic) && bitVectBitValue (_G.regAssigned, sym->key)) + addSetHead (&rset, sym); + } + + return rset; +} + + +/*-----------------------------------------------------------------*/ +/* leastUsedLR - given a set determines which is the least used */ +/*-----------------------------------------------------------------*/ +static symbol * +leastUsedLR (set * sset) +{ + symbol *sym = NULL, *lsym = NULL; + + sym = lsym = setFirstItem (sset); + + if (!lsym) + return NULL; + + for (; lsym; lsym = setNextItem (sset)) + { + + /* if usage is the same then prefer + to spill the smaller of the two */ + if (lsym->used == sym->used) + if (getSize (lsym->type) < getSize (sym->type)) + sym = lsym; + + /* if less usage */ + if (lsym->used < sym->used) + sym = lsym; + + } + + setToNull ((void *) &sset); + sym->blockSpil = 0; + return sym; +} + +/*-----------------------------------------------------------------*/ +/* noOverLap - will iterate through the list looking for over lap */ +/*-----------------------------------------------------------------*/ +static int +noOverLap (set * itmpStack, symbol * fsym) +{ + symbol *sym; + + for (sym = setFirstItem (itmpStack); sym; sym = setNextItem (itmpStack)) + { + if (bitVectBitValue (sym->clashes, fsym->key)) + return 0; + } + return 1; +} + +/*-----------------------------------------------------------------*/ +/* isFree - will return 1 if the a free spil location is found */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (isFree) +{ + symbol *sym = item; + V_ARG (symbol **, sloc); + V_ARG (symbol *, fsym); + + /* if already found */ + if (*sloc) + return 0; + + /* if it is free && and the itmp assigned to + this does not have any overlapping live ranges + with the one currently being assigned and + the size can be accomodated */ + if (sym->isFree && noOverLap (sym->usl.itmpStack, fsym) && getSize (sym->type) >= getSize (fsym->type) + && (IS_BIT (sym->type) == IS_BIT (fsym->type))) + { + *sloc = sym; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* spillLRWithPtrReg :- will spil those live ranges which use PTR */ +/*-----------------------------------------------------------------*/ +static void +spillLRWithPtrReg (symbol * forSym) +{ + symbol *lrsym; + reg_info *r0, *r1; + int k; + + if (!_G.regAssigned || bitVectIsZero (_G.regAssigned)) + return; + + r0 = ds390_regWithIdx (R0_IDX); + r1 = ds390_regWithIdx (R1_IDX); + + /* for all live ranges */ + for (lrsym = hTabFirstItem (liveRanges, &k); lrsym; lrsym = hTabNextItem (liveRanges, &k)) + { + int j; + + /* if no registers assigned to it or spilt */ + /* if it does not overlap this then + no need to spill it */ + + if (lrsym->isspilt || !lrsym->nRegs || (lrsym->liveTo < forSym->liveFrom)) + continue; + + /* go thru the registers : if it is either + r0 or r1 then spill it */ + for (j = 0; j < lrsym->nRegs; j++) + if (lrsym->regs[j] == r0 || lrsym->regs[j] == r1) + { + spillThis (lrsym); + break; + } + } + +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +static symbol * +createStackSpil (symbol * sym) +{ + symbol *sloc = NULL; + int useXstack, model, noOverlay; + struct dbuf_s dbuf; + + /* first go try and find a free one that is already + existing on the stack */ + if (applyToSet (_G.stackSpil, isFree, &sloc, sym)) + { + /* found a free one : just update & return */ + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + sloc->isFree = 0; + addSetHead (&sloc->usl.itmpStack, sym); + return sym; + } + + /* could not then have to create one , this is the hard part + we need to allocate this on the stack : this is really a + hack!! but cannot think of anything better at this time */ + + dbuf_init (&dbuf, 128); + dbuf_printf (&dbuf, "sloc%d", _G.slocNum++); + sloc = newiTemp (dbuf_c_str (&dbuf)); + dbuf_destroy (&dbuf); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain (sym->type); + sloc->etype = getSpec (sloc->type); + if (!IS_BIT (sloc->etype)) + { + if (options.model == MODEL_SMALL) + { + SPEC_SCLS (sloc->etype) = S_DATA; + } + else + { + SPEC_SCLS (sloc->etype) = S_XDATA; + } + } + SPEC_EXTR (sloc->etype) = 0; + SPEC_STAT (sloc->etype) = 0; + SPEC_VOLATILE (sloc->etype) = 0; + SPEC_ABSA (sloc->etype) = 0; + + /* we don't allow it to be allocated + onto the external stack since : so we + temporarily turn it off ; we also + turn off memory model to prevent + the spil from going to the external storage + and turn off overlaying + */ + + useXstack = options.useXstack; + model = options.model; + noOverlay = options.noOverlay; + options.noOverlay = 1; + + /* options.model = options.useXstack = 0; */ + + allocLocal (sloc); + + options.useXstack = useXstack; + options.model = model; + options.noOverlay = noOverlay; + sloc->isref = 1; /* to prevent compiler warning */ + + /* if it is on the stack then update the stack */ + if (IN_STACK (sloc->etype)) + { + currFunc->stack += getSize (sloc->type); + _G.stackExtend += getSize (sloc->type); + } + else + _G.dataExtend += getSize (sloc->type); + + /* add it to the _G.stackSpil set */ + addSetHead (&_G.stackSpil, sloc); + sym->usl.spillLoc = sloc; + sym->stackSpil = 1; + + /* add it to the set of itempStack set + of the spill location */ + addSetHead (&sloc->usl.itmpStack, sym); + return sym; +} + +/*-----------------------------------------------------------------*/ +/* isSpiltOnStack - returns true if the spil location is on stack */ +/*-----------------------------------------------------------------*/ +static bool +isSpiltOnStack (symbol * sym) +{ + sym_link *etype; + + if (!sym) + return FALSE; + + if (!sym->isspilt) + return FALSE; + +/* if (sym->_G.stackSpil) */ +/* return TRUE; */ + + if (!sym->usl.spillLoc) + return FALSE; + + etype = getSpec (sym->usl.spillLoc->type); + if (IN_STACK (etype)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* spillThis - spils a specific operand */ +/*-----------------------------------------------------------------*/ +static void +spillThis (symbol * sym) +{ + int i; + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ + if (!(sym->remat || sym->usl.spillLoc)) + createStackSpil (sym); + + /* mark it has spilt & put it in the spilt set */ + sym->isspilt = sym->spillA = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key); + + bitVectUnSetBit (_G.regAssigned, sym->key); + bitVectUnSetBit (_G.totRegAssigned, sym->key); + + for (i = 0; i < sym->nRegs; i++) + + if (sym->regs[i]) + { + freeReg (sym->regs[i]); + sym->regs[i] = NULL; + } + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to some + LIVE ranges */ + if (!ds390_ptrRegReq && isSpiltOnStack (sym) && !options.stack10bit) + { + ds390_ptrRegReq++; + spillLRWithPtrReg (sym); + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq++; + return; +} + +/*-----------------------------------------------------------------*/ +/* selectSpil - select a iTemp to spil : rather a simple procedure */ +/*-----------------------------------------------------------------*/ +static symbol * +selectSpil (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + bitVect *lrcs = NULL; + set *selectS; + symbol *sym; + + /* get the spillable live ranges */ + lrcs = computeSpillable (ic); + + /* remove incompatible registers */ + if ((forSym->regType == REG_PTR) || (forSym->regType == REG_GPR)) + { + selectS = liveRangesWith (lrcs, bitType, ebp, ic); + + for (sym = setFirstItem (selectS); sym; sym = setNextItem (selectS)) + { + bitVectUnSetBit (lrcs, sym->key); + } + } + + /* get all live ranges that are rematerializable */ + if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic))) + { + /* return the least used of these */ + return leastUsedLR (selectS); + } + + /* get live ranges with spillLocations in direct space */ + if ((selectS = liveRangesWith (lrcs, directSpilLoc, ebp, ic))) + { + sym = leastUsedLR (selectS); + strncpyz (sym->rname, + sym->usl.spillLoc->rname[0] ? sym->usl.spillLoc->rname : sym->usl.spillLoc->name, sizeof (sym->rname)); + sym->spildir = 1; + /* mark it as allocation required */ + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* if the symbol is local to the block then */ + if (forSym->liveTo < ebp->lSeq) + { + /* check if there are any live ranges allocated + to registers that are not used in this block */ + if (!_G.blockSpil && (selectS = liveRangesWith (lrcs, notUsedInBlock, ebp, ic))) + { + sym = leastUsedLR (selectS); + /* if this is not rematerializable */ + if (!sym->remat) + { + _G.blockSpil++; + sym->blockSpil = 1; + } + return sym; + } + + /* check if there are any live ranges that not + used in the remainder of the block */ + if (!_G.blockSpil && !isiCodeInFunctionCall (ic) && (selectS = liveRangesWith (lrcs, notUsedInRemaining, ebp, ic))) + { + sym = leastUsedLR (selectS); + if (sym != forSym) + { + if (!sym->remat) + { + sym->remainSpil = 1; + _G.blockSpil++; + } + return sym; + } + } + } + + /* find live ranges with spillocation && not used as pointers */ + if ((selectS = liveRangesWith (lrcs, hasSpilLocnoUptr, ebp, ic))) + { + sym = leastUsedLR (selectS); + /* mark this as allocation required */ + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* find live ranges with spillocation */ + if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic))) + { + sym = leastUsedLR (selectS); + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* couldn't find then we need to create a spil + location on the stack , for which one? the least + used ofcourse */ + if ((selectS = liveRangesWith (lrcs, noSpilLoc, ebp, ic))) + { + /* return a created spil location */ + sym = createStackSpil (leastUsedLR (selectS)); + sym->usl.spillLoc->allocreq++; + return sym; + } + + /* this is an extreme situation we will spill + this one : happens very rarely but it does happen */ + spillThis (forSym); + return forSym; + +} + +/*-----------------------------------------------------------------*/ +/* spilSomething - spil some variable & mark registers as free */ +/*-----------------------------------------------------------------*/ +static bool +spilSomething (iCode * ic, eBBlock * ebp, symbol * forSym) +{ + symbol *ssym; + int i; + + /* get something we can spil */ + ssym = selectSpil (ic, ebp, forSym); + + /* mark it as spilt */ + ssym->isspilt = ssym->spillA = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, ssym->key); + + /* mark it as not register assigned & + take it away from the set */ + bitVectUnSetBit (_G.regAssigned, ssym->key); + bitVectUnSetBit (_G.totRegAssigned, ssym->key); + + /* mark the registers as free */ + for (i = 0; i < ssym->nRegs; i++) + if (ssym->regs[i]) + freeReg (ssym->regs[i]); + + /* if spilt on stack then free up r0 & r1 + if they could have been assigned to as gprs */ + if (!ds390_ptrRegReq && isSpiltOnStack (ssym) && !options.stack10bit) + { + ds390_ptrRegReq++; + spillLRWithPtrReg (ssym); + } + + /* if this was a block level spil then insert push & pop + at the start & end of block respectively */ + if (ssym->blockSpil) + { + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push to the start of the block */ + addiCodeToeBBlock (ebp, nic, (ebp->sch->op == LABEL ? ebp->sch->next : ebp->sch)); + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + /* if spilt because not used in the remainder of the + block then add a push before this instruction and + a pop at the end of the block */ + if (ssym->remainSpil) + { + + iCode *nic = newiCode (IPUSH, operandFromSymbol (ssym), NULL); + /* add push just before this instruction */ + addiCodeToeBBlock (ebp, nic, ic); + + nic = newiCode (IPOP, operandFromSymbol (ssym), NULL); + /* add pop to the end of the block */ + addiCodeToeBBlock (ebp, nic, NULL); + } + + if (ssym == forSym) + return FALSE; + else + return TRUE; +} + +/*-----------------------------------------------------------------*/ +/* getRegPtr - will try for PTR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + reg_info *reg; + int j; + +tryAgain: + /* try for a ptr type */ + if ((reg = allocReg (REG_PTR))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* make sure partially assigned registers aren't reused */ + for (j = 0; j <= sym->nRegs; j++) + if (sym->regs[j]) + sym->regs[j]->isFree = 0; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegGpr - will try for GPR if not spil */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + reg_info *reg; + int j; + +tryAgain: + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + if (!ds390_ptrRegReq) + if ((reg = allocReg (REG_PTR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* make sure partially assigned registers aren't reused */ + for (j = 0; j <= sym->nRegs; j++) + if (sym->regs[j]) + sym->regs[j]->isFree = 0; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegBit - will try for Bit if not spill this */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegBit (symbol * sym) +{ + reg_info *reg; + + /* try for a bit type */ + if ((reg = allocReg (REG_BIT))) + return reg; + + spillThis (sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* getRegPtrNoSpil - get it cannot be spilt */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegPtrNoSpil () +{ + reg_info *reg; + + /* try for a ptr type */ + if ((reg = allocReg (REG_PTR))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + assert (0); + + /* just to make the compiler happy */ + return 0; +} + +/*-----------------------------------------------------------------*/ +/* getRegGprNoSpil - get it cannot be spilt */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegGprNoSpil () +{ + + reg_info *reg; + if ((reg = allocReg (REG_GPR))) + return reg; + + if (!ds390_ptrRegReq) + if ((reg = allocReg (REG_PTR))) + return reg; + + assert (0); + + /* just to make the compiler happy */ + return 0; +} + +/*-----------------------------------------------------------------*/ +/* getRegBitNoSpil - get it cannot be spilt */ +/*-----------------------------------------------------------------*/ +static reg_info * +getRegBitNoSpil () +{ + reg_info *reg; + + /* try for a bit type */ + if ((reg = allocReg (REG_BIT))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + assert (0); + + /* just to make the compiler happy */ + return 0; +} + +/*-----------------------------------------------------------------*/ +/* symHasReg - symbol has a given register */ +/*-----------------------------------------------------------------*/ +static bool +symHasReg (symbol *sym, reg_info *reg) +{ + int i; + + for (i = 0; i < sym->nRegs; i++) + if (sym->regs[i] == reg) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* updateRegUsage - update the registers in use at the start of */ +/* this icode */ +/*-----------------------------------------------------------------*/ +static void +updateRegUsage (iCode * ic) +{ + int reg; + + for (reg = 0; reg < ds390_nRegs; reg++) + { + if (regs390[reg].isFree) + { + ic->riu &= ~(1 << regs390[reg].offset); + } + else + { + ic->riu |= (1 << regs390[reg].offset); + BitBankUsed |= (reg >= B0_IDX); + } + } +} + +/*-----------------------------------------------------------------*/ +/* deassignLRs - check the live to and if they have registers & are */ +/* not spilt then free up the registers */ +/*-----------------------------------------------------------------*/ +static void +deassignLRs (iCode * ic, eBBlock * ebp) +{ + symbol *sym; + int k; + symbol *result; + + for (sym = hTabFirstItem (liveRanges, &k); sym; sym = hTabNextItem (liveRanges, &k)) + { + + symbol *psym = NULL; + /* if it does not end here */ + if (sym->liveTo > ic->seq) + continue; + + /* if it was spilt on stack then we can + mark the stack spil location as free */ + if (sym->isspilt) + { + if (sym->stackSpil) + { + sym->usl.spillLoc->isFree = 1; + sym->stackSpil = 0; + } + continue; + } + + if (!bitVectBitValue (_G.regAssigned, sym->key)) + continue; + + /* special case check if this is an IFX & + the privious one was a pop and the + previous one was not spilt then keep track + of the symbol */ + if (ic->op == IFX && ic->prev && ic->prev->op == IPOP && !ic->prev->parmPush && !OP_SYMBOL (IC_LEFT (ic->prev))->isspilt) + psym = OP_SYMBOL (IC_LEFT (ic->prev)); + + if (sym->nRegs) + { + int i = 0; + + bitVectUnSetBit (_G.regAssigned, sym->key); + + /* if the result of this one needs registers + and does not have it then assign it right + away */ + if (IC_RESULT (ic) && !(SKIP_IC2 (ic) || /* not a special icode */ + ic->op == JUMPTABLE || ic->op == IFX || ic->op == IPUSH || ic->op == IPOP || ic->op == RETURN || POINTER_SET (ic)) && (result = OP_SYMBOL (IC_RESULT (ic))) && /* has a result */ + result->liveTo > ic->seq && /* and will live beyond this */ + result->liveTo <= ebp->lSeq && /* does not go beyond this block */ + result->liveFrom == ic->seq && /* does not start before here */ + result->regType == sym->regType && /* same register types */ + result->nRegs && /* which needs registers */ + !result->isspilt && /* and does not already have them */ + !result->remat && !bitVectBitValue (_G.regAssigned, result->key) && + /* the number of free regs + number of regs in this LR + can accomodate the what result Needs */ + ((nfreeRegsType (result->regType) + sym->nRegs) >= result->nRegs)) + { + + for (i = 0; i < result->nRegs; i++) + if (i < sym->nRegs) + result->regs[i] = sym->regs[i]; + else + result->regs[i] = getRegGpr (ic, ebp, result); + + _G.regAssigned = bitVectSetBit (_G.regAssigned, result->key); + _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, result->key); + + } + + /* free the remaining */ + for (; i < sym->nRegs; i++) + { + if (psym) + { + if (!symHasReg (psym, sym->regs[i])) + freeReg (sym->regs[i]); + } + else + freeReg (sym->regs[i]); + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* reassignLR - reassign this to registers */ +/*-----------------------------------------------------------------*/ +static void +reassignLR (operand * op) +{ + symbol *sym = OP_SYMBOL (op); + int i; + + /* not spilt any more */ + sym->isspilt = sym->spillA = sym->blockSpil = sym->remainSpil = 0; + bitVectUnSetBit (_G.spiltSet, sym->key); + + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key); + + _G.blockSpil--; + + for (i = 0; i < sym->nRegs; i++) + sym->regs[i]->isFree = 0; +} + +/*-----------------------------------------------------------------*/ +/* willCauseSpill - determines if allocating will cause a spill */ +/*-----------------------------------------------------------------*/ +static int +willCauseSpill (int nr, int rt) +{ + /* first check if there are any available registers + of the type required */ + if (rt == REG_PTR) + { + /* special case for pointer type + if pointer type not avlb then + check for type gpr */ + if (nFreeRegs (rt) >= nr) + return 0; + if (nFreeRegs (REG_GPR) >= nr) + return 0; + } + else if (rt == REG_BIT) + { + if (nFreeRegs (rt) >= nr) + return 0; + } + else + { + if (ds390_ptrRegReq) + { + if (nFreeRegs (rt) >= nr) + return 0; + } + else + { + if (nFreeRegs (REG_PTR) + nFreeRegs (REG_GPR) >= nr) + return 0; + } + } + + /* it will cause a spil */ + return 1; +} + +/*------------------------------------------------------------------*/ +/* positionRegs - the allocator can allocate same registers to res- */ +/* ult and operand, if this happens make sure they are in the same */ +/* position as the operand otherwise chaos results */ +/*------------------------------------------------------------------*/ +static int +positionRegs (symbol *result, symbol *opsym, int chOp) +{ + int count = min (result->nRegs, opsym->nRegs); + int i, j = 0, shared = 0; + int change = 0; + + /* if the result has been spilt then cannot share */ + if (result->isspilt || opsym->isspilt) + return 0; + + for (;;) + { + shared = 0; + /* first make sure that they actually share */ + for (i = 0; i < count; i++) + for (j = 0; j < count; j++) + if (result->regs[i] == opsym->regs[j] && i != j) + { + shared = 1; + goto xchgPositions; + } +xchgPositions: + if (shared) + if (!chOp) + { + reg_info *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + change++; + } + else + { + reg_info *tmp = opsym->regs[i]; + opsym->regs[i] = opsym->regs[j]; + opsym->regs[j] = tmp; + change++; + } + else + return change; + } +} + +/*-----------------------------------------------------------------*/ +/* positionRegs - the allocator can allocate the registers of the */ +/* return value to the result, if this happens make sure they are */ +/* in the same position as the return value otherwise chaos results*/ +/*-----------------------------------------------------------------*/ +static int +positionRegsReturned (symbol *result) +{ + int count = result->nRegs; + int i, j = 0, shared = 0; + int change = 0; + + /* if the result has been spilt then cannot share */ + if (result->isspilt) + return 0; + + for (;;) + { + shared = 0; + /* first make sure that they actually share */ + for (i = 0; i < count; i++) + for (j = 0; j < count; j++) + if (!strcmp(result->regs[i]->name, fReturnDS390[j]) && i != j) + { + shared = 1; + goto xchgPositions; + } +xchgPositions: + if (shared) + { + reg_info *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + change++; + } + else + return change; + } +} + +/*-----------------------------------------------------------------*/ +/* unusedLRS - returns a bitVector of liveranges not used in 'ebp' */ +/*-----------------------------------------------------------------*/ +bitVect * +unusedLRs (eBBlock * ebp) +{ + bitVect *ret = NULL; + symbol *sym; + int key; + + if (!ebp) + return NULL; + for (sym = hTabFirstItem (liveRanges, &key); sym; sym = hTabNextItem (liveRanges, &key)) + { + + if (notUsedInBlock (sym, ebp, NULL)) + { + ret = bitVectSetBit (ret, sym->key); + } + } + + return ret; +} + +/*-----------------------------------------------------------------*/ +/* deassignUnsedLRs - if this baisc block ends in a return then */ +/* deassign symbols not used in this block */ +/*-----------------------------------------------------------------*/ +bitVect * +deassignUnsedLRs (eBBlock * ebp) +{ + bitVect *unused = NULL; + int i; + + switch (returnAtEnd (ebp)) + { + case 2: /* successor block ends in a return */ + unused = unusedLRs ((eBBlock *) setFirstItem (ebp->succList)); + /* fall thru */ + case 1: /* this block ends in a return */ + unused = bitVectIntersect (unused, unusedLRs (ebp)); + break; + } + + if (unused) + { + for (i = 0; i < unused->size; i++) + { + + /* if unused */ + if (bitVectBitValue (unused, i)) + { + + /* if assigned to registers */ + if (bitVectBitValue (_G.regAssigned, i)) + { + symbol *sym; + int j; + + sym = hTabItemWithKey (liveRanges, i); + /* remove it from regassigned & mark the + register free */ + bitVectUnSetBit (_G.regAssigned, i); + for (j = 0; j < sym->nRegs; j++) + freeReg (sym->regs[j]); + } + else + { + /* not assigned to registers : remove from set */ + bitVectUnSetBit (unused, i); + } + } + } + } + return unused; +} + +/*-----------------------------------------------------------------*/ +/* reassignUnusedLRs - put registers to unused Live ranges */ +/*-----------------------------------------------------------------*/ +void +reassignUnusedLRs (bitVect * unused) +{ + int i; + if (!unused) + return; + + for (i = 0; i < unused->size; i++) + { + /* if unused : means it was assigned to registers before */ + if (bitVectBitValue (unused, i)) + { + symbol *sym; + int j; + + /* put it back into reg set */ + bitVectSetBit (_G.regAssigned, i); + + sym = hTabItemWithKey (liveRanges, i); + /* make registers busy */ + for (j = 0; j < sym->nRegs; j++) + sym->regs[j]->isFree = 0; + } + } +} + +/*------------------------------------------------------------------*/ +/* verifyRegsAssigned - make sure an iTemp is properly initialized; */ +/* it should either have registers or have beed spilled. Otherwise, */ +/* there was an uninitialized variable, so just spill this to get */ +/* the operand in a valid state. */ +/*------------------------------------------------------------------*/ +static void +verifyRegsAssigned (operand * op, iCode * ic) +{ + symbol *sym; + + if (!op) + return; + if (!IS_ITEMP (op)) + return; + + sym = OP_SYMBOL (op); + if (sym->isspilt) + return; + if (!sym->nRegs) + return; + if (sym->regs[0]) + return; + + werrorfl (ic->filename, ic->lineno, W_LOCAL_NOINIT, sym->prereqv ? sym->prereqv->name : sym->name); + spillThis (sym); +} + + +/*-----------------------------------------------------------------*/ +/* serialRegAssign - serially allocate registers to the variables */ +/*-----------------------------------------------------------------*/ +static void +serialRegAssign (eBBlock ** ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count; i++) + { /* ebbs */ + + iCode *ic; + bitVect *unusedLRs = NULL; + + if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) + continue; + + unusedLRs = deassignUnsedLRs (ebbs[i]); + + /* for all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + updateRegUsage (ic); + + /* if this is an ipop that means some live + range will have to be assigned again */ + if (ic->op == IPOP) + reassignLR (IC_LEFT (ic)); + + /* if result is present && is a true symbol */ + if (IC_RESULT (ic) && ic->op != IFX && IS_TRUE_SYMOP (IC_RESULT (ic))) + OP_SYMBOL (IC_RESULT (ic))->allocreq++; + + /* take away registers from live + ranges that end at this instruction */ + deassignLRs (ic, ebbs[i]); + + /* some don't need registers */ + if (SKIP_IC2 (ic) || + ic->op == JUMPTABLE || ic->op == IFX || ic->op == IPUSH || ic->op == IPOP || (IC_RESULT (ic) && POINTER_SET (ic))) + continue; + + /* now we need to allocate registers + only for the result */ + if (IC_RESULT (ic)) + { + symbol *sym = OP_SYMBOL (IC_RESULT (ic)); + bitVect *spillable; + int willCS; + int j; + int ptrRegSet = 0; + + /* Make sure any spill location is definitely allocated */ + if (sym->isspilt && !sym->remat && sym->usl.spillLoc && !sym->usl.spillLoc->allocreq) + { + sym->usl.spillLoc->allocreq++; + } + + /* if it does not need or is spilt + or is already assigned to registers + or will not live beyond this instructions */ + if (!sym->nRegs || sym->isspilt || bitVectBitValue (_G.regAssigned, sym->key) || sym->liveTo <= ic->seq) + continue; + + /* if some liverange has been spilt at the block level + and this one live beyond this block then spil this + to be safe */ + if (_G.blockSpil && sym->liveTo > ebbs[i]->lSeq) + { + spillThis (sym); + continue; + } + + willCS = willCauseSpill (sym->nRegs, sym->regType); + /* if this is a bit variable then don't use precious registers + along with expensive bit-to-char conversions but just spill + it */ + if (willCS && SPEC_NOUN (sym->etype) == V_BIT) + { + spillThis (sym); + continue; + } + + /* if trying to allocate this will cause + a spill and there is nothing to spill + or this one is rematerializable then + spill this one */ + spillable = computeSpillable (ic); + if (sym->remat || (willCS && bitVectIsZero (spillable))) + { + spillThis (sym); + continue; + } + + /* If the live range preceeds the point of definition + then ideally we must take into account registers that + have been allocated after sym->liveFrom but freed + before ic->seq. This is complicated, so spill this + symbol instead and let fillGaps handle the allocation. */ + if (sym->liveFrom < ic->seq) + { + spillThis (sym); + continue; + } + + /* if it has a spillocation & is used less than + all other live ranges then spill this */ + if (willCS) + { + if (sym->usl.spillLoc) + { + symbol *leastUsed = leastUsedLR (liveRangesWith (spillable, + allLRs, ebbs[i], ic)); + if (leastUsed && leastUsed->used > sym->used) + { + spillThis (sym); + continue; + } + } + else + { + /* if none of the liveRanges have a spillLocation then better + to spill this one than anything else already assigned to registers */ + if (liveRangesWith (spillable, noSpilLoc, ebbs[i], ic)) + { + /* if this is local to this block then we might find a block spil */ + if (!(sym->liveFrom >= ebbs[i]->fSeq && sym->liveTo <= ebbs[i]->lSeq)) + { + spillThis (sym); + continue; + } + } + } + } + + /* if we need ptr regs for the right side + then mark it */ + if (POINTER_GET (ic) && IS_SYMOP (IC_LEFT (ic)) && getSize (OP_SYMBOL (IC_LEFT (ic))->type) <= (unsigned) NEARPTRSIZE) + { + ds390_ptrRegReq++; + ptrRegSet = 1; + } + /* else we assign registers to it */ + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key); + + for (j = 0; j < sym->nRegs; j++) + { + sym->regs[j] = NULL; + if (sym->regType == REG_PTR) + sym->regs[j] = getRegPtr (ic, ebbs[i], sym); + else if (sym->regType == REG_BIT) + sym->regs[j] = getRegBit (sym); + else + sym->regs[j] = getRegGpr (ic, ebbs[i], sym); + + /* if the allocation failed which means + this was spilt then break */ + if (!sym->regs[j]) + break; + } + + /* if it shares registers with operands make sure + that they are in the same position */ + if (!POINTER_SET (ic) && !POINTER_GET (ic)) + { + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->nRegs) + { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_LEFT (ic)), 0); + } + /* do the same for the right operand */ + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->nRegs) + { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_RIGHT (ic)), 0); + } + } + + if (ic->op == CALL || ic->op == PCALL || ic->op == RECEIVE) + { + positionRegsReturned (OP_SYMBOL (IC_RESULT (ic))); + } + + if (ptrRegSet) + { + ds390_ptrRegReq--; + ptrRegSet = 0; + } + + } + } + reassignUnusedLRs (unusedLRs); + } + + /* Check for and fix any problems with uninitialized operands */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) + continue; + + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + if (SKIP_IC2 (ic)) + continue; + + if (ic->op == IFX) + { + verifyRegsAssigned (IC_COND (ic), ic); + continue; + } + + if (ic->op == JUMPTABLE) + { + verifyRegsAssigned (IC_JTCOND (ic), ic); + continue; + } + + verifyRegsAssigned (IC_RESULT (ic), ic); + verifyRegsAssigned (IC_LEFT (ic), ic); + verifyRegsAssigned (IC_RIGHT (ic), ic); + } + } +} + +/*-----------------------------------------------------------------*/ +/* fillGaps - Try to fill in the Gaps left by Pass1 */ +/*-----------------------------------------------------------------*/ +static void +fillGaps () +{ + symbol *sym = NULL; + int key = 0; + int loop = 0, change; + int pass; + + if (getenv ("DISABLE_FILL_GAPS")) + return; + + /* First try to do DPTRuse once more since now we know what got into + registers */ + + while (loop++ < 10) + { + change = 0; + + for (sym = hTabFirstItem (liveRanges, &key); sym; sym = hTabNextItem (liveRanges, &key)) + { + int size = getSize (sym->type); + + if (sym->liveFrom == sym->liveTo) + continue; + + if (sym->uptr && sym->dptr == 0 && !sym->ruonly && size < 4 && size > 1) + { + + if (packRegsDPTRuse (operandFromSymbol (sym))) + { + + /* if this was assigned to registers then */ + if (bitVectBitValue (_G.totRegAssigned, sym->key)) + { + /* take it out of the register assigned set */ + bitVectUnSetBit (_G.totRegAssigned, sym->key); + } + else if (sym->usl.spillLoc) + { + sym->usl.spillLoc->allocreq--; + sym->usl.spillLoc = NULL; + } + + sym->nRegs = 0; + sym->isspilt = sym->spillA = 0; + continue; + } + + /* try assigning other dptrs */ + if (sym->dptr == 0 && packRegsDPTRnuse (operandFromSymbol (sym), 1) && !getenv ("DPTRnDISABLE")) + { + /* if this was ssigned to registers then */ + if (bitVectBitValue (_G.totRegAssigned, sym->key)) + { + /* take it out of the register assigned set */ + bitVectUnSetBit (_G.totRegAssigned, sym->key); + } + else if (sym->usl.spillLoc) + { + sym->usl.spillLoc->allocreq--; + sym->usl.spillLoc = NULL; + } + sym->nRegs = 0; + sym->isspilt = sym->spillA = 0; + } + } + } + + /* look for liveranges that were spilt by the allocator */ + for (sym = hTabFirstItem (liveRanges, &key); sym; sym = hTabNextItem (liveRanges, &key)) + { + + int i; + int pdone = 0; + + if (!sym->spillA || !sym->clashes || sym->remat) + continue; + if (!sym->uses || !sym->defs) + continue; + /* find the liveRanges this one clashes with, that are + still assigned to registers & mark the registers as used */ + for (i = 0; i < sym->clashes->size; i++) + { + int k; + symbol *clr; + + if (bitVectBitValue (sym->clashes, i) == 0 || /* those that clash with this */ + bitVectBitValue (_G.totRegAssigned, i) == 0) /* and are still assigned to registers */ + continue; + + clr = hTabItemWithKey (liveRanges, i); + assert (clr); + + /* mark these registers as used */ + for (k = 0; k < clr->nRegs; k++) + useReg (clr->regs[k]); + } + + if (willCauseSpill (sym->nRegs, sym->regType)) + { + /* NOPE :( clear all registers & and continue */ + freeAllRegs (); + continue; + } + + /* THERE IS HOPE !!!! */ + for (i = 0; i < sym->nRegs; i++) + { + if (sym->regType == REG_PTR) + sym->regs[i] = getRegPtrNoSpil (); + else if (sym->regType == REG_BIT) + sym->regs[i] = getRegBitNoSpil (); + else + sym->regs[i] = getRegGprNoSpil (); + } + + /* For all its definitions check if the registers + allocated needs positioning NOTE: we can position + only ONCE if more than One positioning required + then give up. + We may need to perform the checks twice; once to + position the registers as needed, the second to + verify any register repositioning is still + compatible. + */ + sym->isspilt = 0; + for (pass = 0; pass < 2; pass++) + { + for (i = 0; i < sym->defs->size; i++) + { + if (bitVectBitValue (sym->defs, i)) + { + iCode *ic; + if (!(ic = hTabItemWithKey (iCodehTab, i))) + continue; + if (SKIP_IC (ic)) + continue; + assert (isSymbolEqual (sym, OP_SYMBOL (IC_RESULT (ic)))); /* just making sure */ + /* if left is assigned to registers */ + if (IS_SYMOP (IC_LEFT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_LEFT (ic))->key)) + { + pdone += (positionRegs (sym, OP_SYMBOL (IC_LEFT (ic)), 0) > 0); + } + if (IS_SYMOP (IC_RIGHT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_RIGHT (ic))->key)) + { + pdone += (positionRegs (sym, OP_SYMBOL (IC_RIGHT (ic)), 0) > 0); + } + if (pdone > 1) + break; + } + } + for (i = 0; i < sym->uses->size; i++) + { + if (bitVectBitValue (sym->uses, i)) + { + iCode *ic; + if (!(ic = hTabItemWithKey (iCodehTab, i))) + continue; + if (SKIP_IC (ic)) + continue; + if (POINTER_SET (ic) || POINTER_GET (ic)) + continue; + + /* if result is assigned to registers */ + if (IS_SYMOP (IC_RESULT (ic)) && bitVectBitValue (_G.totRegAssigned, OP_SYMBOL (IC_RESULT (ic))->key)) + { + pdone += (positionRegs (sym, OP_SYMBOL (IC_RESULT (ic)), 0) > 0); + } + if (pdone > 1) + break; + } + } + if (pdone == 0) + break; /* second pass only if regs repositioned */ + if (pdone > 1) + break; + } + /* had to position more than once GIVE UP */ + if (pdone > 1) + { + /* UNDO all the changes we made to try this */ + sym->isspilt = 1; + for (i = 0; i < sym->nRegs; i++) + { + sym->regs[i] = NULL; + } + freeAllRegs (); + D (fprintf (stderr, "Fill Gap gave up due to positioning for " + "%s in function %s\n", sym->name, currFunc ? currFunc->name : "UNKNOWN")); + continue; + } + D (fprintf (stderr, "FILLED GAP for %s in function %s\n", sym->name, currFunc ? currFunc->name : "UNKNOWN")); + _G.totRegAssigned = bitVectSetBit (_G.totRegAssigned, sym->key); + sym->isspilt = sym->spillA = 0; + sym->usl.spillLoc->allocreq--; + sym->usl.spillLoc = NULL; + freeAllRegs (); + change++; + } + if (!change) + break; + } +} + +/*-----------------------------------------------------------------*/ +/* findAllBitregs :- returns bit vector of all bit registers */ +/*-----------------------------------------------------------------*/ +static bitVect * +findAllBitregs (void) +{ + bitVect *rmask = newBitVect (ds390_nRegs); + int j; + + for (j = 0; j < ds390_nRegs; j++) + { + if (regs390[j].type == REG_BIT) + rmask = bitVectSetBit (rmask, regs390[j].rIdx); + } + + return rmask; +} + +/*-----------------------------------------------------------------*/ +/* ds390_allBitregs :- returns bit vector of all bit registers */ +/*-----------------------------------------------------------------*/ +bitVect * +ds390_allBitregs (void) +{ + return _G.allBitregs; +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +bitVect * +ds390_rUmaskForOp (operand * op) +{ + bitVect *rumask; + symbol *sym; + int j; + + /* only temporaries are assigned registers */ + if (!IS_ITEMP (op)) + return NULL; + + sym = OP_SYMBOL (op); + + /* if spilt or no registers assigned to it + then nothing */ + if (sym->isspilt || !sym->nRegs) + return NULL; + + rumask = newBitVect (ds390_nRegs); + + for (j = 0; j < sym->nRegs; j++) + { + rumask = bitVectSetBit (rumask, sym->regs[j]->rIdx); + } + + return rumask; +} + +/*-----------------------------------------------------------------*/ +/* regsUsedIniCode :- returns bit vector of registers used in iCode */ +/*-----------------------------------------------------------------*/ +static bitVect * +regsUsedIniCode (iCode * ic) +{ + bitVect *rmask = newBitVect (ds390_nRegs); + + /* do the special cases first */ + if (ic->op == IFX) + { + rmask = bitVectUnion (rmask, ds390_rUmaskForOp (IC_COND (ic))); + goto ret; + } + + /* for the jumptable */ + if (ic->op == JUMPTABLE) + { + rmask = bitVectUnion (rmask, ds390_rUmaskForOp (IC_JTCOND (ic))); + + goto ret; + } + + /* of all other cases */ + if (IC_LEFT (ic)) + rmask = bitVectUnion (rmask, ds390_rUmaskForOp (IC_LEFT (ic))); + + + if (IC_RIGHT (ic)) + rmask = bitVectUnion (rmask, ds390_rUmaskForOp (IC_RIGHT (ic))); + + if (IC_RESULT (ic)) + rmask = bitVectUnion (rmask, ds390_rUmaskForOp (IC_RESULT (ic))); + +ret: + return rmask; +} + +/*-----------------------------------------------------------------*/ +/* createRegMask - for each instruction will determine the regsUsed */ +/*-----------------------------------------------------------------*/ +static void +createRegMask (eBBlock ** ebbs, int count) +{ + int i; + + /* for all blocks */ + for (i = 0; i < count; i++) + { + iCode *ic; + + if (ebbs[i]->noPath && (ebbs[i]->entryLabel != entryLabel && ebbs[i]->entryLabel != returnLabel)) + continue; + + /* for all instructions */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) + { + + int j; + + if (SKIP_IC2 (ic) || !ic->rlive) + continue; + + /* first mark the registers used in this + instruction */ + ic->rUsed = regsUsedIniCode (ic); + _G.funcrUsed = bitVectUnion (_G.funcrUsed, ic->rUsed); + + /* now create the register mask for those + registers that are in use : this is a + super set of ic->rUsed */ + ic->rMask = newBitVect (ds390_nRegs + 1); + + /* for all live Ranges alive at this point */ + for (j = 1; j < ic->rlive->size; j++) + { + symbol *sym; + int k; + + /* if not alive then continue */ + if (!bitVectBitValue (ic->rlive, j)) + continue; + + /* find the live range we are interested in */ + if (!(sym = hTabItemWithKey (liveRanges, j))) + { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "createRegMask cannot find live range"); + fprintf (stderr, "\tmissing live range: key=%d\n", j); + exit (0); + } +#if 0 + /* special case for ruonly */ + if (sym->ruonly && sym->liveFrom != sym->liveTo) + { + int size = getSize (sym->type); + int j = DPL_IDX; + for (k = 0; k < size; k++) + ic->rMask = bitVectSetBit (ic->rMask, j++); + continue; + } +#endif + /* if no register assigned to it */ + if (!sym->nRegs || sym->isspilt) + continue; + + /* for all the registers allocated to it */ + for (k = 0; k < sym->nRegs; k++) + if (sym->regs[k]) + ic->rMask = bitVectSetBit (ic->rMask, sym->regs[k]->rIdx); + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static char * +rematStr (symbol * sym) +{ + iCode *ic = sym->rematiCode; + int offset = 0; + static struct dbuf_s dbuf; + + while (1) + { + /* if plus adjust offset to right hand side */ + if (ic->op == '+') + { + offset += (int) operandLitValue (IC_RIGHT (ic)); + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + continue; + } + + /* if minus adjust offset to right hand side */ + if (ic->op == '-') + { + offset -= (int) operandLitValue (IC_RIGHT (ic)); + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + continue; + } + + /* cast then continue */ + if (IS_CAST_ICODE (ic)) + { + ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + continue; + } + /* we reached the end */ + break; + } + + dbuf_init (&dbuf, 128); + if (offset) + { + dbuf_printf (&dbuf, "(%s %c 0x%04x)", OP_SYMBOL (IC_LEFT (ic))->rname, offset >= 0 ? '+' : '-', abs (offset) & 0xffff); + } + else + { + dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname); + } + return dbuf_detach_c_str (&dbuf); +} + +/*-----------------------------------------------------------------*/ +/* regTypeNum - computes the type & number of registers required */ +/*-----------------------------------------------------------------*/ +static void +regTypeNum () +{ + symbol *sym; + int k; + iCode *ic; + + /* for each live range do */ + for (sym = hTabFirstItem (liveRanges, &k); sym; sym = hTabNextItem (liveRanges, &k)) + { + + /* if used zero times then no registers needed */ + if ((sym->liveTo - sym->liveFrom) == 0) + continue; + + + /* if the live range is a temporary */ + if (sym->isitmp) + { + + /* if the type is marked as a conditional */ + if (sym->regType == REG_CND) + continue; + + /* if used in return only then we don't + need registers */ + if (sym->ruonly || sym->accuse) + { + if (IS_AGGREGATE (sym->type) || sym->isptr) + sym->type = aggrToPtr (sym->type, FALSE); + continue; + } + + /* if the symbol has only one definition & + that definition is a get_pointer */ + if (bitVectnBitsOn (sym->defs) == 1 && + (ic = hTabItemWithKey (iCodehTab, + bitVectFirstBit (sym->defs))) && + POINTER_GET (ic) && !IS_BITVAR (sym->etype) && (aggrToPtrDclType (operandType (IC_LEFT (ic)), FALSE) == POINTER)) + { + + if (ptrPseudoSymSafe (sym, ic)) + { + char *s = rematStr (OP_SYMBOL (IC_LEFT (ic))); + ptrPseudoSymConvert (sym, ic, s); + Safe_free (s); + continue; + } + + /* if in data space or idata space then try to + allocate pointer register */ + + } + + /* if not then we require registers */ + sym->nRegs = ((IS_AGGREGATE (sym->type) || sym->isptr) ? + getSize (sym->type = aggrToPtr (sym->type, FALSE)) : getSize (sym->type)); + + if (sym->nRegs > 8) + { + fprintf (stderr, "allocated more than 8 or 0 registers for type "); + printTypeChain (sym->type, stderr); + fprintf (stderr, "\n"); + } + + /* determine the type of register required */ + if (sym->nRegs == 1 && IS_PTR (sym->type) && sym->uptr) + sym->regType = REG_PTR; + else if (IS_BIT (sym->type)) + sym->regType = REG_BIT; + else + sym->regType = REG_GPR; + } + else + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + sym->nRegs = 0; + } + +} + +/*-----------------------------------------------------------------*/ +/* freeAllRegs - mark all registers as free */ +/*-----------------------------------------------------------------*/ +static void +freeAllRegs () +{ + int i; + + for (i = 0; i < ds390_nRegs; i++) + regs390[i].isFree = 1; + + for (i = B0_IDX; i < ds390_nBitRegs; i++) + regs390[i].isFree = 1; +} + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal (sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* farSpacePackable - returns the packable icode for far variables */ +/*-----------------------------------------------------------------*/ +static iCode * +farSpacePackable (iCode * ic) +{ + iCode *dic; + + /* go thru till we find a definition for the + symbol on the right */ + for (dic = ic->prev; dic; dic = dic->prev) + { + /* if the definition is a call then no */ + if ((dic->op == CALL || dic->op == PCALL) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + { + return NULL; + } + + /* if shift by unknown amount then not */ + if ((dic->op == LEFT_OP || dic->op == RIGHT_OP) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + return NULL; + + /* if pointer get and size > 1 */ + if (POINTER_GET (dic) && getSize (aggrToPtr (operandType (IC_LEFT (dic)), FALSE)) > 1) + return NULL; + + if (POINTER_SET (dic) && getSize (aggrToPtr (operandType (IC_RESULT (dic)), FALSE)) > 1) + return NULL; + + /* if any tree is a true symbol in far space */ + if (IC_RESULT (dic) && IS_TRUE_SYMOP (IC_RESULT (dic)) && isOperandInFarSpace (IC_RESULT (dic))) + return NULL; + + if (IC_RIGHT (dic) && + IS_TRUE_SYMOP (IC_RIGHT (dic)) && + isOperandInFarSpace (IC_RIGHT (dic)) && !isOperandEqual (IC_RIGHT (dic), IC_RESULT (ic))) + return NULL; + + if (IC_LEFT (dic) && + IS_TRUE_SYMOP (IC_LEFT (dic)) && + isOperandInFarSpace (IC_LEFT (dic)) && !isOperandEqual (IC_LEFT (dic), IC_RESULT (ic))) + return NULL; + + if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (dic))) + { + if ((dic->op == LEFT_OP || dic->op == RIGHT_OP || dic->op == '-') && IS_OP_LITERAL (IC_RIGHT (dic))) + return NULL; + else + return dic; + } + } + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAssign - register reduction for assignment */ +/*-----------------------------------------------------------------*/ +static int +packRegsForAssign (iCode * ic, eBBlock * ebp) +{ + iCode *dic, *sic; + + if (!IS_ITEMP (IC_RIGHT (ic)) || OP_SYMBOL (IC_RIGHT (ic))->isind || OP_LIVETO (IC_RIGHT (ic)) > ic->seq) + { + return 0; + } + + /* if the true symbol is defined in far space or on stack + then we should not since this will increase register pressure */ +#if 0 + if (isOperandInFarSpace (IC_RESULT (ic))) + { + if ((dic = farSpacePackable (ic))) + goto pack; + else + return 0; + } +#else + if (isOperandInFarSpace (IC_RESULT (ic)) && !farSpacePackable (ic)) + { + return 0; + } +#endif + + /* find the definition of iTempNN scanning backwards if we find a + a use of the true symbol in before we find the definition then + we cannot */ + for (dic = ic->prev; dic; dic = dic->prev) + { + /* if there is a function call then don't pack it */ + if ((dic->op == CALL || dic->op == PCALL)) + { + dic = NULL; + break; + } + + if (SKIP_IC2 (dic)) + continue; + + if (IS_TRUE_SYMOP (IC_RESULT (dic)) && IS_OP_VOLATILE (IC_RESULT (dic))) + { + dic = NULL; + break; + } + + if (IS_SYMOP (IC_RESULT (dic)) && IC_RESULT (dic)->key == IC_RIGHT (ic)->key) + { + if (POINTER_SET (dic)) + dic = NULL; + + break; + } + + if (IS_SYMOP (IC_RIGHT (dic)) && + (IC_RIGHT (dic)->key == IC_RESULT (ic)->key || IC_RIGHT (dic)->key == IC_RIGHT (ic)->key)) + { + dic = NULL; + break; + } + + if (IS_SYMOP (IC_LEFT (dic)) && (IC_LEFT (dic)->key == IC_RESULT (ic)->key || IC_LEFT (dic)->key == IC_RIGHT (ic)->key)) + { + dic = NULL; + break; + } + + if (POINTER_SET (dic) && IC_RESULT (dic)->key == IC_RESULT (ic)->key) + { + dic = NULL; + break; + } + } + + if (!dic) + return 0; /* did not find */ + + /* if assignment then check that right is not a bit */ + if (ASSIGNMENT (ic) && !POINTER_SET (ic)) + { + sym_link *etype = operandType (IC_RESULT (dic)); + if (IS_BITFIELD (etype)) + { + /* if result is a bit too then it's ok */ + etype = operandType (IC_RESULT (ic)); + if (!IS_BITFIELD (etype)) + { + return 0; + } + } + } + /* if the result is on stack or iaccess then it must be + the same atleast one of the operands */ + if (OP_SYMBOL (IC_RESULT (ic))->onStack || OP_SYMBOL (IC_RESULT (ic))->iaccess) + { + + /* the operation has only one symbol + operator then we can pack */ + if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || (IC_RIGHT (dic) && !IS_SYMOP (IC_RIGHT (dic)))) + goto pack; + + if (!((IC_LEFT (dic) && + IC_RESULT (ic)->key == IC_LEFT (dic)->key) || (IC_RIGHT (dic) && IC_RESULT (ic)->key == IC_RIGHT (dic)->key))) + return 0; + } +pack: + /* found the definition */ + + /* delete from liverange table also + delete from all the points inbetween and the new + one */ + for (sic = dic; sic != ic; sic = sic->next) + { + bitVectUnSetBit (sic->rlive, IC_RESULT (ic)->key); + if (IS_ITEMP (IC_RESULT (dic))) + bitVectSetBit (sic->rlive, IC_RESULT (dic)->key); + } + + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + + IC_RESULT (dic) = IC_RESULT (ic); + + if (IS_ITEMP (IC_RESULT (dic)) && OP_SYMBOL (IC_RESULT (dic))->liveFrom > dic->seq) + { + OP_SYMBOL (IC_RESULT (dic))->liveFrom = dic->seq; + } + + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + return 1; +} + +/*------------------------------------------------------------------*/ +/* findAssignToSym : scanning backwards looks for first assig found */ +/*------------------------------------------------------------------*/ +static iCode * +findAssignToSym (operand * op, iCode * ic) +{ + iCode *dic; + + /* This routine is used to find sequences like + iTempAA = FOO; + ...; (intervening ops don't use iTempAA or modify FOO) + blah = blah + iTempAA; + + and eliminate the use of iTempAA, freeing up its register for + other uses. + */ + + for (dic = ic->prev; dic; dic = dic->prev) + { + + /* if definition by assignment */ + if (dic->op == '=' && !POINTER_SET (dic) && IC_RESULT (dic)->key == op->key +/* && IS_TRUE_SYMOP(IC_RIGHT(dic)) */ + ) + { + + /* we are interested only if defined in far space */ + /* or in stack space in case of + & - */ + + /* if assigned to a non-symbol then return + FALSE */ + if (!IS_SYMOP (IC_RIGHT (dic))) + return NULL; + + /* if the symbol is in far space then we should not */ + if (isOperandInFarSpace (IC_RIGHT (dic))) + return NULL; + + /* for + & - operations make sure that + if it is on the stack it is the same + as one of the three operands */ + if ((ic->op == '+' || ic->op == '-') && OP_SYMBOL (IC_RIGHT (dic))->onStack) + { + + if (IC_RESULT (ic)->key != IC_RIGHT (dic)->key && + IC_LEFT (ic)->key != IC_RIGHT (dic)->key && IC_RIGHT (ic)->key != IC_RIGHT (dic)->key) + return NULL; + } + + break; + + } + + /* if we find an usage then we cannot delete it */ + if (IC_LEFT (dic) && IC_LEFT (dic)->key == op->key) + return NULL; + + if (IC_RIGHT (dic) && IC_RIGHT (dic)->key == op->key) + return NULL; + + if (POINTER_SET (dic) && IC_RESULT (dic)->key == op->key) + return NULL; + } + + /* now make sure that the right side of dic + is not defined between ic & dic */ + if (dic) + { + iCode *sic = dic->next; + + for (; sic != ic; sic = sic->next) + if (IC_RESULT (sic) && IC_RESULT (sic)->key == IC_RIGHT (dic)->key) + return NULL; + } + + return dic; + + +} + +/*-----------------------------------------------------------------*/ +/* packRegsForSupport :- reduce some registers for support calls */ +/*-----------------------------------------------------------------*/ +static int +packRegsForSupport (iCode * ic, eBBlock * ebp) +{ + int change = 0; + + /* for the left & right operand :- look to see if the + left was assigned a true symbol in far space in that + case replace them */ + if (IS_ITEMP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->liveTo <= ic->seq) + { + iCode *dic = findAssignToSym (IC_LEFT (ic), ic); + iCode *sic; + + if (!dic) + goto right; + + /* found it we need to remove it from the + block */ + for (sic = dic; sic != ic; sic = sic->next) + { + bitVectUnSetBit (sic->rlive, IC_LEFT (ic)->key); + sic->rlive = bitVectSetBit (sic->rlive, IC_RIGHT (dic)->key); + } + + wassert (IS_SYMOP (IC_LEFT (ic))); + wassert (IS_SYMOP (IC_RIGHT (dic))); + OP_SYMBOL (IC_LEFT (ic)) = OP_SYMBOL (IC_RIGHT (dic)); + OP_SYMBOL (IC_LEFT (ic))->liveTo = ic->seq; + IC_LEFT (ic)->key = OP_KEY (IC_RIGHT (dic)); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + remiCodeFromeBBlock (ebp, dic); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + /* do the same for the right operand */ +right: + if (!change && IS_ITEMP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->liveTo <= ic->seq) + { + iCode *dic = findAssignToSym (IC_RIGHT (ic), ic); + iCode *sic; + + if (!dic) + return change; + + /* if this is a subtraction & the result + is a true symbol in far space then don't pack */ + if (ic->op == '-' && IS_TRUE_SYMOP (IC_RESULT (dic))) + { + sym_link *etype = getSpec (operandType (IC_RESULT (dic))); + if (IN_FARSPACE (SPEC_OCLS (etype))) + return change; + } + /* found it we need to remove it from the + block */ + for (sic = dic; sic != ic; sic = sic->next) + { + bitVectUnSetBit (sic->rlive, IC_RIGHT (ic)->key); + sic->rlive = bitVectSetBit (sic->rlive, IC_RIGHT (dic)->key); + } + + wassert (IS_SYMOP (IC_RIGHT (ic))); + wassert (IS_SYMOP (IC_RIGHT (dic))); + OP_SYMBOL (IC_RIGHT (ic)) = OP_SYMBOL (IC_RIGHT (dic)); + IC_RIGHT (ic)->key = OP_KEY (IC_RIGHT (dic)); + OP_SYMBOL (IC_RIGHT (ic))->liveTo = ic->seq; + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + return change; +} + + + +/*-------------------------------------------------------------------*/ +/* packRegsDPTRnuse - color live ranges that can go into extra DPTRS */ +/*-------------------------------------------------------------------*/ +static int +packRegsDPTRnuse (operand * op, unsigned dptr) +{ + symbol * opsym; + int i, key; + iCode *ic; + + if (!IS_SYMOP (op) || !IS_ITEMP (op)) + return 0; + opsym = OP_SYMBOL (op); + + if (opsym->remat || opsym->ruonly || opsym->dptr) + return 0; + + /* first check if any overlapping liverange has already been + assigned to this DPTR */ + if (opsym->clashes) + { + for (i = 0; i < opsym->clashes->size; i++) + { + symbol *sym; + if (bitVectBitValue (opsym->clashes, i)) + { + sym = hTabItemWithKey (liveRanges, i); + if (sym->dptr == dptr) + return 0; + } + } + } + + /* future for more dptrs */ + if (dptr > 1) + { + opsym->dptr = dptr; + return 1; + } + + /* DPTR1 is special since it is also used as a scratch by the backend. + so we walk thru the entire live range of this operand and make sure + DPTR1 will not be used by the backend. The logic here is to find out if + more than one operand in an icode is in far space then we give up : we + don't keep it live across functions for now + */ + + ic = hTabFirstItemWK (iCodeSeqhTab, opsym->liveFrom); + for (; ic && ic->seq <= opsym->liveTo; ic = hTabNextItem (iCodeSeqhTab, &key)) + { + int nfs = 0; + + if (ic->op == CALL || ic->op == PCALL) + return 0; + + /* single operand icode are ok */ + if (ic->op == IFX || ic->op == IPUSH) + continue; + + if (ic->op == SEND) + { + if (ic->argreg != 1) + return 0; + else + continue; + } + /* four special cases first */ + if (POINTER_GET (ic) && !isOperandEqual (IC_LEFT (ic), op) && /* pointer get */ + !OP_SYMBOL (IC_LEFT (ic))->ruonly && /* with result in far space */ + (isOperandInFarSpace2 (IC_RESULT (ic)) && !isOperandInReg (IC_RESULT (ic)))) + { + return 0; + } + + if (POINTER_GET (ic) && !isOperandEqual (IC_LEFT (ic), op) && /* pointer get */ + !OP_SYMBOL (IC_LEFT (ic))->ruonly && /* with left in far space */ + (isOperandInFarSpace2 (IC_LEFT (ic)) && !isOperandInReg (IC_LEFT (ic)))) + { + return 0; + } + + if (POINTER_SET (ic) && !isOperandEqual (IC_RESULT (ic), op) && /* pointer set */ + !OP_SYMBOL (IC_RESULT (ic))->ruonly && /* with right in far space */ + (isOperandInFarSpace2 (IC_RIGHT (ic)) && !isOperandInReg (IC_RIGHT (ic)))) + { + return 0; + } + + if (POINTER_SET (ic) && !isOperandEqual (IC_RESULT (ic), op) && /* pointer set */ + !OP_SYMBOL (IC_RESULT (ic))->ruonly && /* with result in far space */ + (isOperandInFarSpace2 (IC_RESULT (ic)) && !isOperandInReg (IC_RESULT (ic)))) + { + return 0; + } + + if (IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && /* if symbol operand */ + !isOperandEqual (IC_RESULT (ic), op) && /* not the same as this */ + ((isOperandInFarSpace2 (IC_RESULT (ic)) || /* in farspace or */ + OP_SYMBOL (IC_RESULT (ic))->onStack) && /* on the stack */ + !isOperandInReg (IC_RESULT (ic)))) /* and not in register */ + { + nfs++; + } + /* same for left */ + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && /* if symbol operand */ + !isOperandEqual (IC_LEFT (ic), op) && /* not the same as this */ + ((isOperandInFarSpace2 (IC_LEFT (ic)) || /* in farspace or */ + OP_SYMBOL (IC_LEFT (ic))->onStack) && /* on the stack */ + !isOperandInReg (IC_LEFT (ic)))) /* and not in register */ + { + nfs++; + } + /* same for right */ + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && /* if symbol operand */ + !isOperandEqual (IC_RIGHT (ic), op) && /* not the same as this */ + ((isOperandInFarSpace2 (IC_RIGHT (ic)) || /* in farspace or */ + OP_SYMBOL (IC_RIGHT (ic))->onStack) && /* on the stack */ + !isOperandInReg (IC_RIGHT (ic)))) /* and not in register */ + { + nfs++; + } + + // Check that no other ops in this range have been assigned to dptr1. + // I don't understand why this is not caught by the first check, above. + // But it isn't always, see bug 769624. + if (IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->dptr == 1)) + { + //fprintf(stderr, "dptr1 already in use in live range # 1\n"); + return 0; + } + + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && (OP_SYMBOL (IC_LEFT (ic))->dptr == 1)) + { + //fprintf(stderr, "dptr1 already in use in live range # 2\n"); + return 0; + } + + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && (OP_SYMBOL (IC_RIGHT (ic))->dptr == 1)) + { + //fprintf(stderr, "dptr1 already in use in live range # 3\n"); + return 0; + } + + if (nfs && IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) + return 0; + + if (nfs > 1) + return 0; + } + opsym->dptr = dptr; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* packRegsDPTRuse : - will reduce some registers for single Use */ +/*-----------------------------------------------------------------*/ +static iCode * +packRegsDPTRuse (operand * op) +{ + /* go thru entire liveRange of this variable & check for + other possible usage of DPTR, if we don't find it then + assign this to DPTR (ruonly) + */ + int i, key; + symbol *sym; + iCode *ic, *dic; + sym_link *type; + + if (!IS_SYMOP (op) || !IS_ITEMP (op)) + return NULL; + if (OP_SYMBOL (op)->remat || OP_SYMBOL (op)->ruonly) + return NULL; + + /* first check if any overlapping liverange has already been + assigned to DPTR */ + if (OP_SYMBOL (op)->clashes) + { + for (i = 0; i < OP_SYMBOL (op)->clashes->size; i++) + { + if (bitVectBitValue (OP_SYMBOL (op)->clashes, i)) + { + sym = hTabItemWithKey (liveRanges, i); + if (sym->ruonly) + return NULL; + } + } + } + + /* no then go thru this guys live range */ + dic = ic = hTabFirstItemWK (iCodeSeqhTab, OP_SYMBOL (op)->liveFrom); + for (; ic && ic->seq <= OP_SYMBOL (op)->liveTo; ic = hTabNextItem (iCodeSeqhTab, &key)) + { + if (SKIP_IC3 (ic)) + continue; + + /* if PCALL cannot be sure give up */ + if (ic->op == PCALL) + return NULL; + + /* if SEND & not the first parameter then give up */ + if (ic->op == SEND && ic->argreg != 1 && + ((isOperandInFarSpace2 (IC_LEFT (ic)) && !isOperandInReg (IC_LEFT (ic))) || isOperandEqual (op, IC_LEFT (ic)))) + return NULL; + + /* if CALL then make sure it is VOID || return value not used + or the return value is assigned to this one */ + if (ic->op == CALL) + { + if (OP_SYMBOL (IC_RESULT (ic))->liveTo == OP_SYMBOL (IC_RESULT (ic))->liveFrom) + continue; + type = operandType (IC_RESULT (ic)); + if (getSize (type) == 0 || isOperandEqual (op, IC_RESULT (ic))) + continue; + return NULL; + } + + /* special case of add with a [remat] */ + if (ic->op == '+' && + IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->remat && + isOperandInFarSpace2 (IC_RIGHT (ic)) && !isOperandInReg (IC_RIGHT (ic))) + { + return NULL; + } + + /* special cases */ + /* pointerGet */ + if (POINTER_GET (ic) && !isOperandEqual (IC_LEFT (ic), op) && getSize (operandType (IC_LEFT (ic))) > 1) + return NULL; + + /* pointerSet */ + if (POINTER_SET (ic) && !isOperandEqual (IC_RESULT (ic), op) && getSize (operandType (IC_RESULT (ic))) > 1) + return NULL; + + /* conditionals can destroy 'b' - make sure B wont + be used in this one */ + if ((IS_CONDITIONAL (ic) || ic->op == '*' || ic->op == '/' || + ic->op == LEFT_OP || ic->op == RIGHT_OP) && getSize (operandType (op)) > 3) + return NULL; + + /* if this is a cast to a bigger type */ + if (ic->op == CAST) + { + if (!IS_PTR (OP_SYM_TYPE (IC_RESULT (ic))) && + getSize (OP_SYM_TYPE (IC_RESULT (ic))) > getSize (OP_SYM_TYPE (IC_RIGHT (ic)))) + { + return NULL; + } + } + + /* general case */ + if (IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && + !isOperandEqual (IC_RESULT (ic), op) && + (((isOperandInFarSpace2 (IC_RESULT (ic)) || OP_SYMBOL (IC_RESULT (ic))->onStack) && + !isOperandInReg (IC_RESULT (ic))) || OP_SYMBOL (IC_RESULT (ic))->ruonly)) + return NULL; + + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && + !isOperandEqual (IC_RIGHT (ic), op) && + (OP_SYMBOL (IC_RIGHT (ic))->liveTo >= ic->seq || + IS_TRUE_SYMOP (IC_RIGHT (ic)) || + OP_SYMBOL (IC_RIGHT (ic))->ruonly) && + ((isOperandInFarSpace2 (IC_RIGHT (ic)) || OP_SYMBOL (IC_RIGHT (ic))->onStack) && !isOperandInReg (IC_RIGHT (ic)))) + return NULL; + + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && + !isOperandEqual (IC_LEFT (ic), op) && + (OP_SYMBOL (IC_LEFT (ic))->liveTo >= ic->seq || + IS_TRUE_SYMOP (IC_LEFT (ic)) || + OP_SYMBOL (IC_LEFT (ic))->ruonly) && + ((isOperandInFarSpace2 (IC_LEFT (ic)) || OP_SYMBOL (IC_LEFT (ic))->onStack) && !isOperandInReg (IC_LEFT (ic)))) + return NULL; + + if (IC_LEFT (ic) && IC_RIGHT (ic) && + IS_ITEMP (IC_LEFT (ic)) && IS_ITEMP (IC_RIGHT (ic)) && + (isOperandInFarSpace2 (IC_LEFT (ic)) && !isOperandInReg (IC_LEFT (ic))) && + (isOperandInFarSpace2 (IC_RIGHT (ic)) && !isOperandInReg (IC_RIGHT (ic)))) + return NULL; + } + OP_SYMBOL (op)->ruonly = 1; + if (OP_SYMBOL (op)->usl.spillLoc) + { + if (OP_SYMBOL (op)->spillA) + OP_SYMBOL (op)->usl.spillLoc->allocreq--; + OP_SYMBOL (op)->usl.spillLoc = NULL; + } + return dic; +} + +/*-----------------------------------------------------------------*/ +/* isBitwiseOptimizable - requirements of JEAN LOUIS VERN */ +/*-----------------------------------------------------------------*/ +static bool +isBitwiseOptimizable (iCode * ic) +{ + sym_link *ltype = getSpec (operandType (IC_LEFT (ic))); + sym_link *rtype = getSpec (operandType (IC_RIGHT (ic))); + + /* bitwise operations are considered optimizable + under the following conditions (Jean-Louis VERN) + + x & lit + bit & bit + bit & x + bit ^ bit + bit ^ x + x ^ lit + x | lit + bit | bit + bit | x + */ + if (IS_LITERAL (rtype) || (IS_BITVAR (ltype) && IN_BITSPACE (SPEC_OCLS (ltype)))) + return TRUE; + else + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* packRegsForAccUse - pack registers for acc use */ +/*-----------------------------------------------------------------*/ +static void +packRegsForAccUse (iCode * ic) +{ + iCode *uic; + + /* if this is an aggregate, e.g. a one byte char array */ + if (IS_AGGREGATE (operandType (IC_RESULT (ic)))) + { + return; + } + + /* if we are calling a reentrant function that has stack parameters */ + if (ic->op == CALL && IFFUNC_ISREENT (operandType (IC_LEFT (ic))) && FUNC_HASSTACKPARM (operandType (IC_LEFT (ic)))) + return; + + if (ic->op == PCALL && + IFFUNC_ISREENT (operandType (IC_LEFT (ic))->next) && FUNC_HASSTACKPARM (operandType (IC_LEFT (ic))->next)) + return; + + /* if + or - then it has to be one byte result */ + if ((ic->op == '+' || ic->op == '-') && getSize (operandType (IC_RESULT (ic))) > 1) + return; + + /* if shift operation make sure right side is not a literal */ + if (ic->op == RIGHT_OP && (isOperandLiteral (IC_RIGHT (ic)) || getSize (operandType (IC_RESULT (ic))) > 1)) + return; + + if (ic->op == LEFT_OP && (isOperandLiteral (IC_RIGHT (ic)) || getSize (operandType (IC_RESULT (ic))) > 1)) + return; + + if (IS_BITWISE_OP (ic) && getSize (operandType (IC_RESULT (ic))) > 1) + return; + + + /* has only one definition */ + if (bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) > 1) + return; + + /* has only one use */ + if (bitVectnBitsOn (OP_USES (IC_RESULT (ic))) > 1) + return; + + /* and the usage immediately follows this iCode */ + if (!(uic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_USES (IC_RESULT (ic)))))) + return; + + if (ic->next != uic) + return; + + /* if it is a conditional branch then we definitely can */ + if (uic->op == IFX) + goto accuse; + + if (uic->op == JUMPTABLE) + return; + + /* if the usage is not is an assignment + or an arithmetic / bitwise / shift operation then not */ + if (POINTER_SET (uic) && getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1) + return; + + if (uic->op != '=' && !IS_ARITHMETIC_OP (uic) && !IS_BITWISE_OP (uic) && uic->op != LEFT_OP && uic->op != RIGHT_OP) + return; + + /* if used in ^ operation then make sure right is not a + literal */ + if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic))) + return; + + /* if shift operation make sure right side is not a literal */ + if (uic->op == RIGHT_OP && (isOperandLiteral (IC_RIGHT (uic)) || getSize (operandType (IC_RESULT (uic))) > 1)) + return; + + if (uic->op == LEFT_OP && (isOperandLiteral (IC_RIGHT (uic)) || getSize (operandType (IC_RESULT (uic))) > 1)) + return; + + /* make sure that the result of this icode is not on the + stack, since acc is used to compute stack offset */ + if (isOperandOnStack (IC_RESULT (uic))) + return; + + /* if either one of them in far space then we cannot */ + if ((IS_TRUE_SYMOP (IC_LEFT (uic)) && + isOperandInFarSpace (IC_LEFT (uic))) || (IS_TRUE_SYMOP (IC_RIGHT (uic)) && isOperandInFarSpace (IC_RIGHT (uic)))) + return; + + /* if the usage has only one operand then we can */ + if (IC_LEFT (uic) == NULL || IC_RIGHT (uic) == NULL) + goto accuse; + + /* make sure this is on the left side if not + a '+' since '+' is commutative */ + if (ic->op != '+' && IC_LEFT (uic)->key != IC_RESULT (ic)->key) + return; + + /* if the other one is not on stack then we can */ + if (IC_LEFT (uic)->key == IC_RESULT (ic)->key && + (IS_ITEMP (IC_RIGHT (uic)) || (IS_TRUE_SYMOP (IC_RIGHT (uic)) && !OP_SYMBOL (IC_RIGHT (uic))->onStack))) + goto accuse; + + if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key && + (IS_ITEMP (IC_LEFT (uic)) || (IS_TRUE_SYMOP (IC_LEFT (uic)) && !OP_SYMBOL (IC_LEFT (uic))->onStack))) + goto accuse; + + return; + +accuse: + OP_SYMBOL (IC_RESULT (ic))->accuse = 1; + +} + +/*-----------------------------------------------------------------*/ +/* packForPush - heuristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void +packForPush (iCode * ic, eBBlock ** ebpp, int blockno) +{ + iCode *dic, *lic; + bitVect *dbv; + struct eBBlock *ebp = ebpp[blockno]; + int disallowHiddenAssignment = 0; + + if ((ic->op != IPUSH && ic->op != SEND) || !IS_ITEMP (IC_LEFT (ic))) + return; + + /* must have only definition & one usage */ + if (bitVectnBitsOn (OP_DEFS (IC_LEFT (ic))) != 1 || bitVectnBitsOn (OP_USES (IC_LEFT (ic))) != 1) + return; + + /* find the definition */ + if (!(dic = hTabItemWithKey (iCodehTab, bitVectFirstBit (OP_DEFS (IC_LEFT (ic)))))) + return; + + if (dic->op != '=' || POINTER_SET (dic)) + return; + + if (dic->eBBlockNum != ic->eBBlockNum) + return; + + if (IS_OP_VOLATILE (IC_RIGHT (dic))) + return; + + if ((IS_SYMOP (IC_RIGHT (dic)) && OP_SYMBOL (IC_RIGHT (dic))->addrtaken) || isOperandGlobal (IC_RIGHT (dic))) + disallowHiddenAssignment = 1; + + /* make sure the right side does not have any definitions + inbetween */ + dbv = OP_DEFS (IC_RIGHT (dic)); + for (lic = ic; lic && lic != dic; lic = lic->prev) + { + if (bitVectBitValue (dbv, lic->key)) + return; + if (disallowHiddenAssignment && (lic->op == CALL || lic->op == PCALL || POINTER_SET (lic))) + return; + } + /* make sure they have the same type */ + if (IS_SPEC (operandType (IC_LEFT (ic)))) + { + sym_link *itype = operandType (IC_LEFT (ic)); + sym_link *ditype = operandType (IC_RIGHT (dic)); + + if (SPEC_USIGN (itype) != SPEC_USIGN (ditype) || SPEC_LONG (itype) != SPEC_LONG (ditype)) + return; + } + /* extend the live range of replaced operand if needed */ + if (OP_SYMBOL (IC_RIGHT (dic))->liveTo < OP_SYMBOL (IC_LEFT (ic))->liveTo) + { + OP_SYMBOL (IC_RIGHT (dic))->liveTo = OP_SYMBOL (IC_LEFT (ic))->liveTo; + OP_SYMBOL (IC_RIGHT (dic))->clashes = + bitVectUnion (OP_SYMBOL (IC_RIGHT (dic))->clashes, OP_SYMBOL (IC_LEFT (ic))->clashes); + } + for (lic = ic; lic && lic != dic; lic = lic->prev) + { + bitVectUnSetBit (lic->rlive, IC_LEFT (ic)->key); + if (IS_ITEMP (IC_RIGHT (dic))) + bitVectSetBit (lic->rlive, IC_RIGHT (dic)->key); + } + if (IS_ITEMP (IC_RIGHT (dic))) + OP_USES (IC_RIGHT (dic)) = bitVectSetBit (OP_USES (IC_RIGHT (dic)), ic->key); + /* we now we know that it has one & only one def & use + and the that the definition is an assignment */ + IC_LEFT (ic) = IC_RIGHT (dic); + + remiCodeFromeBBlock (ebp, dic); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); +} + +/*-----------------------------------------------------------------*/ +/* packRegisters - does some transformations to reduce register */ +/* pressure */ +/*-----------------------------------------------------------------*/ +static void +packRegisters (eBBlock ** ebpp, int blockno) +{ + iCode *ic; + int change = 0; + eBBlock *ebp = ebpp[blockno]; + + while (1) + { + change = 0; + + /* look for assignments of the form */ + /* iTempNN = TRueSym (someoperation) SomeOperand */ + /* .... */ + /* TrueSym := iTempNN:1 */ + for (ic = ebp->sch; ic; ic = ic->next) + { + /* find assignment of the form TrueSym := iTempNN:1 */ + if (ic->op == '=' && !POINTER_SET (ic)) + change += packRegsForAssign (ic, ebp); + } + + if (!change) + break; + } + + for (ic = ebp->sch; ic; ic = ic->next) + { + /* Fix for bug #979599: */ + /* P0 &= ~1; */ + + /* Look for two subsequent iCodes with */ + /* iTemp := _c; */ + /* _c = iTemp & op; */ + /* and replace them by */ + /* iTemp := _c; */ + /* _c = _c & op; */ + if ((ic->op == BITWISEAND || ic->op == '|' || ic->op == '^') && + ic->prev && + ic->prev->op == '=' && + IS_ITEMP (IC_LEFT (ic)) && + IC_LEFT (ic) == IC_RESULT (ic->prev) && isOperandEqual (IC_RESULT (ic), IC_RIGHT (ic->prev))) + { + iCode *ic_prev = ic->prev; + symbol *prev_result_sym = OP_SYMBOL (IC_RESULT (ic_prev)); + + ReplaceOpWithCheaperOp (&IC_LEFT (ic), IC_RESULT (ic)); + if (IC_RESULT (ic_prev) != IC_RIGHT (ic)) + { + bitVectUnSetBit (OP_USES (IC_RESULT (ic_prev)), ic->key); + if ( /*IS_ITEMP (IC_RESULT (ic_prev)) && */ + prev_result_sym->liveTo == ic->seq) + { + prev_result_sym->liveTo = ic_prev->seq; + } + } + bitVectSetBit (OP_USES (IC_RESULT (ic)), ic->key); + + bitVectSetBit (ic->rlive, IC_RESULT (ic)->key); + + if (bitVectIsZero (OP_USES (IC_RESULT (ic_prev)))) + { + bitVectUnSetBit (ic->rlive, IC_RESULT (ic)->key); + bitVectUnSetBit (OP_DEFS (IC_RESULT (ic_prev)), ic_prev->key); + remiCodeFromeBBlock (ebp, ic_prev); + hTabDeleteItem (&iCodehTab, ic_prev->key, ic_prev, DELETE_ITEM, NULL); + } + } + + /* if this is an itemp & result of an address of a true sym + then mark this as rematerialisable */ + if (ic->op == ADDRESS_OF && + IS_ITEMP (IC_RESULT (ic)) && + IS_TRUE_SYMOP (IC_LEFT (ic)) && bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && !OP_SYMBOL (IC_LEFT (ic))->onStack) + { + + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + + } + + /* if this is an itemp & used as a pointer + & assigned to a literal then remat */ + if (IS_ASSIGN_ICODE (ic) && + IS_ITEMP (IC_RESULT (ic)) && bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && isOperandLiteral (IC_RIGHT (ic))) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* if straight assignment then carry remat flag if + this is the only definition */ + if (ic->op == '=' && !POINTER_SET (ic) && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->remat && !IS_CAST_ICODE (OP_SYMBOL (IC_RIGHT (ic))->rematiCode) && !isOperandGlobal (IC_RESULT (ic)) && /* due to bug 1618050 */ + bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1 && + !OP_SYMBOL (IC_RESULT (ic))->addrtaken) + { + OP_SYMBOL (IC_RESULT (ic))->remat = OP_SYMBOL (IC_RIGHT (ic))->remat; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = OP_SYMBOL (IC_RIGHT (ic))->rematiCode; + } + + /* if cast to a generic pointer & the pointer being + cast is remat, then we can remat this cast as well */ + if (ic->op == CAST && IS_SYMOP (IC_RIGHT (ic)) && !OP_SYMBOL (IC_RESULT (ic))->isreqv && OP_SYMBOL (IC_RIGHT (ic))->remat && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && + !OP_SYMBOL (IC_RESULT (ic))->addrtaken) + { + sym_link *to_type = operandType (IC_LEFT (ic)); + sym_link *from_type = operandType (IC_RIGHT (ic)); + if (IS_GENPTR (to_type) && IS_PTR (from_type)) + { + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + } + + /* if this is a +/- operation with a rematerizable + then mark this as rematerializable as well */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->remat && + (!IS_SYMOP (IC_RIGHT (ic)) || !IS_CAST_ICODE (OP_SYMBOL (IC_RIGHT (ic))->rematiCode)) && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && IS_OP_LITERAL (IC_RIGHT (ic)))) + { + + //int i = operandLitValue(IC_RIGHT(ic)); + OP_SYMBOL (IC_RESULT (ic))->remat = 1; + OP_SYMBOL (IC_RESULT (ic))->rematiCode = ic; + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* mark the pointer usages */ + if (POINTER_SET (ic) && IS_SYMOP (IC_RESULT (ic))) + OP_SYMBOL (IC_RESULT (ic))->uptr = 1; + + if (POINTER_GET (ic) && IS_SYMOP (IC_LEFT (ic))) + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + + if (ic->op == RETURN && IS_SYMOP (IC_LEFT (ic))) + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + + if (ic->op == RECEIVE && ic->argreg == 1 && IS_SYMOP (IC_RESULT (ic)) && getSize (operandType (IC_RESULT (ic))) <= 3) + OP_SYMBOL (IC_RESULT (ic))->uptr = 1; + + if (ic->op == SEND && ic->argreg == 1 && + IS_SYMOP (IC_LEFT (ic)) && getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) <= 3) + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + + if (!SKIP_IC2 (ic)) + { + /* if we are using a symbol on the stack + then we should say ds390_ptrRegReq */ + if (options.useXstack && ic->parmPush && (ic->op == IPUSH || ic->op == IPOP)) + ds390_ptrRegReq++; + if (ic->op == IFX && IS_SYMOP (IC_COND (ic))) + ds390_ptrRegReq += ((OP_SYMBOL (IC_COND (ic))->onStack ? !options.stack10bit : 0) + + OP_SYMBOL (IC_COND (ic))->iaccess + (SPEC_OCLS (OP_SYMBOL (IC_COND (ic))->etype) == idata)); + else if (ic->op == JUMPTABLE && IS_SYMOP (IC_JTCOND (ic))) + ds390_ptrRegReq += ((OP_SYMBOL (IC_JTCOND (ic))->onStack ? !options.stack10bit : 0) + + OP_SYMBOL (IC_JTCOND (ic))->iaccess + (SPEC_OCLS (OP_SYMBOL (IC_JTCOND (ic))->etype) == idata)); + else + { + if (IS_SYMOP (IC_LEFT (ic))) + ds390_ptrRegReq += ((OP_SYMBOL (IC_LEFT (ic))->onStack ? !options.stack10bit : 0) + + OP_SYMBOL (IC_LEFT (ic))->iaccess + (SPEC_OCLS (OP_SYMBOL (IC_LEFT (ic))->etype) == idata)); + if (IS_SYMOP (IC_RIGHT (ic))) + ds390_ptrRegReq += ((OP_SYMBOL (IC_RIGHT (ic))->onStack ? !options.stack10bit : 0) + + OP_SYMBOL (IC_RIGHT (ic))->iaccess + + (SPEC_OCLS (OP_SYMBOL (IC_RIGHT (ic))->etype) == idata)); + if (IS_SYMOP (IC_RESULT (ic))) + ds390_ptrRegReq += ((OP_SYMBOL (IC_RESULT (ic))->onStack ? !options.stack10bit : 0) + + OP_SYMBOL (IC_RESULT (ic))->iaccess + + (SPEC_OCLS (OP_SYMBOL (IC_RESULT (ic))->etype) == idata)); + } + } + + /* if the condition of an if instruction + is defined in the previous instruction and + this is the only usage then + mark the itemp as a conditional */ + if ((IS_CONDITIONAL (ic) || + (IS_BITWISE_OP (ic) && isBitwiseOptimizable (ic))) && + ic->next && ic->next->op == IFX && + bitVectnBitsOn (OP_USES (IC_RESULT (ic))) == 1 && + isOperandEqual (IC_RESULT (ic), IC_COND (ic->next)) && OP_SYMBOL (IC_RESULT (ic))->liveTo <= ic->next->seq) + { + OP_SYMBOL (IC_RESULT (ic))->regType = REG_CND; + continue; + } +#if 1 + /* reduce for support function calls */ + if (ic->supportRtn || ic->op == '+' || ic->op == '-') + packRegsForSupport (ic, ebp); +#endif + /* some cases the redundant moves can + can be eliminated for return statements . Can be elminated for the first SEND */ + if ((ic->op == RETURN || + ((ic->op == SEND || ic->op == RECEIVE) && ic->argreg == 1)) && !isOperandInFarSpace (IC_LEFT (ic)) && !options.model) + { + + packRegsDPTRuse (IC_LEFT (ic)); + } + + if (ic->op == CALL) + { + sym_link *ftype = operandType (IC_LEFT (ic)); + if (getSize (operandType (IC_RESULT (ic))) <= 4 && !IFFUNC_ISBUILTIN (ftype)) + { + packRegsDPTRuse (IC_RESULT (ic)); + } + } + + /* if pointer set & left has a size more than + one and right is not in far space */ + if (POINTER_SET (ic) && + !isOperandInFarSpace2 (IC_RIGHT (ic)) && + IS_SYMOP (IC_RESULT (ic)) && + !OP_SYMBOL (IC_RESULT (ic))->remat && + !IS_OP_RUONLY (IC_RIGHT (ic)) && getSize (aggrToPtr (operandType (IC_RESULT (ic)), FALSE)) > 1) + { + + packRegsDPTRuse (IC_RESULT (ic)); + } + + /* if pointer get */ + if (POINTER_GET (ic) && + !isOperandInFarSpace2 (IC_RESULT (ic)) && + IS_SYMOP (IC_LEFT (ic)) && + !OP_SYMBOL (IC_LEFT (ic))->remat && + !IS_OP_RUONLY (IC_RESULT (ic)) && getSize (aggrToPtr (operandType (IC_LEFT (ic)), FALSE)) > 1) + { + + packRegsDPTRuse (IC_LEFT (ic)); + } + + /* if this is a cast for intergral promotion then + check if it's the only use of the definition of the + operand being casted/ if yes then replace + the result of that arithmetic operation with + this result and get rid of the cast */ + if (ic->op == CAST) + { + sym_link *fromType = operandType (IC_RIGHT (ic)); + sym_link *toType = operandType (IC_LEFT (ic)); + + if (IS_INTEGRAL (fromType) && IS_INTEGRAL (toType) && + getSize (fromType) != getSize (toType) && SPEC_USIGN (fromType) == SPEC_USIGN (toType)) + { + + iCode *dic = packRegsDPTRuse (IC_RIGHT (ic)); + if (dic) + { + if (IS_ARITHMETIC_OP (dic)) + { + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (dic))->defs, dic->key); + IC_RESULT (dic) = IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } + else + OP_SYMBOL (IC_RIGHT (ic))->ruonly = 0; + } + } + else + { + + /* if the type from and type to are the same + then if this is the only use then packit */ + if (compareType (operandType (IC_RIGHT (ic)), operandType (IC_LEFT (ic))) == 1) + { + iCode *dic = packRegsDPTRuse (IC_RIGHT (ic)); + if (dic) + { + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); + IC_RESULT (dic) = IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + bitVectUnSetBit (OP_SYMBOL (IC_RESULT (ic))->defs, ic->key); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + OP_DEFS (IC_RESULT (dic)) = bitVectSetBit (OP_DEFS (IC_RESULT (dic)), dic->key); + ic = ic->prev; + } + } + } + } + + /* pack for PUSH + iTempNN := (some variable in farspace) V1 + push iTempNN ; + ------------- + push V1 + */ + if (ic->op == IPUSH || ic->op == SEND) + { + packForPush (ic, ebpp, blockno); + } + + /* pack registers for accumulator use, when the + result of an arithmetic or bit wise operation + has only one use, that use is immediately following + the defintion and the using iCode has only one + operand or has two operands but one is literal & + the result of that operation is not on stack then + we can leave the result of this operation in acc:b + combination */ + if ((IS_ARITHMETIC_OP (ic) + || IS_CONDITIONAL (ic) + || IS_BITWISE_OP (ic) + || ic->op == LEFT_OP || ic->op == RIGHT_OP + || (ic->op == ADDRESS_OF && isOperandOnStack (IC_LEFT (ic)))) && + IS_ITEMP (IC_RESULT (ic)) && getSize (operandType (IC_RESULT (ic))) <= 2) + + packRegsForAccUse (ic); + } +} + +/*------------------------------------------------------------------------*/ +/* positionRegsReverse - positioning registers from end to begin to avoid */ +/* conflict among result, left and right operands in some extrem cases */ +/*------------------------------------------------------------------------*/ +static void +positionRegsReverse (eBBlock ** ebbs, int count) +{ + int i; + iCode *ic; + + for (i = count - 1; i >= 0; i--) + for (ic = ebbs[i]->ech; ic; ic = ic->prev) + { + if (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && OP_SYMBOL (IC_LEFT (ic))->nRegs && + IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic))->nRegs) + { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_LEFT (ic)), 1); + } + if (IC_RIGHT (ic) && IS_SYMOP (IC_RIGHT (ic)) && OP_SYMBOL (IC_RIGHT (ic))->nRegs && + IC_RESULT (ic) && IS_SYMOP (IC_RESULT (ic)) && OP_SYMBOL (IC_RESULT (ic))->nRegs) + { + positionRegs (OP_SYMBOL (IC_RESULT (ic)), OP_SYMBOL (IC_RIGHT (ic)), 1); + } + } +} + +/*-----------------------------------------------------------------*/ +/* assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void +ds390_assignRegisters (ebbIndex * ebbi) +{ + eBBlock **ebbs = ebbi->bbOrder; + int count = ebbi->count; + iCode *ic; + int i; + + setToNull ((void *) &_G.funcrUsed); + setToNull ((void *) &_G.regAssigned); + setToNull ((void *) &_G.totRegAssigned); + setToNull ((void *) &_G.funcrUsed); + ds390_ptrRegReq = _G.stackExtend = _G.dataExtend = 0; + if ((currFunc && IFFUNC_ISREENT (currFunc->type)) || options.stackAuto) + { + ds390_nBitRegs = 8; + } + else + { + ds390_nBitRegs = 0; + } + ds390_nRegs = 12 + ds390_nBitRegs; + _G.allBitregs = findAllBitregs (); + + if (options.model != MODEL_FLAT24) + options.stack10bit = 0; + /* change assignments this will remove some + live ranges reducing some register pressure */ + for (i = 0; i < count; i++) + packRegisters (ebbs, i); + + /* liveranges probably changed by register packing + so we compute them again */ + recomputeLiveRanges (ebbs, count, FALSE); + + if (options.dump_i_code) + dumpEbbsToFileExt (DUMP_PACK, ebbi); + + /* first determine for each live range the number of + registers & the type of registers required for each */ + regTypeNum (); + + /* and serially allocate registers */ + serialRegAssign (ebbs, count); + + ds390_nRegs = 8; + freeAllRegs (); + fillGaps (); + positionRegsReverse (ebbs, count); + ds390_nRegs = 12 + ds390_nBitRegs; + + /* if stack was extended then tell the user */ + if (_G.stackExtend) + { +/* werror(W_TOOMANY_SPILS,"stack", */ +/* _G.stackExtend,currFunc->name,""); */ + _G.stackExtend = 0; + } + + if (_G.dataExtend) + { +/* werror(W_TOOMANY_SPILS,"data space", */ +/* _G.dataExtend,currFunc->name,""); */ + _G.dataExtend = 0; + } + + /* after that create the register mask + for each of the instruction */ + createRegMask (ebbs, count); + + /* redo that offsets for stacked automatic variables */ + if (currFunc) + redoStackOffsets (); + + /* make sure r0 & r1 are flagged as used if they might be used */ + /* as pointers */ + if (currFunc && ds390_ptrRegReq) + { + currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, R0_IDX); + currFunc->regsUsed = bitVectSetBit (currFunc->regsUsed, R1_IDX); + } + + if (options.dump_i_code) + { + dumpEbbsToFileExt (DUMP_RASSGN, ebbi); + dumpLiveRanges (DUMP_LRANGE, liveRanges); + } + + /* do the overlaysegment stuff SDCCmem.c */ + doOverlays (ebbs, count); + + /* now get back the chain */ + ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); + + gen390Code (ic); + + /* free up any _G.stackSpil locations allocated */ + applyToSet (_G.stackSpil, deallocStackSpil); + _G.slocNum = 0; + setToNull ((void *) &_G.stackSpil); + setToNull ((void *) &_G.spiltSet); + /* mark all registers as free */ + ds390_nRegs = 8; + freeAllRegs (); + + return; +} diff --git a/src/ds390/ralloc.h b/src/ds390/ralloc.h new file mode 100644 index 0000000..e9dae2e --- /dev/null +++ b/src/ds390/ralloc.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + + SDCCralloc.h - header file register allocation + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1998) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ +#include "SDCCicode.h" +#include "SDCCBBlock.h" +#ifndef SDCCRALLOC_H +#define SDCCRALLOC_H 1 + +enum +{ + R2_IDX = 0, R3_IDX, R4_IDX, R5_IDX, + R6_IDX, R7_IDX, R0_IDX, R1_IDX, + DPL_IDX, DPH_IDX, DPX_IDX, B_IDX, + B0_IDX, B1_IDX, B2_IDX, B3_IDX, + B4_IDX, B5_IDX, B6_IDX, B7_IDX, + X8_IDX, X9_IDX, X10_IDX, X11_IDX, + X12_IDX, CND_IDX, + A_IDX, DPL1_IDX, DPH1_IDX, + DPX1_IDX, DPS_IDX, AP_IDX, + END_IDX +}; + + +#define REG_PTR 0x01 +#define REG_GPR 0x02 +#define REG_CND 0x04 +#define REG_BIT 0x08 +/* definition for the registers */ +typedef struct reg_info +{ + short type; /* can have value + REG_GPR, REG_PTR or REG_CND */ + short rIdx; /* index into register table */ + short otype; + char *name; /* name */ + char *dname; /* name when direct access needed */ + char *base; /* base address */ + short offset; /* offset from the base */ + unsigned isFree:1; /* is currently unassigned */ + int print; /* needs to be printed */ +} +reg_info; +extern reg_info regs390[]; + +reg_info *ds390_regWithIdx (int); + +bitVect *ds390_rUmaskForOp (operand * op); +bitVect *ds390_allBitregs (void); + +extern int ds390_ptrRegReq; +extern int ds390_nRegs; +extern int ds390_nBitRegs; + +#endif |
