Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,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 @@ -1957,6 +1969,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 @@ -6234,6 +6234,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 @@ -6297,6 +6311,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 @@ -119,6 +119,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