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/avr | |
| 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/avr')
| -rw-r--r-- | src/avr/Makefile.in | 8 | ||||
| -rw-r--r-- | src/avr/avr.vcxproj | 149 | ||||
| -rw-r--r-- | src/avr/avr.vcxproj.filters | 43 | ||||
| -rw-r--r-- | src/avr/gen.c | 5361 | ||||
| -rw-r--r-- | src/avr/gen.h | 84 | ||||
| -rw-r--r-- | src/avr/main.c | 290 | ||||
| -rw-r--r-- | src/avr/main.h | 8 | ||||
| -rw-r--r-- | src/avr/peeph.def | 1701 | ||||
| -rw-r--r-- | src/avr/ralloc.c | 2307 | ||||
| -rw-r--r-- | src/avr/ralloc.h | 68 |
10 files changed, 10019 insertions, 0 deletions
diff --git a/src/avr/Makefile.in b/src/avr/Makefile.in new file mode 100644 index 0000000..bd13649 --- /dev/null +++ b/src/avr/Makefile.in @@ -0,0 +1,8 @@ +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/avr/avr.vcxproj b/src/avr/avr.vcxproj new file mode 100644 index 0000000..70753b5 --- /dev/null +++ b/src/avr/avr.vcxproj @@ -0,0 +1,149 @@ +<?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>{493CAAA0-FCCC-455F-9127-706B20C3D4C9}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|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)'=='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>
+ <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>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">port</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">port</TargetName>
+ </PropertyGroup>
+ <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/avr.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/avr.bsc</OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <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/avr.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/avr.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 %(FullPath) >peeph.rul</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">gawk -f ../SDCCpeeph.awk %(FullPath) >peeph.rul</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">peeph.rul;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">peeph.rul;%(Outputs)</Outputs>
+ </CustomBuild>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/src/avr/avr.vcxproj.filters b/src/avr/avr.vcxproj.filters new file mode 100644 index 0000000..4de7d59 --- /dev/null +++ b/src/avr/avr.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>{07fa3e89-f797-4389-ac20-0323d39b8b1e}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{e6af9e78-fabb-498f-8f93-cd15d05e83d6}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Custom Build">
+ <UniqueIdentifier>{7ccacde4-11c6-4300-83aa-79d51e17bcf7}</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/avr/gen.c b/src/avr/gen.c new file mode 100644 index 0000000..8f04afe --- /dev/null +++ b/src/avr/gen.c @@ -0,0 +1,5361 @@ +/*------------------------------------------------------------------------- + gen.c - source file for code generation for ATMEL AVR + + Copyright (C) 2000, 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. +-------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "SDCCglobl.h" +#include "newalloc.h" + +#include "common.h" +#include "SDCCpeeph.h" +#include "ralloc.h" +#include "gen.h" + +char *aopLiteral (value * val, int offset); +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; + +char *fReturnAVR[] = { "r16", "r17", "r18", "r19" }; +unsigned fAVRReturnSize = 4; /* shared with ralloc.c */ +char **fAVRReturn = fReturnAVR; +static char *larray[4] = { ">", "<", "hlo8", "hhi8" }; + +static struct { + short xPushed; + short zPushed; + short accInUse; + short inLine; + short debugLine; + short nRegsSaved; + set *sendSet; +} _G; + +extern int avr_ptrRegReq; +extern int avr_nRegs; +extern struct dbuf_s *codeOutBuf; +#define RESULTONSTACK(x) \ + (IC_RESULT(x) && IC_RESULT(x)->aop && \ + IC_RESULT(x)->aop->type == AOP_STK ) + +#define MOVR0(x) if (strcmp(x,"r0")) emitcode("mov","r0,%s",x); +#define MOVR24(x) if (strcmp(x,"r24")) emitcode("mov","r24,%s",x); +#define AOP_ISHIGHREG(a,n) (a->type == AOP_REG && a->aopu.aop_reg[n] && a->aopu.aop_reg[n]->rIdx >= R16_IDX) +#define CLRC emitcode("clc","") +#define SETC emitcode("stc","") +#define MOVA(x) +#define IS_REGIDX(a,r) (a->type == AOP_REG && a->aopu.aop_reg[0]->rIdx == r) + +static lineNode *lineHead = NULL; +static lineNode *lineCurr = NULL; + +#define LSB 0 +#define MSB16 1 +#define MSB24 2 +#define MSB32 3 + +#if 0 +// PENDING: Unused. +/*-----------------------------------------------------------------*/ +/* reAdjustPreg - points a register back to where it should */ +/*-----------------------------------------------------------------*/ +static void +reAdjustPreg (asmop * aop) +{ + int size; + + aop->coff = 0; + if ((size = aop->size) <= 1) + return; + size--; + switch (aop->type) { + case AOP_X: + case AOP_Z: + emitcode ("sbiw", "%s,%d", aop->aopu.aop_ptr->name, size); + break; + } + +} + +/*-----------------------------------------------------------------*/ +/* outBitC - output a bit C */ +/*-----------------------------------------------------------------*/ +static void +outBitC (operand * result) +{ + emitcode ("clr", "r0"); + emitcode ("rol", "r0"); + outAcc (result); +} + +/*-----------------------------------------------------------------*/ +/* inExcludeList - return 1 if the string is in exclude Reg list */ +/*-----------------------------------------------------------------*/ +static bool +inExcludeList (char *s) +{ + int i = 0; + + if (options.excludeRegs[i] && + STRCASECMP (options.excludeRegs[i], "none") == 0) + return FALSE; + + for (i = 0; options.excludeRegs[i]; i++) { + if (options.excludeRegs[i] && + STRCASECMP (s, options.excludeRegs[i]) == 0) + return TRUE; + } + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* 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 (ic->op == LABEL && IC_LABEL (ic)->key == key) { + /* printf("findLabelBackwards = %d\n", count); */ + return count; + } + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* addSign - complete with sign */ +/*-----------------------------------------------------------------*/ +static void +addSign (operand * result, int offset, int sign) +{ + int size = (getDataSize (result) - offset); + if (size > 0) { + if (sign) { + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + while (size--) + aopPut (AOP (result), "a", offset++); + } + else + while (size--) + aopPut (AOP (result), zero, offset++); + } +} + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* outAcc - output Acc */ +/*-----------------------------------------------------------------*/ +static void +outAcc (operand * result) +{ + int size, offset; + size = getDataSize (result); + if (size) { + aopPut (AOP (result), "r0", 0); + size--; + offset = 1; + /* unsigned or positive */ + while (size--) { + aopPut (AOP (result), zero, offset++); + } + } +} + +#endif // End Unused code section + +/*-----------------------------------------------------------------*/ +/* emitcode - writes the code into a file : for now it is simple */ +/*-----------------------------------------------------------------*/ +static void +emitcode (char *inst, char *fmt, ...) +{ + va_list ap; + const char *lbp, *lb; + + va_start (ap, fmt); + + lbp = lb = format_opcode (inst, va_list ap); + + while (isspace ((unsigned char)*lbp)) + lbp++; + + if (lbp && *lbp) + { + lineCurr = (lineCurr ? connectLine (lineCurr, newLineNode (lb)) : (lineHead = newLineNode (lb))); + lineCurr->isInline = _G.inLine; + lineCurr->isDebug = _G.debugLine; + } + + va_end (ap); +} + +/*-----------------------------------------------------------------*/ +/* avr_emitDebuggerSymbol - associate the current code location */ +/* with a debugger symbol */ +/*-----------------------------------------------------------------*/ +void +avr_emitDebuggerSymbol (const char * debugSym) +{ + _G.debugLine = 1; + emitcode ("", "%s ==.", debugSym); + _G.debugLine = 0; +} + +/*-----------------------------------------------------------------*/ +/* hasInc - operand is incremented before any other use */ +/*-----------------------------------------------------------------*/ +static iCode * +hasInc (operand *op, iCode *ic) +{ + sym_link *type = operandType(op); + sym_link *retype = getSpec (type); + iCode *lic = ic->next; + int isize ; + + if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL; + if (IS_AGGREGATE(type->next)) return NULL; + isize = getSize(type->next); + 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; + } + lic = lic->next; + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* getFreePtr - returns X or Z whichever is free or can be pushed */ +/*-----------------------------------------------------------------*/ +static regs * +getFreePtr (iCode * ic, asmop ** aopp, bool result, bool zonly) +{ + bool xiu = FALSE, ziu = FALSE; + bool xou = FALSE, zou = FALSE; + + /* the logic: if x & z used in the instruction + then we are in trouble otherwise */ + + /* first check if x & z are used by this + instruction, in which case we are in trouble */ + if ((xiu = bitVectBitValue (ic->rUsed, X_IDX)) && + (ziu = bitVectBitValue (ic->rUsed, Z_IDX))) { + goto endOfWorld; + } + + xou = bitVectBitValue (ic->rMask, X_IDX); + zou = bitVectBitValue (ic->rMask, Z_IDX); + + /* if no usage of Z then return it */ + if (!ziu && !zou) { + ic->rUsed = bitVectSetBit (ic->rUsed, Z_IDX); + (*aopp)->type = AOP_Z; + + (*aopp)->aop_ptr2 = avr_regWithIdx (R31_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx (R30_IDX); + } + + /* if no usage of X then return it */ + if (!xiu && !xou && !zonly) { + ic->rUsed = bitVectSetBit (ic->rUsed, X_IDX); + (*aopp)->type = AOP_X; + + (*aopp)->aop_ptr2 = avr_regWithIdx (R27_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx (R26_IDX); + } + + /* if z not used then */ + + if (!ziu) { + /* push it if not already pushed */ + if (!_G.zPushed) { + emitcode ("push", "%s", + avr_regWithIdx (R30_IDX)->dname); + emitcode ("push", "%s", + avr_regWithIdx (R31_IDX)->dname); + _G.zPushed++; + } + + ic->rUsed = bitVectSetBit (ic->rUsed, Z_IDX); + (*aopp)->type = AOP_Z; + (*aopp)->aop_ptr2 = avr_regWithIdx (R31_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx (R30_IDX); + } + + /* now we know they both have usage */ + /* if x not used in this instruction */ + if (!xiu && !zonly) { + /* push it if not already pushed */ + if (!_G.xPushed) { + emitcode ("push", "%s", + avr_regWithIdx (R26_IDX)->dname); + emitcode ("push", "%s", + avr_regWithIdx (R27_IDX)->dname); + _G.xPushed++; + } + + ic->rUsed = bitVectSetBit (ic->rUsed, X_IDX); + (*aopp)->type = AOP_X; + + (*aopp)->aop_ptr2 = avr_regWithIdx (R27_IDX); + return (*aopp)->aopu.aop_ptr = avr_regWithIdx (R26_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; + } + + /* other wise this is true end of the world */ + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "getFreePtr should never reach here"); + exit (0); +} + +/*-----------------------------------------------------------------*/ +/* newAsmop - creates a new asmOp */ +/*-----------------------------------------------------------------*/ +static asmop * +newAsmop (short type) +{ + asmop *aop; + + aop = Safe_calloc (1, sizeof (asmop)); + aop->type = type; + return aop; +} + +/*-----------------------------------------------------------------*/ +/* pointerCode - returns the code for a pointer type */ +/*-----------------------------------------------------------------*/ +static int +pointerCode (sym_link * etype) +{ + + return PTR_TYPE (SPEC_OCLS (etype)); + +} + +/*-----------------------------------------------------------------*/ +/* aopForSym - for a true symbol */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForSym (iCode * ic, symbol * sym, bool result) +{ + asmop *aop; + memmap *space = SPEC_OCLS (sym->etype); + + /* if already has one */ + if (sym->aop) + return sym->aop; + + /* assign depending on the storage class */ + /* if it is on the stack */ + if (sym->onStack) { + sym->aop = aop = newAsmop (0); + aop->size = getSize (sym->type); + + /* we can use std / ldd instruction */ + if (sym->stack > 0 + && (sym->stack + getSize (sym->type) - 1) <= 63) { + aop->type = AOP_STK_D; + aop->aopu.aop_stk = sym->stack; + return aop; + } + + /* otherwise get a free pointer register X/Z */ + aop->aopu.aop_ptr = getFreePtr (ic, &aop, result, FALSE); + + /* now assign the address of the variable to + the pointer register */ + if (aop->type != AOP_STK) { + emitcode ("movw", "%s,r28", aop->aopu.aop_ptr->name); + if (sym->stack < 0) { + if ((sym->stack - _G.nRegsSaved) > -63) { + emitcode ("sbiw", "%s,0x%02x", + aop->aopu.aop_ptr->name, + (sym->stack - + _G.nRegsSaved)); + } + else { + emitcode ("subi", "%s,<(%d)", + aop->aopu.aop_ptr->name, + sym->stack - _G.nRegsSaved); + emitcode ("sbci", "%s,>(%d)", + aop->aop_ptr2->name, + sym->stack - _G.nRegsSaved); + } + } + else { + if (sym->stack <= 63) { + emitcode ("adiw", "%s,0x%02x", + aop->aopu.aop_ptr->name, + sym->stack); + } + else { + emitcode ("subi", "%s,<(-%d)", + aop->aopu.aop_ptr->name, + sym->stack); + emitcode ("sbci", "%s,>(-%d)", + aop->aop_ptr2->name, + sym->stack); + } + } + } + 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->aop = aop = newAsmop (AOP_IMMD); + aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1); + strcpy (aop->aopu.aop_immd, sym->rname); + aop->size = FPTRSIZE; + return aop; + } + + /* only remaining is code / eeprom which will need pointer reg */ + /* if it is in code space */ + + sym->aop = aop = newAsmop (0); + + if (IN_CODESPACE (space)) + aop->code = 1; + + aop->aopu.aop_ptr = getFreePtr (ic, &aop, result, aop->code); + aop->size = getSize (sym->type); + emitcode ("ldi", "%s,<(%s)", aop->aopu.aop_ptr->name, sym->rname); + emitcode ("ldi", "%s,>(%s)", aop->aop_ptr2); + + return aop; +} + +/*-----------------------------------------------------------------*/ +/* aopForRemat - rematerialzes an object */ +/*-----------------------------------------------------------------*/ +static asmop * +aopForRemat (symbol * sym) +{ + iCode *ic = sym->rematiCode; + asmop *aop = newAsmop (AOP_IMMD); + int val = 0; + + for (;;) { + if (ic->op == '+') + val += (int) operandLitValue (IC_RIGHT (ic)); + else if (ic->op == '-') + val -= (int) operandLitValue (IC_RIGHT (ic)); + else + break; + + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + } + + if (val) + sprintf (buffer, "(%s %c 0x%04x)", + OP_SYMBOL (IC_LEFT (ic))->rname, + val >= 0 ? '+' : '-', abs (val) & 0xffff); + else + strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname); + + aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1); + strcpy (aop->aopu.aop_immd, buffer); + return aop; +} + +/*-----------------------------------------------------------------*/ +/* 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 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 (strcmp (sym1->rname, sym2->rname) == 0) + 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; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* sameRegs - two asmops have the same registers */ +/*-----------------------------------------------------------------*/ +static bool +sameRegs (asmop * aop1, asmop * aop2) +{ + int i; + + if (aop1 == aop2) + return TRUE; + + if (aop1->type != AOP_REG || aop2->type != AOP_REG) + 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; +} + +/*-----------------------------------------------------------------*/ +/* isRegPair - for size 2 if this operand has a register pair */ +/*-----------------------------------------------------------------*/ +static int +isRegPair (asmop * aop) +{ + if (!aop || aop->size < 2) + return 0; + if (aop->type == AOP_X || aop->type == AOP_Z) + return 1; + if (aop->type != AOP_REG) + return 0; + if ( ((aop->aopu.aop_reg[1]->rIdx - aop->aopu.aop_reg[0]->rIdx) == 1) && + (aop->aopu.aop_reg[0]->rIdx & 1) == 0) + + return 1; + return 0; +} + +/*-----------------------------------------------------------------*/ +/* allHigh - all registers are high registers */ +/*-----------------------------------------------------------------*/ +static int allHigh (asmop * aop) +{ + int i; + + if (aop->type == AOP_X || aop->type == AOP_Z) + return 1; + if (aop->type != AOP_REG) + return 0; + for (i=0; i < aop->size ; i++ ) + if (aop->aopu.aop_reg[i]->rIdx < R16_IDX) return 0; + return 1; +} + +/*-----------------------------------------------------------------*/ +/* aopOp - allocates an asmop for an operand : */ +/*-----------------------------------------------------------------*/ +static void +aopOp (operand * op, iCode * ic, bool result) +{ + 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) + return; + + /* if the underlying symbol has a aop */ + if (IS_SYMOP (op) && OP_SYMBOL (op)->aop) { + op->aop = OP_SYMBOL (op)->aop; + return; + } + + /* if this is a true symbol */ + if (IS_TRUE_SYMOP (op)) { + op->aop = aopForSym (ic, OP_SYMBOL (op), result); + return; + } + + /* this is a temporary : this has + only four 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) { + aop = op->aop = sym->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) { + + asmop *oldAsmOp = NULL; + + /* rematerialize it NOW */ + if (sym->remat) { + sym->aop = op->aop = aop = aopForRemat (sym); + aop->size = getSize (sym->type); + return; + } + + if (sym->accuse) { + assert ("ACC_USE cannot happen in AVR\n"); + } + + if (sym->ruonly) { + int i; + aop = op->aop = sym->aop = newAsmop (AOP_STR); + aop->size = getSize (sym->type); + for (i = 0; i < (int) fAVRReturnSize; i++) + aop->aopu.aop_str[i] = fAVRReturn[i]; + return; + } + + /* else spill location */ + if (sym->usl.spillLoc && 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); + 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; + } + + /* 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; + + if (aop->freed) + goto dealloc; + + aop->freed = 1; + + /* depending on the asmop type only three cases need work AOP_RO + , AOP_R1 && AOP_STK */ + switch (aop->type) { + case AOP_X: + if (_G.xPushed) { + if (pop) { + emitcode ("pop", "r26"); + emitcode ("pop", "r27"); + _G.xPushed--; + } + } + bitVectUnSetBit (ic->rUsed, X_IDX); + break; + + case AOP_Z: + if (_G.zPushed) { + if (pop) { + emitcode ("pop", "r30"); + emitcode ("pop", "r31"); + _G.zPushed--; + } + } + bitVectUnSetBit (ic->rUsed, Z_IDX); + break; + + case AOP_STK: + { + int sz = aop->size; + int stk = aop->aopu.aop_stk + aop->size; + bitVectUnSetBit (ic->rUsed, X_IDX); + bitVectUnSetBit (ic->rUsed, Z_IDX); + + getFreePtr (ic, &aop, FALSE, 0); + + emitcode ("movw", "%s,r28"); + if (stk) { + if (stk <= 63 && stk > 0) { + emitcode ("adiw", "%s,0x%02x", + aop->aopu.aop_ptr->name, + stk + 1); + } + else { + emitcode ("subi", "%s,<(%d)", + aop->aopu.aop_ptr->name, + -(stk + 1)); + emitcode ("sbci", "%s,>(%d)", + aop->aop_ptr2->name, + -(stk + 1)); + } + } + + while (sz--) { + emitcode ("pop", "r24"); + emitcode ("st", "-%s,r24", + aop->type == AOP_X ? "X" : "Z"); + if (!sz) + break; + } + op->aop = aop; + freeAsmop (op, NULL, ic, TRUE); + if (_G.xPushed) { + emitcode ("pop", "r26"); + emitcode ("pop", "r27"); + _G.xPushed--; + } + + if (_G.zPushed) { + emitcode ("pop", "r30"); + emitcode ("pop", "r31"); + _G.zPushed--; + } + } + } + + 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; + } + } +} + +/*-----------------------------------------------------------------*/ +/* aopGet - for fetching value of the aop */ +/*-----------------------------------------------------------------*/ +static char * +aopGet (asmop * aop, int offset) +{ + char *s = buffer; + char *rs; + + /* offset is greater than + size then zero */ + if (offset > (aop->size - 1) && aop->type != AOP_LIT) + return zero; + + /* depending on type */ + switch (aop->type) { + + case AOP_X: + if (offset > aop->coff) { + emitcode ("adiw", "%s,%d", aop->aopu.aop_ptr->name, + offset - aop->coff); + } + + if (offset < aop->coff) { + emitcode ("sbiw", "%s,%d", aop->aopu.aop_ptr->name, + aop->coff - offset); + } + + aop->coff = offset; + emitcode ("ld", "%s,x", + (rs = ((offset & 1) ? "r25" : "r24"))); + return rs; + + case AOP_Z: + if (aop->code) { + if (offset > aop->coff) { + emitcode ("adiw", "r30,%d", + offset - aop->coff); + } + else { + emitcode ("sbiw", "r30,%d", + aop->coff - offset); + } + emitcode ("lpm", "%s,z", + (rs = ((offset & 1) ? "r25" : "r24"))); + } + else { + /* we can use lds */ + if (offset > aop->coff) { + emitcode ("ldd", "%s,z+%d", + (rs = + ((offset & 1) ? "r25" : "r24")), + offset - aop->coff); + } + else { + emitcode ("sbiw", "%s,%d", + aop->aopu.aop_ptr->name, + aop->coff - offset); + aop->coff = offset; + emitcode ("ld", "%s,z", + (rs = + ((offset & 1) ? "r25" : "r24"))); + } + } + return rs; + + case AOP_IMMD: + + emitcode ("lds", "%s,(%s)+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_immd, offset); + return rs; + + case AOP_DIR: + emitcode ("lds", "%s,(%s)+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_dir, offset); + return rs; + + case AOP_REG: + return aop->aopu.aop_reg[offset]->name; + + case AOP_CRY: + assert ("cannot be in bit space AOP_CRY\n"); + break; + + case AOP_LIT: + s = aopLiteral (aop->aopu.aop_lit, offset); + emitcode ("ldi", "%s,<(%s)", + (rs = ((offset & 1) ? "r24" : "r25")), s); + return rs; + + case AOP_STR: + aop->coff = offset; + return aop->aopu.aop_str[offset]; + + case AOP_STK_D: + emitcode ("ldd", "%s,Y+%d", + (rs = ((offset & 1) ? "r25" : "r24")), + aop->aopu.aop_stk + offset); + return rs; + } + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "aopget got unsupported aop->type"); + exit (0); +} + +/*-----------------------------------------------------------------*/ +/* aopPut - puts a string for a aop */ +/*-----------------------------------------------------------------*/ +static void +aopPut (asmop * aop, char *s, int offset) +{ + char *d = buffer; + + if (aop->size && offset > (aop->size - 1)) { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "aopPut got offset > aop->size"); + exit (0); + } + + /* will assign value to value */ + /* depending on where it is ofcourse */ + switch (aop->type) { + case AOP_DIR: + if (offset) { + sprintf (d, "(%s)+%d", aop->aopu.aop_dir, offset); + } + else { + sprintf (d, "%s", aop->aopu.aop_dir); + } + + emitcode ("sts", "%s,%s", d, s); + break; + + case AOP_REG: + if (toupper ((unsigned char)*s) != 'R') { + if (s == zero) { + emitcode ("clr", "%s", + aop->aopu.aop_reg[offset]->name); + } + else { + emitcode ("ldi", "r25,%s", s); + emitcode ("mov", "%s,r35", + aop->aopu.aop_reg[offset]->name); + } + } + else { + if (strcmp (aop->aopu.aop_reg[offset]->name, s)) { + emitcode ("mov", "%s,%s", + aop->aopu.aop_reg[offset]->name, s); + } + } + break; + + case AOP_X: + if (offset > aop->coff) { + emitcode ("adiw", "%s,%d", aop->aopu.aop_ptr->name, + offset - aop->coff); + } + + if (offset < aop->coff) { + emitcode ("sbiw", "%s,%d", aop->aopu.aop_ptr->name, + aop->coff - offset); + } + + aop->coff = offset; + emitcode ("st", "x,%s", s); + break; + + case AOP_Z: + if (aop->code) { + if (offset > aop->coff) { + emitcode ("adiw", "r30,%d", + offset - aop->coff); + } + else { + emitcode ("sbiw", "r30,%d", + aop->coff - offset); + } + emitcode ("lpm", "%s,z", s); + } + else { + /* we can use lds */ + if (offset > aop->coff) { + emitcode ("sdd", "z+%d,%s", + offset - aop->coff, s); + } + else { + emitcode ("sbiw", "%s,%d", + aop->aopu.aop_ptr->name, + aop->coff - offset); + aop->coff = offset; + emitcode ("ld", "%s,z", s); + } + } + break; + + case AOP_STK: + emitcode ("push", "%s", s); + break; + + case AOP_CRY: + /* if used only for a condition code check */ + assert (toupper ((unsigned char)*s) == 'R'); + if (offset == 0) { + emitcode ("xrl", "r0,r0"); + emitcode ("cpi", "%s,0", s); + } + else { + emitcode ("cpc", "r0,%s", s); + } + break; + + case AOP_STR: + aop->coff = offset; + if (strcmp (aop->aopu.aop_str[offset], s)) + emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], + s); + break; + + case AOP_STK_D: + emitcode ("std", "y+%d,%s", offset, s); + break; + + default: + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "aopPut got unsupported aop->type"); + exit (0); + } + +} + +#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_X || \ + AOP_TYPE(x) == AOP_Z)) +#define AOP_INPREG(x) (x && (x->type == AOP_REG && \ + ((x->aopu.aop_reg[0] == avr_regWithIdx(R26_IDX) && x->aopu.aop_reg[1] == avr_regWithIdx(R27_IDX)) || \ + (x->aopu.aop_reg[0] == avr_regWithIdx(R30_IDX) && x->aopu.aop_reg[1] == avr_regWithIdx(R31_IDX)) ))) +#define AOP_ISX(x) (x && (x->type == AOP_REG && \ + ((x->aopu.aop_reg[0] == avr_regWithIdx(R26_IDX) && x->aopu.aop_reg[1] == avr_regWithIdx(R27_IDX))))) +#define AOP_ISZ(x) (x && (x->type == AOP_REG && \ + ((x->aopu.aop_reg[0] == avr_regWithIdx(R30_IDX) && x->aopu.aop_reg[1] == avr_regWithIdx(R31_IDX))))) + +/*-----------------------------------------------------------------*/ +/* genNotFloat - generates not for float operations */ +/*-----------------------------------------------------------------*/ +static void +genNotFloat (operand * op, operand * res) +{ + int size, offset; + char *l; + symbol *tlbl; + + /* we will put 127 in the first byte of + the result */ + aopPut (AOP (res), "127", 0); + size = AOP_SIZE (op) - 1; + offset = 1; + + l = aopGet (op->aop, offset++); + MOVR0 (l); + + while (size--) { + emitcode ("or", "R0,%s", aopGet (op->aop, offset++)); + } + tlbl = newiTempLabel (NULL); + + tlbl = newiTempLabel (NULL); + aopPut (res->aop, zero, 1); + emitcode ("cpi", "r0,0"); + emitcode ("breq", "L%05d", tlbl->key); + aopPut (res->aop, one, 1); + emitcode ("", "L%05d:", tlbl->key); + + size = res->aop->size - 2; + offset = 2; + /* put zeros in the rest */ + while (size--) + aopPut (res->aop, zero, offset++); +} + +/*-----------------------------------------------------------------*/ +/* opIsGptr: returns non-zero if the passed operand is */ +/* a generic pointer type. */ +/*-----------------------------------------------------------------*/ +static int +opIsGptr (operand * op) +{ + sym_link *type = operandType (op); + + if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type)) { + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* getDataSize - get the operand data size */ +/*-----------------------------------------------------------------*/ +static int +getDataSize (operand * op) +{ + int size; + 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; +} + +/*-----------------------------------------------------------------*/ +/* toBoolean - emit code for orl a,operator(sizeop) */ +/*-----------------------------------------------------------------*/ +static void +toBoolean (operand * oper, char *r, bool clr) +{ + int size = AOP_SIZE (oper); + int offset = 0; + if (clr) { + emitcode ("clr", "%s", r); + while (size--) + emitcode ("or", "%s,%s", r, aopGet (AOP (oper), offset++)); + } else { + size--; + emitcode("mov","%s,%s",r,aopGet (AOP (oper), offset++)); + if (size) while (size--) emitcode ("or", "%s,%s", r, aopGet (AOP (oper), offset++)); + } +} + + +/*-----------------------------------------------------------------*/ +/* genNot - generate code for ! operation */ +/*-----------------------------------------------------------------*/ +static void +genNot (iCode * ic) +{ + symbol *tlbl; + sym_link *optype = operandType (IC_LEFT (ic)); + int size, offset = 1; + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + + /* if type float then do float */ + if (IS_FLOAT (optype)) { + genNotFloat (IC_LEFT (ic), IC_RESULT (ic)); + goto release; + } + emitcode ("clr", "r24"); + tlbl = newiTempLabel (NULL); + size = AOP_SIZE (IC_LEFT (ic)); + offset = 0; + if (size == 1) { + emitcode ("cpse", "%s,r24", aopGet (AOP (IC_LEFT (ic)), 0)); + } + else { + while (size--) { + if (offset) + emitcode ("cpc", "%s,r24", + aopGet (AOP (IC_LEFT (ic)), + offset)); + else + emitcode ("cpi", "%s,0", + aopGet (AOP (IC_LEFT (ic)), + offset)); + offset++; + } + emitcode ("bne", "L%05d", tlbl->key); + } + emitcode ("ldi", "r24,1"); + emitcode ("", "L%05d:", tlbl->key); + aopPut (AOP (IC_RESULT (ic)), "r24", 0); + size = AOP_SIZE (IC_RESULT (ic)) - 1; + offset = 1; + while (size--) + aopPut (AOP (IC_RESULT (ic)), zero, offset++); + + + release: + /* release the aops */ + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genCpl - generate code for complement */ +/*-----------------------------------------------------------------*/ +static void +genCpl (iCode * ic) +{ + int offset = 0; + int size; + int samer; + + /* assign asmOps to operand & result */ + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + samer = sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))); + size = AOP_SIZE (IC_RESULT (ic)); + while (size--) { + char *l = aopGet (AOP (IC_LEFT (ic)), offset); + if (samer) { + emitcode ("com", "%s", l); + } + else { + aopPut (AOP (IC_RESULT (ic)), l, offset); + emitcode ("com", "%s", + aopGet (AOP (IC_RESULT (ic)), offset)); + } + offset++; + } + + /* release the aops */ + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genUminusFloat - unary minus for floating points */ +/*-----------------------------------------------------------------*/ +static void +genUminusFloat (operand * op, operand * result) +{ + int size, offset = 0; + char *l; + /* for this we just need to flip the + first it then copy the rest in place */ + size = AOP_SIZE (op) - 1; + l = aopGet (AOP (op), 3); + + emitcode ("ldi", "r24,0x80"); + if (sameRegs (AOP (op), AOP (result))) { + emitcode ("eor", "%s,r24", l); + } + else { + aopPut (AOP (result), l, 3); + emitcode ("eor", "%s,r24", aopGet (AOP (result), 3)); + } + while (size--) { + aopPut (AOP (result), aopGet (AOP (op), offset), offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* genUminus - unary minus code generation */ +/*-----------------------------------------------------------------*/ +static void +genUminus (iCode * ic) +{ + int offset, size; + sym_link *optype, *rtype; + int samer; + + /* assign asmops */ + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + + optype = operandType (IC_LEFT (ic)); + rtype = operandType (IC_RESULT (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; + samer = sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))); + if (size == 1) { + if (samer) { + emitcode ("neg", "%s", + aopGet (AOP (IC_LEFT (ic)), 0)); + } + else { + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_LEFT (ic)), 0), 0); + emitcode ("neg", "%s", + aopGet (AOP (IC_RESULT (ic)), 0)); + } + } + else { + offset = size - 1; + while (size--) { + char *l = aopGet (AOP (IC_LEFT (ic)), offset); + if (!samer) { + aopPut (AOP (IC_RESULT (ic)), l, offset); + l = aopGet (AOP (IC_RESULT (ic)), offset); + } + if (offset) + emitcode ("com", "%s", l); + else + emitcode ("neg", "%s", l); + offset--; + } + size = AOP_SIZE (IC_LEFT (ic)) - 1; + offset = 1; + while (size--) { + emitcode ("sbci", "%s,0xff", + aopGet (AOP (IC_RESULT (ic)), offset++)); + } + } + + /* 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))))) { + symbol *tlbl = newiTempLabel (NULL); + emitcode ("clr", "r0"); + emitcode ("brcc", "L%05d", tlbl->key); + emitcode ("com", "r0"); + emitcode ("", "L%05d:", tlbl->key); + while (size--) + aopPut (AOP (IC_RESULT (ic)), "r0", offset++); + } + + release: + /* release the aops */ + freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* assignResultValue - */ +/*-----------------------------------------------------------------*/ +static void +assignResultValue (operand * oper) +{ + int offset = 0; + int size = AOP_SIZE (oper); + while (size--) { + aopPut (AOP (oper), fAVRReturn[offset], offset); + offset++; + } +} + +/*-----------------------------------------------------------------*/ +/* saveZreg - if indirect call then save z-pointer register */ +/*-----------------------------------------------------------------*/ +static void +saveZreg (iCode * ic) +{ + /* only if live accross this call */ + if (ic->regsSaved == 0 && + (bitVectBitValue (ic->rMask, R30_IDX) || + bitVectBitValue (ic->rMask, R31_IDX))) { + ic->regsSaved = 1; + emitcode ("push", "r30"); + emitcode ("push", "r31"); + } +} + +/*-----------------------------------------------------------------*/ +/* popZreg - restore values of zreg */ +/*-----------------------------------------------------------------*/ +static void +popZreg (iCode * ic) +{ + if (ic->regsSaved) { + emitcode ("pop", "r31"); + emitcode ("pop", "r30"); + } +} + +/*-----------------------------------------------------------------*/ +/* genIpush - genrate code for pushing this gets a little complex */ +/*-----------------------------------------------------------------*/ +static void +genIpush (iCode * ic) +{ + int size, offset = 0; + char *l; + + + if (!ic->parmPush) { + /* and the item is spilt then do nothing */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt) + return; + } + else { + iCode *lic; + for (lic = ic->next; lic; lic = lic->next) + if (lic->op == PCALL) + break; + if (lic) + saveZreg (lic); + } + + /* this is a paramter push */ + aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + while (size--) { + l = aopGet (AOP (IC_LEFT (ic)), offset++); + emitcode ("push", "%s", l); + } + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genIpop - recover the registers: can happen only for spilling */ +/*-----------------------------------------------------------------*/ +static void +genIpop (iCode * ic) +{ + int size, offset; + + + /* if the temp was not pushed then */ + if (OP_SYMBOL (IC_LEFT (ic))->isspilt) + return; + + aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + offset = (size - 1); + while (size--) + emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--)); + + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCall - generates a call statement */ +/*-----------------------------------------------------------------*/ +static void +genCall (iCode * ic) +{ + + /* if send set is not empty then assign */ + if (_G.sendSet) { + iCode *sic; + int rnum = 16; + for (sic = setFirstItem (_G.sendSet); sic; + sic = setNextItem (_G.sendSet)) { + int size, offset = 0; + aopOp (IC_LEFT (sic), sic, FALSE); + size = AOP_SIZE (IC_LEFT (sic)); + while (size--) { + char *l = + aopGet (AOP (IC_LEFT (sic)), offset); + char *b = buffer; + sprintf (buffer, "r%d", rnum++); + if (strcmp (l, b)) + emitcode ("mov", "%s,%s", b, l); + offset++; + } + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + _G.sendSet = NULL; + } + /* make the call */ + emitcode ("call", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ? + OP_SYMBOL (IC_LEFT (ic))->rname : + OP_SYMBOL (IC_LEFT (ic))->name)); + + /* if we need assign a result value */ + if ((IS_ITEMP (IC_RESULT (ic)) && + (OP_SYMBOL (IC_RESULT (ic))->nRegs || + OP_SYMBOL (IC_RESULT (ic))->spildir)) || + IS_TRUE_SYMOP (IC_RESULT (ic))) { + + aopOp (IC_RESULT (ic), ic, FALSE); + assignResultValue (IC_RESULT (ic)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + /* adjust the stack for parameters if required */ + if (ic->parmBytes) { + if (ic->parmBytes > 63) { + emitcode ("sbiw", "r28,%d", ic->parmBytes); + } + else { + emitcode ("subi", "r28,<(%d)", + ic->parmBytes); + emitcode ("sbci", "r29,>(%d)", + ic->parmBytes); + } + } + +} + +/*-----------------------------------------------------------------*/ +/* genPcall - generates a call by pointer statement */ +/*-----------------------------------------------------------------*/ +static void +genPcall (iCode * ic) +{ + + if (!ic->regsSaved) + saveZreg (ic); + + aopOp (IC_LEFT (ic), ic, FALSE); + emitcode ("mov", "r30", aopGet (AOP (IC_LEFT (ic)), 0)); + emitcode ("mov", "r31", aopGet (AOP (IC_RIGHT (ic)), 0)); + freeAsmop (IC_LEFT (ic), NULL, ic, TRUE); + + /* if send set is not empty the assign */ + if (_G.sendSet) { + iCode *sic; + int rnum = 16; + for (sic = setFirstItem (_G.sendSet); sic; + sic = setNextItem (_G.sendSet)) { + int size, offset = 0; + aopOp (IC_LEFT (sic), sic, FALSE); + size = AOP_SIZE (IC_LEFT (sic)); + while (size--) { + char *l = + aopGet (AOP (IC_LEFT (sic)), offset); + char *b = buffer; + sprintf (b, "r%d", rnum++); + if (strcmp (l, b)) + emitcode ("mov", "%s,%s", b, l); + offset++; + } + freeAsmop (IC_LEFT (sic), NULL, sic, TRUE); + } + _G.sendSet = NULL; + } + + emitcode ("icall", ""); + + /* if we need assign a result value */ + if ((IS_ITEMP (IC_RESULT (ic)) && + (OP_SYMBOL (IC_RESULT (ic))->nRegs || + OP_SYMBOL (IC_RESULT (ic))->spildir)) || + IS_TRUE_SYMOP (IC_RESULT (ic))) { + + aopOp (IC_RESULT (ic), ic, FALSE); + + assignResultValue (IC_RESULT (ic)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + } + + /* adjust the stack for parameters if + required */ + if (ic->parmBytes) { + int i; + if (ic->parmBytes > 3) { + emitcode ("mov", "a,%s", spname); + emitcode ("add", "a,#0x%02x", + (-ic->parmBytes) & 0xff); + emitcode ("mov", "%s,a", spname); + } + else + for (i = 0; i < ic->parmBytes; i++) + emitcode ("dec", "%s", spname); + + } + + /* adjust the stack for parameters if required */ + if (ic->parmBytes) { + if (ic->parmBytes > 63) { + emitcode ("sbiw", "r28,%d", ic->parmBytes); + } + else { + emitcode ("subi", "r28,<(%d)", + ic->parmBytes); + emitcode ("sbci", "r29,>(%d)", + ic->parmBytes); + } + } + if (ic->regsSaved) + popZreg (ic); +} + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* genFunction - generated code for function entry */ +/*-----------------------------------------------------------------*/ +static void +genFunction (iCode * ic) +{ + symbol *sym; + sym_link *ftype; + int i = 0; + + _G.nRegsSaved = 0; + /* create the function header */ + emitcode (";", "-----------------------------------------"); + emitcode (";", " function %s", + (sym = OP_SYMBOL (IC_LEFT (ic)))->name); + emitcode (";", "-----------------------------------------"); + + emitcode ("", "%s:", sym->rname); + ftype = operandType (IC_LEFT (ic)); + + /* if critical function then turn interrupts off */ + if (IFFUNC_ISCRITICAL (ftype)) + emitcode ("cli", ""); + + if (IFFUNC_ISISR (sym->type)) { + } + + /* save the preserved registers that are used in this function */ + for (i = R2_IDX; i <= R15_IDX; i++) { + if (bitVectBitValue (sym->regsUsed, i)) { + _G.nRegsSaved++; + emitcode ("push", "%s", avr_regWithIdx (i)->name); + } + } + /* now for the pointer registers */ + if (bitVectBitValue (sym->regsUsed, R26_IDX)) { + _G.nRegsSaved++; + emitcode ("push", "r26"); + } + if (bitVectBitValue (sym->regsUsed, R27_IDX)) { + _G.nRegsSaved++; + emitcode ("push", "r27"); + } + if (bitVectBitValue (sym->regsUsed, R30_IDX)) { + _G.nRegsSaved++; + emitcode ("push", "r30"); + } + if (bitVectBitValue (sym->regsUsed, R31_IDX)) { + _G.nRegsSaved++; + emitcode ("push", "r31"); + } + /* adjust the stack for the function */ + if (sym->stack) { + emitcode ("push", "r28"); + emitcode ("push", "r29"); + emitcode ("in", "r28,__SP_L__"); + emitcode ("in", "r29,__SP_H__"); + if (sym->stack <= 63) { + emitcode ("sbiw", "r28,%d", sym->stack); + } + else { + emitcode ("subi", "r28,<(%d)", sym->stack); + emitcode ("sbci", "r29,>(%d)", sym->stack); + } + emitcode ("out", "__SP_L__,r28"); + emitcode ("out", "__SP_H__,r29"); + } +} + +/*-----------------------------------------------------------------*/ +/* genEndFunction - generates epilogue for functions */ +/*-----------------------------------------------------------------*/ +static void +genEndFunction (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + int i; + + /* restore stack pointer */ + if (sym->stack) { + if (sym->stack <= 63) { + emitcode ("adiw", "r28,%d", sym->stack); + } + else { + emitcode ("subi", "r28,<(-%d)", sym->stack); + emitcode ("sbci", "r29,>(-%d)", sym->stack); + } + emitcode ("out", "__SP_L__,r28"); + emitcode ("out", "__SP_H__,r29"); + + /* pop frame pointer */ + emitcode ("pop", "r29"); + emitcode ("pop", "r28"); + } + /* restore preserved registers */ + if (bitVectBitValue (sym->regsUsed, R31_IDX)) { + _G.nRegsSaved--; + emitcode ("pop", "r31"); + } + if (bitVectBitValue (sym->regsUsed, R30_IDX)) { + _G.nRegsSaved--; + emitcode ("pop", "r30"); + } + if (bitVectBitValue (sym->regsUsed, R27_IDX)) { + _G.nRegsSaved--; + emitcode ("pop", "r27"); + } + if (bitVectBitValue (sym->regsUsed, R26_IDX)) { + _G.nRegsSaved--; + emitcode ("pop", "r26"); + } + for (i = R15_IDX; i >= R2_IDX; i--) { + if (bitVectBitValue (sym->regsUsed, i)) { + _G.nRegsSaved--; + emitcode ("pop", "%s", avr_regWithIdx (i)->name); + } + } + + if (IFFUNC_ISCRITICAL (sym->type)) + emitcode ("sti", ""); + + if (options.debug && currFunc) { + debugFile->writeEndFunction (currFunc, ic, 1); + } + + if (IFFUNC_ISISR (sym->type)) { + emitcode ("rti", ""); + } + else { + emitcode ("ret", ""); + } + +} + +/*-----------------------------------------------------------------*/ +/* genRet - generate code for return statement */ +/*-----------------------------------------------------------------*/ +static void +genRet (iCode * ic) +{ + int size, offset = 0; + + /* if we have no return value then + just generate the "ret" */ + if (!IC_LEFT (ic)) + goto jumpret; + + /* we have something to return then + move the return value into place */ + aopOp (IC_LEFT (ic), ic, FALSE); + size = AOP_SIZE (IC_LEFT (ic)); + + while (size--) { + if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) { + emitcode ("ldi", "%s,%s(%d)", fAVRReturn[offset], + larray[offset], + (int) ulFromVal (AOP (IC_LEFT (ic))-> + aopu.aop_lit), offset); + } + else { + char *l; + l = aopGet (AOP (IC_LEFT (ic)), offset); + if (strcmp (fAVRReturn[offset], l)) + emitcode ("mov", "%s,%s", fAVRReturn[offset], + l); + } + offset++; + } + + 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 ("rjmp", "L%05d", returnLabel->key); + +} + +/*-----------------------------------------------------------------*/ +/* genLabel - generates a label */ +/*-----------------------------------------------------------------*/ +static void +genLabel (iCode * ic) +{ + /* special case never generate */ + if (IC_LABEL (ic) == entryLabel) + return; + + emitcode ("", "L%05d:", IC_LABEL (ic)->key); +} + +/*-----------------------------------------------------------------*/ +/* genGoto - generates a ljmp */ +/*-----------------------------------------------------------------*/ +static void +genGoto (iCode * ic) +{ + emitcode ("rjmp", "L%05d", (IC_LABEL (ic)->key)); +} + +/*-----------------------------------------------------------------*/ +/* genPlusIncr :- does addition with increment if possible */ +/*-----------------------------------------------------------------*/ +static bool +genPlusIncr (iCode * ic) +{ + unsigned int icount; + int offset = 0; + + /* 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; + + icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu. + aop_lit); + + /* if the sizes are greater than 2 or they are not the same regs + then we cannot */ + if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + return FALSE; + + /* so we know LEFT & RESULT in the same registers and add + amount <= 63 */ + /* for short & char types */ + if (AOP_SIZE (IC_RESULT (ic)) < 2) { + if (icount == 1) { + emitcode ("inc", "%s", + aopGet (AOP (IC_LEFT (ic)), 0)); + return TRUE; + } + if (AOP_ISHIGHREG( AOP (IC_LEFT (ic)),0)) { + emitcode ("subi", "%s,<(%d)", + aopGet (AOP (IC_LEFT (ic)), 0), 0-icount); + return TRUE; + } + } + + for (offset = 0 ; offset < AOP_SIZE(IC_RESULT(ic)) ; offset++) { + if (!(AOP_ISHIGHREG(AOP(IC_RESULT(ic)),offset))) return FALSE; + } + + if (AOP_SIZE (IC_RESULT (ic)) <= 3) { + /* if register pair and starts with 26/30 then adiw */ + if (isRegPair (AOP (IC_RESULT (ic))) && icount > 0 + && icount < 64 + && (IS_REGIDX (AOP (IC_RESULT (ic)), R26_IDX) || + IS_REGIDX (AOP (IC_RESULT (ic)), R24_IDX) || + IS_REGIDX (AOP (IC_RESULT (ic)), R30_IDX))) { + emitcode ("adiw", "%s,%d", + aopGet (AOP (IC_RESULT (ic)), 0), icount); + return TRUE; + } + + /* use subi */ + emitcode ("subi", "%s,<(%d)", + aopGet (AOP (IC_RESULT (ic)), 0), 0-icount); + emitcode ("sbci", "%s,>(%d)", + aopGet (AOP (IC_RESULT (ic)), 1), 0-icount); + return TRUE; + } + + /* for 32 bit longs */ + emitcode ("subi", "%s,<(%d)", aopGet (AOP (IC_RESULT (ic)), 0), + 0-icount); + emitcode ("sbci", "%s,>(%d)", aopGet (AOP (IC_RESULT (ic)), 1), + 0-icount); + emitcode ("sbci", "%s,hlo8(%d)", aopGet (AOP (IC_RESULT (ic)), 2), + 0-icount); + emitcode ("sbci", "%s,hhi8(%d)", aopGet (AOP (IC_RESULT (ic)), 3), + 0-icount); + return TRUE; + +} + +/* This is the pure and virtuous version of this code. + * I'm pretty certain it's right, but not enough to toss the old + * code just yet... + */ +static void +adjustArithmeticResult (iCode * ic) +{ + if (opIsGptr (IC_RESULT (ic)) && + opIsGptr (IC_LEFT (ic)) && + !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)))) { + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1), + GPTRSIZE - 1); + } + + if (opIsGptr (IC_RESULT (ic)) && + opIsGptr (IC_RIGHT (ic)) && + !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic)))) { + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1), + GPTRSIZE - 1); + } + + if (opIsGptr (IC_RESULT (ic)) && + AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE && + AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE && + !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) && + !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic)))) { + char buffer[5]; + sprintf (buffer, "%d", + pointerCode (getSpec (operandType (IC_LEFT (ic))))); + aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1); + } +} + +/*-----------------------------------------------------------------*/ +/* genPlus - generates code for addition */ +/*-----------------------------------------------------------------*/ +static void +genPlus (iCode * ic) +{ + int size, offset = 0; + int samer; + char *l; + + /* special cases :- */ + + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RIGHT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + + /* if I can do an increment instead + of add then GOOD for ME */ + if (genPlusIncr (ic) == TRUE) + goto release; + + size = getDataSize (IC_RESULT (ic)); + samer = sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))); + + while (size--) { + if (!samer) + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_LEFT (ic)), offset), offset); + + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) { + + if (offset == 0) + l = "add"; + else + l = "adc"; + + emitcode (l, "%s,%s", + aopGet (AOP (IC_RESULT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + else { + if (AOP_ISHIGHREG( AOP( IC_RESULT(ic)),offset)) { + if (offset == 0) + l = "subi"; + else + l = "sbci"; + + emitcode (l, "%s,%s(-%d)", + aopGet (AOP (IC_RESULT (ic)), offset), + larray[offset], + (int) ulFromVal (AOP (IC_RIGHT (ic))-> + aopu.aop_lit)); + } else { + if (offset == 0) + l = "add"; + else + l = "adc"; + + emitcode (l, "%s,%s", + aopGet (AOP (IC_RESULT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + } + offset++; + } + + adjustArithmeticResult (ic); + + release: + freeAsmop (IC_LEFT (ic), NULL, ic, + (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_RIGHT (ic), NULL, ic, + (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genMinusDec :- does subtraction with deccrement if possible */ +/*-----------------------------------------------------------------*/ +static bool +genMinusDec (iCode * ic) +{ + unsigned int icount; + int 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; + + icount = + (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu. + aop_lit); + + /* if the sizes are greater than 2 or they are not the same regs + then we cannot */ + if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic)))) + return FALSE; + + /* so we know LEFT & RESULT in the same registers and add + amount <= 63 */ + /* for short & char types */ + if (AOP_SIZE (IC_RESULT (ic)) < 2) { + if (icount == 1) { + emitcode ("dec", "%s", + aopGet (AOP (IC_LEFT (ic)), 0)); + return TRUE; + } + if (AOP_ISHIGHREG( AOP ( IC_LEFT(ic)),0)) { + emitcode ("subi", "%s,<(%d)", + aopGet (AOP (IC_LEFT (ic)), 0), icount); + return TRUE; + } + } + + for (offset = 0 ; offset < AOP_SIZE(IC_RESULT(ic)) ; offset++) { + if (!(AOP_ISHIGHREG(AOP(IC_RESULT(ic)),offset))) return FALSE; + } + + if (AOP_SIZE (IC_RESULT (ic)) <= 3) { + /* if register pair and starts with 26/30 then adiw */ + if (isRegPair (AOP (IC_RESULT (ic))) && icount > 0 + && icount < 64 + && (IS_REGIDX (AOP (IC_RESULT (ic)), R26_IDX) || + IS_REGIDX (AOP (IC_RESULT (ic)), R24_IDX) || + IS_REGIDX (AOP (IC_RESULT (ic)), R30_IDX))) { + emitcode ("sbiw", "%s,%d", + aopGet (AOP (IC_RESULT (ic)), 0), icount); + return TRUE; + } + + /* use subi */ + emitcode ("subi", "%s,<(%d)", + aopGet (AOP (IC_RESULT (ic)), 0), icount); + emitcode ("sbci", "%s,>(%d)", + aopGet (AOP (IC_RESULT (ic)), 1), icount); + return TRUE; + } + /* for 32 bit longs */ + emitcode ("subi", "%s,<(%d)", aopGet (AOP (IC_RESULT (ic)), 0), + icount); + emitcode ("sbci", "%s,>(%d)", aopGet (AOP (IC_RESULT (ic)), 1), + icount); + emitcode ("sbci", "%s,hlo8(%d)", aopGet (AOP (IC_RESULT (ic)), 2), + icount); + emitcode ("sbci", "%s,hhi8(%d)", aopGet (AOP (IC_RESULT (ic)), 3), + icount); + return TRUE; + +} + +/*-----------------------------------------------------------------*/ +/* genMinus - generates code for subtraction */ +/*-----------------------------------------------------------------*/ +static void +genMinus (iCode * ic) +{ + int size, offset = 0, samer; + char *l; + + aopOp (IC_LEFT (ic), ic, FALSE); + aopOp (IC_RIGHT (ic), ic, FALSE); + aopOp (IC_RESULT (ic), ic, TRUE); + + /* if I can do an decrement instead + of subtract then GOOD for ME */ + if (genMinusDec (ic) == TRUE) + goto release; + + size = getDataSize (IC_RESULT (ic)); + samer = sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))); + while (size--) { + if (!samer) + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_LEFT (ic)), offset), offset); + + if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) { + + if (offset == 0) + l = "sub"; + else + l = "sbc"; + + emitcode (l, "%s,%s", + aopGet (AOP (IC_RESULT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + else { + if (AOP_ISHIGHREG(AOP (IC_RESULT (ic)),offset)) { + if (offset == 0) + l = "subi"; + else + l = "sbci"; + + emitcode (l, "%s,%s(%d)", + aopGet (AOP (IC_RESULT (ic)), offset), + larray[offset], + (int) ulFromVal (AOP (IC_RIGHT (ic))-> + aopu.aop_lit)); + } else { + if (offset == 0) + l = "sub"; + else + l = "sbc"; + + emitcode (l, "%s,%s", + aopGet (AOP (IC_RESULT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + } + offset++; + } + + adjustArithmeticResult (ic); + + release: + freeAsmop (IC_LEFT (ic), NULL, ic, + (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_RIGHT (ic), NULL, ic, + (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genMultOneByte : 8 bit multiplication & division */ +/*-----------------------------------------------------------------*/ +static void +genMultOneByte (operand * left, operand * right, operand * result) +{ + sym_link *opetype = operandType (result); + symbol *lbl; + int size, offset; + + /* (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; + } + + size = AOP_SIZE (result); + + if (SPEC_USIGN (opetype)) { + emitcode ("mul", "%s,%s", aopGet (AOP (left), 0), + aopGet (AOP (right), 0)); + } + else { + emitcode ("muls", "%s,%s", aopGet (AOP (left), 0), + aopGet (AOP (right), 0)); + } + aopPut (AOP (result), "r0", 0); + if (size > 1) { + aopPut (AOP (result), "r1", 1); + offset = 2; + size -= 2; + if (SPEC_USIGN (opetype)) { + while (size--) { + aopPut (AOP (result), zero, offset++); + } + } + else { + if (size) { + lbl = newiTempLabel (NULL); + emitcode ("ldi", "r24,0"); + emitcode ("brcc", "L%05d", lbl->key); + emitcode ("ldi", "r24,0xff)"); + emitcode ("", "L%05d:", lbl->key); + while (size--) + aopPut (AOP (result), "r24", + offset++); + } + } + } + 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); + + /* assign the amsops */ + aopOp (left, ic, FALSE); + aopOp (right, ic, FALSE); + aopOp (result, ic, TRUE); + + /* if both are of size == 1 */ + if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1) { + genMultOneByte (left, right, result); + goto release; + } + + /* should have been converted to function call */ + assert (0); + + release: + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDiv - generates code for division */ +/*-----------------------------------------------------------------*/ +static void +genDiv (iCode * ic) +{ + /* should have been converted to function call */ + assert (0); +} + +/*-----------------------------------------------------------------*/ +/* genMod - generates code for division */ +/*-----------------------------------------------------------------*/ +static void +genMod (iCode * ic) +{ + /* should have been converted to function call */ + assert (0); + +} + +enum { + AVR_EQ = 0, + AVR_NE, + AVR_LT, + AVR_GE +}; + +/*-----------------------------------------------------------------*/ +/* revavrcnd - reverse a conditional for avr */ +/*-----------------------------------------------------------------*/ +static int +revavrcnd (int type) +{ + static struct { + int type, rtype; + } rar[] = { + { + AVR_EQ, AVR_NE} + , { + AVR_LT, AVR_GE} + }; + int i; + + for (i = 0; i < (sizeof (rar) / sizeof (rar[0])); i++) { + if (rar[i].type == type) + return rar[i].rtype; + if (rar[i].rtype == type) + return rar[i].type; + } + assert (0); /* cannot happen */ + return 0; /* makes the compiler happy */ +} + +static char *br_name[4] = { "breq", "brne", "brlt", "brge" }; +static char *br_uname[4] = { "breq", "brne", "brlo", "brcc" }; + +/*-----------------------------------------------------------------*/ +/* genBranch - generate the branch instruction */ +/*-----------------------------------------------------------------*/ +static void +genBranch (iCode * ifx, int br_type, int sign) +{ + int tj = (IC_TRUE (ifx) ? 1 : 0); + + if (tj) { /* if true jump */ + char *nm = (sign ? br_name[br_type] : br_uname[br_type]); + emitcode (nm, "L%05d", IC_TRUE (ifx)->key); + } + else { /* if false jump */ + int rtype = revavrcnd (br_type); + char *nm = (sign ? br_name[rtype] : br_uname[rtype]); + emitcode (nm, "L%05d", IC_FALSE (ifx)->key); + } + ifx->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genCmp - compare & jump */ +/*-----------------------------------------------------------------*/ +static void +genCmp (iCode * ic, iCode * ifx, int br_type) +{ + operand *left, *right, *result; + sym_link *letype, *retype; + symbol *lbl; + int sign, size, offset = 0; + + left = IC_LEFT (ic); + right = IC_RIGHT (ic); + result = IC_RESULT (ic); + + letype = getSpec (operandType (left)); + retype = getSpec (operandType (right)); + sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype)); + + /* assign the amsops */ + aopOp (left, ic, FALSE); + aopOp (right, ic, FALSE); + aopOp (result, ic, TRUE); + size = AOP_SIZE (left); + + if (ifx) { + if (size == 1) { + if (AOP_TYPE (right) == AOP_LIT) { + emitcode ("cpi", "%s,<(%d)", + aopGet (AOP (left), 0), + (int) ulFromVal (AOP (IC_RIGHT (ic))-> + aopu.aop_lit)); + genBranch (ifx, br_type, sign); + } + else { /* right != literal */ + emitcode ("cp", "%s,%s", + aopGet (AOP (left), 0), + aopGet (AOP (right), 0)); + genBranch (ifx, br_type, sign); + } + } + else { /* size != 1 */ + while (size--) { + if (offset == 0) + emitcode ("cp", "%s,%s", + aopGet (AOP (left), 0), + aopGet (AOP (right), 0)); + else + emitcode ("cpc", "%s,%s", + aopGet (AOP (left), offset), + aopGet (AOP (right), + offset)); + offset++; + } + genBranch (ifx, br_type, sign); + } + } + else { /* no ifx */ + emitcode ("clr", "r0"); + while (size--) { + if (offset == 0) + emitcode ("cp", "%s,%s", + aopGet (AOP (left), 0), + aopGet (AOP (right), 0)); + else + emitcode ("cpc", "%s,%s", + aopGet (AOP (left), offset), + aopGet (AOP (right), offset)); + offset++; + } + lbl = newiTempLabel (NULL); + br_type = revavrcnd (br_type); + if (sign) + emitcode (br_uname[br_type], "L%05d", lbl->key); + else + emitcode (br_name[br_type], "L%05d", lbl->key); + emitcode ("inc", "r0"); + emitcode ("", "L%05d:", lbl->key); + aopPut (AOP (result), "r0", 0); + size = AOP_SIZE (result) - 1; + offset = 1; + while (size--) + aopPut (AOP (result), zero, offset++); + } + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genCmpGt :- greater than comparison */ +/*-----------------------------------------------------------------*/ +static void +genCmpGt (iCode * ic, iCode * ifx) +{ + /* should have transformed by the parser */ + assert (0); +} + +/*-----------------------------------------------------------------*/ +/* genCmpLt - less than comparisons */ +/*-----------------------------------------------------------------*/ +static void +genCmpLt (iCode * ic, iCode * ifx) +{ + genCmp (ic, ifx, AVR_LT); +} + +/*-----------------------------------------------------------------*/ +/* genCmpEq - generates code for equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpEq (iCode * ic, iCode * ifx) +{ + genCmp (ic, ifx, AVR_EQ); +} + +/*-----------------------------------------------------------------*/ +/* genCmpNe - generates code for not equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpNe (iCode * ic, iCode * ifx) +{ + genCmp (ic, ifx, AVR_NE); +} + +/*-----------------------------------------------------------------*/ +/* genCmpGe - generates code for greater than equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpGe (iCode * ic, iCode * ifx) +{ + genCmp (ic, ifx, AVR_GE); +} + +/*-----------------------------------------------------------------*/ +/* genCmpLe - generates code for less than equal to */ +/*-----------------------------------------------------------------*/ +static void +genCmpLe (iCode * ic, iCode * ifx) +{ + operand *left = IC_LEFT (ic); + operand *right = IC_RIGHT (ic); + + IC_RIGHT (ic) = left; + IC_LEFT (ic) = right; + genCmp (ic, ifx, AVR_GE); +} + +/*-----------------------------------------------------------------*/ +/* ifxForOp - returns the icode containing the ifx for operand */ +/*-----------------------------------------------------------------*/ +static iCode * +ifxForOp (operand * op, iCode * ic) +{ + /* if true symbol then needs to be assigned */ + if (IS_TRUE_SYMOP (op)) + return NULL; + + /* if this has register type condition and + the next instruction is ifx with the same operand + and live to of the operand is upto the ifx only then */ + if (ic->next && + ic->next->op == IFX && + IC_COND (ic->next)->key == op->key && + OP_SYMBOL (op)->liveTo <= ic->next->seq) return ic->next; + + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* genAndOp - for && operation */ +/*-----------------------------------------------------------------*/ +static void +genAndOp (iCode * ic) +{ + operand *left, *right, *result; + symbol *tlbl; + int size, offset; + + /* note here that && operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, FALSE); + + tlbl = newiTempLabel (NULL); + toBoolean (left, "r0", TRUE); + toBoolean (right, "r1", TRUE); + emitcode ("and", "r0,r1"); + emitcode ("ldi", "r24,1"); + emitcode ("breq", "L%05d", tlbl->key); + emitcode ("dec", "r24"); + emitcode ("", "L%05d:", tlbl->key); + aopPut (AOP (result), "r24", 0); + size = AOP_SIZE (result) - 1; + offset = 1; + while (size--) + aopPut (AOP (result), zero, offset++); + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + + +/*-----------------------------------------------------------------*/ +/* genOrOp - for || operation */ +/*-----------------------------------------------------------------*/ +static void +genOrOp (iCode * ic) +{ + operand *left, *right, *result; + symbol *tlbl; + int size, offset; + + /* note here that || operations that are in an + if statement are taken away by backPatchLabels + only those used in arthmetic operations remain */ + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, FALSE); + + tlbl = newiTempLabel (NULL); + toBoolean (left, "r0", TRUE); + toBoolean (right, "r0", FALSE); + emitcode ("ldi", "r24,1"); + emitcode ("breq", "L%05d", tlbl->key); + emitcode ("dec", "r24"); + emitcode ("", "L%05d:", tlbl->key); + aopPut (AOP (result), "r24", 0); + size = AOP_SIZE (result) - 1; + offset = 1; + while (size--) + aopPut (AOP (result), zero, offset++); + + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +enum { + AVR_AND = 0, AVR_OR, AVR_XOR +}; +static char *bopnames_lit[] = { "andi", "ori" }; +static char *bopnames[] = { "and", "or", "eor" }; +/*-----------------------------------------------------------------*/ +/* genBitWise - generate bitwise operations */ +/*-----------------------------------------------------------------*/ +static void +genBitWise (iCode * ic, iCode * ifx, int bitop) +{ + operand *left, *right, *result; + int size, offset = 0; + char *l; + symbol *lbl, *lbl1; + int samerl, samerr; + + aopOp ((left = IC_LEFT (ic)), ic, FALSE); + aopOp ((right = IC_RIGHT (ic)), ic, FALSE); + aopOp ((result = IC_RESULT (ic)), ic, TRUE); + + size = AOP_SIZE (left); + offset = 0; + if (ifx) { /* used only for jumps */ + if (AOP_TYPE (right) == AOP_LIT && + (bitop == AVR_AND || bitop == AVR_OR)) { + int lit = + (int) ulFromVal (AOP (right)->aopu. + aop_lit); + int p2 = powof2 (lit); + if (bitop == AVR_AND && (p2 >= 0)) { /* right side is a power of 2 */ + l = aopGet (AOP (left), p2 / 8); + if (IC_TRUE (ifx)) { + emitcode ("sbrc", "%s,%d", l, + (p2 % 8)); + emitcode ("rjmp", "L%05d", + IC_TRUE (ifx)->key); + } + else { + emitcode ("sbrs", "%s,%d", l, + (p2 % 8)); + emitcode ("rjmp", "L%05d", + IC_FALSE (ifx)->key); + } + } + else { /* right not power of two */ + int eh = OP_SYMBOL (left)->liveTo <= ic->seq; + if (size == 1) { + if (eh && AOP_ISHIGHREG(AOP(IC_LEFT(ic)),0)) { + emitcode (bopnames_lit[bitop], + "%s,<(%d)", + aopGet (AOP (IC_LEFT (ic)), 0), lit); + } + else { + MOVR24 (aopGet (AOP (IC_LEFT (ic)), 0)); + emitcode (bopnames_lit[bitop], "r24,<(%d)", lit); + } + lbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) { + emitcode ("breq", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_TRUE (ifx)->key); + } + else { + emitcode ("brne", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_FALSE (ifx)-> key); + } + emitcode ("", "L%05d:", lbl->key); + } + else if (size == 2) { + emitcode ("mov", "r24,%s", aopGet (AOP (IC_LEFT (ic)), 0)); + emitcode ("mov", "r25,%s", aopGet (AOP (IC_LEFT (ic)), 1)); + emitcode (bopnames_lit[bitop], "r24,<(%d)", lit); + emitcode (bopnames_lit[bitop], "r25,>(%d)", lit); + emitcode ("sbiw", "r24,0"); + lbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) { + emitcode ("breq", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_TRUE (ifx)->key); + } + else { + emitcode ("brne", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_FALSE (ifx)->key); + } + emitcode ("", "L%05d:", lbl->key); + } + else { + lbl = newiTempLabel (NULL); + lbl1 = newiTempLabel (NULL); + while (size--) { + if (eh && AOP_ISHIGHREG(AOP(IC_LEFT(ic)),offset)) { + emitcode (bopnames_lit [bitop], "%s,<(%d)", + aopGet (AOP (IC_LEFT (ic)), offset), + lit); + } + else { + char *l = aopGet (AOP (IC_LEFT (ic)), offset); + MOVR24 (l); + emitcode ("andi", "r24,<(%d)", lit); + } + emitcode ("brne", "L%05d", lbl->key); + offset++; + } + /* all are zero */ + if (IC_FALSE (ifx)) + emitcode ("rjmp", "L%05d", IC_FALSE (ifx)-> key); + else + emitcode ("rjmp", "L%05d", lbl1->key); + emitcode ("", "L%05d:", lbl->key); + /* not zero */ + if (IC_TRUE (ifx)) + emitcode ("rjmp", "L%05d", IC_TRUE (ifx)->key); + emitcode ("", "L%05d:", lbl1->key); + + } + } + } + else { /* right is not a literal */ + int eh = OP_SYMBOL (left)->liveTo <= ic->seq; + int reh = OP_SYMBOL (right)->liveTo <= ic->seq; + if (size == 1) { + if (eh) { + emitcode (bopnames[bitop], "%s,%s", aopGet (AOP (IC_LEFT (ic)), 0), + aopGet (AOP (IC_RIGHT (ic)), 0)); + } + else if (reh) { + emitcode (bopnames[bitop], "%s,%s", + aopGet (AOP (IC_RIGHT (ic)), 0), + aopGet (AOP (IC_LEFT (ic)), 0)); + } + else { + MOVR0 (aopGet (AOP (IC_LEFT (ic)), 0)); + emitcode (bopnames[bitop], "r0,%s", + aopGet (AOP (IC_RIGHT (ic)), 0)); + } + lbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) { + emitcode ("breq", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", + IC_TRUE (ifx)->key); + } + else { + emitcode ("brne", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", + IC_FALSE (ifx)->key); + } + emitcode ("", "L%05d:", lbl->key); + } + else if (size == 2) { + emitcode ("mov", "r24,%s", + aopGet (AOP (IC_LEFT (ic)), 0)); + emitcode ("mov", "r25,%s", + aopGet (AOP (IC_LEFT (ic)), 1)); + emitcode (bopnames[bitop], "r24,%s", + aopGet (AOP (IC_RIGHT (ic)), 0)); + emitcode (bopnames[bitop], "r25,%s", + aopGet (AOP (IC_RIGHT (ic)), 1)); + emitcode ("sbiw", "r24,0"); + lbl = newiTempLabel (NULL); + if (IC_TRUE (ifx)) { + emitcode ("breq", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_TRUE (ifx)->key); + } + else { + emitcode ("brne", "L%05d", lbl->key); + emitcode ("rjmp", "L%05d", IC_FALSE (ifx)->key); + } + emitcode ("", "L%05d:", lbl->key); + } + else { + lbl = newiTempLabel (NULL); + lbl1 = newiTempLabel (NULL); + while (size--) { + if (eh) { + emitcode (bopnames[bitop], "%s,%s", + aopGet (AOP (IC_LEFT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + else if (reh) { + emitcode (bopnames[bitop], "%s,%s", + aopGet (AOP (IC_RIGHT (ic)), offset), + aopGet (AOP (IC_LEFT (ic)), offset)); + } + else { + MOVR0 (aopGet (AOP (IC_LEFT (ic)), offset)); + emitcode (bopnames[bitop], "r0,%s", + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + emitcode ("brne", "L%05d", lbl->key); + offset++; + } + /* all are zero */ + if (IC_FALSE (ifx)) + emitcode ("rjmp", "L%05d", IC_FALSE (ifx)->key); + else + emitcode ("rjmp", "L%05d", lbl1->key); + emitcode ("", "L%05d:", lbl->key); + /* not zero */ + if (IC_TRUE (ifx)) + emitcode ("rjmp", "L%05d", IC_TRUE (ifx)->key); + emitcode ("", "L%05d:", lbl1->key); + + } + } + goto release; + } + + /* result needs to go a register */ + samerl = sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))); + samerr = sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))); + while (size--) { + if (AOP_TYPE (right) == AOP_LIT) { + unsigned int lit = + (int) ulFromVal (AOP (right)->aopu. + aop_lit); + if (((lit >> (8 * offset)) & 0xff) == 0) { + if (bitop == AVR_AND) { + aopPut (AOP (result), zero, offset++); + continue; + } + else if (bitop == AVR_OR) { + if (!samerl) + aopPut (AOP (result), + aopGet (AOP (left), + offset), + offset); + offset++; + continue; + } + } + } + if (samerl) { + if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && + AOP_ISHIGHREG(AOP(IC_LEFT(ic)),offset) && + (bitop == AVR_AND || bitop == AVR_OR)) { + emitcode (bopnames_lit[bitop], "%s,%s(%d)", + aopGet (AOP (IC_LEFT (ic)), offset), + larray[offset], + (int) ulFromVal (AOP (right)-> aopu.aop_lit)); + } + else { + emitcode (bopnames[bitop], "%s,%s", + aopGet (AOP (IC_LEFT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + } + else if (samerr) { + emitcode (bopnames[bitop], "%s,%s", + aopGet (AOP (IC_RIGHT (ic)), offset), + aopGet (AOP (IC_LEFT (ic)), offset)); + } + else { + aopPut (AOP (IC_RESULT (ic)), + aopGet (AOP (IC_LEFT (ic)), offset), offset); + emitcode (bopnames[bitop], + aopGet (AOP (IC_RESULT (ic)), offset), + aopGet (AOP (IC_RIGHT (ic)), offset)); + } + offset++; + } + release: + freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE)); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genAnd - code for and */ +/*-----------------------------------------------------------------*/ +static void +genAnd (iCode * ic, iCode * ifx) +{ + genBitWise (ic, ifx, AVR_AND); +} + +/*-----------------------------------------------------------------*/ +/* genOr - code for or */ +/*-----------------------------------------------------------------*/ +static void +genOr (iCode * ic, iCode * ifx) +{ + genBitWise (ic, ifx, AVR_OR); +} + +/*-----------------------------------------------------------------*/ +/* genXor - code for xclusive or */ +/*-----------------------------------------------------------------*/ +static void +genXor (iCode * ic, iCode * ifx) +{ + genBitWise (ic, ifx, AVR_XOR); +} + +/*-----------------------------------------------------------------*/ +/* genInline - write the inline code out */ +/*-----------------------------------------------------------------*/ +static void +genInline (iCode * ic) +{ + char *buffer, *bp, *bp1; + bool inComment = FALSE; + + _G.inLine += (!options.asmpeep); + + buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic)); + + /* emit each line as a code */ + while (*bp) + { + switch (*bp) + { + case ';': + inComment = TRUE; + ++bp; + break; + + case '\n': + inComment = FALSE; + *bp++ = '\0'; + emitcode (bp1, ""); + bp1 = bp; + break; + + default: + /* Add \n for labels, not dirs such as c:\mydir */ + if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1]))) + { + ++bp; + *bp = '\0'; + ++bp; + emitcode (bp1, ""); + bp1 = bp; + } + else + ++bp; + break; + } + } + if (bp1 != bp) + emitcode (bp1, ""); + + Safe_free (buffer); + + /* consumed; we can free it here */ + dbuf_free (IC_INLINE (ic)); + + _G.inLine -= (!options.asmpeep); +} + +/*-----------------------------------------------------------------*/ +/* genRotC - rotate right/left with carry , lr = 1 rotate right */ +/*-----------------------------------------------------------------*/ +static void +genRotC (iCode * ic, int lr) +{ + operand *left, *result; + int size, offset = 0; + + /* rotate right with carry */ + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + /* move it to the result */ + size = AOP_SIZE (result); + if (!sameRegs (AOP (left), AOP (result))) { + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (left), offset), offset); + offset++; + } + size = AOP_SIZE (result); + } + if (lr) + offset = size - 1; + else + offset = 0; + + CLRC; + emitcode ("sbrc", "%s,%d", aopGet (AOP (result), offset), + (lr ? 0 : 7)); + emitcode ("sec", ""); + + while (size--) { + emitcode ((lr ? "ror" : "rol"), "%s", + aopGet (AOP (result), offset)); + if (lr) + offset--; + else + offset++; + } + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRRC - rotate right with carry */ +/*-----------------------------------------------------------------*/ +static void +genRRC (iCode * ic) +{ + genRotC (ic, 1); +} + +/*-----------------------------------------------------------------*/ +/* genRLC - generate code for rotate left with carry */ +/*-----------------------------------------------------------------*/ +static void +genRLC (iCode * ic) +{ + genRotC (ic, 0); +} + +/*-----------------------------------------------------------------*/ +/* genGetHbit - generates code get highest order bit */ +/*-----------------------------------------------------------------*/ +static void +genGetHbit (iCode * ic) +{ + operand *left, *result; + int size, offset; + + left = IC_LEFT (ic); + result = IC_RESULT (ic); + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + + size = AOP_SIZE (result); + if (!sameRegs (AOP (left), AOP (result))) { + emitcode ("clr", "%s", aopGet (AOP (result), size - 1)); + emitcode ("sbrc", "%s,7", aopGet (AOP (left), size - 1)); + emitcode ("subi", "%s,<(-1)", + aopGet (AOP (result), size - 1)); + } + else { + emitcode ("clr", "r0"); + emitcode ("sbrc", "%s,7", aopGet (AOP (left), size - 1)); + emitcode ("subi", "r0,<(-1)"); + aopPut (AOP (result), "r0", 0); + } + offset = 1; + size--; + while (size--) { + emitcode ("clr", aopGet (AOP (result), offset++)); + } + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genShiftLeftLit - shift left by a known amount */ +/*-----------------------------------------------------------------*/ +static void +genShiftLeftLit (iCode * ic) +{ + operand *left, *right, *result; + int size, shCount, offset = 0; + int lByteZ = 0; + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + size = AOP_SIZE (result); + shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + + if (shCount > (size * 8 - 1)) { + while (size--) + aopPut (AOP (result), zero, offset++); + goto release; + } + switch (size) { + case 1: + if (!sameRegs (AOP (left), AOP (result))) + aopPut (AOP (result), aopGet (AOP (left), 0), 0); + if (shCount >= 4) { + if (AOP_ISHIGHREG(AOP(result),0)) { + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + emitcode ("andi", "%s,0xf0"); + } else { + emitcode ("ldi","r24,0xf0"); + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + emitcode ("and", "%s,r24"); + } + shCount -= 4; + } + if (shCount == 1) { + emitcode ("add", "%s,%s", aopGet (AOP (result), 0), + aopGet (AOP (result), 0)); + shCount--; + } + while (shCount--) + emitcode ("lsl", "%s", aopGet (AOP (result), 0)); + break; + case 2: + if (shCount >= 12) { + aopPut (AOP (result), aopGet (AOP (left), 0), 1); + aopPut (AOP (result), zero, 0); + emitcode ("swap", "%s", aopGet (AOP (result), 1)); + if (AOP_ISHIGHREG(AOP(result),1)) { + emitcode ("andi", "%s,0xf0", aopGet (AOP (result), 1)); + } else { + emitcode ("ldi","r24,0xf0"); + emitcode ("and", "%s,r24", aopGet (AOP (result), 1)); + } + shCount -= 12; + lByteZ = 1; + } + if (shCount >= 8) { + aopPut (AOP (result), aopGet (AOP (left), 0), 1); + aopPut (AOP (result), zero, 0); + shCount -= 8; + lByteZ = 1; + } + if (shCount >= 4) { + shCount -= 4; + if (!sameRegs (AOP (left), AOP (result))) { + aopPut (AOP (result), aopGet (AOP (left), 0), + 0); + aopPut (AOP (result), aopGet (AOP (left), 1), + 1); + } + emitcode ("mov", "r24,%s", aopGet (AOP (result), 0)); + emitcode ("andi", "r24,0x0f"); + if (!(AOP_ISHIGHREG(AOP(result),0) && AOP_ISHIGHREG(AOP(result),1))) { + emitcode("ldi","r25,0xf0"); + } + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + if (AOP_ISHIGHREG(AOP(result),0)) { + emitcode ("andi", "%s,0xf0", aopGet (AOP (result), 0)); + } else { + emitcode ("and", "%s,r25", aopGet (AOP (result), 0)); + } + emitcode ("swap", "%s", aopGet (AOP (result), 1)); + if (AOP_ISHIGHREG(AOP(result),1)) { + emitcode ("andi", "%s,0xf0", aopGet (AOP (result), 1)); + } else { + emitcode ("and", "%s,r25", aopGet (AOP (result), 1)); + } + emitcode ("or", "%s,r24", aopGet (AOP (result), 1)); + while (shCount--) { + emitcode ("lsl", "%s", aopGet (AOP (result), 0)); + emitcode ("rol", "%s", aopGet (AOP (result), 1)); + } + } + if (!lByteZ && !sameRegs (AOP (result), AOP (left)) + && shCount) { + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (left), offset), offset); + offset++; + } + } + while (shCount--) { + if (lByteZ) { + emitcode ("lsl", "%s", aopGet (AOP (result), 1)); + } + else { + emitcode ("lsl", "%s", aopGet (AOP (result), 0)); + emitcode ("rol", "%s", aopGet (AOP (result), 1)); + } + } + break; + case 3: + assert ("shifting generic pointer ?\n"); + break; + case 4: + /* 32 bits we do only byte boundaries */ + if (shCount >= 24) { + aopPut (AOP (result), aopGet (AOP (left), 0), 3); + aopPut (AOP (result), zero, 2); + aopPut (AOP (result), zero, 1); + aopPut (AOP (result), zero, 0); + lByteZ = 3; + shCount -= 24; + } + if (shCount >= 16) { + aopPut (AOP (result), aopGet (AOP (left), 0), 3); + aopPut (AOP (result), aopGet (AOP (left), 1), 2); + aopPut (AOP (result), zero, 1); + aopPut (AOP (result), zero, 0); + lByteZ = 2; + shCount -= 16; + } + if (shCount >= 8) { + aopPut (AOP (result), aopGet (AOP (left), 0), 3); + aopPut (AOP (result), aopGet (AOP (left), 1), 2); + aopPut (AOP (result), aopGet (AOP (left), 2), 1); + aopPut (AOP (result), zero, 0); + shCount -= 8; + lByteZ = 1; + } + if (!lByteZ && !sameRegs (AOP (left), AOP (right))) { + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (left), offset), offset); + offset++; + } + offset = 0; + size = AOP_SIZE (result); + } + if (shCount) { + switch (lByteZ) { + case 0: + while (shCount--) { + emitcode ("lsl", "%s", aopGet (AOP (result), 0)); + emitcode ("rol", "%s", aopGet (AOP (result), 1)); + emitcode ("rol", "%s", aopGet (AOP (result), 2)); + emitcode ("rol", "%s", aopGet (AOP (result), 3)); + } + break; + case 1: + while (shCount--) { + emitcode ("lsl", "%s", aopGet (AOP (result), 1)); + emitcode ("rol", "%s", aopGet (AOP (result), 2)); + emitcode ("rol", "%s", aopGet (AOP (result), 3)); + } + break; + case 2: + while (shCount--) { + emitcode ("lsl", "%s", aopGet (AOP (result), 2)); + emitcode ("rol", "%s", aopGet (AOP (result), 3)); + } + break; + case 3: + while (shCount--) { + emitcode ("lsl", "%s", aopGet (AOP (result), 3)); + } + break; + } + } + } + + release: + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genLeftShift - generates code for left shifting */ +/*-----------------------------------------------------------------*/ +static void +genLeftShift (iCode * ic) +{ + operand *left, *right, *result; + int size, offset; + symbol *tlbl; + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (right, ic, FALSE); + + if (AOP_TYPE (right) == AOP_LIT) { + genShiftLeftLit (ic); + return; + } + + /* unknown count */ + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + size = AOP_SIZE (result); + offset = 0; + if (AOP_SIZE (right) > 1) { + if (isRegPair (AOP (right))) { + emitcode ("movw", "r24,%s", aopGet (AOP (right), 0)); + } + else { + emitcode ("mov", "r24,%s", aopGet (AOP (right), 0)); + emitcode ("mov", "r25,%s", aopGet (AOP (right), 1)); + } + } + else { + emitcode ("mov", "r24,%s", aopGet (AOP (right), 0)); + } + if (!sameRegs (AOP (left), AOP (result))) { + while (size--) { + aopPut (AOP (result), aopGet (AOP (left), offset), + offset); + offset++; + } + size = AOP_SIZE (result); + } + tlbl = newiTempLabel (NULL); + emitcode ("", "L%05d:", tlbl->key); + offset = 0; + while (size--) { + if (offset) + emitcode ("rol", "%s", aopGet (AOP (result), offset)); + else + emitcode ("lsl", "%s", aopGet (AOP (result), 0)); + offset++; + } + if (AOP_SIZE (right) > 1) + emitcode ("sbiw", "r24,1"); + else + emitcode ("dec", "r24"); + emitcode ("brne", "L%05d", tlbl->key); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genShiftRightLit - generate for right shift with known count */ +/*-----------------------------------------------------------------*/ +static void +genShiftRightLit (iCode * ic) +{ + operand *left = IC_LEFT (ic) + , *right = IC_RIGHT (ic) + , *result = IC_RESULT (ic); + int size, shCount, offset = 0; + int hByteZ = 0; + sym_link *letype = getSpec (operandType (left)); + int sign = !SPEC_USIGN (letype); + + right = IC_RIGHT (ic); + left = IC_LEFT (ic); + result = IC_RESULT (ic); + + aopOp (left, ic, FALSE); + aopOp (result, ic, FALSE); + size = AOP_SIZE (result); + shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit); + + /* if signed then give up and use a loop to shift */ + if (sign) { + symbol *tlbl; + if (!sameRegs (AOP (left), AOP (result))) { + while (size--) { + aopPut (AOP (result), + aopGet (AOP (left), offset), offset); + offset++; + } + size = AOP_SIZE (result); + offset = 0; + } + /* be as economical as possible */ + if (shCount <= 4) { + while (shCount--) { + size = AOP_SIZE (result); + offset = size - 1; + while (size--) { + /* highest order byte */ + if (offset == (AOP_SIZE(result)-1)) + emitcode ("asr", "%s", aopGet (AOP (result), offset)); + else + emitcode ("ror", "%s", aopGet (AOP (result), offset)); + offset--; + } + } + } + else { + emitcode ("ldi", "r24,<(%d)", shCount); + tlbl = newiTempLabel (NULL); + emitcode ("", "L%05d:", tlbl->key); + offset = size - 1; + while (size--) { + if (offset == (AOP_SIZE(result) - 1)) + emitcode ("asr", "%s", aopGet (AOP (result), offset)); + else + emitcode ("ror", "%s", aopGet (AOP (result), offset)); + offset--; + } + emitcode ("dec", "r24"); + emitcode ("brne", "L%05d", tlbl->key); + } + goto release; + } + if (shCount > (size * 8 - 1)) { + while (size--) + aopPut (AOP (result), zero, offset++); + goto release; + } + /* for unsigned we can much more efficient */ + switch (size) { + case 1: + if (!sameRegs (AOP (left), AOP (result))) + aopPut (AOP (result), aopGet (AOP (left), 0), 0); + if (shCount >= 4) { + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + if (AOP_ISHIGHREG(AOP(result),0)) { + emitcode ("andi", "%s,0x0f",aopGet(AOP(result),0)); + } else { + emitcode ("ldi","r24,0x0f"); + emitcode ("and", "%s,r24",aopGet(AOP(result),0)); + } + shCount -= 4; + } + while (shCount--) + emitcode ("lsr", "%s", aopGet (AOP (result), 0)); + break; + case 2: + if (shCount >= 12) { + aopPut (AOP (result), aopGet (AOP (left), 1), 0); + aopPut (AOP (result), zero, 1); + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + if (AOP_ISHIGHREG(AOP(result),0)) { + emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 0)); + } else { + emitcode ("ldi","r24,0x0f"); + emitcode ("and", "%s,r24",aopGet(AOP(result),0)); + } + shCount -= 12; + hByteZ = 1; + } + if (shCount >= 8) { + aopPut (AOP (result), aopGet (AOP (left), 1), 0); + aopPut (AOP (result), zero, 1); + shCount -= 8; + hByteZ = 1; + } + if (shCount >= 4) { + shCount -= 4; + if (!sameRegs (AOP (left), AOP (result))) { + aopPut (AOP (result), aopGet (AOP (left), 0), 0); + aopPut (AOP (result), aopGet (AOP (left), 1), 1); + } + if (!(AOP_ISHIGHREG(AOP(result),0) && AOP_ISHIGHREG(AOP(result),1))) { + emitcode("ldi","r25,0x0f"); + } + emitcode ("mov", "r24,%s", aopGet (AOP (result), 1)); + emitcode ("andi", "r24,0xf0"); + emitcode ("swap", "%s", aopGet (AOP (result), 0)); + if (AOP_ISHIGHREG(AOP(result),0)) { + emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 0)); + } else { + emitcode ("and", "%s,r25", aopGet (AOP (result), 0)); + } + emitcode ("or", "%s,r24", aopGet (AOP (result), 0)); + emitcode ("swap", "%s", aopGet (AOP (result), 1)); + if (AOP_ISHIGHREG(AOP(result),1)) { + emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 1)); + } else { + emitcode ("and", "%s,r24", aopGet (AOP (result), 1)); + } + while (shCount--) { + emitcode ("lsr", "%s", aopGet (AOP (result), 1)); + emitcode ("ror", "%s", aopGet (AOP (result), 0)); + } + + } + if (!hByteZ && !sameRegs (AOP (result), AOP (left)) + && shCount) { + offset = 0; + while (size--) { + aopPut (AOP (result), aopGet (AOP (left), offset), offset); + offset++; + } + } + while (shCount--) { + if (hByteZ) { + emitcode ("lsr", "%s", aopGet (AOP (result), 0)); + } + else { + emitcode ("lsr", "%s", aopGet (AOP (result), 1)); + emitcode ("ror", "%s", aopGet (AOP (result), 0)); + } + } + break; + + case 3: + assert ("shifting generic pointer ?\n"); + break; + case 4: + /* 32 bits we do only byte boundaries */ + if (shCount >= 24) { + aopPut (AOP (result), aopGet (AOP (left), 3), 0); + aopPut (AOP (result), zero, 1); + aopPut (AOP (result), zero, 2); + aopPut (AOP (result), zero, 3); + hByteZ = 3; + shCount -= 24; + } + if (shCount >= 16) { + aopPut (AOP (result), aopGet (AOP (left), 3), 1); + aopPut (AOP (result), aopGet (AOP (left), 2), 0); + aopPut (AOP (result), zero, 2); + aopPut (AOP (result), zero, 3); + hByteZ = 2; + shCount -= 16; + } + if (shCount >= 8) { + aopPut (AOP (result), aopGet (AOP (left), 1), 0); + aopPut (AOP (result), aopGet (AOP (left), 2), 1); + aopPut (AOP (result), aopGet (AOP (left), 3), 2); + aopPut (AOP (result), zero, 3); + shCount -= 8; + hByteZ = 1; + } + if (!hByteZ && !sameRegs (AOP (left), AOP (right))) { + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (left), offset), offset); + offset++; + } + offset = 0; + size = AOP_SIZE (result); + } + if (shCount) { + switch (hByteZ) { + case 0: + while (shCount--) { + emitcode ("lsr", "%s", aopGet (AOP (result), 3)); + emitcode ("ror", "%s", aopGet (AOP (result), 2)); + emitcode ("ror", "%s", aopGet (AOP (result), 1)); + emitcode ("ror", "%s", aopGet (AOP (result), 0)); + } + break; + case 1: + while (shCount--) { + emitcode ("lsr", "%s", aopGet (AOP (result), 2)); + emitcode ("ror", "%s", aopGet (AOP (result), 1)); + emitcode ("ror", "%s", aopGet (AOP (result), 0)); + } + break; + case 2: + while (shCount--) { + emitcode ("lsr", "%s", aopGet (AOP (result), 1)); + emitcode ("ror", "%s", aopGet (AOP (result), 0)); + } + break; + case 3: + while (shCount--) { + emitcode ("lsr", "%s", aopGet (AOP (result), 0)); + } + break; + } + } + } + release: + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genRightShift - generate code for right shifting */ +/*-----------------------------------------------------------------*/ +static void +genRightShift (iCode * ic) +{ + operand *right, *left, *result; + sym_link *letype; + int size, offset; + int sign = 0, first = 1; + symbol *tlbl; + + aopOp (right = IC_RIGHT (ic), ic, FALSE); + + if (AOP_TYPE (right) == AOP_LIT) { + genShiftRightLit (ic); + return; + } + /* unknown count */ + if (AOP_SIZE (right) > 1) { + if (isRegPair (AOP (right))) { + emitcode ("movw", "r24,%s", aopGet (AOP (right), 0)); + } + else { + emitcode ("mov", "r24,%s", aopGet (AOP (right), 0)); + emitcode ("mov", "r25,%s", aopGet (AOP (right), 1)); + } + } + else { + emitcode ("mov", "r24,%s", aopGet (AOP (right), 0)); + } + aopOp (left = IC_LEFT (ic), ic, FALSE); + aopOp (result = IC_RESULT (ic), ic, FALSE); + size = AOP_SIZE (result); + tlbl = newiTempLabel (NULL); + emitcode ("", "L%05d:", tlbl->key); + offset = size - 1; + letype = getSpec (operandType (left)); + sign = !SPEC_USIGN (letype); + if (!sameRegs (AOP (left), AOP (result))) { + while (size--) { + aopPut (AOP (result), aopGet (AOP (left), offset), offset); + offset++; + } + size = AOP_SIZE (result); + } + size = AOP_SIZE (result); + while (size--) { + if (first) { + if (sign) + emitcode ("asr", "%s", aopGet (AOP (result), offset)); + else + emitcode ("lsr", "%s", aopGet (AOP (result), offset)); + first = 0; + } + else + emitcode ("ror", "%s", aopGet (AOP (result), offset)); + offset--; + } + if (AOP_SIZE (right) > 1) + emitcode ("sbiw", "r24,1"); + else + emitcode ("dec", "r24"); + emitcode ("brne", "L%05d", tlbl->key); + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* RRsh - shift right rn by known count */ +/*-----------------------------------------------------------------*/ +static void +RRsh (int shCount,int reg) +{ + shCount &= 0x0007; // shCount : 0..7 + + switch (shCount) { + case 0: + break; + case 1: + emitcode ("lsr", "r%d",reg); + break; + case 2: + emitcode ("lsr", "r%d",reg); + emitcode ("lsr", "r%d",reg); + break; + case 3: + emitcode ("swap", "r%d",reg); + emitcode ("lsl", "r%d",reg); + break; + case 4: + emitcode ("swap", "r%d",reg); + break; + case 5: + emitcode ("swap", "r%d",reg); + emitcode ("lsr", "r%d",reg); + break; + case 6: + emitcode ("swap","r%d",reg); + emitcode ("lsr", "r%d",reg); + emitcode ("lsr", "r%d",reg); + break; + case 7: + emitcode ("swap","r%d",reg); + emitcode ("lsr", "r%d",reg); + emitcode ("lsr", "r%d",reg); + emitcode ("lsr", "r%d",reg); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* RLsh - shift left rn by known count */ +/*-----------------------------------------------------------------*/ +static void +RLsh (int shCount, int reg) +{ + shCount &= 0x0007; // shCount : 0..7 + + switch (shCount) { + case 0: + break; + case 1: + emitcode ("lsl", "r%d",reg); + break; + case 2: + emitcode ("lsl", "r%d",reg); + emitcode ("lsl", "r%d",reg); + break; + case 3: + emitcode ("swap","r%d",reg); + emitcode ("lsr", "r%d",reg); + break; + case 4: + emitcode ("swap", "r%d",reg); + break; + case 5: + emitcode ("swap","r%d",reg); + emitcode ("lsl", "r%d",reg); + break; + case 6: + emitcode ("swap","r%d",reg); + emitcode ("lsl", "r%d",reg); + emitcode ("lsl", "r%d",reg); + break; + case 7: + emitcode ("swap","r%d",reg); + emitcode ("lsl", "r%d",reg); + emitcode ("lsl", "r%d",reg); + emitcode ("lsl", "r%d",reg); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* genUnpackBits - generates code for unpacking bits */ +/*-----------------------------------------------------------------*/ +static void +genUnpackBits (operand * result, char *rname, int ptype) +{ + int shCnt; + int rlen = 0; + sym_link *etype; + int offset = 0; + int rsize; + + etype = getSpec (operandType (result)); + rsize = getSize (operandType (result)); + /* read the first byte */ + switch (ptype) { + + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("ld", "r24,%s+", rname); + break; + + case CPOINTER: + emitcode ("lpm", "r24,%s+", rname); + break; + + case GPOINTER: + emitcode ("call","__gptrget_pi"); + emitcode ("mov","r24,r0"); + break; + } + + rlen = SPEC_BLEN (etype); + + /* if we have bitdisplacement then it fits */ + /* into this byte completely or if length is */ + /* less than a byte */ + if ((shCnt = SPEC_BSTR (etype)) || (SPEC_BLEN (etype) <= 8)) { + + /* shift right acc */ + RRsh (shCnt,24); + + emitcode ("andi", "r24,lo(0x%x)", + ((unsigned char) -1) >> (8 - SPEC_BLEN (etype))); + aopPut (AOP (result), "r24", offset++); + goto finish; + } + + /* bit field did not fit in a byte */ + aopPut (AOP (result), "r24", offset++); + + while (1) { + + switch (ptype) { + + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("ld", "r24,%s+"); + break; + + case CPOINTER: + emitcode ("lpm", "r24,%s+"); + break; + + case GPOINTER: + emitcode ("call", "__gptrget_pi"); + break; + } + + rlen -= 8; + /* if we are done */ + if (rlen < 8) + break; + + aopPut (AOP (result), "r24", offset++); + + } + + if (rlen) { + aopPut (AOP (result), "r24", offset++); + } + + finish: + if (offset < rsize) { + rsize -= offset; + while (rsize--) + aopPut (AOP (result), zero, offset++); + } + return; +} + +/*-----------------------------------------------------------------*/ +/* genDataPointerGet - generates code when ptr offset is known */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerGet (operand * left, operand * result, iCode * ic) +{ + char *l; + char buffer[256]; + int size, offset = 0; + aopOp (result, ic, TRUE); + + /* get the string representation of the name */ + l = aopGet (AOP (left), 0); + size = AOP_SIZE (result); + while (size--) { + if (offset) + sprintf (buffer, "(%s + %d)", l, offset); + else + sprintf (buffer, "%s", l); + emitcode ("lds", "%s,%s", aopGet (AOP (result), offset++), + buffer); + } + + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerGet - emitcode for near pointer fetch */ +/*-----------------------------------------------------------------*/ +static void +genMemPointerGet (operand * left, operand * result, iCode * ic, iCode *pi) +{ + asmop *aop = NULL; + regs *preg = NULL; + int gotFreePtr = 0; + char *rname, *frname = NULL; + sym_link *rtype, *retype; + sym_link *ltype = operandType (left); + + rtype = operandType (result); + retype = getSpec (rtype); + + aopOp (left, ic, FALSE); + + /* if left is rematerialisable and + result is not bit variable type and + the left is pointer to data space i.e + lower 128 bytes of space */ + if (AOP_TYPE (left) == AOP_IMMD && + !IS_BITVAR (retype) && 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, 0); + if (isRegPair (AOP (left) )) { + emitcode ("movw", "%s,%s", + aop->aopu.aop_ptr->name, + aopGet(AOP(left),0)); + } else { + emitcode ("mov", "%s,%s", aop->aopu.aop_ptr->name, + aopGet (AOP (left), 0)); + emitcode ("mov", "%s,%s", aop->aop_ptr2->name, + aopGet (AOP (left), 1)); + } + gotFreePtr = 1; + } + else { + aop = AOP(left); + frname = aopGet(aop,0); + } + if (AOP_ISX(aop)) { + rname = "X"; + } else if (AOP_ISZ(aop)) { + rname = "Z"; + } else { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "pointer not in correct register"); + exit (0); + } + + aopOp (result, ic, FALSE); + + /* if bitfield then unpack the bits */ + if (IS_BITVAR (retype)) + genUnpackBits (result, rname, POINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE (result); + int offset = 0; + + while (size--) { + if (size || pi) { + emitcode ("ld","%s,%s+",aopGet(AOP(result),offset), rname); + } else { + emitcode ("ld","%s,%s",aopGet(AOP(result),offset), rname); + } + } + } + + /* now some housekeeping stuff */ + if (gotFreePtr) { + /* we had to allocate for this iCode */ + if (pi) { + if (isRegPair (AOP (left) )) { + emitcode ("movw", "%s,%s", + aopGet (AOP(left),0), + aop->aopu.aop_ptr->name); + } else { + emitcode ("mov", "%s,%s", + aopGet (AOP (left), 0), + aop->aopu.aop_ptr->name); + emitcode ("mov", "%s,%s", + aopGet (AOP (left), 1), + aop->aop_ptr2->name); + } + } + 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; + emitcode ("sbiw", "%s,%d",frname,size); + } + } + + /* done */ + if (pi) pi->generated = 1; + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genCodePointerGet - gget value from code space */ +/*-----------------------------------------------------------------*/ +static void +genCodePointerGet (operand * left, operand * result, iCode * ic, iCode *pi) +{ + int size, offset; + sym_link *retype = getSpec (operandType (result)); + asmop *aop = NULL; + int gotFreePtr = 0; + + aopOp (left, ic, FALSE); + + /* if the operand is already in Z register + then we do nothing else we move the value to Z register */ + if (AOP_ISZ(AOP(left))) { + aop = AOP (left); + } else { + aop = newAsmop(0); + getFreePtr(ic,&aop,FALSE,TRUE); + if (isRegPair(AOP (left))) { + emitcode ("movw","r30,%s",aopGet (AOP (left), 0)); + } else { + emitcode ("mov", "r30,%s", aopGet (AOP (left), 0)); + emitcode ("mov", "r31,%s", aopGet (AOP (left), 1)); + } + gotFreePtr = 1; + } + + aopOp (result, ic, FALSE); + + /* if bit then unpack */ + if (IS_BITVAR (retype)) + genUnpackBits (result, "Z", CPOINTER); + else { + size = AOP_SIZE (result); + offset = 0; + + while (size--) { + if (size || pi) { + emitcode ("lpm","%s,Z+",aopGet(AOP(result),offset++)); + } else { + emitcode ("lpm","%s,Z",aopGet(AOP(result),offset++)); + } + } + } + + /* now some housekeeping stuff */ + if (gotFreePtr) { + /* we had to allocate for this iCode */ + if (pi) { + if (isRegPair(AOP (left))) { + emitcode ("movw","%s,r30",aopGet (AOP (left), 0)); + } else { + emitcode ("mov", "%s,r30", aopGet (AOP (left), 0)); + emitcode ("mov", "%s,r31", aopGet (AOP (left), 1)); + } + } + 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; + emitcode ("sbiw", "r30,%d",size); + } + } + + /* done */ + if (pi) pi->generated=1; + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genGenPointerGet - gget value from generic pointer space */ +/*-----------------------------------------------------------------*/ +static void +genGenPointerGet (operand * left, operand * result, iCode * ic, iCode *pi) +{ + int size, offset; + int gotFreePtr = 0; + sym_link *retype = getSpec (operandType (result)); + asmop *aop = NULL; + + aopOp (left, ic, FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_ISZ(AOP(left))) { + aop = AOP(left); + } else { + aop = newAsmop(0); + getFreePtr(ic,&aop,FALSE,TRUE); + if (isRegPair(AOP(left))) { + emitcode ("movw", "r30,%s", aopGet (AOP (left), 0)); + } else { + emitcode ("mov", "r30,%s", aopGet (AOP (left), 0)); + emitcode ("mov", "r31,%s", aopGet (AOP (left), 1)); + } + emitcode ("mov", "r24,%s", aopGet (AOP (left), 2)); + gotFreePtr=1; + } + + /* so Z register now contains the address */ + + aopOp (result, ic, FALSE); + + /* if bit then unpack */ + if (IS_BITVAR (retype)) + genUnpackBits (result, "Z", GPOINTER); + else { + size = AOP_SIZE (result); + offset = 0; + + while (size--) { + if (size || pi) + emitcode ("call", "__gptrget_pi"); + else + emitcode ("call", "__gptrget"); + aopPut (AOP (result), "r0", offset++); + } + } + + + /* now some housekeeping stuff */ + if (gotFreePtr) { + /* we had to allocate for this iCode */ + if (pi) { + if (isRegPair(AOP (left))) { + emitcode ("movw","%s,r30",aopGet (AOP (left), 0)); + } else { + emitcode ("mov", "%s,r30", aopGet (AOP (left), 0)); + emitcode ("mov", "%s,r31", aopGet (AOP (left), 1)); + } + } + 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; + emitcode ("sbiw", "r30,%d",size); + } + } + if (pi) pi->generated=1; + freeAsmop (left, NULL, ic, TRUE); + freeAsmop (result, 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; + + 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)); + + + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) { + + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + genMemPointerGet (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, + char *rname, int p_type) +{ + int shCount = 0; + int offset = 0; + int rLen = 0; + int blen, bstr; + char *l; + + blen = SPEC_BLEN (etype); + bstr = SPEC_BSTR (etype); + + l = aopGet (AOP (right), offset++); + MOVR24 (l); + + /* if the bit lenth is less than or */ + /* it exactly fits a byte then */ + if (SPEC_BLEN (etype) <= 8) { + shCount = SPEC_BSTR (etype); + + /* shift left acc */ + RLsh (shCount,24); + + if (SPEC_BLEN (etype) < 8) { /* if smaller than a byte */ + + switch (p_type) { + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("ld", "r1,%s",rname); + break; + + case GPOINTER: + emitcode ("push", "r1"); + emitcode ("push", "r24"); + emitcode ("call", "__gptrget"); + emitcode ("pop", "r1"); + emitcode ("mov","r24,r0"); + break; + } + + emitcode ("andi", "r24,#0x%02x", (unsigned char) + ((unsigned char) (0xFF << (blen + bstr)) | + (unsigned char) (0xFF >> (8 - bstr)))); + emitcode ("or", "r24,r1"); + if (p_type == GPOINTER) + emitcode ("pop", "r1"); + } + } + + switch (p_type) { + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode("st","%s+,r24"); + break; + + case GPOINTER: + emitcode("mov","r0,r24"); + emitcode ("call", "__gptrput_pi"); + break; + } + + /* if we r done */ + if (SPEC_BLEN (etype) <= 8) + return; + + rLen = SPEC_BLEN (etype); + + /* now generate for lengths greater than one byte */ + while (1) { + + l = aopGet (AOP (right), offset++); + + rLen -= 8; + if (rLen < 8) + break; + + switch (p_type) { + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("st", "%s+,%s",rname,l); + break; + + case GPOINTER: + MOVR0 (l); + emitcode ("lcall", "__gptrput_pi"); + break; + } + } + + MOVR24 (l); + + /* last last was not complete */ + if (rLen) { + /* save the byte & read byte */ + switch (p_type) { + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("st","%s+,r24",rname); + break; + case GPOINTER: + emitcode ("push", "r1"); + emitcode ("push", "r24"); + emitcode ("lcall", "__gptrget"); + emitcode ("mov","r24,r0"); + emitcode ("pop", "r1"); + break; + } + + emitcode ("andi", "r24,0x%02x", (((unsigned char) -1 << rLen) & 0xff)); + emitcode ("or", "r24,r1"); + } + + if (p_type == GPOINTER) + emitcode ("pop", "r1"); + + switch (p_type) { + + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + emitcode ("st", "%s,r24", rname); + break; + + case GPOINTER: + emitcode ("mov","r0,r24"); + emitcode ("call", "__gptrput"); + break; + } +} + +/*-----------------------------------------------------------------*/ +/* genDataPointerSet - remat pointer to data space */ +/*-----------------------------------------------------------------*/ +static void +genDataPointerSet (operand * right, operand * result, iCode * ic) +{ + int size, offset = 0; + char *l, buffer[256]; + + aopOp (right, ic, FALSE); + + l = aopGet (AOP (result), 0); + size = AOP_SIZE (right); + while (size--) { + if (offset) + sprintf (buffer, "(%s + %d)", l, offset); + else + sprintf (buffer, "%s", l); + emitcode ("sts", "%s,%s", buffer, + aopGet (AOP (right), offset++)); + } + + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genNearPointerSet - emitcode for near pointer put */ +/*-----------------------------------------------------------------*/ +static void +genMemPointerSet (operand * right, operand * result, iCode * ic, iCode *pi) +{ + asmop *aop = NULL; + char *frname = NULL, *rname, *l; + int gotFreePtr = 0; + sym_link *retype; + sym_link *ptype = operandType (result); + + retype = getSpec (operandType (right)); + + aopOp (result, ic, 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)) { + genDataPointerSet (right, result, ic); + return; + } + if (!AOP_INPREG(AOP(result))) { + /* otherwise get a free pointer register */ + aop = newAsmop (0); + getFreePtr (ic, &aop, FALSE, 0); + if (isRegPair (AOP (result) )) { + emitcode ("movw", "%s,%s",aop->aopu.aop_ptr->name, + aopGet(AOP (result), 0)); + } else { + emitcode ("mov", "%s,%s", aop->aopu.aop_ptr->name, + aopGet (AOP (result), 0)); + emitcode ("mov", "%s,%s", aop->aop_ptr2->name, + aopGet (AOP (result), 1)); + } + gotFreePtr = 1; + } else { + aop = AOP(result); + frname = aopGet(aop,0); + } + + aopOp (right, ic, FALSE); + if (AOP_ISX(aop)) { + rname = "X"; + } else if (AOP_ISZ(aop)) { + rname = "Z"; + } else { + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, + "pointer not in correct register"); + exit (0); + } + /* if bitfield then unpack the bits */ + if (IS_BITVAR (retype)) + genPackBits (retype, right, rname, POINTER); + else { + /* we have can just get the values */ + int size = AOP_SIZE (right); + int offset = 0; + + while (size--) { + l = aopGet (AOP (right), offset); + if (size || pi) + emitcode ("st", "%s+,%s", rname,l); + else + emitcode ("st", "%s,%s", rname,l); + offset++; + } + } + + /* now some housekeeping stuff */ + if (gotFreePtr) { + /* we had to allocate for this iCode */ + if (pi) { + if (isRegPair (AOP (result) )) { + emitcode ("movw", "%s,%s", + aopGet(AOP(result),0), + aop->aopu.aop_ptr->name); + } else { + emitcode ("mov", "%s,%s", aop->aopu.aop_ptr->name, + aopGet (AOP (result), 0)); + emitcode ("mov", "%s,%s", aop->aop_ptr2->name, + aopGet (AOP (result), 1)); + } + } + 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 (right)->liveTo > ic->seq || ic->depth)) && !pi) { + int size = AOP_SIZE (right) - 1; + emitcode ("sbiw", "%s,%d",frname,size); + } + } + + /* done */ + if (pi) pi->generated = 1; + 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; + int gotFreePtr = 0; + sym_link *retype = getSpec (operandType (right)); + asmop *aop = NULL; + + aopOp (result, ic, FALSE); + + /* if the operand is already in dptr + then we do nothing else we move the value to dptr */ + if (AOP_ISZ(AOP(result))) { + aop = AOP(right); + } else { + aop = newAsmop(0); + getFreePtr(ic,&aop,FALSE,TRUE); + if (isRegPair(AOP(result))) { + emitcode ("movw", "r30,%s", aopGet (AOP (result), 0)); + } else { + emitcode ("mov", "r30,%s", aopGet (AOP (result), 0)); + emitcode ("mov", "r31,%s", aopGet (AOP (result), 1)); + } + emitcode ("mov", "r24,%s", aopGet (AOP (result), 2)); + gotFreePtr=1; + } + + /* so Z register now contains the address */ + aopOp (right, ic, FALSE); + + /* if bit then unpack */ + if (IS_BITVAR (retype)) + genUnpackBits (result, "Z", GPOINTER); + else { + size = AOP_SIZE (right); + offset = 0; + + while (size--) { + char *l = aopGet(AOP (right), offset++); + MOVR0(l); + + if (size || pi) + emitcode ("call", "__gptrput_pi"); + else + emitcode ("call", "__gptrput"); + } + } + + /* now some housekeeping stuff */ + if (gotFreePtr) { + /* we had to allocate for this iCode */ + if (pi) { + if (isRegPair(AOP(result))) { + emitcode ("movw", "%s,r30", aopGet (AOP (result), 0)); + } else { + emitcode ("mov", "%s,r30", aopGet (AOP (result), 0)); + emitcode ("mov", "%s,r31", aopGet (AOP (result), 1)); + } + } + 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; + emitcode ("sbiw", "r30,%d",size); + } + } + if (pi) pi->generated = 1; + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, 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; + + 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)); + + } + + /* now that we have the pointer type we assign + the pointer values */ + switch (p_type) { + + case POINTER: + case IPOINTER: + case PPOINTER: + case FPOINTER: + genMemPointerSet (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); + char *cname ; + symbol *lbl; + int tob = 0; + + aopOp (cond, ic, FALSE); + + /* get the value into acc */ + if (AOP_SIZE(cond) == 1 && AOP_ISHIGHREG(AOP(cond),0)) { + cname = aopGet(AOP(cond),0); + } else { + toBoolean (cond, "r24", 0); + tob = 1; + cname = "r24"; + } + /* the result is now in the accumulator */ + freeAsmop (cond, NULL, ic, TRUE); + + /* if there was something to be popped then do it */ + if (popIc) { + genIpop (popIc); + emitcode("cpi","%s,0",cname); + } else if (!tob) emitcode("cpi","%s,0",cname); + + lbl = newiTempLabel(NULL); + if (IC_TRUE(ic)) { + emitcode ("breq","L%05d",lbl->key); + emitcode ("jmp","L%05d",IC_TRUE(ic)->key); + emitcode ("","L%05d:",lbl->key); + } else { + emitcode ("brne","L%05d",lbl->key); + emitcode ("jmp","L%05d",IC_FALSE(ic)->key); + emitcode ("","L%05d:",lbl->key); + } + ic->generated = 1; +} + +/*-----------------------------------------------------------------*/ +/* genAddrOf - generates code for address of */ +/*-----------------------------------------------------------------*/ +static void +genAddrOf (iCode * ic) +{ + symbol *sym = OP_SYMBOL (IC_LEFT (ic)); + int size, offset; + + aopOp (IC_RESULT (ic), ic, FALSE); + assert(AOP_SIZE(IC_RESULT(ic)) >= 2); + /* if the operand is on the stack then we + need to get the stack offset of this + variable */ + if (sym->onStack) { + /* if it has an offset then we need to compute it */ + if (sym->stack) { + if (allHigh(AOP(IC_RESULT(ic)))) { + if (isRegPair (AOP(IC_RESULT(ic)))) { + emitcode ("movw","%s,r28",aopGet(AOP(IC_RESULT(ic)),0)); + } else { + emitcode ("mov","%s,r28",aopGet(AOP(IC_RESULT(ic)),0)); + emitcode ("mov","%s,r29",aopGet(AOP(IC_RESULT(ic)),1)); + } + if (sym->stack < 0) { + emitcode("subi","%s,<(%d)",aopGet(AOP(IC_RESULT(ic)),0),-sym->stack); + emitcode("sbci","%s,>(%d)",aopGet(AOP(IC_RESULT(ic)),1),-sym->stack); + } else { + emitcode("subi","%s,<(-%d)",aopGet(AOP(IC_RESULT(ic)),0),sym->stack); + emitcode("sbci","%s,>(-%d)",aopGet(AOP(IC_RESULT(ic)),1),sym->stack); + } + } else { + emitcode("movw","r24,r28"); + if (sym->stack > -63 && sym->stack < 63) { + if (sym->stack < 0) + emitcode("sbiw","r24,%d",-sym->stack); + else + emitcode("sbiw","r24,%d",sym->stack); + } else { + if (sym->stack < 0) { + emitcode("subi","r24,<(%d)",-sym->stack); + emitcode("sbci","r25,>(%d)",-sym->stack); + } else { + emitcode("subi","r24,<(-%d)",sym->stack); + emitcode("sbci","r25,>(-%d)",sym->stack); + } + } + + aopPut(AOP(IC_RESULT(ic)),"r24",0); + aopPut(AOP(IC_RESULT(ic)),"r25",1); + } + } + else { + aopPut(AOP(IC_RESULT(ic)),"r28",0); + aopPut(AOP(IC_RESULT(ic)),"r29",1); + } + /* fill the result with zero */ + size = AOP_SIZE (IC_RESULT (ic)) - 2; + offset = 2; + while (size--) { + aopPut (AOP (IC_RESULT (ic)), zero, offset++); + } + + goto release; + } + + /* object not on stack then we need the name */ + size = AOP_SIZE (IC_RESULT (ic)); + offset = 0; + assert(size<=2); + while (size--) { + char s[SDCC_NAME_MAX]; + if (offset) + sprintf (s, ">(%s)", sym->rname); + else + sprintf (s, "<(%s)", sym->rname); + aopPut (AOP (IC_RESULT (ic)), s, offset++); + } + + 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; + char *l; + /* first push the right side on to the stack */ + while (size--) { + l = aopGet (AOP (right), offset++); + MOVA (l); + emitcode ("push", "acc"); + } + + freeAsmop (right, NULL, ic, FALSE); + /* now assign DPTR to result */ + aopOp (result, ic, FALSE); + size = AOP_SIZE (result); + while (size--) { + emitcode ("pop", "acc"); + aopPut (AOP (result), "a", --offset); + } + freeAsmop (result, NULL, ic, FALSE); + +} + +/*-----------------------------------------------------------------*/ +/* genAssign - generate code for assignment */ +/*-----------------------------------------------------------------*/ +static void +genAssign (iCode * ic) +{ + operand *result, *right; + int size, offset; + unsigned long lit = 0L; + + result = IC_RESULT (ic); + right = IC_RIGHT (ic); + + /* if they are the same */ + if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) + return; + + aopOp (right, ic, FALSE); + + /* special case both in far space */ + if (AOP_TYPE (right) == AOP_DPTR && + IS_TRUE_SYMOP (result) && isOperandInFarSpace (result)) { + + genFarFarAssign (result, right, ic); + return; + } + + aopOp (result, ic, TRUE); + + /* if they are the same registers */ + if (sameRegs (AOP (right), AOP (result))) + goto release; + + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) { + + /* 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 (AOP (result), one, 0); + else + aopPut (AOP (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 (AOP (result), "c", 0); + goto release; + } + + /* we need to or */ + toBoolean (right, "", 0); + aopPut (AOP (result), "a", 0); + goto release; + } + + /* bit variables done */ + /* general case */ + size = AOP_SIZE (result); + offset = 0; + if (AOP_TYPE (right) == AOP_LIT) + lit = ulFromVal (AOP (right)->aopu. + aop_lit); + if ((size > 1) && (AOP_TYPE (result) != AOP_REG) + && (AOP_TYPE (right) == AOP_LIT) + && !IS_FLOAT (operandType (right)) && (lit < 256L)) { + emitcode ("clr", "a"); + while (size--) { + if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == + 0) aopPut (AOP (result), "a", size); + else + aopPut (AOP (result), + aopGet (AOP (right), size), size); + } + } + else { + while (size--) { + aopPut (AOP (result), + aopGet (AOP (right), offset), offset); + offset++; + } + } + + release: + freeAsmop (right, NULL, ic, FALSE); + freeAsmop (result, NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genJumpTab - genrates code for jump table */ +/*-----------------------------------------------------------------*/ +static void +genJumpTab (iCode * ic) +{ + symbol *jtab; + char *l; + + aopOp (IC_JTCOND (ic), ic, FALSE); + /* get the condition into accumulator */ + l = aopGet (AOP (IC_JTCOND (ic)), 0); + MOVA (l); + /* multiply by three */ + emitcode ("add", "a,acc"); + emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0)); + freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE); + + jtab = newiTempLabel (NULL); + emitcode ("mov", "dptr,#%05d$", jtab->key + 100); + emitcode ("jmp", "@a+dptr"); + emitcode ("", "%05d$:", jtab->key + 100); + /* now generate the jump labels */ + for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; + jtab = setNextItem (IC_JTLABELS (ic))) + emitcode ("ljmp", "%05d$", jtab->key + 100); + +} + +/*-----------------------------------------------------------------*/ +/* 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; + + /* if they are equivalent then do nothing */ + if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic))) + return; + + aopOp (right, ic, FALSE); + aopOp (result, ic, FALSE); + + /* if the result is a bit */ + if (AOP_TYPE (result) == AOP_CRY) { + /* 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 (AOP (result), one, 0); + else + aopPut (AOP (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 (AOP (result), "c", 0); + goto release; + } + + /* we need to or */ + toBoolean (right, "", 0); + aopPut (AOP (result), "a", 0); + goto release; + } + + /* if they are the same size : or less */ + if (AOP_SIZE (result) <= AOP_SIZE (right)) { + + /* 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; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (right), offset), offset); + offset++; + } + goto release; + } + + + /* if the result is of type pointer */ + if (IS_PTR (ctype)) { + + int p_type; + sym_link *type = operandType (right); + sym_link *etype = getSpec (type); + + /* pointer to generic pointer */ + if (IS_GENPTR (ctype)) { + if (IS_PTR (type)) + p_type = DCL_TYPE (type); + else { + /* we have to go by the storage class */ + p_type = PTR_TYPE (SPEC_OCLS (etype)); + } + + /* the first two bytes are known */ + size = GPTRSIZE - 1; + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (right), offset), offset); + offset++; + } + + /* the last byte depending on type */ + { + int gpVal = pointerTypeToGPByte(p_type, NULL, NULL); + char gpValStr[10]; + + if (gpVal == -1) + { + // pointerTypeToGPByte will have bitched. + exit(1); + } + + sprintf(gpValStr, "#0x%x", gpVal); + aopPut (AOP (result), gpValStr, GPTRSIZE - 1); + } + goto release; + } + + /* just copy the pointers */ + size = AOP_SIZE (result); + offset = 0; + while (size--) { + aopPut (AOP (result), + aopGet (AOP (right), offset), offset); + offset++; + } + 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; + while (size--) { + aopPut (AOP (result), aopGet (AOP (right), offset), offset); + offset++; + } + + /* now depending on the sign of the source && destination */ + size = AOP_SIZE (result) - AOP_SIZE (right); + /* if unsigned or not an integral type */ + if (SPEC_USIGN (rtype) || !IS_SPEC (rtype)) { + while (size--) + aopPut (AOP (result), zero, offset++); + } + else { + /* we need to extend the sign :{ */ + // PENDING: Does nothing on avr +#if 0 + char *l = aopGet (AOP (right), AOP_SIZE (right) - 1); + MOVA (l); +#endif + emitcode ("rlc", "a"); + emitcode ("subb", "a,acc"); + while (size--) + aopPut (AOP (result), "a", offset++); + } + + /* we are done hurray !!!! */ + + release: + freeAsmop (right, NULL, ic, TRUE); + freeAsmop (result, NULL, ic, TRUE); + +} + +/*-----------------------------------------------------------------*/ +/* genDjnz - generate decrement & jump if not zero instrucion */ +/*-----------------------------------------------------------------*/ +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 */ + lbl = newiTempLabel (NULL); + lbl1 = newiTempLabel (NULL); + + aopOp (IC_RESULT (ic), ic, FALSE); + + if (IS_AOP_PREG (IC_RESULT (ic))) { + emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0)); + emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0)); + emitcode ("jnz", "%05d$", lbl->key + 100); + } + else { + emitcode ("djnz", "%s,%05d$", + aopGet (AOP (IC_RESULT (ic)), 0), lbl->key + 100); + } + emitcode ("sjmp", "%05d$", lbl1->key + 100); + emitcode ("", "%05d$:", lbl->key + 100); + emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100); + emitcode ("", "%05d$:", lbl1->key + 100); + + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); + ifx->generated = 1; + return 1; +} + +static char *recvregs[8] = { + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23" +}; + +static int recvCnt = 0; + +/*-----------------------------------------------------------------*/ +/* genReceive - generate code for a receive iCode */ +/*-----------------------------------------------------------------*/ +static void +genReceive (iCode * ic) +{ + int size, offset = 0; + aopOp (IC_RESULT (ic), ic, FALSE); + size = AOP_SIZE (IC_RESULT (ic)); + while (size--) { + aopPut (AOP (IC_RESULT (ic)), recvregs[recvCnt++], offset); + offset++; + } + freeAsmop (IC_RESULT (ic), NULL, ic, TRUE); +} + +/*-----------------------------------------------------------------*/ +/* genDummyRead - generate code for dummy read of volatiles */ +/*-----------------------------------------------------------------*/ +static void +genDummyRead (iCode * ic) +{ + emitcode ("; genDummyRead",""); + emitcode ("; not implemented",""); + + ic = ic; +} + +/*-----------------------------------------------------------------*/ +/* gen51Code - generate code for 8051 based controllers */ +/*-----------------------------------------------------------------*/ +void +genAVRCode (iCode * lic) +{ + iCode *ic; + int cln = 0; + + lineHead = lineCurr = NULL; + recvCnt = 0; + /* print the allocation information */ + if (allocInfo) + printAllocInfo (currFunc, codeOutBuf); + /* if debug information required */ + if (options.debug && currFunc) { + debugFile->writeFunction (currFunc, lic); + } + /* stack pointer name */ + spname = "sp"; + + + for (ic = lic; ic; ic = ic->next) { + + if (cln != ic->lineno) { + if (options.debug) { + debugFile->writeCLine (ic); + } + emitcode (";", "%s %d", ic->filename, ic->lineno); + cln = ic->lineno; + } + /* 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: + /* IPOP happens only when trying to restore a + spilt live range, if there is an ifx statement + following this pop then the if statement might + be using some of the registers being popped which + would destory the contents of the register so + we need to check for this condition and handle it */ + if (ic->next && + ic->next->op == IFX && + regsInCommon (IC_LEFT (ic), IC_COND (ic->next))) + genIfx (ic->next, 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: + genCmpLe (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case GE_OP: + genCmpGe (ic, ifxForOp (IC_RESULT (ic), ic)); + break; + + case NE_OP: + genCmpNe (ic, ifxForOp (IC_RESULT (ic), ic)); + 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)); + break; + + case '=': + if (POINTER_SET (ic)) + genPointerSet (ic, hasInc(IC_RESULT(ic),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: + addSet (&_G.sendSet, ic); + break; + + case DUMMY_READ_VOLATILE: + genDummyRead (ic); + break; + + default: + ic = ic; + } + } + + + /* now we are ready to call the + peep hole optimizer */ + if (!options.nopeep) + peepHole (&lineHead); + + /* now do the actual printing */ + printLine (lineHead, codeOutBuf); + return; +} diff --git a/src/avr/gen.h b/src/avr/gen.h new file mode 100644 index 0000000..0d3bd0d --- /dev/null +++ b/src/avr/gen.h @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + SDCCgen51.h - header file for code generation for 8051 + + 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! +-------------------------------------------------------------------------*/ + +#ifndef SDCCGEN51_H +#define SDCCGEN51_H + +enum + { + AOP_LIT = 1, + AOP_REG, AOP_DIR, + AOP_DPTR, AOP_X, AOP_Z, + AOP_STK, AOP_IMMD, AOP_STR, + AOP_CRY, AOP_ACC, AOP_STK_D + }; + +/* 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_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 + */ + short coff; /* current offset */ + short size; /* total size */ + unsigned code:1; /* is in Code space */ + unsigned paged:1; /* in paged memory */ + unsigned freed:1; /* already freed */ + union + { + value *aop_lit; /* if literal */ + regs *aop_reg[4]; /* array of registers */ + char *aop_dir; /* if direct */ + regs *aop_ptr; /* either -> R26 or R30 */ + char *aop_immd; /* if immediate others are implied */ + int aop_stk; /* stack offset when AOP_STK */ + char *aop_str[4]; /* just a string array containing the location */ + } + aopu; + regs *aop_ptr2; /* either -> R27 or R31 */ + } +asmop; + +void genAVRCode (iCode *); +void avr_emitDebuggerSymbol (const char *); + +extern char *fReturn8051[]; +extern char *fReturn390[]; +extern unsigned fAVRReturnSize; +extern char **fAVRReturn; + +#endif diff --git a/src/avr/main.c b/src/avr/main.c new file mode 100644 index 0000000..0d62d84 --- /dev/null +++ b/src/avr/main.c @@ -0,0 +1,290 @@ +/** @file main.c + avr specific general functions. + + Note that mlh prepended _avr_ 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" + +static char _defaultRules[] = { +#include "peeph.rul" +}; + +/* list of key words used by msc51 */ +static char *_avr_keywords[] = { + "at", + "code", + "critical", + "eeprom", + "interrupt", + "sfr", + "xdata", + "_code", + "_eeprom", + "_generic", + "_xdata", + "sram", + "_sram", + "flash", + "_flash", + NULL +}; + +static int regParmFlg = 0; /* determine if we can register a parameter */ + +static void +_avr_init (void) +{ + asm_addTree (&asm_asxxxx_mapping); +} + +static void +_avr_reset_regparm (void) +{ + regParmFlg = 0; +} + +static int +_avr_regparm (sym_link * l, bool reentrant) +{ + /* the first eight bytes will be passed in + registers r16-r23. but we won't split variables + i.e. if not enough registers left to hold + the parameter then the whole parameter along + with rest of the parameters go onto the stack */ + if (regParmFlg < 8) { + int size; + if ((size = getSize (l)) > (8 - regParmFlg)) { + /* all remaining go on stack */ + regParmFlg = 8; + return 0; + } + regParmFlg += size; + return 1; + } + + return 0; +} + +void avr_assignRegisters (ebbIndex *); + +static bool +_avr_parseOptions (int *pargc, char **argv, int *i) +{ + /* TODO: allow port-specific command line options to specify + * segment names here. + */ + return FALSE; +} + +static void +_avr_finaliseOptions (void) +{ + port->mem.default_local_map = port->mem.default_globl_map = xdata; + /* change stack to be in far space */ + /* internal stack segment ; + SFRSPACE - NO + FAR-SPACE - YES + PAGED - NO + DIRECT-ACCESS - NO + BIT-ACCESS - NO + CODE-ACESS - NO + DEBUG-NAME - 'B' + POINTER-TYPE - FPOINTER + */ + istack = + allocMap (0, 1, 0, 0, 0, 0, options.stack_loc, ISTACK_NAME, + 'B', FPOINTER); + + /* also change xdata to be direct space since we can use lds/sts */ + xdata->direct = 1; + +} + +static void +_avr_setDefaultOptions (void) +{ + options.stackAuto = 1; +} + +static const char * +_avr_getRegName (struct regs *reg) +{ + if (reg) + return reg->name; + return "err"; +} + +static void +_avr_genAssemblerPreamble (FILE * of) +{ + +} + +/* Generate interrupt vector table. */ +static int +_avr_genIVT (struct dbuf_s * oBuf, symbol ** interrupts, int maxInterrupts) +{ + return TRUE; +} + +/* Indicate which extended bit operations this port supports */ +static bool +hasExtBitOp (int op, int size) +{ + if (op == RRC + || op == RLC + || op == GETHBIT + ) + 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; +} + +/** $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[] = { + "linkavr", "", "$1", NULL +}; + +/* $3 is replaced by assembler.debug_opts resp. port->assembler.plain_opts */ +static const char *_asmCmd[] = { + "asavr", "$l" , "$3", "$1.s", NULL +}; + +/* Globals */ +PORT avr_port = { + TARGET_ID_AVR, + "avr", + "ATMEL AVR", /* Target name */ + NULL, /* processor */ + { + glue, + TRUE, /* Emit glue around main */ + MODEL_LARGE | MODEL_SMALL, + MODEL_SMALL, + NULL, /* model == target */ + }, + { + _asmCmd, + NULL, + "-plosgff", /* Options with debug */ + "-plosgff", /* Options without debug */ + 0, + ".s", + NULL, /* no do_assemble */ + }, + { + _linkCmd, + NULL, + NULL, + ".rel", + 1}, + { + _defaultRules}, + { + /* Sizes: char, short, int, long, long long, ptr, fptr, gptr, bit, float, max */ + 1, 2, 2, 4, 8, 2, 2, 3, 1, 4, 4}, + + /* tags for generic pointers */ + { 0x00, 0x40, 0x60, 0x80 }, /* far, near, xstack, code */ + + { + "XSEG", + "STACK", + "CSEG", + "DSEG", + "ISEG", + NULL, //PSEG + "XSEG", + "BSEG", + "RSEG", + "GSINIT", + "OSEG", + "GSFINAL", + "HOME", + NULL, // initialized xdata + NULL, // 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, + NULL, + 0, + }, + { NULL, NULL }, + { + -1, 1, 4, 1, 1, 0, 1}, + /* avr has an 8 bit mul */ + { + 1, -1, FALSE + }, + { + avr_emitDebuggerSymbol + }, + { + 255/3, /* maxCount */ + 3, /* sizeofElement */ + /* The rest of these costs are bogus. They approximate */ + /* the behavior of src/SDCCicode.c 1.207 and earlier. */ + {4,4,4}, /* sizeofMatchJump[] */ + {0,0,0}, /* sizeofRangeCompare[] */ + 0, /* sizeofSubtract */ + 3, /* sizeofDispatch */ + }, + "_", + _avr_init, + _avr_parseOptions, + NULL, + NULL, + _avr_finaliseOptions, + _avr_setDefaultOptions, + avr_assignRegisters, + _avr_getRegName, + _avr_keywords, + _avr_genAssemblerPreamble, + NULL, /* no genAssemblerEnd */ + _avr_genIVT, + NULL, // _avr_genXINIT + NULL, /* genInitStartup */ + _avr_reset_regparm, + _avr_regparm, + NULL, + NULL, + NULL, + hasExtBitOp, /* hasExtBitOp */ + oclsExpense, /* oclsExpense */ + FALSE, + TRUE, /* little endian */ + 0, /* leave lt */ + 1, /* transform gt ==> not le */ + 0, /* leave le */ + 0, /* leave ge */ + 0, /* leave != */ + 0, /* leave == */ + FALSE, /* No array initializer support. */ + 0, /* no CSE cost estimation yet */ + NULL, /* no builtin functions */ + GPOINTER, /* treat unqualified pointers as "generic" pointers */ + 1, /* reset labelKey to 1 */ + 1, /* globals & local static allowed */ + PORT_MAGIC +}; diff --git a/src/avr/main.h b/src/avr/main.h new file mode 100644 index 0000000..6555225 --- /dev/null +++ b/src/avr/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_INCLUDE +#define MAIN_INCLUDE + +bool x_parseOptions (char **argv, int *pargc); +void x_setDefaultOptions (void); +void x_finaliseOptions (void); + +#endif diff --git a/src/avr/peeph.def b/src/avr/peeph.def new file mode 100644 index 0000000..5d111fb --- /dev/null +++ b/src/avr/peeph.def @@ -0,0 +1,1701 @@ +//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 { + 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 + +replace { + jz %1 + ljmp %5 +%1: +} by { + ; Peephole 109 removed ljmp by inverse jump logic + jnz %5 +%1: +} if labelInRange + +replace { + jnz %1 + ljmp %5 +%1: +} by { + ; Peephole 110 removed ljmp by inverse jump logic + jz %5 +%1: +} if labelInRange + +replace { + jb %1,%2 + ljmp %5 +%2: +} by { + ; Peephole 111 removed ljmp by inverse jump logic + jnb %1,%5 +%2: +} if labelInRange + +replace { + jnb %1,%2 + ljmp %5 +%2: +} by { + ; Peephole 112 removed ljmp by inverse jump logic + jb %1,%5 +%2: +} if labelInRange + +replace { + ljmp %5 +%1: +} by { + ; Peephole 132 changed ljmp to sjmp + sjmp %5 +%1: +} if labelInRange + + +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: +} + +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: +} + +replace { + clr a + cjne %1,%2,%3 + cpl a +%3: + jnz %4 +} by { + ; Peephole 115 jump optimization + cjne %1,%2,%3 + sjmp %4 +%3: +} + +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: +} + +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: +} + +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: +} +replace { + mov a,#0x01 + cjne %1,%2,%3 + clr a +%3: + jnz %4 +} by { + ; Peephole 119 jump optimization + cjne %1,%2,%4 +%3: +} + +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: +} +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: +} + +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: +} + +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: +} +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 + smp %4 +%3: +} + +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: +} + +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: +} + +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 +} + +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 +} + +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: +} + +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: +} + +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:} + +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:} + +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:} + +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:} + +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 +} + +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 +} + +// saves 2 bytes, ?? cycles. +replace { + mov dpl,#%1 + mov dph,#(%1 >> 8) + mov dpx,#(%1 >> 16) +} by { + ; Peephole 182a used 24 bit load of dptr + mov dptr,#%1 +} if 24bitMode + +// 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 +} + +replace { + 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 +} by { + ; Peephole 186.a optimized movc sequence + mov dptr,#%1 + mov b,acc + movc a,@a+dptr + mov %2,a + mov acc,b + inc dptr + movc a,@a+dptr + mov %3,a + mov acc,b + inc dptr + mov %4,a + mov acc,b + inc dptr +} + +replace { + 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 +} by { + ; Peephole 186.b optimized movc sequence + mov dptr,#%1 + mov b,acc + movc a,@a+dptr + mov %2,a + mov acc,b + inc dptr + movc a,@a+dptr + mov %3,a + mov acc,b + inc dptr +} + +replace { + 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 +} by { + ; Peephole 186.c optimized movc sequence + mov dptr,#%1 + mov b,acc + movc a,@a+dptr + mov %2,a + mov acc,b + inc dptr +} + +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 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: +} + +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: +} + +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: +} + +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: +} + +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: +} + +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: +} + +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: +} + +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: +} + +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: +} + +replace { + cjne %1,%2,%3 + sjmp %4 +%3: + sjmp %5 +} by { + ; Peephole 199 optimized misc jump sequence + cjne %1,%2,%5 + sjmp %4 +%3: +} + +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 { + 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: +} + +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 { + push %1 + pop %1 +} by { + ; Peephole 211 removed redundant push %1 pop %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 { + mov %1,#(%2 >> 8) + xrl %1,#0x80 +} + +replace { + mov %1,#(( %2 + %3 >> 8 ) ^ 0x80) +} by { + mov %1,#((%2 + %3) >> 8) + xrl %1,#0x80 +} + +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 +} diff --git a/src/avr/ralloc.c b/src/avr/ralloc.c new file mode 100644 index 0000000..2026c06 --- /dev/null +++ b/src/avr/ralloc.c @@ -0,0 +1,2307 @@ +/*------------------------------------------------------------------------ + + SDCCralloc.c - source file for register allocation. (ATMEL AVR) 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" + +/*-----------------------------------------------------------------*/ +/* 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 */ +/*-----------------------------------------------------------------*/ + +extern void genAVRCode (iCode *); + +/* Global data */ +static struct { + bitVect *spiltSet; + set *stackSpil; + bitVect *regAssigned; + short blockSpil; + int slocNum; + bitVect *funcrUsed; /* registers used in a function */ + int stackExtend; + int dataExtend; +} _G; + +/* Shared with gen.c */ +int avr_ptrRegReq; /* pointer register required */ + +/* AVR registers */ +regs regsAVR[] = { + {REG_GPR|REG_PAIR, R0_IDX, REG_GPR|REG_PAIR, "r0", "r0", "", 0, 0, 0}, /* scratch */ + {REG_GPR, R1_IDX, REG_GPR , "r1", "r1", "", 0, 0, 0}, /* scratch */ + {REG_GPR|REG_PAIR, R2_IDX, REG_GPR|REG_PAIR, "r2", "r2", "", 0, 1, 1}, /* gpr */ + {REG_GPR, R3_IDX, REG_GPR , "r3", "r3", "", 0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R4_IDX, REG_GPR|REG_PAIR, "r4", "r4", "", 0, 1, 1}, /* gpr */ + {REG_GPR, R5_IDX, REG_GPR , "r5", "r5", "", 0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R6_IDX, REG_GPR|REG_PAIR, "r6", "r6", "", 0, 1, 1}, /* gpr */ + {REG_GPR, R7_IDX, REG_GPR , "r7", "r7", "", 0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R8_IDX, REG_GPR|REG_PAIR, "r8", "r8", "", 0, 1, 1}, /* gpr */ + {REG_GPR, R9_IDX, REG_GPR , "r9", "r9", "", 0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R10_IDX,REG_GPR|REG_PAIR, "r10", "r10","",0, 1, 1}, /* gpr */ + {REG_GPR, R11_IDX,REG_GPR , "r11", "r11","",0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R12_IDX,REG_GPR|REG_PAIR, "r12", "r12","",0, 1, 1}, /* gpr */ + {REG_GPR, R13_IDX,REG_GPR , "r13", "r13","",0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R14_IDX,REG_GPR|REG_PAIR, "r14", "r14","",0, 1, 1}, /* gpr */ + {REG_GPR, R15_IDX,REG_GPR , "r15", "r15","",0, 1, 1}, /* gpr */ + {REG_GPR|REG_PAIR, R16_IDX,REG_GPR|REG_PAIR, "r16", "r16","",0, 1, 0}, /* parm/gpr */ + {REG_GPR, R17_IDX,REG_GPR , "r17", "r17","",0, 1, 0}, /* parm/gpr */ + {REG_GPR|REG_PAIR, R18_IDX,REG_GPR|REG_PAIR, "r18", "r18","",0, 1, 0}, /* parm/gpr */ + {REG_GPR, R19_IDX,REG_GPR , "r19", "r19","",0, 1, 0}, /* parm/gpr */ + {REG_GPR|REG_PAIR, R20_IDX,REG_GPR|REG_PAIR, "r20", "r20","",0, 1, 0}, /* parm/gpr */ + {REG_GPR, R21_IDX,REG_GPR , "r21", "r21","",0, 1, 0}, /* parm/gpr */ + {REG_GPR|REG_PAIR, R22_IDX,REG_GPR|REG_PAIR, "r22", "r22","",0, 1, 0}, /* parm/gpr */ + {REG_GPR, R23_IDX,REG_GPR , "r23", "r23","",0, 1, 0}, /* parm/gpr */ + {REG_GPR|REG_PAIR, R24_IDX,REG_GPR|REG_PAIR, "r24", "r24","",0, 0, 0}, /* scratch */ + {REG_GPR, R25_IDX,REG_GPR , "r25", "r25","",0, 0, 0}, /* scratch */ + {REG_GPR|REG_PAIR, R26_IDX,REG_GPR|REG_PAIR, "r26", "r26","",0, 1, 1}, /* used as pointer reg X */ + {REG_GPR, R27_IDX,REG_GPR , "r27", "r27","",0, 1, 1}, /* used as pointer reg X */ + {REG_GPR|REG_PAIR, R28_IDX,REG_GPR|REG_PAIR, "r28", "r28","",0, 1, 0}, /* stack frame Y */ + {REG_GPR, R29_IDX,REG_GPR , "r29", "r29","",0, 1, 0}, /* stack frame Y */ + {REG_GPR|REG_PAIR, R30_IDX,REG_GPR|REG_PAIR, "r30", "r30","",0, 1, 1}, /* used as pointer reg Z */ + {REG_GPR, R31_IDX,REG_GPR , "r31", "r31","",0, 1, 1}, /* used as pointer reg Z */ + {REG_PTR, X_IDX, REG_PTR, "X", "X", "", 0, 1, 0}, + {REG_PTR, Z_IDX, REG_PTR, "Z", "Z", "", 0, 1, 0}, +}; +int avr_nRegs = 32; +int avr_fReg = 0; /* first allocatable register */ + +static void spillThis (symbol *); + +#if 0 +// PENDING: Unused +/*-----------------------------------------------------------------*/ +/* findAssignToSym : scanning backwards looks for first assig found */ +/*-----------------------------------------------------------------*/ +static iCode * +findAssignToSym (operand * op, iCode * ic) +{ + iCode *dic; + + 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 + true */ + if (!IS_SYMOP (IC_RIGHT (dic))) + break; + + /* 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; + + +} + +/*-----------------------------------------------------------------*/ +/* packForPush - hueristics to reduce iCode for pushing */ +/*-----------------------------------------------------------------*/ +static void +packForPush (iCode * ic, eBBlock * ebp) +{ + iCode *dic; + + if (ic->op != IPUSH || !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; + + /* 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); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); +} + +/*-----------------------------------------------------------------*/ +/* 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); + + IC_LEFT (ic)->operand.symOperand = + IC_RIGHT (dic)->operand.symOperand; + IC_LEFT (ic)->key = IC_RIGHT (dic)->operand.symOperand->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); + + IC_RIGHT (ic)->operand.symOperand = + IC_RIGHT (dic)->operand.symOperand; + IC_RIGHT (ic)->key = IC_RIGHT (dic)->operand.symOperand->key; + + remiCodeFromeBBlock (ebp, dic); + hTabDeleteItem (&iCodehTab, dic->key, dic, DELETE_ITEM, NULL); + change++; + } + + return change; +} + +/*-----------------------------------------------------------------*/ +/* 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 three 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; +} + +/*-----------------------------------------------------------------*/ +/* rematStr - returns the rematerialized string for a remat var */ +/*-----------------------------------------------------------------*/ +static char * +rematStr (symbol * sym) +{ + char *s = buffer; + iCode *ic = sym->rematiCode; + + while (1) { + + /* if plus or minus print the right hand side */ + if (ic->op == '+' || ic->op == '-') { + sprintf (s, "0x%04x %c ", + (int) operandLitValue (IC_RIGHT (ic)), + ic->op); + s += strlen (s); + ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode; + continue; + } + + /* we reached the end */ + sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname); + break; + } + + return buffer; +} + +/*-----------------------------------------------------------------*/ +/* 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->usl.spillLoc) + return FALSE; + + etype = getSpec (sym->usl.spillLoc->type); + if (IN_STACK (etype)) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* spillLRWithPtrReg :- will spil those live ranges which use PTR */ +/*-----------------------------------------------------------------*/ +static void +spillLRWithPtrReg (symbol * forSym) +{ + symbol *lrsym; + regs *X, *Z, *X1, *Z1; + int k; + + if (!_G.regAssigned || bitVectIsZero (_G.regAssigned)) + return; + + X = avr_regWithIdx (R26_IDX); + X1= avr_regWithIdx (R27_IDX); + Z = avr_regWithIdx (R30_IDX); + Z1= avr_regWithIdx (R31_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 with this then + not 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 spil it */ + for (j = 0; j < lrsym->nRegs; j++) + if (lrsym->regs[j] == X || lrsym->regs[j] == Z || + lrsym->regs[j] == X1 || lrsym->regs[j] == Z1) { + spillThis (lrsym); + break; + } + } + +} +#endif + +/*-----------------------------------------------------------------*/ +/* allocReg - allocates register of given type */ +/*-----------------------------------------------------------------*/ +static regs * +allocReg (short type) +{ + int i; + + for (i = avr_fReg; i < avr_nRegs; i++) { + + /* if type is given as 0 then any + free register will do */ + if (!type && regsAVR[i].isFree) { + regsAVR[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = + bitVectSetBit (currFunc->regsUsed, i); + return ®sAVR[i]; + } + + /* other wise look for specific type + of register */ + if (regsAVR[i].isFree && (regsAVR[i].type & type)) { + regsAVR[i].isFree = 0; + if (currFunc) + currFunc->regsUsed = + bitVectSetBit (currFunc->regsUsed, i); + return ®sAVR[i]; + } + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* allocRegPair - allocates register pair of given */ +/*-----------------------------------------------------------------*/ +static regs * +allocRegPair (short type) +{ + int i; + + for (i = avr_fReg; i < avr_nRegs; i++) { + + /* look for specific type of register pair */ + if (regsAVR[i].isFree && (regsAVR[i].type & type) + && (regsAVR[i].type & REG_PAIR) && regsAVR[i+1].isFree) { + + regsAVR[i].isFree = 0; + regsAVR[i+1].isFree = 0; + if (currFunc) { + currFunc->regsUsed = + bitVectSetBit (currFunc->regsUsed, i); + currFunc->regsUsed = + bitVectSetBit (currFunc->regsUsed, i+1); + } + return ®sAVR[i]; + } + } + return NULL; +} + +/*-----------------------------------------------------------------*/ +/* avr_regWithIdx - returns pointer to register wit index number */ +/*-----------------------------------------------------------------*/ +regs * +avr_regWithIdx (int idx) +{ + int i; + + for (i = 0; i < avr_nRegs; i++) + if (regsAVR[i].rIdx == idx) + return ®sAVR[i]; + + werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "regWithIdx not found"); + exit (1); +} + +/*-----------------------------------------------------------------*/ +/* freeReg - frees a register */ +/*-----------------------------------------------------------------*/ +static void +freeReg (regs * reg) +{ + reg->isFree = 1; +} + + +/*-----------------------------------------------------------------*/ +/* nFreeRegs - returns number of free registers */ +/*-----------------------------------------------------------------*/ +static int +nFreeRegs (int type) +{ + int i; + int nfr = 0; + + for (i = avr_fReg; i < avr_nRegs; i++) + if (regsAVR[i].isFree && regsAVR[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); +} + +/*-----------------------------------------------------------------*/ +/* 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; + +} + +/*-----------------------------------------------------------------*/ +/* 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); +} + +/*-----------------------------------------------------------------*/ +/* 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, ic->seq, 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 + the 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 (sym->liveTo > fsym->liveFrom) + 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)) { + *sloc = sym; + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------------*/ +/* createStackSpil - create a location on the stack to spil */ +/*-----------------------------------------------------------------*/ +static symbol * +createStackSpil (symbol * sym) +{ + symbol *sloc = NULL; + int useXstack, model, noOverlay; + int stackAuto; + + char slocBuffer[30]; + + /* 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 */ + + if (sprintf (slocBuffer, "sloc%d", _G.slocNum++) >= + sizeof (slocBuffer)) { + fprintf (stderr, + "***Internal error: slocBuffer overflowed: %s:%d\n", + __FILE__, __LINE__); + exit (1); + } + + sloc = newiTemp (slocBuffer); + + /* set the type to the spilling symbol */ + sloc->type = copyLinkChain (sym->type); + sloc->etype = getSpec (sloc->type); + SPEC_SCLS (sloc->etype) = S_AUTO; + SPEC_EXTR (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; + stackAuto = options.stackAuto; + options.noOverlay = 1; + options.model = options.useXstack = 0; + + allocLocal (sloc); + + options.useXstack = useXstack; + options.model = model; + options.noOverlay = noOverlay; + options.stackAuto = stackAuto; + 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; +} + +/*-----------------------------------------------------------------*/ +/* 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 = 1; + _G.spiltSet = bitVectSetBit (_G.spiltSet, sym->key); + + bitVectUnSetBit (_G.regAssigned, sym->key); + + for (i = 0; i < sym->nRegs; i++) + + if (sym->regs[i]) { + freeReg (sym->regs[i]); + sym->regs[i] = NULL; + } + + if (sym->usl.spillLoc && !sym->remat) + sym->usl.spillLoc->allocreq = 1; + 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); + + /* get all live ranges that are rematerizable */ + if ((selectS = liveRangesWith (lrcs, rematable, ebp, ic))) { + + /* return the least used of these */ + return leastUsedLR (selectS); + } + + /* 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 = 1; + return sym; + } + + /* find live ranges with spillocation */ + if ((selectS = liveRangesWith (lrcs, hasSpilLoc, ebp, ic))) { + + sym = leastUsedLR (selectS); + sym->usl.spillLoc->allocreq = 1; + 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 = 1; + 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 = 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); + + /* mark the registers as free */ + for (i = 0; i < ssym->nRegs; i++) + if (ssym->regs[i]) + freeReg (ssym->regs[i]); + + /* 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 regs * +getRegPtr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + regs *reg; + + tryAgain: + /* try for a ptr type */ + if ((reg = allocReg (REG_PTR|REG_PAIR))) + return reg; + + /* try for gpr type / pair */ + if ((reg = allocReg (REG_GPR|REG_PAIR))) + return reg; + + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* this looks like an infinite loop but + in reality selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegScr - will try for SCR if not a GPR type if not spil */ +/*-----------------------------------------------------------------*/ +static regs * +getRegScr (iCode * ic, eBBlock * ebp, symbol * sym) +{ + regs *reg; + + tryAgain: + + /* try for a scratch non-pair */ + if ((reg = allocReg (REG_SCR))) + return reg; + + if ((reg = allocReg (REG_GPR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* this looks like an infinite loop but + in really selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* getRegGpr - will try for GPR if not spil */ +/*-----------------------------------------------------------------*/ +static regs * +getRegGpr (iCode * ic, eBBlock * ebp, symbol * sym ) +{ + regs *reg; + + tryAgain: + /* try for gpr type */ + if ((reg = allocReg (REG_GPR))) + return reg; + + if (!avr_ptrRegReq) + if ((reg = allocReg (REG_PTR))) + return reg; + + /* we have to spil */ + if (!spilSomething (ic, ebp, sym)) + return NULL; + + /* this looks like an infinite loop but + in reality selectSpil will abort */ + goto tryAgain; +} + +/*-----------------------------------------------------------------*/ +/* symHasReg - symbol has a given register */ +/*-----------------------------------------------------------------*/ +static bool +symHasReg (symbol * sym, regs * reg) +{ + int i; + + for (i = 0; i < sym->nRegs; i++) + if (sym->regs[i] == reg) + return TRUE; + + return FALSE; +} + +/*-----------------------------------------------------------------*/ +/* 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 if (result->regType == REG_SCR) + result->regs[i] = getRegScr (ic, ebp, result); + else + result->regs[i] = getRegGpr (ic, ebp, result); + } + _G.regAssigned = bitVectSetBit (_G.regAssigned, 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->blockSpil = sym->remainSpil = 0; + bitVectUnSetBit (_G.spiltSet, sym->key); + + _G.regAssigned = bitVectSetBit (_G.regAssigned, 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 avlb registers + of te 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 (avr_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 void +positionRegs (symbol * result, symbol * opsym, int lineno) +{ + int count = min (result->nRegs, opsym->nRegs); + int i, j = 0, shared = 0; + + /* if the result has been spilt then cannot share */ + if (opsym->isspilt) + return; + again: + 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) { + regs *tmp = result->regs[i]; + result->regs[i] = result->regs[j]; + result->regs[j] = tmp; + goto again; + } +} + +/*-----------------------------------------------------------------*/ +/* needsPair - heuristic to determine if a pair would be good */ +/*-----------------------------------------------------------------*/ +static int needsPair (iCode *ic) +{ + symbol *sym = OP_SYMBOL(IC_RESULT(ic)); + bitVect *uses_defs = + bitVectUnion(OP_USES (IC_RESULT(ic)),OP_DEFS(IC_RESULT(ic))); + + /* if size is less than 2 then NO */ + if (sym->nRegs < 2) return 0; + /* if type Pointer then YES */ + if (IS_PTR(sym->type)) return 1; + + /* go thru the usages of this operand if used with + a constant then yes */ + while (!bitVectIsZero(uses_defs)) { + int ikey = bitVectFirstBit(uses_defs); + iCode *uic = hTabItemWithKey(iCodehTab,ikey); + sym_link *otype = NULL; + bitVectUnSetBit(uses_defs,ikey); + if (!uic) continue; + otype = (IC_RIGHT(uic) ? operandType(IC_RIGHT(uic)) : NULL); + if (otype && IS_LITERAL(otype)) return 1; + } + return 0; +} + +/*-----------------------------------------------------------------*/ +/* 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++) { + + iCode *ic; + + if (ebbs[i]->noPath && + (ebbs[i]->entryLabel != entryLabel && + ebbs[i]->entryLabel != returnLabel)) + continue; + + /* of all instructions do */ + for (ic = ebbs[i]->sch; ic; ic = ic->next) { + + /* 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 = 1; + + /* 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=0; + + /* Make sure any spill location is definately 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; + } + /* if trying to allocate this will cause + a spill and there is nothing to spill + or this one is rematerializable then + spill this one */ + willCS = + willCauseSpill (sym->nRegs, + sym->regType); + 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)) { + spillThis (sym); + continue; + } + } + } + + /* we assign registers to it */ + _G.regAssigned = bitVectSetBit (_G.regAssigned, sym->key); + if (needsPair(ic)) { + short regtype ; + regs *preg; + if (sym->regType == REG_PTR) regtype = REG_PTR; + else if (sym->regType == REG_SCR) regtype = REG_SCR; + else regtype = REG_GPR; + preg = allocRegPair(regtype); + if (preg) { + sym->regs[j++] = preg; + sym->regs[j++] = ®sAVR[preg->rIdx+1]; + } + } + for (; j < sym->nRegs; j++) { + if (sym->regType == REG_PTR) + sym->regs[j] = getRegPtr (ic, ebbs[i], sym); + else if (sym->regType == REG_SCR) + sym->regs[j] = getRegScr (ic, ebbs[i], sym); + else + sym->regs[j] = getRegGpr (ic, ebbs[i], sym); + /* if the allocation falied 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 (IC_LEFT (ic) && IS_SYMOP (IC_LEFT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->nRegs + && ic->op != '=') + positionRegs (OP_SYMBOL (IC_RESULT (ic)), + OP_SYMBOL (IC_LEFT (ic)), ic->lineno); + /* 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)), ic->lineno); + + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* rUmaskForOp :- returns register mask for an operand */ +/*-----------------------------------------------------------------*/ +static bitVect * +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 (avr_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 (avr_nRegs); + + /* do the special cases first */ + if (ic->op == IFX) { + rmask = bitVectUnion (rmask, rUmaskForOp (IC_COND (ic))); + goto ret; + } + + /* for the jumptable */ + if (ic->op == JUMPTABLE) { + rmask = bitVectUnion (rmask, rUmaskForOp (IC_JTCOND (ic))); + + goto ret; + } + + /* of all other cases */ + if (IC_LEFT (ic)) + rmask = bitVectUnion (rmask, rUmaskForOp (IC_LEFT (ic))); + + + if (IC_RIGHT (ic)) + rmask = bitVectUnion (rmask, rUmaskForOp (IC_RIGHT (ic))); + + if (IC_RESULT (ic)) + rmask = bitVectUnion (rmask, 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 (avr_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"); + exit (0); + } + + /* 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]) { + int rIdx = sym->regs[k]->rIdx; + ic->rMask = bitVectSetBit (ic-> rMask,rIdx); + /* special case for X & Z registers */ + if (rIdx == R26_IDX || rIdx == R27_IDX) + ic->rMask = bitVectSetBit (ic->rMask, X_IDX); + if (rIdx == R30_IDX || rIdx == R31_IDX) + ic->rMask = bitVectSetBit (ic->rMask, Z_IDX); + } + } + } + } + } +} + + +/*-----------------------------------------------------------------*/ +/* 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 and the + pointer we are getting is rematerializable and + in "data" space */ + + if (bitVectnBitsOn (sym->defs) == 1 && + (ic = hTabItemWithKey (iCodehTab, bitVectFirstBit (sym-> defs))) + && POINTER_GET (ic) && !IS_BITVAR (sym->etype)) { + + /* 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 > 4) { + fprintf (stderr, + "allocated more than 4 or 0 registers for type "); + printTypeChain (sym->type, stderr); + fprintf (stderr, "\n"); + } + + /* determine the type of register required */ + if (sym->nRegs == 2 && /* size is two */ + IS_PTR (sym->type) && /* is a pointer */ + sym->uptr) { /* has pointer usage i.e. get/set pointer */ + sym->regType = REG_PTR; + avr_ptrRegReq++; + } + else { + /* live accross a function call then gpr else scratch */ + if (sym->isLiveFcall) + sym->regType = REG_GPR; + else + sym->regType = REG_SCR; + } + } + else + /* for the first run we don't provide */ + /* registers for true symbols we will */ + /* see how things go */ + sym->nRegs = 0; + } + +} + +/*-----------------------------------------------------------------*/ +/* deallocStackSpil - this will set the stack pointer back */ +/*-----------------------------------------------------------------*/ +static +DEFSETFUNC (deallocStackSpil) +{ + symbol *sym = item; + + deallocLocal (sym); + return 0; +} + +/*-----------------------------------------------------------------*/ +/* 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; + } + + /* 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 and this is + a parameter & not my parameter then don't pack it */ + if ((dic->op == CALL || dic->op == PCALL) && + (OP_SYMBOL (IC_RESULT (ic))->_isparm && + !OP_SYMBOL (IC_RESULT (ic))->ismyparm)) { + 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 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: + /* if in far space & tru symbol then don't */ + if ((IS_TRUE_SYMOP (IC_RESULT (ic))) + && isOperandInFarSpace (IC_RESULT (ic))) return 0; + /* found the definition */ + /* replace the result with the result of */ + /* this assignment and remove this assignment */ + 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; + } + /* 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); + } + + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, ic->key, ic, DELETE_ITEM, NULL); + return 1; + +} + + +/*-----------------------------------------------------------------*/ +/* packRegsForOneuse : - will reduce some registers for single Use */ +/*-----------------------------------------------------------------*/ +static iCode * +packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp) +{ + bitVect *uses; + iCode *dic, *sic; + + /* if returning a literal then do nothing */ + if (!IS_SYMOP (op)) + return NULL; + + /* returns only */ + if (ic->op != RETURN) + return NULL; + + /* this routine will mark the a symbol as used in one + instruction use only && if the defintion is local + (ie. within the basic block) && has only one definition && + that definiion is either a return value from a + function or does not contain any variables in + far space */ + uses = bitVectCopy (OP_USES (op)); + bitVectUnSetBit (uses, ic->key); /* take away this iCode */ + if (!bitVectIsZero (uses)) /* has other uses */ + return NULL; + + /* if it has only one defintion */ + if (bitVectnBitsOn (OP_DEFS (op)) > 1) + return NULL; /* has more than one definition */ + + /* get the that definition */ + if (!(dic = + hTabItemWithKey (iCodehTab, + bitVectFirstBit (OP_DEFS (op))))) return NULL; + + /* found the definition now check if it is local */ + if (dic->seq < ebp->fSeq || dic->seq > ebp->lSeq) + return NULL; /* non-local */ + + /* now check if it is the return from + a function call */ + if (dic->op == CALL || dic->op == PCALL) { + if (ic->op != SEND && ic->op != RETURN && + !POINTER_SET(ic) && !POINTER_GET(ic)) { + OP_SYMBOL (op)->ruonly = 1; + return dic; + } + dic = dic->next; + } + + + /* otherwise check that the definition does + not contain any symbols in far space */ + if (IS_OP_RUONLY (IC_LEFT (ic)) || IS_OP_RUONLY (IC_RIGHT (ic))) { + return NULL; + } + + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_RESULT (dic)), FALSE))) + return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr (operandType (IC_LEFT (dic)), FALSE))) + return NULL; + + sic = dic; + + /* also make sure the intervenening instructions + don't have any thing in far space */ + for (dic = dic->next; dic && dic != ic; dic = dic->next) { + + /* if there is an intervening function call then no */ + if (dic->op == CALL || dic->op == PCALL) + return NULL; + /* if pointer set then make sure the pointer + is one byte */ + if (POINTER_SET (dic) && + !IS_DATA_PTR (aggrToPtr + (operandType (IC_RESULT (dic)), + FALSE))) return NULL; + + if (POINTER_GET (dic) && + !IS_DATA_PTR (aggrToPtr + (operandType (IC_LEFT (dic)), + FALSE))) return NULL; + + /* if address of & the result is remat the okay */ + if (dic->op == ADDRESS_OF && + OP_SYMBOL (IC_RESULT (dic))->remat) continue; + + /* if operand has size of three or more & this + operation is a '*','/' or '%' then 'b' may + cause a problem */ + if ((dic->op == '%' || dic->op == '/' || dic->op == '*') && + getSize (operandType (op)) >= 3) + return NULL; + + /* if left or right or result is in far space */ + if (IS_OP_RUONLY (IC_LEFT (dic)) || + IS_OP_RUONLY (IC_RIGHT (dic)) || + IS_OP_RUONLY (IC_RESULT (dic))) { + return NULL; + } + } + + OP_SYMBOL (op)->ruonly = 1; + return sic; + +} + +/*-----------------------------------------------------------------*/ +/* 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; +} + +/*-----------------------------------------------------------------*/ +/* packRegisters - does some transformations to reduce register */ +/* pressure */ +/*-----------------------------------------------------------------*/ +static void +packRegisters (eBBlock * ebp) +{ + iCode *ic; + int change = 0; + + 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) { + + /* if this is an itemp & result of a 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 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 && + bitVectnBitsOn (OP_SYMBOL (IC_RESULT (ic))->defs) <= 1) { + + 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 this is a +/- operation with a rematerizable + then mark this as rematerializable as well only + if the literal value is within the range -255 and + 255 + the assembler cannot handle it other wise */ + if ((ic->op == '+' || ic->op == '-') && + (IS_SYMOP (IC_LEFT (ic)) && + IS_ITEMP (IC_RESULT (ic)) && + OP_SYMBOL (IC_LEFT (ic))->remat && + bitVectnBitsOn (OP_DEFS (IC_RESULT (ic))) == 1 && + IS_OP_LITERAL (IC_RIGHT (ic)))) { + + int i = (int) operandLitValue (IC_RIGHT (ic)); + if (i < 255 && i > -255) { + 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)) + OP_SYMBOL (IC_RESULT (ic))->uptr = 1; + + if (POINTER_GET (ic)) { + OP_SYMBOL (IC_LEFT (ic))->uptr = 1; + if (OP_SYMBOL (IC_LEFT(ic))->remat) + OP_SYMBOL (IC_RESULT (ic))->usl.spillLoc = NULL; + } + + /* if the condition of an if instruction + is defined in the previous instruction then + mark the itemp as a conditional */ + if ((IS_CONDITIONAL (ic) || + ((ic->op == BITWISEAND || + ic->op == '|' || + ic->op == '^') && + isBitwiseOptimizable (ic))) && + ic->next && ic->next->op == IFX && + 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; + } + + /* some cases the redundant moves can + can be eliminated for return statements */ + if ((ic->op == RETURN || ic->op == SEND)) + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + + /* if this is cast for intergral promotion then + check if 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 = + packRegsForOneuse (ic, IC_RIGHT (ic), + ebp); + if (dic) { + if (IS_ARITHMETIC_OP (dic)) { + IC_RESULT (dic) = + IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, + ic->key, ic, + DELETE_ITEM, + NULL); + 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 = + packRegsForOneuse (ic, + IC_RIGHT + (ic), ebp); + if (dic) { + IC_RESULT (dic) = + IC_RESULT (ic); + remiCodeFromeBBlock (ebp, ic); + hTabDeleteItem (&iCodehTab, + ic->key, ic, + DELETE_ITEM, + NULL); + ic = ic->prev; + } + } + } + } + } +} + +/*-----------------------------------------------------------------*/ +/* preAssignParms - we have a leaf function preassign registers */ +/*-----------------------------------------------------------------*/ +static void +preAssignParms (iCode * ic) +{ + int i = R16_IDX; + /* look for receives and assign registers + to the result of the receives */ + while (ic) { + /* if it is a receive */ + if (ic->op == RECEIVE) { + symbol *r = OP_SYMBOL (IC_RESULT (ic)); + int size = getSize (r->type); + if (r->regType == REG_GPR || r->regType == REG_SCR) { + int j = 0; + while (size--) { + r->regs[j++] = ®sAVR[i++]; + regsAVR[i - 1].isFree = 0; + } + /* put in the regassigned vector */ + _G.regAssigned = + bitVectSetBit (_G.regAssigned, + r->key); + } + else { + /* not a GPR then we should mark as free */ + while (size--) { + regsAVR[i++].isFree = 1; + } + } + } + ic = ic->next; + } + /* mark anything remaining as free */ + while (i <= R23_IDX) + regsAVR[i++].isFree = 1; +} + +/*-----------------------------------------------------------------*/ +/* setdefaultRegs - do setup stuff for register allocation */ +/*-----------------------------------------------------------------*/ +static void +setDefaultRegs (eBBlock ** ebbs, int count) +{ + int i; + + /* if no pointer registers required in this function + then mark r26-27 & r30-r31 as GPR & free */ + regsAVR[R26_IDX].isFree = + regsAVR[R27_IDX].isFree = + regsAVR[R30_IDX].isFree = regsAVR[R31_IDX].isFree = 1; + + if (!avr_ptrRegReq) { + regsAVR[R26_IDX].type = (regsAVR[R26_IDX].type & ~REG_MASK) | REG_GPR; + regsAVR[R27_IDX].type = (regsAVR[R27_IDX].type & ~REG_MASK) | REG_GPR; + regsAVR[R28_IDX].type = (regsAVR[R28_IDX].type & ~REG_MASK) | REG_GPR; + regsAVR[R29_IDX].type = (regsAVR[R29_IDX].type & ~REG_MASK) | REG_GPR; + } + else { + regsAVR[R26_IDX].type = (regsAVR[R26_IDX].type & ~REG_MASK) | REG_PTR; + regsAVR[R27_IDX].type = (regsAVR[R27_IDX].type & ~REG_MASK) | REG_PTR; + regsAVR[R30_IDX].type = (regsAVR[R30_IDX].type & ~REG_MASK) | REG_PTR; + regsAVR[R31_IDX].type = (regsAVR[R31_IDX].type & ~REG_MASK) | REG_PTR; + } + + /* registers 0-1 / 24-25 used as scratch */ + regsAVR[R0_IDX].isFree = + regsAVR[R1_IDX].isFree = + regsAVR[R24_IDX].isFree = regsAVR[R25_IDX].isFree = 0; + + /* if this has no function calls then we need + to do something special + a) pre-assign registers to parameters RECEIVE + b) mark the remaining parameter regs as free */ + /* mark the parameter regs as SCRACH */ + for (i = R16_IDX; i <= R23_IDX; i++) { + regsAVR[i].type = (regsAVR[i].type & ~REG_MASK) | REG_SCR; + regsAVR[i].isFree = 1; + } + if (!IFFUNC_HASFCALL(currFunc->type)) { + preAssignParms (ebbs[0]->sch); + } + /* Y - is not allocated (it is the stack frame) */ + regsAVR[R28_IDX].isFree = regsAVR[R28_IDX].isFree = 0; +} + +/*-----------------------------------------------------------------*/ +/* assignRegisters - assigns registers to each live range as need */ +/*-----------------------------------------------------------------*/ +void +avr_assignRegisters (ebbIndex * ebbi) +{ + eBBlock ** ebbs = ebbi->bbOrder; + int count = ebbi->count; + iCode *ic; + int i; + + setToNull ((void *) &_G.funcrUsed); + avr_ptrRegReq = _G.stackExtend = _G.dataExtend = 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); + + 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 (); + + /* setup the default registers */ + setDefaultRegs (ebbs, count); + + /* and serially allocate registers */ + serialRegAssign (ebbs, count); + + /* 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 */ + redoStackOffsets (); + + if (options.dump_i_code) + dumpEbbsToFileExt (DUMP_RASSGN, ebbi); + + /* now get back the chain */ + ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); + + + genAVRCode (ic); + /* for (; ic ; ic = ic->next) */ + /* piCode(ic,stdout); */ + /* 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 */ + + return; +} diff --git a/src/avr/ralloc.h b/src/avr/ralloc.h new file mode 100644 index 0000000..b146bca --- /dev/null +++ b/src/avr/ralloc.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + + 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 + { + R0_IDX = 0, R1_IDX, R2_IDX, R3_IDX, R4_IDX, + R5_IDX, R6_IDX, R7_IDX, R8_IDX, R9_IDX, + R10_IDX, R11_IDX, R12_IDX, R13_IDX, R14_IDX, + R15_IDX, R16_IDX, R17_IDX, R18_IDX, R19_IDX, + R20_IDX, R21_IDX, R22_IDX, R23_IDX, R24_IDX, + R25_IDX, R26_IDX, R27_IDX, R28_IDX, R29_IDX, + R30_IDX, R31_IDX, X_IDX, Z_IDX, CND_IDX + }; + + +#define REG_PTR 0x01 +#define REG_GPR 0x02 +#define REG_SCR 0x04 +#define REG_CND 0x08 +#define REG_MASK 0x0f +#define REG_PAIR 0x10 + +/* definition for the registers */ +typedef struct regs + { + 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 */ + unsigned saveReq:1; /* save required @ function entry ? */ + } +regs; +extern regs regsAVR[]; + +regs *avr_regWithIdx (int); + +#endif |
