Skip to content

Commit

Permalink
Add parser and some semantic support for gdc extended asm statements
Browse files Browse the repository at this point in the history
  • Loading branch information
ibuclaw committed Dec 31, 2017
1 parent 62c913e commit 1528dc3
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,18 @@ public:
// we can't compile asm statements
}

version (IN_GCC)
{
override void visit(ExtAsmStatement s)
{
debug (LOGCOMPILE)
{
printf("%s ExtAsmStatement::ctfeCompile\n", s.loc.toChars());
}
// we can't compile extended asm statements
}
}

void ctfeCompile(Statement s)
{
s.accept(this);
Expand Down Expand Up @@ -1931,6 +1943,25 @@ public:
result = CTFEExp.cantexp;
}

version (IN_GCC)
{
override void visit(ExtAsmStatement s)
{
debug (LOG)
{
printf("%s ExtAsmStatement::interpret()\n", s.loc.toChars());
}
if (istate.start)
{
if (istate.start != s)
return;
istate.start = null;
}
s.error("extended asm statements cannot be interpreted at compile time");
result = CTFEExp.cantexp;
}
}

override void visit(ImportStatement s)
{
debug (LOG)
Expand Down
61 changes: 61 additions & 0 deletions src/dmd/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,67 @@ public:
buf.writenl();
}

version (IN_GCC)
{
override void visit(ExtAsmStatement s)
{
buf.writestring ("gcc asm { ");

if (s.insn)
buf.writestring (s.insn.toChars());

buf.writestring (" : ");

if (s.args)
{
for (size_t i = 0; i < s.args.dim; i++)
{
Identifier name = (*s.names)[i];
Expression constr = (*s.constraints)[i];
Expression arg = (*s.args)[i];

if (name)
{
buf.writestring ("[");
buf.writestring (name.toChars());
buf.writestring ("] ");
}

if (constr)
{
buf.writestring (constr.toChars());
buf.writestring (" ");
}

if (arg)
buf.writestring (arg.toChars());

if (i < s.outputargs - 1)
buf.writestring (", ");
else if (i == s.outputargs - 1)
buf.writestring (" : ");
else if (i < s.args.dim - 1)
buf.writestring (", ");
}
}

if (s.clobbers)
{
buf.writestring (" : ");
for (size_t i = 0; i < s.clobbers.dim; i++)
{
Expression clobber = (*s.clobbers)[i];
buf.writestring (clobber.toChars());
if (i < s.clobbers.dim - 1)
buf.writestring (", ");
}
}

buf.writestring ("; }");
buf.writenl();
}
}

override void visit(ImportStatement s)
{
foreach (imp; *s.imports)
Expand Down
236 changes: 236 additions & 0 deletions src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -5989,6 +5989,20 @@ final class Parser(AST) : Lexer
error("matching `}` expected, not end of file");
goto Lerror;

static if (IN_GCC)
{
case TOKlparen:
case TOKstring:
// If the first token is a string or '(', parse as extended asm.
if (!toklist)
{
s = parseExtAsm(stc);
statements.push(s);
continue;
}
goto default;
}

default:
*ptoklist = Token.alloc();
memcpy(*ptoklist, &token, Token.sizeof);
Expand Down Expand Up @@ -6034,6 +6048,228 @@ final class Parser(AST) : Lexer
return s;
}

static if (IN_GCC)
{
/***********************************
* Parse list of extended asm input or output operands.
* ExtAsmOperand:
* [Identifier] StringLiteral (Identifier), ...
*/
int parseExtAsmOperands(AST.Expressions* args, AST.Identifiers* names, AST.Expressions* constraints)
{
int numargs = 0;

while (1)
{
AST.Expression arg;
Identifier name;
AST.Expression constraint;

switch (token.value)
{
case TOKsemicolon:
case TOKcolon:
case TOKeof:
return numargs;

case TOKlbracket:
nextToken();
if (token.value == TOKidentifier)
{
name = token.ident;
nextToken();
}
else
{
error("expected identifier after '['");
return numargs;
}
check(TOKrbracket);
goto default; // fall through

default:
constraint = parsePrimaryExp();
if (constraint.op != TOKstring)
{
error(constraint.loc, "expected constant string constraint for operand, not '%s'", constraint.toChars());
goto Lerror;
}
arg = parseAssignExp();

args.push(arg);
names.push(name);
constraints.push(constraint);
numargs++;

if (token.value == TOKcomma)
nextToken();
break;

}
}
Lerror:
while (token.value != TOKrcurly &&
token.value != TOKsemicolon &&
token.value != TOKeof)
nextToken();

return numargs;
}

/***********************************
* Parse list of extended asm clobbers.
* ExtAsmClobbers:
* StringLiteral, ...
*/
AST.Expressions *parseExtAsmClobbers()
{
AST.Expressions *clobbers;

while (1)
{
AST.Expression clobber;

switch (token.value)
{
case TOKsemicolon:
case TOKcolon:
case TOKeof:
return clobbers;

case TOKstring:
clobber = parseAssignExp();
if (!clobbers)
clobbers = new AST.Expressions();
clobbers.push(clobber);

if (token.value == TOKcomma)
nextToken();
break;

default:
error("expected constant string constraint for clobber name, not '%s'", token.toChars());
goto Lerror;
}
}
Lerror:
while (token.value != TOKrcurly &&
token.value != TOKsemicolon &&
token.value != TOKeof)
nextToken();

return clobbers;
}

/***********************************
* Parse list of extended asm goto labels.
* ExtAsmGotoLabels:
* Identifier, ...
*/
AST.Identifiers *parseExtAsmGotoLabels()
{
AST.Identifiers *labels;

while (1)
{
switch (token.value)
{
case TOKsemicolon:
case TOKeof:
return labels;

case TOKidentifier:
if (!labels)
labels = new AST.Identifiers();
labels.push(token.ident);

if (nextToken() == TOKcomma)
nextToken();
break;

default:
error("expected identifier for goto label name, not '%s'", token.toChars());
goto Lerror;
}
}
Lerror:
while (token.value != TOKrcurly &&
token.value != TOKsemicolon &&
token.value != TOKeof)
nextToken();

return labels;
}

/***********************************
* Parse an extended asm statement.
* ExtAsmStatement:
* asm { StringLiterals [ : InputOperands [ : OutputOperands [ : Clobbers [ : GotoLabels ] ] ] ] }
*/

AST.Statement parseExtAsm(StorageClass stc)
{
AST.Expressions *args;
AST.Identifiers *names;
AST.Expressions *constraints;
int outputargs = 0;
AST.Expressions *clobbers;
AST.Identifiers *labels;
Loc loc = token.loc;

AST.Expression insn = parseExpression();
if (token.value == TOKsemicolon)
goto Ldone;

for (int section = 0; section < 4; ++section)
{
check(TOKcolon);

final switch (section)
{
case 0:
if (!args)
{
args = new AST.Expressions();
constraints = new AST.Expressions();
names = new AST.Identifiers();
}
outputargs = parseExtAsmOperands(args, names, constraints);
break;

case 1:
parseExtAsmOperands(args, names, constraints);
break;

case 2:
clobbers = parseExtAsmClobbers();
break;

case 3:
labels = parseExtAsmGotoLabels();
break;
}

switch (token.value)
{
case TOKsemicolon:
goto Ldone;

case TOKeof:
error("matching '}' expected, not end of file");
goto Ldone;

default:
continue;
}
}
Ldone:
check(TOKsemicolon);

return new AST.ExtAsmStatement(loc, stc, insn, args, names,
constraints, outputargs, clobbers, labels);
}
}

/*****************************************
* Parse initializer for variable declaration.
*/
Expand Down
1 change: 1 addition & 0 deletions src/dmd/parsetimevisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public:
void visit(AST.TryFinallyStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.ThrowStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.AsmStatement s) { visit(cast(AST.Statement)s); }
version (IN_GCC) void visit(AST.ExtAsmStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.ExpStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.CompoundStatement s) { visit(cast(AST.Statement)s); }

Expand Down
Loading

0 comments on commit 1528dc3

Please sign in to comment.