# CPU Architectures

### CPU Architectures

The architecture part of a target tells Zig what kind of processor the program will run on.

In this target:

```text
x86_64-linux-gnu
```

the architecture is:

```text
x86_64
```

In this target:

```text
aarch64-linux-musl
```

the architecture is:

```text
aarch64
```

In this target:

```text
wasm32-freestanding-none
```

the architecture is:

```text
wasm32
```

The architecture affects instruction encoding, register names, calling convention, pointer size, alignment, atomic operations, and available CPU features.

A program can inspect its architecture at compile time:

```zig
const std = @import("std");
const builtin = @import("builtin");

pub fn main() void {
    std.debug.print("arch = {s}\n", .{@tagName(builtin.cpu.arch)});
}
```

On an x86-64 target, this prints:

```text
arch = x86_64
```

On an ARM64 target, it prints:

```text
arch = aarch64
```

The architecture is not only a label. It changes what code can be generated.

For example, pointer size follows the target architecture. A 64-bit target has 64-bit pointers. A 32-bit target has 32-bit pointers.

```zig
const std = @import("std");

pub fn main() void {
    std.debug.print("pointer bits = {d}\n", .{@bitSizeOf(usize)});
}
```

On `x86_64-linux-gnu`, this normally prints:

```text
pointer bits = 64
```

On `wasm32-freestanding-none`, this normally prints:

```text
pointer bits = 32
```

`usize` is the unsigned integer type large enough to hold a pointer. Its size is selected by the target.

Sometimes code must choose a different implementation for a different architecture.

```zig
const builtin = @import("builtin");

pub fn cacheLineSize() usize {
    return switch (builtin.cpu.arch) {
        .x86_64 => 64,
        .aarch64 => 64,
        else => 64,
    };
}
```

This example is deliberately simple. Real machines may vary. Architecture is only one part of the answer. CPU model and features may also matter.

Zig exposes CPU information through `builtin.cpu`.

```zig
const std = @import("std");
const builtin = @import("builtin");

pub fn main() void {
    std.debug.print("arch = {s}\n", .{@tagName(builtin.cpu.arch)});
    std.debug.print("model = {s}\n", .{builtin.cpu.model.name});
}
```

A target may also include CPU features.

On x86-64, examples include SIMD extensions. On ARM, examples include crypto or floating-point extensions. These features affect which instructions are legal for the compiler to emit.

For ordinary programs, the architecture is selected by the `-target` option:

```sh
zig build-exe main.zig -target x86_64-linux-gnu
zig build-exe main.zig -target aarch64-linux-musl
zig build-exe main.zig -target wasm32-freestanding-none
```

For more specific control, Zig also accepts CPU settings. These are useful when optimizing for a known machine or when avoiding instructions unsupported by older hardware.

The important distinction is this:

```text
architecture: the family of machine
cpu model:    a particular kind of machine in that family
features:     individual instruction-set capabilities
```

Most portable Zig code should depend on the architecture only at narrow boundaries. The rest of the program should use normal Zig types and standard-library functions.

A good place for architecture-specific code is a small module.

```zig
const builtin = @import("builtin");

pub fn wordBits() comptime_int {
    return switch (builtin.cpu.arch) {
        .x86, .arm, .wasm32 => 32,
        .x86_64, .aarch64, .riscv64, .wasm64 => 64,
        else => @bitSizeOf(usize),
    };
}
```

The caller does not need to know the target. It calls `wordBits`.

This is the same rule as for operating systems: isolate the difference.

The compiler already knows the target. Use that knowledge when it removes duplication or prevents mistakes. Do not scatter target tests through the program.

Exercise 17-9. Print `builtin.cpu.arch` and `builtin.cpu.model.name`.

Exercise 17-10. Print `@bitSizeOf(usize)` for a 64-bit target and a 32-bit target.

Exercise 17-11. Write a function that returns `true` for 64-bit architectures.

Exercise 17-12. Build the same source file for `x86_64-linux-gnu`, `aarch64-linux-musl`, and `wasm32-freestanding-none`.

