]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/dmd/iasmgcc.c
ipa-param-manip: Be careful about a reallocating hash_map
[thirdparty/gcc.git] / gcc / d / dmd / iasmgcc.c
CommitLineData
b4c522fa
IB
1
2/* Compiler implementation of the D programming language
a3b38b77 3 * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
b4c522fa
IB
4 * written by Iain Buclaw
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/iasmgcc.c
9 */
10
11/* Inline assembler for the GCC D compiler.
12 */
13
14#include "scope.h"
a3b38b77 15#include "expression.h"
b4c522fa 16#include "declaration.h"
e41d4a0a 17#include "errors.h"
b4c522fa
IB
18#include "parse.h"
19#include "statement.h"
20
b4c522fa
IB
21/***********************************
22 * Parse list of extended asm input or output operands.
23 * Grammar:
24 * | Operands:
e41d4a0a
IB
25 * | SymbolicName(opt) StringLiteral ( AssignExpression )
26 * | SymbolicName(opt) StringLiteral ( AssignExpression ), Operands
b4c522fa
IB
27 * |
28 * | SymbolicName:
29 * | [ Identifier ]
30 * Params:
31 * p = parser state
32 * s = asm statement to parse
33 * Returns:
34 * number of operands added to the gcc asm statement
35 */
36static int parseExtAsmOperands(Parser *p, GccAsmStatement *s)
37{
38 int numargs = 0;
39
40 while (1)
41 {
42 Expression *arg = NULL;
43 Identifier *name = NULL;
44 Expression *constraint = NULL;
45
46 switch (p->token.value)
47 {
48 case TOKsemicolon:
49 case TOKcolon:
50 case TOKeof:
51 return numargs;
52
53 case TOKlbracket:
54 if (p->peekNext() == TOKidentifier)
55 {
e41d4a0a 56 // Skip over openings `[`
b4c522fa 57 p->nextToken();
e41d4a0a 58 // Store the symbolic name
b4c522fa
IB
59 name = p->token.ident;
60 p->nextToken();
61 }
62 else
63 {
64 p->error(s->loc, "expected identifier after `[`");
65 goto Lerror;
66 }
e41d4a0a 67 // Look for closing `]`
b4c522fa 68 p->check(TOKrbracket);
e41d4a0a
IB
69 // Look for the string literal and fall through
70 if (p->token.value != TOKstring)
71 goto Ldefault;
b4c522fa
IB
72 // fall through
73
74 case TOKstring:
75 constraint = p->parsePrimaryExp();
e41d4a0a
IB
76 // @@@DEPRECATED@@@
77 // Old parser allowed omitting parentheses around the expression.
78 // Deprecated in 2.091. Can be made permanent error after 2.100
79 if (p->token.value != TOKlparen)
80 {
81 arg = p->parseAssignExp();
82 deprecation(arg->loc, "`%s` must be surrounded by parentheses", arg->toChars());
83 }
84 else
85 {
86 // Look for the opening `(`
87 p->check(TOKlparen);
88 // Parse the assign expression
89 arg = p->parseAssignExp();
90 // Look for the closing `)`
91 p->check(TOKrparen);
92 }
b4c522fa
IB
93
94 if (!s->args)
95 {
96 s->names = new Identifiers();
97 s->constraints = new Expressions();
98 s->args = new Expressions();
99 }
100 s->names->push(name);
101 s->args->push(arg);
102 s->constraints->push(constraint);
103 numargs++;
104
105 if (p->token.value == TOKcomma)
106 p->nextToken();
107 break;
108
109 default:
e41d4a0a 110 Ldefault:
b4c522fa
IB
111 p->error("expected constant string constraint for operand, not `%s`",
112 p->token.toChars());
113 goto Lerror;
114 }
115 }
116Lerror:
117 while (p->token.value != TOKrcurly &&
118 p->token.value != TOKsemicolon &&
119 p->token.value != TOKeof)
120 p->nextToken();
121
122 return numargs;
123}
124
125/***********************************
126 * Parse list of extended asm clobbers.
127 * Grammar:
128 * | Clobbers:
129 * | StringLiteral
130 * | StringLiteral , Clobbers
131 * Params:
132 * p = parser state
133 * Returns:
134 * array of parsed clobber expressions
135 */
136static Expressions *parseExtAsmClobbers(Parser *p)
137{
138 Expressions *clobbers = NULL;
139
140 while (1)
141 {
142 Expression *clobber;
143
144 switch (p->token.value)
145 {
146 case TOKsemicolon:
147 case TOKcolon:
148 case TOKeof:
149 return clobbers;
150
151 case TOKstring:
152 clobber = p->parsePrimaryExp();
153 if (!clobbers)
154 clobbers = new Expressions();
155 clobbers->push(clobber);
156
157 if (p->token.value == TOKcomma)
158 p->nextToken();
159 break;
160
161 default:
162 p->error("expected constant string constraint for clobber name, not `%s`",
163 p->token.toChars());
164 goto Lerror;
165 }
166 }
167Lerror:
168 while (p->token.value != TOKrcurly &&
169 p->token.value != TOKsemicolon &&
170 p->token.value != TOKeof)
171 p->nextToken();
172
173 return clobbers;
174}
175
176/***********************************
177 * Parse list of extended asm goto labels.
178 * Grammar:
179 * | GotoLabels:
180 * | Identifier
181 * | Identifier , GotoLabels
182 * Params:
183 * p = parser state
184 * Returns:
185 * array of parsed goto labels
186 */
187static Identifiers *parseExtAsmGotoLabels(Parser *p)
188{
189 Identifiers *labels = NULL;
190
191 while (1)
192 {
193 switch (p->token.value)
194 {
195 case TOKsemicolon:
196 case TOKeof:
197 return labels;
198
199 case TOKidentifier:
200 if (!labels)
201 labels = new Identifiers();
202 labels->push(p->token.ident);
203
204 if (p->nextToken() == TOKcomma)
205 p->nextToken();
206 break;
207
208 default:
209 p->error("expected identifier for goto label name, not `%s`",
210 p->token.toChars());
211 goto Lerror;
212 }
213 }
214Lerror:
215 while (p->token.value != TOKrcurly &&
216 p->token.value != TOKsemicolon &&
217 p->token.value != TOKeof)
218 p->nextToken();
219
220 return labels;
221}
222
223/***********************************
224 * Parse a gcc asm statement.
225 * There are three forms of inline asm statements, basic, extended, and goto.
226 * Grammar:
227 * | AsmInstruction:
228 * | BasicAsmInstruction
229 * | ExtAsmInstruction
230 * | GotoAsmInstruction
231 * |
232 * | BasicAsmInstruction:
233 * | Expression
234 * |
235 * | ExtAsmInstruction:
236 * | Expression : Operands(opt) : Operands(opt) : Clobbers(opt)
237 * |
238 * | GotoAsmInstruction:
239 * | Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
240 * Params:
241 * p = parser state
242 * s = asm statement to parse
243 * Returns:
244 * the parsed gcc asm statement
245 */
246static GccAsmStatement *parseGccAsm(Parser *p, GccAsmStatement *s)
247{
248 s->insn = p->parseExpression();
2b5e01fa 249 if (p->token.value == TOKsemicolon || p->token.value == TOKeof)
b4c522fa
IB
250 goto Ldone;
251
252 // No semicolon followed after instruction template, treat as extended asm.
253 for (int section = 0; section < 4; ++section)
254 {
255 p->check(TOKcolon);
256
257 switch (section)
258 {
259 case 0:
260 s->outputargs = parseExtAsmOperands(p, s);
261 break;
262
263 case 1:
264 parseExtAsmOperands(p, s);
265 break;
266
267 case 2:
268 s->clobbers = parseExtAsmClobbers(p);
269 break;
270
271 case 3:
272 s->labels = parseExtAsmGotoLabels(p);
273 break;
274
275 default:
276 assert(0);
277 }
278
2b5e01fa 279 if (p->token.value == TOKsemicolon || p->token.value == TOKeof)
b4c522fa
IB
280 goto Ldone;
281 }
282Ldone:
283 p->check(TOKsemicolon);
284
285 return s;
286}
287
288/***********************************
289 * Parse and run semantic analysis on a GccAsmStatement.
290 * Params:
291 * s = gcc asm statement being parsed
292 * sc = the scope where the asm statement is located
293 * Returns:
294 * the completed gcc asm statement, or null if errors occurred
295 */
296Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc)
297{
298 //printf("GccAsmStatement::semantic()\n");
299 Parser p(sc->_module, (const utf8_t *)";", 1, false);
300
301 // Make a safe copy of the token list before parsing.
302 Token *toklist = NULL;
303 Token **ptoklist = &toklist;
304
305 for (Token *token = s->tokens; token; token = token->next)
306 {
307 *ptoklist = Token::alloc();
308 memcpy(*ptoklist, token, sizeof(Token));
309 ptoklist = &(*ptoklist)->next;
310 *ptoklist = NULL;
311 }
312 p.token = *toklist;
2b5e01fa 313 p.scanloc = s->loc;
b4c522fa
IB
314
315 // Parse the gcc asm statement.
316 s = parseGccAsm(&p, s);
317 if (p.errors)
318 return NULL;
319 s->stc = sc->stc;
320
321 // Fold the instruction template string.
a3b38b77 322 s->insn = expressionSemantic(s->insn, sc);
b4c522fa
IB
323 s->insn = s->insn->ctfeInterpret();
324
325 if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1)
326 s->insn->error("asm instruction template must be a constant char string");
327
328 if (s->labels && s->outputargs)
329 s->error("extended asm statements with labels cannot have output constraints");
330
331 // Analyse all input and output operands.
332 if (s->args)
333 {
2cbc99d1 334 for (size_t i = 0; i < s->args->length; i++)
b4c522fa
IB
335 {
336 Expression *e = (*s->args)[i];
a3b38b77 337 e = expressionSemantic(e, sc);
b4c522fa
IB
338 // Check argument is a valid lvalue/rvalue.
339 if (i < s->outputargs)
340 e = e->modifiableLvalue(sc, NULL);
341 else if (e->checkValue())
342 e = new ErrorExp();
343 (*s->args)[i] = e;
344
345 e = (*s->constraints)[i];
a3b38b77 346 e = expressionSemantic(e, sc);
b4c522fa
IB
347 assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
348 (*s->constraints)[i] = e;
349 }
350 }
351
352 // Analyse all clobbers.
353 if (s->clobbers)
354 {
2cbc99d1 355 for (size_t i = 0; i < s->clobbers->length; i++)
b4c522fa
IB
356 {
357 Expression *e = (*s->clobbers)[i];
a3b38b77 358 e = expressionSemantic(e, sc);
b4c522fa
IB
359 assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
360 (*s->clobbers)[i] = e;
361 }
362 }
363
364 // Analyse all goto labels.
365 if (s->labels)
366 {
2cbc99d1 367 for (size_t i = 0; i < s->labels->length; i++)
b4c522fa
IB
368 {
369 Identifier *ident = (*s->labels)[i];
370 GotoStatement *gs = new GotoStatement(s->loc, ident);
371 if (!s->gotos)
372 s->gotos = new GotoStatements();
373 s->gotos->push(gs);
a3b38b77 374 statementSemantic(gs, sc);
b4c522fa
IB
375 }
376 }
377
378 return s;
379}