1 2 /* Compiler implementation of the D programming language 3 * Copyright (C) 2018-2019 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 || p->token.value == TOKeof) 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 || p->token.value == TOKeof) 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 p.scanloc = s->loc; 292 293 // Parse the gcc asm statement. 294 s = parseGccAsm(&p, s); 295 if (p.errors) 296 return NULL; 297 s->stc = sc->stc; 298 299 // Fold the instruction template string. 300 s->insn = semantic(s->insn, sc); 301 s->insn = s->insn->ctfeInterpret(); 302 303 if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1) 304 s->insn->error("asm instruction template must be a constant char string"); 305 306 if (s->labels && s->outputargs) 307 s->error("extended asm statements with labels cannot have output constraints"); 308 309 // Analyse all input and output operands. 310 if (s->args) 311 { 312 for (size_t i = 0; i < s->args->dim; i++) 313 { 314 Expression *e = (*s->args)[i]; 315 e = semantic(e, sc); 316 // Check argument is a valid lvalue/rvalue. 317 if (i < s->outputargs) 318 e = e->modifiableLvalue(sc, NULL); 319 else if (e->checkValue()) 320 e = new ErrorExp(); 321 (*s->args)[i] = e; 322 323 e = (*s->constraints)[i]; 324 e = semantic(e, sc); 325 assert(e->op == TOKstring && ((StringExp *) e)->sz == 1); 326 (*s->constraints)[i] = e; 327 } 328 } 329 330 // Analyse all clobbers. 331 if (s->clobbers) 332 { 333 for (size_t i = 0; i < s->clobbers->dim; i++) 334 { 335 Expression *e = (*s->clobbers)[i]; 336 e = semantic(e, sc); 337 assert(e->op == TOKstring && ((StringExp *) e)->sz == 1); 338 (*s->clobbers)[i] = e; 339 } 340 } 341 342 // Analyse all goto labels. 343 if (s->labels) 344 { 345 for (size_t i = 0; i < s->labels->dim; i++) 346 { 347 Identifier *ident = (*s->labels)[i]; 348 GotoStatement *gs = new GotoStatement(s->loc, ident); 349 if (!s->gotos) 350 s->gotos = new GotoStatements(); 351 s->gotos->push(gs); 352 semantic(gs, sc); 353 } 354 } 355 356 return s; 357 } 358