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