オフィスアワーがそろそろ始まるよ!()

組込み定数

Zenコンパイラに組み込まれている型や列挙型の情報です。Zenのプログラム内では、builtinをインポートすることで、これらの情報にアクセスできます。

コンパイラビルトインは、マルチプラットフォーム対応、クロスビルド、アトミック操作、リフレクションなどで利用します。これらのトピックに現時点で興味がない場合は、この節はスキップしても問題ありません。

コンパイラが組込みで持っている情報を全てを見たい場合、次のコマンドを実行します。

$ zen build-exe --builtin

ノート: zen builtin コマンドは非推奨となりました。

ここでは、その中から特によく利用するものについて解説を行います。

  • ターゲット環境
    • アーキテクチャ
    • OS
    • ABI
  • 命令セットアーキテクチャ
    • 浮動小数点ABI
    • 浮動小数点モード
    • エンディアン
  • リンカ
    • グローバルリンケージ
  • アトミック
    • オーダ
    • 命令
  • ビルドオプション
  • 型情報
    • 整数、浮動小数点、ポインタ、配列、構造体、オプション型、エラー型、列挙型
  • ターゲット環境定数

組込み定数の利用方法

コンパイラビルトインの用途の1つとして、コンパイル時にターゲット環境に合わせて分岐を実行する、というものが挙げられます。ビルドターゲットのOSごとに異なるメッセージを表示する例を示します。

まずbuiltinをインポートします。ターゲットのOS情報は、builtin.os.tagに格納されており、その値はstd.Target.Os.Tag (大文字O) で定義されている列挙型です。そこで、switchのパターンは、各列挙型のヴァリアントとします。

examples/ch07-builtins/src/builtin.zen:2:11

const builtin = @import("builtin");
const Target = std.Target;

const message = switch (builtin.os.tag) {
    .windows => "hello Windows!",
    .macosx => "hello macOS!",
    .linux => "hello Linux!",
    else => "hello others!",
};

これでmessageにはターゲット環境に合わせた文字列が格納されます。ためしに表示してみます。

examples/ch07-builtins/src/builtin.zen:13:15

test "simple builtin usage" {
    std.debug.warn("{}\n", .{message});
}

このテストを Linux 環境で実行すると、次の結果になります。

hello Linux!

ビルトインは、コンパイル時計算可能です。そのため、実行時には余分なコストがかかりません。

examples/ch07-builtins/src/builtin.zen:17:22

const equal = std.testing.equal;
test "builtin is comptime known" {
    comptime {
        equal("hello Linux!", message);
    }
}

注意: 上記コードの期待値hello Linux!は、お使いのOSに合わせて変更して下さい。

ターゲット環境

Zenコンパイラがサポートしているターゲット環境です。プロセッサ (CPU) アーキテクチャ、OS、ABIの3つを組み合わせます。 例えば、x86_64-linux-gnu は、プロセッサアーキテクチャがx86_64 (Intel) 、OSがLinux、ABIがGNUであることを意味します。

アーキテクチャ

Zenがサポートするプロセッサアーキテクチャです。タグ付き共用体std.Target.Archにまとめられています。

pub const Arch = union(enum) {
    arm: Arm32,
    armeb: Arm32,
    aarch64: Arm64,
    aarch64_be: Arm64,
    aarch64_32: Arm64,
    arc,
    avr,
    bpfel,
    bpfeb,
    hexagon,
    mips,
    mipsel,
    mips64,
    mips64el,
    msp430,
    powerpc,
    powerpc64,
    powerpc64le,
    r600,
    amdgcn,
    riscv32,
    riscv64,
    sparc,
    sparcv9,
    sparcel,
    s390x,
    tce,
    tcele,
    thumb: Arm32,
    thumbeb: Arm32,
    i386,
    x86_64,
    xcore,
    nvptx,
    nvptx64,
    le32,
    le64,
    amdil,
    amdil64,
    hsail,
    hsail64,
    spir,
    spir64,
    kalimba: Kalimba,
    shave,
    lanai,
    wasm32,
    wasm64,
    renderscript32,
    renderscript64,
...
};

ARMは32ビット / 64ビットのアーキテクチャがさらに細分化されています。これは、Cortex-A / Cortex-R / Cortex-Mの違いや命令セットアーキテクチャバージョンの違いを識別するためのものです。

ビルドターゲットのアーキテクチャは、builtin.archに格納されています。 Intel や AMD の 64ビット CPU 上で 64ビット OS をインストールしている場合のネイティブ環境ではx86_64です。

examples/ch07-builtins/src/builtin.zen:24:26

test "builtin arch" {
    comptime ok(builtin.arch == Target.Arch.x86_64);
}

OS

ZenがサポートするOSです。列挙型std.Target.Os.Tagにまとめられています。

pub const Target = struct {
    ...
    pub const Os = struct {
        ...
        pub const Tag = enum {
            freestanding,
            ananas,
            cloudabi,
            dragonfly,
            freebsd,
            fuchsia,
            ios,
            kfreebsd,
            linux,
            lv2,
            macosx,
            netbsd,
            openbsd,
            solaris,
            windows,
            haiku,
            minix,
            rtems,
            nacl,
            cnk,
            aix,
            cuda,
            nvcl,
            amdhsa,
            ps4,
            elfiamcu,
            tvos,
            watchos,
            mesa3d,
            contiki,
            amdpal,
            hermit,
            hurd,
            wasi,
            emscripten,
            uefi,
            other,
        ...

ビルドターゲットのOSは、builtin.os.tagに格納されています。Linux ネイティブ環境で実行する場合は次のテストが OK となります。

examples/ch07-builtins/src/builtin.zen:28:30

test "builtin os" {
    comptime ok(builtin.os.tag == .linux);
}

ABI

ZenがサポートするABIです。列挙型std.Target.Abiにまとめられています。

pub const Abi = enum {
    none,
    gnu,
    gnuabin32,
    gnuabi64,
    gnueabi,
    gnueabihf,
    gnux32,
    code16,
    eabi,
    eabihf,
    android,
    musl,
    musleabi,
    musleabihf,
    msvc,
    itanium,
    cygnus,
    coreclr,
    simulator,
};

ビルドターゲットのABIは、builtin.abiに格納されています。デスクトップ Linux 環境では通常 gnu になります。

examples/ch07-builtins/src/builtin.zen:32:34

test "builtin abi" {
    comptime ok(builtin.abi == Target.Abi.gnu);
}

命令セットアーキテクチャ

命令セットアーキテクチャの浮動小数点ABI、浮動小数点モード、バイトエンディアンに関連する列挙型です。

pub const FloatABI = enum {
    Soft,
    SoftFp,
    Hard,
};

pub const FloatMode = enum {
    Strict,
    Optimized,
};

pub const Endian = enum {
    Big,
    Little,
};

リンカ

リンク時のグローバルリンケージに関する列挙型です。組込み関数@exportでシンボルをエスクポートするときに、グローバルリンケージを指定するために利用します。

pub const GlobalLinkage = enum {
    Internal,
    Strong,
    Weak,
    LinkOnce,
};

アトミック

アトミックな操作とオーダーに関連する列挙型です。

pub const AtomicRmwOp = enum {
    Xchg,
    Add,
    Sub,
    And,
    Nand,
    Or,
    Xor,
    Max,
    Min,
};

pub const AtomicOrder = enum {
    Unordered,
    Monotonic,
    Acquire,
    Release,
    AcqRel,
    SeqCst,
};

アトミックな (不可分な) データアクセスをする場合は一般に、 不可分性の保証が強いほどアクセス性能が低下します。 そこで Zen では、不可分性とアクセス性能とのバランスを AtomicOrder で指定するようになっています。 この指定内容は LLVM の Atomic Orderings を継承しています。

  • Unordered
    最も不可分性の保証が弱い指定で、未定義動作が起きないこと、およびロック獲得が起きないことが保証されます。

  • Monotonic
    Unordered の保証に加え、このデータアクセスの不可分性が保証されます。 他のデータアクセスとの順番関係は保証されません。

  • Acquire
    Monotonic の保証に加え、データアクセスのためのロック獲得に必要なバリアを提供します。 この指定は C++11 や C でいう memory_order_acquire に相当します。

  • Release
    Acquire と同様ですが、ロック解放に必要なバリアを提供します。 C++11 や C でいう memory_order_release に相当します。

  • AcqRel
    Monotonic の保証に加え、データアクセスのためのロックの獲得および解放に必要なバリアを提供します。 C++11 や C でいう memory_order_acq_rel に相当します。

  • SeqCst
    Monotonic の保証に加え、データ読み出しのための Acquire 動作、およびデータ書き込みのための Release 動作を行います。 更に、SeqCst が指定された他のデータアクセスとの順番関係が保証されます。
    この指定は、C++11 や C でいう memory_order_seq_cst や、Java の volatile 指定や、gcc 互換な __sync_* ビルトイン (他に相反する指定がない場合) に相当します。

ビルドオプション

ビルドモードに関連する列挙型です。

pub const Mode = enum {
    Debug,
    ReleaseSafe,
    ReleaseFast,
    ReleaseSmall,
};

型情報

TypeInfoは、Zenの型に関するメタ情報が定義されています。

pub const TypeInfo = union(enum) {
    Type: void,
    Void: void,
    Bool: void,
    NoReturn: void,
    Int: Int,
    Float: Float,
    Pointer: Pointer,
    Array: Array,
    Struct: Struct,
    ComptimeFloat: void,
    ComptimeInt: void,
    Undefined: void,
    Null: void,
    Optional: Optional,
    ErrorUnion: ErrorUnion,
    ErrorSet: ErrorSet,
    Enum: Enum,
    Union: Union,
    Fn: Fn,
    BoundFn: Fn,
    Opaque: void,
    Frame: void,
    AnyFrame: AnyFrame,
    Vector: Vector,
    EnumLiteral: void,
    Interface: void,
...
};

例えば、配列型を示すタグ Array のヴァリアント Array 構造体は次のように定義されています。

    pub const Array = struct {
        len: comptime_int,
        child: type,
        ...
    };

型情報は次のようにして組み込み関数 @typeInfo を使用することで取得することができます。ここで定数 a の型を取得するために @TypeOf を使用しています。

examples/ch07-builtins/src/builtin.zen:42:49

test "TypeInfo" {
    const a = [_]u32{0} ** 10;
    const a_type = @typeInfo(@TypeOf(a));

    ok(a_type == .Array);
    ok(a_type.Array.len == 10);
    ok(a_type.Array.child == u32);
}

ターゲット環境定数

ビルドターゲットの環境を知るためにはどうすれば良いのでしょうか?zen build-exe --builtinコマンドを実行すると、ネイティブ環境のデフォルト設定が取得できます。

Linux 環境で実行した場合デフォルト設定は次のようになります。

usingnamespace @import("std").builtin;
const Target = @import("std").Target;

pub const version_major = 0;
pub const version_minor = 8;
pub const version_patch = 20200610;
pub const version_string = "0.8.20200609LTS";
pub const endian = Endian.Little;
pub const output_mode = OutputMode.Exe;
pub const link_mode = LinkMode.Dynamic;
pub const is_test = false;
pub const single_threaded = false;
pub const arch = Target.Arch.x86_64;
pub const abi = Target.Abi.gnu;
pub const compile_output = CompileOutput.Exe;
pub const mcmodel = MCModel.Default;
pub const os = Target.Os{
    .tag = .macosx,
    .version_range = .{ .semver = .{
        .min = .{
            .major = 10,
            .minor = 14,
            .patch = 6,
        },
        .max = .{
            .major = 10,
            .minor = 14,
            .patch = 6,
        },
    }},
};
pub const object_format = Target.ObjectFormat.elf;
pub const mode = Mode.Debug;
pub const link_libc = false;
pub const have_error_return_tracing = true;
pub const valgrind_support = true;
pub const position_independent_code = false;
pub const strip_debug_info = false;
pub const lib_dir = "<path to zen>/lib/zen";
pub const std_dir = "<path to zen>/lib/zen/std";
pub const special_dir = "<path to zen>/lib/zen/std/special";
pub const cpu_attrs = packed struct {
    const @"16bit-mode" = false;
    const @"32bit-mode" = false;
    const @"3dnow" = false;
    const @"3dnowa" = false;
    const @"64bit" = true;
    const @"64bit-mode" = true;
    const @"adx" = true;
    const @"aes" = true;
    const @"avx" = true;
    const @"avx2" = true;
    const @"avx512bf16" = false;
    const @"avx512bitalg" = false;
    const @"avx512bw" = false;
    const @"avx512cd" = false;
    const @"avx512dq" = false;
    const @"avx512er" = false;
    const @"avx512f" = false;
    const @"avx512ifma" = false;
    const @"avx512pf" = false;
    const @"avx512vbmi" = false;
    const @"avx512vbmi2" = false;
    const @"avx512vl" = false;
    const @"avx512vnni" = false;
    const @"avx512vp2intersect" = false;
    const @"avx512vpopcntdq" = false;
    const @"bmi" = true;
    const @"bmi2" = true;
    const @"branchfusion" = false;
    const @"cldemote" = false;
    const @"clflushopt" = true;
    const @"clwb" = false;
    const @"clzero" = false;
    const @"cmov" = true;
    const @"cx16" = true;
    const @"cx8" = true;
    const @"enqcmd" = false;
    const @"ermsb" = true;
    const @"f16c" = true;
    const @"false-deps-lzcnt-tzcnt" = false;
    const @"false-deps-popcnt" = true;
    const @"fast-11bytenop" = false;
    const @"fast-15bytenop" = false;
    const @"fast-bextr" = false;
    const @"fast-gather" = true;
    const @"fast-hops" = false;
    const @"fast-lzcnt" = false;
    const @"fast-partial-ymm-or-zmm-write" = false;
    const @"fast-scalar-fsqrt" = true;
    const @"fast-scalar-shift-masks" = false;
    const @"fast-shld-rotate" = true;
    const @"fast-variable-shuffle" = true;
    const @"fast-vector-fsqrt" = true;
    const @"fast-vector-shift-masks" = false;
    const @"fma" = true;
    const @"fma4" = false;
    const @"fsgsbase" = true;
    const @"fxsr" = true;
    const @"gfni" = false;
    const @"idivl-to-divb" = false;
    const @"idivq-to-divl" = true;
    const @"invpcid" = true;
    const @"lea-sp" = false;
    const @"lea-uses-ag" = false;
    const @"lwp" = false;
    const @"lzcnt" = true;
    const @"macrofusion" = true;
    const @"merge-to-threeway-branch" = true;
    const @"mmx" = true;
    const @"movbe" = true;
    const @"movdir64b" = false;
    const @"movdiri" = false;
    const @"mpx" = true;
    const @"mwaitx" = false;
    const @"nopl" = true;
    const @"pad-short-functions" = false;
    const @"pclmul" = true;
    const @"pconfig" = false;
    const @"pku" = false;
    const @"popcnt" = true;
    const @"prefer-256-bit" = false;
    const @"prefetchwt1" = false;
    const @"prfchw" = true;
    const @"ptwrite" = false;
    const @"rdpid" = false;
    const @"rdrnd" = true;
    const @"rdseed" = true;
    const @"retpoline" = false;
    const @"retpoline-external-thunk" = false;
    const @"retpoline-indirect-branches" = false;
    const @"retpoline-indirect-calls" = false;
    const @"rtm" = false;
    const @"sahf" = true;
    const @"sgx" = false;
    const @"sha" = false;
    const @"shstk" = false;
    const @"slow-3ops-lea" = true;
    const @"slow-incdec" = false;
    const @"slow-lea" = false;
    const @"slow-pmaddwd" = false;
    const @"slow-pmulld" = false;
    const @"slow-shld" = false;
    const @"slow-two-mem-ops" = false;
    const @"slow-unaligned-mem-16" = false;
    const @"slow-unaligned-mem-32" = false;
    const @"soft-float" = false;
    const @"sse" = true;
    const @"sse-unaligned-mem" = false;
    const @"sse2" = true;
    const @"sse3" = true;
    const @"sse4.1" = true;
    const @"sse4.2" = true;
    const @"sse4a" = false;
    const @"ssse3" = true;
    const @"tbm" = false;
    const @"vaes" = false;
    const @"vpclmulqdq" = false;
    const @"waitpkg" = false;
    const @"wbnoinvd" = false;
    const @"x87" = true;
    const @"xop" = false;
    const @"xsave" = true;
    const @"xsavec" = true;
    const @"xsaveopt" = true;
    const @"xsaves" = true;
};

これらの設定は、コマンドラインオプションや、ビルドスクリプトの設定によって変更することが可能です。例えば、クロスビルドのターゲットとして、ARM Cortex-M3 (-target thumb-freestanding-eabi) を指定して、ビルドモードをリリースセーフモード (--release-safe) にすると、次のようになります。

ターゲットアーキテクチャや浮動小数点ABI、リリースモードなどがネイティブ環境とは異なってきます。上のネイティブ環境をターゲットとした出力と見比べて見て下さい。

$ zen build-exe --builtin -target thumb-freestanding-eabi --release-safe
usingnamespace @import("std").builtin;
const Target = @import("std").Target;

pub const version_major = 0;
pub const version_minor = 8;
pub const version_patch = 20200610;
pub const version_string = "0.8.20200609LTS";
pub const endian = Endian.Little;
pub const output_mode = OutputMode.Exe;
pub const link_mode = LinkMode.Static;
pub const is_test = false;
pub const single_threaded = false;
pub const arch = Target.Arch.thumb;
pub const abi = Target.Abi.eabi;
pub const compile_output = CompileOutput.Exe;
pub const mcmodel = MCModel.Default;
pub const os = Target.Os{
    .tag = .freestanding,
    .version_range = .{ .none = {} }
};
pub const object_format = Target.ObjectFormat.elf;
pub const mode = Mode.ReleaseSafe;
pub const link_libc = false;
pub const have_error_return_tracing = true;
pub const valgrind_support = false;
pub const position_independent_code = false;
pub const strip_debug_info = false;
pub const lib_dir = "<path to zen>/lib/zen";
pub const std_dir = "<path to zen>/lib/zen/std";
pub const special_dir = "<path to zen>/lib/zen/std/special";
pub const cpu_attrs = packed struct {
    const @"32bit" = false;
    const @"8msecext" = false;
    const @"a12" = false;
    const @"a15" = false;
    const @"a17" = false;
    const @"a32" = false;
    const @"a35" = false;
    const @"a5" = false;
    const @"a53" = false;
    const @"a55" = false;
    const @"a57" = false;
    const @"a7" = false;
    const @"a72" = false;
    const @"a73" = false;
    const @"a75" = false;
    const @"a76" = false;
    const @"a8" = false;
    const @"a9" = false;
    const @"aclass" = false;
    const @"acquire-release" = false;
    const @"aes" = false;
    const @"armv2" = false;
    const @"armv2a" = false;
    const @"armv3" = false;
    const @"armv3m" = false;
    const @"armv4" = false;
    const @"armv4t" = false;
    const @"armv5t" = false;
    const @"armv5te" = false;
    const @"armv5tej" = false;
    const @"armv6" = false;
    const @"armv6-m" = false;
    const @"armv6j" = false;
    const @"armv6k" = false;
    const @"armv6kz" = false;
    const @"armv6s-m" = false;
    const @"armv6t2" = false;
    const @"armv7-a" = false;
    const @"armv7-m" = false;
    const @"armv7-r" = false;
    const @"armv7e-m" = false;
    const @"armv7k" = false;
    const @"armv7s" = false;
    const @"armv7ve" = false;
    const @"armv8-a" = false;
    const @"armv8-m.base" = false;
    const @"armv8-m.main" = false;
    const @"armv8-r" = false;
    const @"armv8.1-a" = false;
    const @"armv8.1-m.main" = false;
    const @"armv8.2-a" = false;
    const @"armv8.3-a" = false;
    const @"armv8.4-a" = false;
    const @"armv8.5-a" = false;
    const @"avoid-movs-shop" = false;
    const @"avoid-partial-cpsr" = false;
    const @"cheap-predicable-cpsr" = false;
    const @"crc" = false;
    const @"crypto" = false;
    const @"d32" = false;
    const @"db" = false;
    const @"dfb" = false;
    const @"disable-postra-scheduler" = false;
    const @"dont-widen-vmovs" = false;
    const @"dotprod" = false;
    const @"dsp" = false;
    const @"execute-only" = false;
    const @"expand-fp-mlx" = false;
    const @"exynos" = false;
    const @"fp-armv8" = false;
    const @"fp-armv8d16" = false;
    const @"fp-armv8d16sp" = false;
    const @"fp-armv8sp" = false;
    const @"fp16" = false;
    const @"fp16fml" = false;
    const @"fp64" = false;
    const @"fpao" = false;
    const @"fpregs" = false;
    const @"fpregs16" = false;
    const @"fpregs64" = false;
    const @"fullfp16" = false;
    const @"fuse-aes" = false;
    const @"fuse-literals" = false;
    const @"hwdiv" = false;
    const @"hwdiv-arm" = false;
    const @"iwmmxt" = false;
    const @"iwmmxt2" = false;
    const @"krait" = false;
    const @"kryo" = false;
    const @"lob" = false;
    const @"long-calls" = false;
    const @"loop-align" = false;
    const @"m3" = false;
    const @"mclass" = false;
    const @"mp" = false;
    const @"muxed-units" = false;
    const @"mve" = false;
    const @"mve.fp" = false;
    const @"nacl-trap" = false;
    const @"neon" = false;
    const @"neon-fpmovs" = false;
    const @"neonfp" = false;
    const @"no-branch-predictor" = false;
    const @"no-movt" = false;
    const @"no-neg-immediates" = false;
    const @"noarm" = false;
    const @"nonpipelined-vfp" = false;
    const @"perfmon" = false;
    const @"prefer-ishst" = false;
    const @"prefer-vmovsr" = false;
    const @"prof-unpr" = false;
    const @"r4" = false;
    const @"r5" = false;
    const @"r52" = false;
    const @"r7" = false;
    const @"ras" = false;
    const @"rclass" = false;
    const @"read-tp-hard" = false;
    const @"reserve-r9" = false;
    const @"ret-addr-stack" = false;
    const @"sb" = false;
    const @"sha2" = false;
    const @"slow-fp-brcc" = false;
    const @"slow-load-D-subreg" = false;
    const @"slow-odd-reg" = false;
    const @"slow-vdup32" = false;
    const @"slow-vgetlni32" = false;
    const @"slowfpvmlx" = false;
    const @"soft-float" = false;
    const @"splat-vfp-neon" = false;
    const @"strict-align" = false;
    const @"swift" = false;
    const @"thumb-mode" = true;
    const @"thumb2" = false;
    const @"trustzone" = false;
    const @"use-aa" = false;
    const @"use-misched" = false;
    const @"v4t" = true;
    const @"v5t" = false;
    const @"v5te" = false;
    const @"v6" = false;
    const @"v6k" = false;
    const @"v6m" = false;
    const @"v6t2" = false;
    const @"v7" = false;
    const @"v7clrex" = false;
    const @"v8" = false;
    const @"v8.1a" = false;
    const @"v8.1m.main" = false;
    const @"v8.2a" = false;
    const @"v8.3a" = false;
    const @"v8.4a" = false;
    const @"v8.5a" = false;
    const @"v8m" = false;
    const @"v8m.main" = false;
    const @"vfp2" = false;
    const @"vfp2d16" = false;
    const @"vfp2d16sp" = false;
    const @"vfp2sp" = false;
    const @"vfp3" = false;
    const @"vfp3d16" = false;
    const @"vfp3d16sp" = false;
    const @"vfp3sp" = false;
    const @"vfp4" = false;
    const @"vfp4d16" = false;
    const @"vfp4d16sp" = false;
    const @"vfp4sp" = false;
    const @"virtualization" = false;
    const @"vldn-align" = false;
    const @"vmlx-forwarding" = false;
    const @"vmlx-hazards" = false;
    const @"wide-stride-vfp" = false;
    const @"xscale" = false;
    const @"zcz" = false;
};

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Appendix

Error Explanation

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2020 connectFree Corporation. All rights reserved. | 特定商取引法に基づく表示
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.