summaryrefslogtreecommitdiff
path: root/src/SDCCgen.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCgen.c
downloadsdcc-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/SDCCgen.c')
-rw-r--r--src/SDCCgen.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/SDCCgen.c b/src/SDCCgen.c
new file mode 100644
index 0000000..fb775fd
--- /dev/null
+++ b/src/SDCCgen.c
@@ -0,0 +1,355 @@
+/*-------------------------------------------------------------------------
+ SDCCgen.c - source files for target code generation common functions
+
+ Copyright (C) 2012, Borut Razem
+
+ 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 "common.h"
+#include "dbuf_string.h"
+
+/* Use the D macro for basic (unobtrusive) debugging messages */
+#define D(x) do if (options.verboseAsm) {x;} while(0)
+
+genLine_t genLine;
+
+/*-----------------------------------------------------------------*/
+/* newLineNode - creates a new peep line */
+/*-----------------------------------------------------------------*/
+lineNode *
+newLineNode (const char *line)
+{
+ lineNode *pl;
+
+ pl = Safe_alloc (sizeof (lineNode));
+ pl->line = Safe_strdup (line);
+ pl->ic = NULL;
+ return pl;
+}
+
+/*-----------------------------------------------------------------*/
+/* connectLine - connects two lines */
+/*-----------------------------------------------------------------*/
+lineNode *
+connectLine (lineNode * pl1, lineNode * pl2)
+{
+ if (!pl1 || !pl2)
+ {
+ fprintf (stderr, "trying to connect null line\n");
+ return NULL;
+ }
+
+ pl2->prev = pl1;
+ pl1->next = pl2;
+
+ return pl2;
+}
+
+void
+destroy_line_list (void)
+{
+ lineNode *pl;
+
+ pl = genLine.lineCurr;
+
+ while (pl)
+ {
+ lineNode *p;
+
+ if (pl->line)
+ Safe_free (pl->line);
+
+ if (pl->aln)
+ Safe_free (pl->aln);
+
+ p = pl;
+ pl = pl->prev;
+ Safe_free (p);
+ }
+ genLine.lineHead = genLine.lineCurr = NULL;
+}
+
+/*-----------------------------------------------------------------*/
+/* emit_raw - emit raw unformatted line */
+/*-----------------------------------------------------------------*/
+static void
+add_line_node (const char *line)
+{
+ lineNode *pl;
+
+ pl = Safe_alloc (sizeof (lineNode));
+
+ memcpy (pl, (lineElem_t *) & genLine.lineElement, sizeof (lineElem_t));
+
+ pl->line = Safe_strdup (line);
+
+ if (genLine.lineCurr)
+ {
+ pl->next = NULL;
+ genLine.lineCurr->next = pl;
+ pl->prev = genLine.lineCurr;
+ genLine.lineCurr = pl;
+ }
+ else
+ {
+ pl->prev = pl->next = NULL;
+ genLine.lineCurr = genLine.lineHead = pl;
+ }
+}
+
+void
+emit_raw (const char *line)
+{
+ const char *p = line;
+
+ while (isspace ((unsigned char) *p))
+ p++;
+
+ if (*p)
+ {
+ if (!port->rtrackUpdate || !port->rtrackUpdate(line))
+ {
+ genLine.lineElement.isComment = (*p == ';');
+ add_line_node (line);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* format_opcode - format the opcode and arguments for emitting */
+/*-----------------------------------------------------------------*/
+const char *
+format_opcode (const char *inst, const char *fmt, va_list ap)
+{
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, INITIAL_INLINEASM);
+
+ if (inst && *inst)
+ {
+ dbuf_append_str (&dbuf, inst);
+
+ if (fmt && *fmt)
+ {
+ dbuf_append_char (&dbuf, '\t');
+ dbuf_tvprintf (&dbuf, fmt, ap);
+ }
+ }
+ else
+ {
+ if (fmt && *fmt)
+ {
+ dbuf_tvprintf (&dbuf, fmt, ap);
+ }
+ }
+
+ return dbuf_detach_c_str (&dbuf);
+}
+
+void
+va_emitcode (const char *inst, const char *fmt, va_list ap)
+{
+ const char *line = format_opcode (inst, fmt, ap);
+ emit_raw (line);
+ dbuf_free (line);
+}
+
+/*-----------------------------------------------------------------*/
+/* emitcode - writes the code into a file : for now it is simple */
+/*-----------------------------------------------------------------*/
+void
+emitcode (const char *inst, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ va_emitcode (inst, fmt, ap);
+ va_end (ap);
+}
+
+void
+emitLabel (symbol *tlbl)
+{
+ if (!tlbl)
+ return;
+ emitcode ("", "!tlabeldef", labelKey2num (tlbl->key));
+ genLine.lineCurr->isLabel = 1;
+}
+
+/*-----------------------------------------------------------------*/
+/* genInline - write the inline code out */
+/*-----------------------------------------------------------------*/
+void
+genInline (iCode * ic)
+{
+ char *buf, *bp, *begin;
+ bool inComment = FALSE;
+ bool inLiteral = FALSE;
+ bool inLiteralString = FALSE;
+
+ D (emitcode (";", "genInline"));
+
+ genLine.lineElement.isInline += (!options.asmpeep);
+
+ buf = bp = begin = Safe_strdup (IC_INLINE (ic));
+
+ /* Emit each line as a code */
+ while (*bp)
+ {
+ switch (*bp)
+ {
+ case '\'':
+ inLiteral = !inLiteral;
+ ++bp;
+ break;
+
+ case '"':
+ inLiteralString = !inLiteralString;
+ ++bp;
+ break;
+
+ case ';':
+ if (!inLiteral && !inLiteralString)
+ {
+ inComment = TRUE;
+ }
+ ++bp;
+ break;
+
+ case ':':
+ /* Add \n for labels, not dirs such as c:\mydir */
+ if (!inComment && !inLiteral && !inLiteralString && (isspace ((unsigned char) bp[1])))
+ {
+ ++bp;
+ *bp = '\0';
+ ++bp;
+ emitcode (begin, NULL);
+ begin = bp;
+ }
+ else
+ {
+ ++bp;
+ }
+ break;
+
+ case '\x87':
+ case '\n':
+ inLiteral = FALSE;
+ inLiteralString = FALSE;
+ inComment = FALSE;
+ *bp++ = '\0';
+
+ /* Don't emit leading whitespaces */
+ while (isspace (*begin))
+ ++begin;
+
+ if (*begin)
+ emitcode (begin, NULL);
+
+ begin = bp;
+ break;
+
+ default:
+ ++bp;
+ break;
+ }
+ }
+ if (begin != bp)
+ {
+ /* Don't emit leading whitespaces */
+ while (isspace (*begin))
+ ++begin;
+
+ if (*begin)
+ emitcode (begin, NULL);
+ }
+
+ Safe_free (buf);
+
+ /* consumed; we can free it here */
+ dbuf_free (IC_INLINE (ic));
+
+ genLine.lineElement.isInline -= (!options.asmpeep);
+}
+
+/*-----------------------------------------------------------------*/
+/* printLine - prints a line chain into a given file */
+/*-----------------------------------------------------------------*/
+void
+printLine (lineNode * head, struct dbuf_s *oBuf)
+{
+ iCode *last_ic = NULL;
+ bool debug_iCode_tracking = (getenv ("DEBUG_ICODE_TRACKING") != NULL);
+
+ while (head)
+ {
+ if (head->ic != last_ic)
+ {
+ last_ic = head->ic;
+ if (debug_iCode_tracking)
+ {
+ if (head->ic)
+ dbuf_printf (oBuf, "; block = %d, seq = %d\n", head->ic->block, head->ic->seq);
+ else
+ dbuf_append_str (oBuf, "; iCode lost\n");
+ }
+ }
+
+ /* don't indent comments & labels */
+ if (head->line && (head->isComment || head->isLabel))
+ {
+ dbuf_printf (oBuf, "%s\n", head->line);
+ }
+ else
+ {
+ if (head->isInline && *head->line == '#')
+ {
+ /* comment out preprocessor directives in inline asm */
+ dbuf_append_char (oBuf, ';');
+ }
+ dbuf_printf (oBuf, "\t%s\n", head->line);
+ }
+ head = head->next;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* ifxForOp - returns the icode containing the ifx for operand */
+/*-----------------------------------------------------------------*/
+iCode *
+ifxForOp (const operand *op, const iCode *ic)
+{
+ iCode *ifxIc;
+
+ /* if true symbol then needs to be assigned */
+ if (!IS_TRUE_SYMOP (op))
+ {
+ /* if this has register type condition and
+ while skipping ipop's (see bug 1509084),
+ the next instruction is ifx with the same operand
+ and live to of the operand is upto the ifx only then */
+ for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next)
+ ;
+
+ if (ifxIc && ifxIc->op == IFX &&
+ IC_COND (ifxIc)->key == op->key &&
+ OP_SYMBOL_CONST (op)->liveFrom >= ic->seq &&
+ OP_SYMBOL_CONST (op)->liveTo <= ifxIc->seq)
+ return ifxIc;
+ }
+
+ return NULL;
+}