D-GDC(Dlang)的更友好asm语法糖

D-GDC(Dlang)的更友好asm语法糖,d,inline-assembly,gdc,D,Inline Assembly,Gdc,我有一个想法,可以简化使用GDC的扩展asm语法创建D+asm代码的过程。我不想到处插入\n\t标记,比如说,使用单独的字符串并让d编译器连接它们。但我愿意接受其他建议。我的尝试失败了,因为不幸的是,在编译时连接D字符串在GDC中不起作用,我需要CTFE。正如你所料,这是一个要求,这片糖是零成本的 我想我需要和mixin做点什么。关于在CTFE中的位置和如何停留的任何提示都是错误的,因为扩展内联ASM中的AssemblerTemplate应该是编译时生成字符串,但实际上不是。您可以做的是生成字符

我有一个想法,可以简化使用GDC的扩展asm语法创建D+asm代码的过程。我不想到处插入\n\t标记,比如说,使用单独的字符串并让d编译器连接它们。但我愿意接受其他建议。我的尝试失败了,因为不幸的是,在编译时连接D字符串在GDC中不起作用,我需要CTFE。正如你所料,这是一个要求,这片糖是零成本的

我想我需要和mixin做点什么。关于在CTFE中的位置和如何停留的任何提示都是错误的,因为扩展内联ASM中的AssemblerTemplate应该是编译时生成字符串,但实际上不是。您可以做的是生成字符串,将所有ASM内容放在其周围,然后将其混合。我一直在为自定义系统调用实现(仍然是内联的)使用类似的东西

但坦率地说,这看起来很可怕。创建一个模板来为您处理所有这些,它需要一个字符串数组,这样会更容易,也更美观。您可以在模板中实现额外的内容,以处理某些操作码并基于它们自动添加约束。这将使代码能够在DMD和LDC上工作,如果您希望的话。您可以使用一些编译时魔法来解决这一切。(编辑)这确实有效

module test2;

import std.traits: AliasSeq;

// Input operand type
struct IOp(string _name) {
    string constraints; // A set of constraints. This is the whole thing.
    string asmName; // A label to be given to the operand (the "[<name>]" thing)
    enum name = _name; // Inner usage, to ease accessing `_name`.
}

// Output operand type
struct OOp(string _name) {
    // For variable details, see IOp comments.
    string constraints;
    string asmName;
    enum name = _name;
}

// type for register (and "cc" and "memory") clobbers
struct Clobber(string _reg) {enum reg = _reg;}

// type for goto labels
struct Goto(string _goto) {enum name = _goto;} // note that `goto` is a D keyword.

// filters out types as S!(string blah)
template filterOp(alias S, T...) {
    static if (T.length == 0) alias filterOp = AliasSeq!();
    else static if (T.length == 1) {
        static if (is(typeof(T[0]) : S!(N), string N))
            alias filterOp = AliasSeq!(T[0]);
        else
            alias filterOp = AliasSeq!();
    } else
        alias filterOp = AliasSeq!(filterOp!(S, T[0..$/2]), filterOp!(S, T[$/2..$]));
}

// joiner function for input and output operands.
template joinOps(T...) {
    static if (T.length == 0) enum joinOps = "";
    else static if (T.length == 1) enum joinOps = ((T[0].asmName != "")?"[" ~ T[0].asmName ~ "] ":"") ~ "\"" ~ T[0].constraints ~ "\" " ~ T[0].name; // The .name unescapes the name
    else enum joinOps = joinOps!(T[0..$/2]) ~ ", " ~ joinOps!(T[$/2..$]);
}

// joiner function for clobbers
template joinClobbers(T...) {
    static if (T.length == 0) enum joinClobbers = "";
    else static if (T.length == 1) enum joinClobbers = "\"" ~ T[0].reg ~ "\"";
    else enum joinClobbers = joinClobbers!(T[0..$/2]) ~ ", " ~ joinClobbers!(T[$/2..$]);
}

// joiner function for goto labels
template joinGotos(T...) {
    static if (T.length == 0) enum joinGotos = "";
    else static if (T.length == 1) enum joinGotos = T[0].name; // Here the label is unescaped
    else enum joinGotos = joinGotos!(T[0..$/2]) ~ ", " ~ joinGotos!(T[$/2..$]); // Recursively executes itself on halves of the input. Eventually, the halves become lengths of `1` or `0`, and they are actually evaluated.
}

// joiner function for instructions.
template joinInstrs(string[] instrs) {
    static if (instrs.length == 0) enum joinInstrs = "";
    else static if (instrs.length == 1) enum joinInstrs = instrs[0];
    else enum joinInstrs = joinInstrs!(instrs[0..$/2]) ~ "\\n\\t" ~ joinInstrs!(instrs[$/2..$]);
}

// complete assembly generator function. Output is to be mixed in.
template ASM(string[] ops, T...) {
    enum iops = joinOps!(filterOp!(IOp, T));
    enum oops = joinOps!(filterOp!(OOp, T));
    enum clobbers = joinClobbers!(filterOp!(Clobber, T));
    enum gotos = joinGotos!(filterOp!(Goto, T));
    enum instrs = "\"" ~ joinInstrs!(ops) ~ "\"";
    enum ASM = "asm { " ~ instrs ~ " : " ~ oops ~ " : " ~ iops ~ " : " ~ clobbers ~ " : " ~ gotos ~ "; }";
}

void main() {
    ulong src = 24, dst;
    mixin(ASM!(["mov %[dst], %[src]"], IOp!"src"("ri,rmi", "src"), OOp!"dst"("=rm,r", "dst")));
}
模块test2;
导入标准特征:AliasSeq;
//输入操作数类型
结构IOp(字符串_名称){
字符串约束;//一组约束。这就是全部内容。
字符串asmName;//给操作数的标签(“[]”东西)
enum name=\u name;//内部用法,以便于访问“\u name”。
}
//输出操作数类型
结构OOp(字符串_名称){
//有关变量详细信息,请参见IOp注释。
字符串约束;
字符串名称;
枚举名称=_名称;
}
//寄存器(以及“cc”和“内存”)缓冲区的类型
结构Clobber(字符串_reg){enum reg=_reg;}
//转到标签的类型
struct Goto(string _Goto){enum name=_Goto;}//注意'Goto'是一个D关键字。
//将类型过滤为S!(胡说八道)
模板过滤器op(别名S,T…){
静态if(T.length==0)别名过滤器op=AliasSeq!();
else静态如果(T.length==1){
静态if(is(typeof(T[0]):S!(N),字符串N))
别名过滤器op=AliasSeq!(T[0]);
其他的
别名过滤器op=AliasSeq!();
}否则
别名filterOp=AliasSeq!(filterOp!(S,T[0..$/2]),filterOp!(S,T[$/2..$]);
}
//输入和输出操作数的联接函数。
模板连接操作(T…){
静态if(T.length==0)enum joinOps=“”;
如果(T.length==1)枚举joinOps=((T[0].asmName!=”)?“[”~T[0].asmName~“]:”)~“\”“~T[0]。约束条件~“\”“~T[0].name;//名称将取消对名称的替换
else枚举joinOps=joinOps!(T[0..$/2])~,“~joinOps!(T[$/2..$]);
}
//冲击器的joiner函数
模板接缝(T…){
静态if(T.length==0)枚举joinClobbers=“”;
如果(T.length==1)枚举joinClobbers=“\”~T[0].reg~“\”,则else为静态;
else枚举joinClobbers=joinClobbers!(T[0..$/2])~“,“~joinClobbers!(T[$/2..$]);
}
//goto标签的joiner函数
模板joinGotos(T…){
静态如果(T.length==0)枚举joinGotos=“”;
else static if(T.length==1)enum joinGotos=T[0].name;//此处标签未被替换
else enum joinGotos=joinGotos!(T[0..$/2])~,“~joinGotos!(T[$/2..$]);//在输入的一半上递归执行自身。最后,一半变为'1'或'0'的长度,并实际计算它们。
}
//用于指令的joiner函数。
模板联接(字符串[]指令){
静态如果(instrs.length==0)枚举joinInstrs=“”;
如果(instrs.length==1)枚举joinInstrs=instrs[0],则else为静态;
else枚举joinInstrs=joinInstrs!(instrs[0..$/2])~“\\n\\t”~joinInstrs!(instrs[$/2..$]);
}
//完整的装配生成器功能。产出要混合在一起。
模板ASM(字符串[]操作,T…){
枚举iops=joinOps!(filterOp!(IOp,T));
枚举oops=joinOps!(filterOp!(OOp,T));
enum clobbers=joinClobbers!(filterOp!(Clobber,T));
enum gotos=joinGotos!(filterOp!(Goto,T));
enum instrs=“\”~joinInstrs!(操作)~“\”;
enum ASM=“ASM{”~instrs~”:“~oops~”:“~iops~”:“~clobbers~”:“~gotos~”;}”;
}
void main(){
ulong src=24,dst;
混音(ASM!([“mov%[dst],%[src]”],IOp!“src”(“ri,rmi”,“src”),OOp!“dst”(“=rm,r”,“dst”));
}
注:

  • 您可能希望结合
    IOp
    OOp
    并根据约束区分输入和输出,而不是将
    =
    添加到输出约束中(有关有效的输出约束,请参阅GCC文档)。其他一切都将构成共享
    结构Op
    或类似结构下的输入操作数。
    • 这是我的第一次尝试,有更好的方法可以做到这一点,并简化我忽略的代码

顺便说一句,谢谢你让我想到这个!我现在需要为我自己的东西实现它。

有几种字符串样式,如
q{…}
,backticks保留插入的换行符。此外,我建议避免使用汇编块,它们在编译时不工作,而且也很难读取和维护。您首先要解决的问题是什么?我一直在为新的超轻量包装器编写一些编译器内部函数,这些包装器包含单个x86-64指令,用于面向GDC用户的库中。这些函数允许在应用程序代码中内联插入零开销指令(例如haswell指令),甚至可以使用新指令可用的全范围if寻址模式与调用代码无缝匹配。感谢这一技巧,我忘记了其他文字字符串样式。我是一名经验丰富的专业asm和C程序员,但对D来说还是新手。我还想
module test2;

import std.traits: AliasSeq;

// Input operand type
struct IOp(string _name) {
    string constraints; // A set of constraints. This is the whole thing.
    string asmName; // A label to be given to the operand (the "[<name>]" thing)
    enum name = _name; // Inner usage, to ease accessing `_name`.
}

// Output operand type
struct OOp(string _name) {
    // For variable details, see IOp comments.
    string constraints;
    string asmName;
    enum name = _name;
}

// type for register (and "cc" and "memory") clobbers
struct Clobber(string _reg) {enum reg = _reg;}

// type for goto labels
struct Goto(string _goto) {enum name = _goto;} // note that `goto` is a D keyword.

// filters out types as S!(string blah)
template filterOp(alias S, T...) {
    static if (T.length == 0) alias filterOp = AliasSeq!();
    else static if (T.length == 1) {
        static if (is(typeof(T[0]) : S!(N), string N))
            alias filterOp = AliasSeq!(T[0]);
        else
            alias filterOp = AliasSeq!();
    } else
        alias filterOp = AliasSeq!(filterOp!(S, T[0..$/2]), filterOp!(S, T[$/2..$]));
}

// joiner function for input and output operands.
template joinOps(T...) {
    static if (T.length == 0) enum joinOps = "";
    else static if (T.length == 1) enum joinOps = ((T[0].asmName != "")?"[" ~ T[0].asmName ~ "] ":"") ~ "\"" ~ T[0].constraints ~ "\" " ~ T[0].name; // The .name unescapes the name
    else enum joinOps = joinOps!(T[0..$/2]) ~ ", " ~ joinOps!(T[$/2..$]);
}

// joiner function for clobbers
template joinClobbers(T...) {
    static if (T.length == 0) enum joinClobbers = "";
    else static if (T.length == 1) enum joinClobbers = "\"" ~ T[0].reg ~ "\"";
    else enum joinClobbers = joinClobbers!(T[0..$/2]) ~ ", " ~ joinClobbers!(T[$/2..$]);
}

// joiner function for goto labels
template joinGotos(T...) {
    static if (T.length == 0) enum joinGotos = "";
    else static if (T.length == 1) enum joinGotos = T[0].name; // Here the label is unescaped
    else enum joinGotos = joinGotos!(T[0..$/2]) ~ ", " ~ joinGotos!(T[$/2..$]); // Recursively executes itself on halves of the input. Eventually, the halves become lengths of `1` or `0`, and they are actually evaluated.
}

// joiner function for instructions.
template joinInstrs(string[] instrs) {
    static if (instrs.length == 0) enum joinInstrs = "";
    else static if (instrs.length == 1) enum joinInstrs = instrs[0];
    else enum joinInstrs = joinInstrs!(instrs[0..$/2]) ~ "\\n\\t" ~ joinInstrs!(instrs[$/2..$]);
}

// complete assembly generator function. Output is to be mixed in.
template ASM(string[] ops, T...) {
    enum iops = joinOps!(filterOp!(IOp, T));
    enum oops = joinOps!(filterOp!(OOp, T));
    enum clobbers = joinClobbers!(filterOp!(Clobber, T));
    enum gotos = joinGotos!(filterOp!(Goto, T));
    enum instrs = "\"" ~ joinInstrs!(ops) ~ "\"";
    enum ASM = "asm { " ~ instrs ~ " : " ~ oops ~ " : " ~ iops ~ " : " ~ clobbers ~ " : " ~ gotos ~ "; }";
}

void main() {
    ulong src = 24, dst;
    mixin(ASM!(["mov %[dst], %[src]"], IOp!"src"("ri,rmi", "src"), OOp!"dst"("=rm,r", "dst")));
}