mirror of
https://github.com/dlang/dmd.git
synced 2025-04-28 06:00:13 +03:00
Implement GccAsmStatement for gcc-style asm statements
This commit is contained in:
parent
89fdf188f1
commit
dad81c06bc
10 changed files with 441 additions and 3 deletions
2
dub.sdl
2
dub.sdl
|
@ -62,5 +62,5 @@ subPackage {
|
|||
versions "MARS"
|
||||
sourcePaths "src/dmd"
|
||||
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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
Expression exp;
|
||||
|
|
|
@ -23,6 +23,10 @@ version (MARS)
|
|||
{
|
||||
import dmd.iasmdmd;
|
||||
}
|
||||
else version (IN_GCC)
|
||||
{
|
||||
import dmd.iasmgcc;
|
||||
}
|
||||
|
||||
/************************ AsmStatement ***************************************/
|
||||
|
||||
|
@ -44,6 +48,11 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
|
|||
auto ias = new InlineAsmStatement(s.loc, s.tokens);
|
||||
return inlineAsmSemantic(ias, sc);
|
||||
}
|
||||
else version (IN_GCC)
|
||||
{
|
||||
auto eas = new GccAsmStatement(s.loc, s.tokens);
|
||||
return gccAsmSemantic(eas, sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("D inline assembler statements are not supported");
|
||||
|
|
363
src/dmd/iasmgcc.d
Normal file
363
src/dmd/iasmgcc.d
Normal 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;
|
||||
}
|
|
@ -128,6 +128,7 @@ public:
|
|||
|
||||
// AsmStatements
|
||||
void visit(AST.InlineAsmStatement s) { visit(cast(AST.AsmStatement)s); }
|
||||
void visit(AST.GccAsmStatement s) { visit(cast(AST.AsmStatement)s); }
|
||||
|
||||
//=========================================================================================
|
||||
// Types
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -695,6 +695,24 @@ public:
|
|||
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
|
||||
class CompoundAsmStatement : public CompoundStatement
|
||||
{
|
||||
|
|
|
@ -54,6 +54,7 @@ class GotoStatement;
|
|||
class LabelStatement;
|
||||
class AsmStatement;
|
||||
class InlineAsmStatement;
|
||||
class GccAsmStatement;
|
||||
class CompoundAsmStatement;
|
||||
class ImportStatement;
|
||||
|
||||
|
@ -414,6 +415,7 @@ public:
|
|||
|
||||
// AsmStatements
|
||||
virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); }
|
||||
virtual void visit(GccAsmStatement *s) { visit((AsmStatement *)s); }
|
||||
|
||||
// Types
|
||||
virtual void visit(TypeBasic *t) { visit((Type *)t); }
|
||||
|
|
|
@ -323,7 +323,7 @@ GLUE_OBJS =
|
|||
G_GLUE_OBJS = $(addprefix $G/, $(GLUE_OBJS))
|
||||
|
||||
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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
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 \
|
||||
$C/obj.d $C/oper.d $C/outbuf.d $C/rtlsym.d $C/code_x86.d $C/iasm.d \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue