この記事は、 DMD 2.077.0 Released – The D Blog を自分用に翻訳したものを 許可を得て 公開するものである。

ソース中にコメントの形で原文を残している。 内容が理解できる程度のざっくりした翻訳であり誤字や誤訳などが多いので、気になったら Pull requestだ!


D FoundationはDMD 2.077.0を発表しました。 このDプログラミング言語のリファレンスコンパイラの最新のリリースはdlang.orgのダウンロードページから利用できます。 このリリースは、通常のバグとリグレッションの修正の中で、既存のプロジェクトに即座に影響のある特に有益な拡張がもたらされます。

シンボルの肥大化のカット

Rainer Schützeにより、名前が制御を離れた時、特にヴォルデモート型に関わるIFTI(暗黙の関数テンプレートインスタンス化)の時に、コンパイラはかなり小さくマングルされた名前を提供するようになりました。 ちょっと説明が必要かもしれません。

命名されない型

ヴォルデモート型はおそらくDの中でも面白い機能です。 このようなものです:

auto getHeWhoShallNotBeNamed() 
{
    struct NoName 
    {
        void castSpell() 
        {
            import std.stdio : writeln;
            writeln("クルーシオ!");
        }           
    }
    return NoName();
}

void main() 
{
    auto voldemort = getHeWhoShallNotBeNamed();
    voldemort.castSpell();
}

auto functionという返値の型が推論される関数があり、それが関数の中で宣言された型のインスタンスを返しています。 宣言された関数の外で型が名づけられないのにも関わらず、インスタンスのパブリックメンバにアクセスが可能です。 変数の宣言の型推論と合わせて、返されたインスタンスの保持と再利用が可能です。 これは、高いレベルのカプセル化として機能します。

Dにおいて、任意のAPIについて、モジュールの外の世界に関してモジュールプライベートは最も低いレベルのカプセル化です。

module foobar;

private struct Foo
{
    int x;
}

struct Bar 
{
    private int y;
    int z;
}

ここで、型Fooはモジュールプライベートです。 Dの新人はしばしばaggregate typeのプライベートメンバもまたモジュールプライベートであるということを知って驚くので(C++のfriendと等価です)、Barは完全性のために表記してあります。 ここに低いレベルのカプセル化を示すキーワードはありません。

Fooを見えないようにしたくなる時があるかもしれません。 Fooのインターフェースに破壊的変更を加える人はそのモジュールの一部にもアクセスできますが(これはモジュールプライベートメンバの背後にある根拠です)、モジュール全体がFooにアクセスしてほしくない時があります。 ヴォルデモート型は、モジュールの外の世界だけでなくモジュールの中でも詳細を隠蔽する役割を果たします。

ヴォルデモート型の悪い面

テンプレート化された関数を使う時に発生する、マングルされた関数名のサイズの深刻な爆発(場合によっては1MBを超えます!)により、オブジェクトファイルが肥大化するというヴォルデモート型による意外な影響が2016年なかばに報告されました 。 この問題を解決するため、フォーラムのディスカッションで様々な意見が提案されました。 最終的に、Rainer Schützeが引き受けました。 彼の努力によりマングルされた名前は全体的に短くなり、これは特にIFTIとヴォルデモート型にいい影響をもたらします(RainerはVisual Dという、Dプログラミング言語のVisual Studioのプラグインのメンテナーでもあります)。

Dの名前修飾スキームはABI documentationで詳細に説明されています。 新しい拡張の説明は‘Back references’というタイトルのセクションにのっています。

ベクトル化の改善

Dは昔から要素ごとの加算、乗算などの配列操作をサポートしています。 たとえば:

int[] arr1 = [0, 1, 2];
int[] arr2 = [3, 4, 5];
int[3] arr3 = arr1[] + arr2[];
assert(arr3 == [3, 5, 7]);

いくつかのケースで、このような操作はベクトル化されます。 いくつかのケースであってすべてのケースでは無いのは、ベクトル化のためには専用のアセンブリルーチンが使われており、すべてのケースに専用のルーチンが実装されているわけではなかったからです。

2.077.0において、これはもはや正しくありません。 ベクトル化はすべての配列操作のためにテンプレート化されました。 これまでベクトル化されていなかった配列操作を使ったコードベースは、スループットの向上により大幅な速度の改善が期待できるかもしれません(もちろんケースによります)。 恩恵を受けられる度合いは使うコンパイラによります。 チェンジログ曰く:

GDC/LDCの実装は自動ベクトル化に依存しており、DMDの実装は自分でベクトル化をおこないます。 DMDのベクトル操作のサポートはバイナリの肥大化とテストのオーバーヘッドを避けるため静的に(-mcpu=native, -mcpu=avx2)決定されます。 DMDは64ビットターゲットにおいてデフォルトでSSE2を有効にしています。

チェンジログは初め-mcpuではなく-marchと書かれていて、このアナウンスメントの公開時点で更新版はまだ公開されていないことに注意してください。

DMDの実装はDRuntimeのパブリックAPIの一部でもある core.simdで実装されています。

チェンジログは既存のコードの浮動小数点数の配列の除算において精度と引き換えにパフォーマンスが低下する可能性があるということにも触れています。

精度の低下を引き起こす可能性があるため、実装は浮動小数点数の除算(たとえば ary[] / scalar)の乗算(ary[] * (1.0 / scalar))への強度低減を行わなくなりました。 精度の低下が許容できる場面で浮動小数点数の高いパフォーマンスを維持するには、GDC/LDCで-ffast-mathを使うか、DMDではコードを乗算(1.0 / scalar)に書き換えてください。

その他いろいろ

この間、誰かがフォーラムでDMDはreproducible buildsをサポートしないのかと聞いていました。 2.077.0では、答えは肯定になります。 DMDのコンパイルは決定論的に、同じソースコードと同じコンパイラバージョンでは、同じバイナリが出力されるようになりました。 これが重要な場合は、コードに非決定論的lexerトークン(__DATE____TIME____TIMESTAMP__)を含めないでください。

このリリースでDMDの-betterCコマンドラインオプションはより愛されるようになりました。 これを有効にすると、DRuntimeは使えなくなります。 ライブラリの作者は定義済みバージョン識別子 D_BetterCを使うことができるようになったので、ランタイムのある時と無い時を判断し便利にアプリケーションをサポートできます。 -betterCオプションの振る舞いは文書化されたので、もはやBetterCモードで何がサポートされ、何がサポートされないか調べるためにフォーラムに行ったり検索結果をパースする必要はありません。

チェンジログ全体は、いつもどおりdlang.orgで見ることができます