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