1 /*-------------------------------------------------------------------------
2 SDCCgen.c - source files for target code generation common functions
4 Copyright (C) 2012, Borut Razem
5 Copyright (C) 2022, Sebastian 'basxto' Riedel <sdcc@basxto.de>
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 -------------------------------------------------------------------------*/
23 #include "dbuf_string.h"
25 /* Use the D macro for basic (unobtrusive) debugging messages */
26 #define D(x) do if (options.verboseAsm) {x;} while(0)
30 /*-----------------------------------------------------------------*/
31 /* newLineNode - creates a new peep line */
32 /*-----------------------------------------------------------------*/
34 newLineNode (const char *line
)
38 pl
= Safe_alloc (sizeof (lineNode
));
39 pl
->line
= Safe_strdup (line
);
44 /*-----------------------------------------------------------------*/
45 /* connectLine - connects two lines */
46 /*-----------------------------------------------------------------*/
48 connectLine (lineNode
* pl1
, lineNode
* pl2
)
52 fprintf (stderr
, "trying to connect null line\n");
63 destroy_line_list (void)
67 pl
= genLine
.lineCurr
;
83 genLine
.lineHead
= genLine
.lineCurr
= NULL
;
86 /*-----------------------------------------------------------------*/
87 /* emit_raw - emit raw unformatted line */
88 /*-----------------------------------------------------------------*/
90 add_line_node (const char *line
)
94 pl
= Safe_alloc (sizeof (lineNode
));
96 memcpy (pl
, (lineElem_t
*) & genLine
.lineElement
, sizeof (lineElem_t
));
98 pl
->line
= Safe_strdup (line
);
100 if (genLine
.lineCurr
)
103 genLine
.lineCurr
->next
= pl
;
104 pl
->prev
= genLine
.lineCurr
;
105 genLine
.lineCurr
= pl
;
109 pl
->prev
= pl
->next
= NULL
;
110 genLine
.lineCurr
= genLine
.lineHead
= pl
;
115 emit_raw (const char *line
)
117 const char *p
= line
;
119 while (isspace ((unsigned char) *p
))
124 if (!port
->rtrackUpdate
|| !port
->rtrackUpdate(line
))
126 genLine
.lineElement
.isComment
= (*p
== ';');
127 add_line_node (line
);
132 /*-----------------------------------------------------------------*/
133 /* format_opcode - format the opcode and arguments for emitting */
134 /*-----------------------------------------------------------------*/
136 format_opcode (const char *inst
, const char *fmt
, va_list ap
)
140 dbuf_init (&dbuf
, INITIAL_INLINEASM
);
144 dbuf_append_str (&dbuf
, inst
);
148 dbuf_append_char (&dbuf
, '\t');
149 dbuf_tvprintf (&dbuf
, fmt
, ap
);
156 dbuf_tvprintf (&dbuf
, fmt
, ap
);
160 return dbuf_detach_c_str (&dbuf
);
164 va_emitcode (const char *inst
, const char *fmt
, va_list ap
)
166 const char *line
= format_opcode (inst
, fmt
, ap
);
171 /*-----------------------------------------------------------------*/
172 /* emitcode - writes the code into a file : for now it is simple */
173 /*-----------------------------------------------------------------*/
175 emitcode (const char *inst
, const char *fmt
, ...)
180 va_emitcode (inst
, fmt
, ap
);
185 emitLabel (const symbol
*tlbl
)
189 emitcode ("", "!tlabeldef", labelKey2num (tlbl
->key
));
190 genLine
.lineCurr
->isLabel
= 1;
193 /*-----------------------------------------------------------------*/
194 /* genInline - write the inline code out */
195 /*-----------------------------------------------------------------*/
197 genInline (iCode
* ic
)
199 char *buf
, *bp
, *begin
;
200 bool inComment
= FALSE
;
201 bool inLiteral
= FALSE
;
202 bool inLiteralString
= FALSE
;
204 D (emitcode (";", "genInline"));
206 genLine
.lineElement
.isInline
+= (!options
.asmpeep
);
208 buf
= bp
= begin
= Safe_strdup (IC_INLINE (ic
));
210 /* Emit each line as a code */
216 inLiteral
= !inLiteral
;
221 inLiteralString
= !inLiteralString
;
226 if (!inLiteral
&& !inLiteralString
)
234 /* Add \n for labels, not dirs such as c:\mydir, not local direct assignment =: */
235 if (!inComment
&& !inLiteral
&& !inLiteralString
&& (isspace ((unsigned char) bp
[1])) && (*(bp
-1) != '='))
240 /* Don't emit leading whitespaces */
241 while (isspace (*begin
))
243 emitcode (begin
, NULL
);
244 genLine
.lineCurr
->isLabel
= 1;
256 inLiteralString
= FALSE
;
260 /* Don't emit leading whitespaces */
261 while (isspace (*begin
))
265 emitcode (begin
, NULL
);
277 /* Don't emit leading whitespaces */
278 while (isspace (*begin
))
282 emitcode (begin
, NULL
);
287 /* consumed; we can free it here */
288 dbuf_free (IC_INLINE (ic
));
290 genLine
.lineElement
.isInline
-= (!options
.asmpeep
);
293 /*-----------------------------------------------------------------*/
294 /* printLine - prints a line chain into a given file */
295 /*-----------------------------------------------------------------*/
297 printLine (lineNode
* head
, struct dbuf_s
*oBuf
)
299 iCode
*last_ic
= NULL
;
300 bool debug_iCode_tracking
= (getenv ("DEBUG_ICODE_TRACKING") != NULL
);
304 if (head
->ic
!= last_ic
)
307 if (debug_iCode_tracking
)
310 dbuf_printf (oBuf
, "; block = %d, seq = %d\n", head
->ic
->block
, head
->ic
->seq
);
312 dbuf_append_str (oBuf
, "; iCode lost\n");
316 /* don't indent comments & labels */
317 if (head
->line
&& (head
->isComment
|| head
->isLabel
))
319 dbuf_printf (oBuf
, "%s\n", head
->line
);
323 if (head
->isInline
&& *head
->line
== '#')
325 /* comment out preprocessor directives in inline asm */
326 dbuf_append_char (oBuf
, ';');
328 dbuf_printf (oBuf
, "\t%s\n", head
->line
);
334 /*-----------------------------------------------------------------*/
335 /* ifxForOp - returns the icode containing the ifx for operand */
336 /*-----------------------------------------------------------------*/
338 ifxForOp (const operand
*op
, const iCode
*ic
)
342 /* if true symbol then needs to be assigned */
343 if (!IS_TRUE_SYMOP (op
))
345 /* if this has register type condition and
346 while skipping ipop's (see bug 1509084),
347 the next instruction is ifx with the same operand
348 and live to of the operand is upto the ifx only then */
349 for (ifxIc
= ic
->next
; ifxIc
&& ifxIc
->op
== IPOP
; ifxIc
= ifxIc
->next
)
352 if (ifxIc
&& ifxIc
->op
== IFX
&&
353 IC_COND (ifxIc
)->key
== op
->key
&&
354 OP_SYMBOL_CONST (op
)->liveFrom
>= ic
->seq
&&
355 OP_SYMBOL_CONST (op
)->liveTo
<= ifxIc
->seq
)