Implement GccAsmStatement for gcc-style asm statements

This commit is contained in:
Iain Buclaw 2018-08-06 00:30:52 +02:00
parent 89fdf188f1
commit dad81c06bc
10 changed files with 441 additions and 3 deletions

View file

@ -62,5 +62,5 @@ subPackage {
versions "MARS" versions "MARS"
sourcePaths "src/dmd" sourcePaths "src/dmd"
excludedSourceFiles "src/dmd/backend/*" excludedSourceFiles "src/dmd/backend/*"
excludedSourceFiles "src/dmd/{e2ir,eh,glue,iasm,iasmdmd,objc_glue,s2ir,tocsym,toctype,toobj,todt,toir}.d" excludedSourceFiles "src/dmd/{e2ir,eh,glue,iasm,iasmdmd,iasmgcc,objc_glue,s2ir,tocsym,toctype,toobj,todt,toir}.d"
} }

View file

@ -2453,6 +2453,19 @@ struct ASTBase
} }
} }
extern (C++) final class GccAsmStatement : AsmStatement
{
extern (D) this(const ref Loc loc, Token* tokens)
{
super(loc, tokens);
}
override void accept(Visitor v)
{
v.visit(this);
}
}
extern (C++) class ExpStatement : Statement extern (C++) class ExpStatement : Statement
{ {
Expression exp; Expression exp;

View file

@ -23,6 +23,10 @@ version (MARS)
{ {
import dmd.iasmdmd; import dmd.iasmdmd;
} }
else version (IN_GCC)
{
import dmd.iasmgcc;
}
/************************ AsmStatement ***************************************/ /************************ AsmStatement ***************************************/
@ -44,6 +48,11 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
auto ias = new InlineAsmStatement(s.loc, s.tokens); auto ias = new InlineAsmStatement(s.loc, s.tokens);
return inlineAsmSemantic(ias, sc); return inlineAsmSemantic(ias, sc);
} }
else version (IN_GCC)
{
auto eas = new GccAsmStatement(s.loc, s.tokens);
return gccAsmSemantic(eas, sc);
}
else else
{ {
error("D inline assembler statements are not supported"); error("D inline assembler statements are not supported");

363
src/dmd/iasmgcc.d Normal file
View file

@ -0,0 +1,363 @@
/**
* Compiler implementation of the
* $(LINK2 http://www.dlang.org, D programming language).
*
* Copyright (C) 2018 by The D Language Foundation, All Rights Reserved
* Authors: Iain Buclaw
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d)
* Documentation: https://dlang.org/phobos/dmd_iasmgcc.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasmgcc.d
*/
/* Inline assembler for the GCC D compiler.
*/
module dmd.iasmgcc;
import core.stdc.string;
import dmd.arraytypes;
import dmd.astcodegen;
import dmd.dscope;
import dmd.expression;
import dmd.expressionsem;
import dmd.identifier;
import dmd.globals;
import dmd.parse;
import dmd.tokens;
import dmd.statement;
import dmd.statementsem;
private:
/***********************************
* Parse list of extended asm input or output operands.
* Grammar:
* | Operands:
* | SymbolicName(opt) StringLiteral AssignExpression
* | SymbolicName(opt) StringLiteral AssignExpression , Operands
* |
* | SymbolicName:
* | [ Identifier ]
* Params:
* p = parser state
* s = asm statement to parse
* Returns:
* number of operands added to the gcc asm statement
*/
int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
{
int numargs = 0;
while (1)
{
Expression arg;
Identifier name;
Expression constraint;
switch (p.token.value)
{
case TOK.semicolon:
case TOK.colon:
case TOK.endOfFile:
return numargs;
case TOK.leftBracket:
if (p.peekNext() == TOK.identifier)
{
p.nextToken();
name = p.token.ident;
p.nextToken();
}
else
{
p.error(s.loc, "expected identifier after `[`");
goto Lerror;
}
p.check(TOK.rightBracket);
goto case;
case TOK.string_:
constraint = p.parsePrimaryExp();
arg = p.parseAssignExp();
if (!s.args)
{
s.names = new Identifiers();
s.constraints = new Expressions();
s.args = new Expressions();
}
s.names.push(name);
s.args.push(arg);
s.constraints.push(constraint);
numargs++;
if (p.token.value == TOK.comma)
p.nextToken();
break;
default:
p.error("expected constant string constraint for operand, not `%s`",
p.token.toChars());
goto Lerror;
}
}
Lerror:
while (p.token.value != TOK.rightCurly &&
p.token.value != TOK.semicolon &&
p.token.value != TOK.endOfFile)
p.nextToken();
return numargs;
}
/***********************************
* Parse list of extended asm clobbers.
* Grammar:
* | Clobbers:
* | StringLiteral
* | StringLiteral , Clobbers
* Params:
* p = parser state
* Returns:
* array of parsed clobber expressions
*/
Expressions *parseExtAsmClobbers(Parser)(Parser p)
{
Expressions *clobbers;
while (1)
{
Expression clobber;
switch (p.token.value)
{
case TOK.semicolon:
case TOK.colon:
case TOK.endOfFile:
return clobbers;
case TOK.string_:
clobber = p.parsePrimaryExp();
if (!clobbers)
clobbers = new Expressions();
clobbers.push(clobber);
if (p.token.value == TOK.comma)
p.nextToken();
break;
default:
p.error("expected constant string constraint for clobber name, not `%s`",
p.token.toChars());
goto Lerror;
}
}
Lerror:
while (p.token.value != TOK.rightCurly &&
p.token.value != TOK.semicolon &&
p.token.value != TOK.endOfFile)
p.nextToken();
return clobbers;
}
/***********************************
* Parse list of extended asm goto labels.
* Grammar:
* | GotoLabels:
* | Identifier
* | Identifier , GotoLabels
* Params:
* p = parser state
* Returns:
* array of parsed goto labels
*/
Identifiers *parseExtAsmGotoLabels(Parser)(Parser p)
{
Identifiers *labels;
while (1)
{
switch (p.token.value)
{
case TOK.semicolon:
case TOK.endOfFile:
return labels;
case TOK.identifier:
if (!labels)
labels = new Identifiers();
labels.push(p.token.ident);
if (p.nextToken() == TOK.comma)
p.nextToken();
break;
default:
p.error("expected identifier for goto label name, not `%s`",
p.token.toChars());
goto Lerror;
}
}
Lerror:
while (p.token.value != TOK.rightCurly &&
p.token.value != TOK.semicolon &&
p.token.value != TOK.endOfFile)
p.nextToken();
return labels;
}
/***********************************
* Parse a gcc asm statement.
* There are three forms of inline asm statements, basic, extended, and goto.
* Grammar:
* | AsmInstruction:
* | BasicAsmInstruction
* | ExtAsmInstruction
* | GotoAsmInstruction
* |
* | BasicAsmInstruction:
* | Expression
* |
* | ExtAsmInstruction:
* | Expression : Operands(opt) : Operands(opt) : Clobbers(opt)
* |
* | GotoAsmInstruction:
* | Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
* Params:
* p = parser state
* s = asm statement to parse
* Returns:
* the parsed gcc asm statement
*/
GccAsmStatement parseGccAsm(Parser)(Parser p, GccAsmStatement s)
{
s.insn = p.parseExpression();
if (p.token.value == TOK.semicolon)
goto Ldone;
// No semicolon followed after instruction template, treat as extended asm.
foreach (section; 0 .. 4)
{
p.check(TOK.colon);
final switch (section)
{
case 0:
s.outputargs = p.parseExtAsmOperands(s);
break;
case 1:
p.parseExtAsmOperands(s);
break;
case 2:
s.clobbers = p.parseExtAsmClobbers();
break;
case 3:
s.labels = p.parseExtAsmGotoLabels();
break;
}
if (p.token.value == TOK.semicolon)
goto Ldone;
}
Ldone:
p.check(TOK.semicolon);
return s;
}
/***********************************
* Parse and run semantic analysis on a GccAsmStatement.
* Params:
* s = gcc asm statement being parsed
* sc = the scope where the asm statement is located
* Returns:
* the completed gcc asm statement, or null if errors occurred
*/
public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
{
//printf("GccAsmStatement.semantic()\n");
scope p = new Parser!ASTCodegen(sc._module, ";", false);
// Make a safe copy of the token list before parsing.
Token *toklist = null;
Token **ptoklist = &toklist;
for (Token *token = s.tokens; token; token = token.next)
{
*ptoklist = Token.alloc();
memcpy(*ptoklist, token, Token.sizeof);
ptoklist = &(*ptoklist).next;
*ptoklist = null;
}
p.token = *toklist;
// Parse the gcc asm statement.
s = p.parseGccAsm(s);
if (p.errors)
return null;
s.stc = sc.stc;
// Fold the instruction template string.
if (s.insn.op == TOK.mixin_)
s.insn = (cast(CompileExp)s.insn).e1;
s.insn = semanticString(sc, s.insn, "asm instruction template");
if (s.labels && s.outputargs)
s.error("extended asm statements with labels cannot have output constraints");
// Analyse all input and output operands.
if (s.args)
{
foreach (i; 0 .. s.args.dim)
{
Expression e = (*s.args)[i];
e = e.expressionSemantic(sc);
// Check argument is a valid lvalue/rvalue.
if (i < s.outputargs)
e = e.modifiableLvalue(sc, null);
else if (e.checkValue())
e = new ErrorExp();
(*s.args)[i] = e;
e = (*s.constraints)[i];
e = e.expressionSemantic(sc);
assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
(*s.constraints)[i] = e;
}
}
// Analyse all clobbers.
if (s.clobbers)
{
foreach (i; 0 .. s.clobbers.dim)
{
Expression e = (*s.clobbers)[i];
e = e.expressionSemantic(sc);
assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
(*s.clobbers)[i] = e;
}
}
// Analyse all goto labels.
if (s.labels)
{
foreach (i; 0 .. s.labels.dim)
{
Identifier ident = (*s.labels)[i];
GotoStatement gs = new GotoStatement(s.loc, ident);
if (!s.gotos)
s.gotos = new GotoStatements();
s.gotos.push(gs);
gs.statementSemantic(sc);
}
}
return s;
}

View file

@ -128,6 +128,7 @@ public:
// AsmStatements // AsmStatements
void visit(AST.InlineAsmStatement s) { visit(cast(AST.AsmStatement)s); } void visit(AST.InlineAsmStatement s) { visit(cast(AST.AsmStatement)s); }
void visit(AST.GccAsmStatement s) { visit(cast(AST.AsmStatement)s); }
//========================================================================================= //=========================================================================================
// Types // Types

View file

@ -2427,6 +2427,38 @@ extern (C++) final class InlineAsmStatement : AsmStatement
} }
} }
/***********************************************************
* https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
* Assembler instructions with D expression operands.
*/
extern (C++) final class GccAsmStatement : AsmStatement
{
StorageClass stc; // attributes of the asm {} block
Expression insn; // string expression that is the template for assembler code
Expressions* args; // input and output operands of the statement
uint outputargs; // of the operands in 'args', the number of output operands
Identifiers* names; // list of symbolic names for the operands
Expressions* constraints; // list of string constants specifying constraints on operands
Expressions* clobbers; // list of string constants specifying clobbers and scratch registers
Identifiers* labels; // list of goto labels
GotoStatements* gotos; // of the goto labels, the equivalent statements they represent
extern (D) this(const ref Loc loc, Token* tokens)
{
super(loc, tokens);
}
override Statement syntaxCopy()
{
return new GccAsmStatement(loc, tokens);
}
override void accept(Visitor v)
{
v.visit(this);
}
}
/*********************************************************** /***********************************************************
* a complete asm {} block * a complete asm {} block
*/ */

View file

@ -695,6 +695,24 @@ public:
void accept(Visitor *v) { v->visit(this); } void accept(Visitor *v) { v->visit(this); }
}; };
// A GCC asm statement - assembler instructions with D expression operands
class GccAsmStatement : public AsmStatement
{
public:
StorageClass stc; // attributes of the asm {} block
Expression *insn; // string expression that is the template for assembler code
Expressions *args; // input and output operands of the statement
unsigned outputargs; // of the operands in 'args', the number of output operands
Identifiers *names; // list of symbolic names for the operands
Expressions *constraints; // list of string constants specifying constraints on operands
Expressions *clobbers; // list of string constants specifying clobbers and scratch registers
Identifiers *labels; // list of goto labels
GotoStatements *gotos; // of the goto labels, the equivalent statements they represent
Statement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
// a complete asm {} block // a complete asm {} block
class CompoundAsmStatement : public CompoundStatement class CompoundAsmStatement : public CompoundStatement
{ {

View file

@ -54,6 +54,7 @@ class GotoStatement;
class LabelStatement; class LabelStatement;
class AsmStatement; class AsmStatement;
class InlineAsmStatement; class InlineAsmStatement;
class GccAsmStatement;
class CompoundAsmStatement; class CompoundAsmStatement;
class ImportStatement; class ImportStatement;
@ -414,6 +415,7 @@ public:
// AsmStatements // AsmStatements
virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); } virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); }
virtual void visit(GccAsmStatement *s) { visit((AsmStatement *)s); }
// Types // Types
virtual void visit(TypeBasic *t) { visit((Type *)t); } virtual void visit(TypeBasic *t) { visit((Type *)t); }

View file

@ -323,7 +323,7 @@ GLUE_OBJS =
G_GLUE_OBJS = $(addprefix $G/, $(GLUE_OBJS)) G_GLUE_OBJS = $(addprefix $G/, $(GLUE_OBJS))
GLUE_SRCS=$(addsuffix .d, $(addprefix $D/,irstate toctype glue gluelayer todt tocsym toir dmsc \ GLUE_SRCS=$(addsuffix .d, $(addprefix $D/,irstate toctype glue gluelayer todt tocsym toir dmsc \
tocvdebug s2ir toobj e2ir eh iasm iasmdmd objc_glue)) tocvdebug s2ir toobj e2ir eh iasm iasmdmd iasmgcc objc_glue))
DMD_SRCS=$(FRONT_SRCS) $(GLUE_SRCS) $(BACK_HDRS) $(TK_HDRS) DMD_SRCS=$(FRONT_SRCS) $(GLUE_SRCS) $(BACK_HDRS) $(TK_HDRS)

View file

@ -175,7 +175,7 @@ LEXER_ROOT=$(ROOT)/array.d $(ROOT)/ctfloat.d $(ROOT)/file.d $(ROOT)/filename.d \
PARSER_SRCS=$D/astbase.d $D/parsetimevisitor.d $D/parse.d $D/transitivevisitor.d $D/permissivevisitor.d $D/strictvisitor.d PARSER_SRCS=$D/astbase.d $D/parsetimevisitor.d $D/parse.d $D/transitivevisitor.d $D/permissivevisitor.d $D/strictvisitor.d
GLUE_SRCS=$D/irstate.d $D/toctype.d $D/glue.d $D/gluelayer.d $D/todt.d $D/tocsym.d $D/toir.d $D/dmsc.d \ GLUE_SRCS=$D/irstate.d $D/toctype.d $D/glue.d $D/gluelayer.d $D/todt.d $D/tocsym.d $D/toir.d $D/dmsc.d \
$D/tocvdebug.d $D/s2ir.d $D/toobj.d $D/e2ir.d $D/objc_glue.d $D/eh.d $D/iasm.d $D/iasmdmd.d $D/tocvdebug.d $D/s2ir.d $D/toobj.d $D/e2ir.d $D/objc_glue.d $D/eh.d $D/iasm.d $D/iasmdmd.d $D/iasmgcc.d
BACK_HDRS=$C/cc.d $C/cdef.d $C/cgcv.d $C/code.d $C/cv4.d $C/dt.d $C/el.d $C/global.d \ BACK_HDRS=$C/cc.d $C/cdef.d $C/cgcv.d $C/code.d $C/cv4.d $C/dt.d $C/el.d $C/global.d \
$C/obj.d $C/oper.d $C/outbuf.d $C/rtlsym.d $C/code_x86.d $C/iasm.d \ $C/obj.d $C/oper.d $C/outbuf.d $C/rtlsym.d $C/code_x86.d $C/iasm.d \