1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::settings::{PredicateNode, SettingGroupBuilder};

macro_rules! define_zvl_ext {
    (DEF: $settings:expr, $size:expr) => {{
        let name = concat!("has_zvl", $size, "b");
        let desc = concat!("has extension Zvl", $size, "b?");
        let comment = concat!(
            "Zvl",
            $size,
            "b: Vector register has a minimum of ",
            $size,
            " bits"
        );
        $settings.add_bool(&name, &desc, &comment, false)
    }};
    ($settings:expr, $size:expr $(, $implies:expr)*) => {{
        let has_feature = define_zvl_ext!(DEF: $settings, $size);

        let name = concat!("zvl", $size, "b");
        let desc = concat!("Has a vector register size of at least ", $size, " bits");

        let preset = $settings.add_preset(&name, &desc, preset!(has_feature $( && $implies )*));
        (has_feature, preset)
    }};
}

pub(crate) fn define() -> TargetIsa {
    let mut setting = SettingGroupBuilder::new("riscv64");

    // We target a minimum of riscv64g. That means that we have the following extensions by default:
    //
    // * M (integer multiplication and division)
    // * A (atomic instructions)
    // * F (single-precision floating point)
    // * D (double-precision floating point)
    // * Zicsr (control and status register instructions)
    // * Zifencei (instruction-fetch fence)

    let has_m = setting.add_bool(
        "has_m",
        "has extension M?",
        "Integer multiplication and division",
        true,
    );
    let has_a = setting.add_bool("has_a", "has extension A?", "Atomic instructions", true);
    let has_f = setting.add_bool(
        "has_f",
        "has extension F?",
        "Single-precision floating point",
        true,
    );
    let has_d = setting.add_bool(
        "has_d",
        "has extension D?",
        "Double-precision floating point",
        true,
    );
    let _has_v = setting.add_bool(
        "has_v",
        "has extension V?",
        "Vector instruction support",
        false,
    );

    let has_zca = setting.add_bool(
        "has_zca",
        "has extension Zca?",
        "Zca is the C extension without floating point loads",
        false,
    );
    let has_zcd = setting.add_bool(
        "has_zcd",
        "has extension Zcd?",
        "Zcd contains only the double precision floating point loads from the C extension",
        false,
    );
    setting.add_preset(
        "has_c",
        "Support for compressed instructions",
        preset!(has_zca && has_zcd),
    );

    let _has_zcb = setting.add_bool(
        "has_zcb",
        "has extension Zcb?",
        "Zcb: Extra compressed instructions",
        false,
    );

    let _has_zbkb = setting.add_bool(
        "has_zbkb",
        "has extension zbkb?",
        "Zbkb: Bit-manipulation for Cryptography",
        false,
    );
    let _has_zba = setting.add_bool(
        "has_zba",
        "has extension zba?",
        "Zba: Address Generation",
        false,
    );
    let _has_zbb = setting.add_bool(
        "has_zbb",
        "has extension zbb?",
        "Zbb: Basic bit-manipulation",
        false,
    );
    let _has_zbc = setting.add_bool(
        "has_zbc",
        "has extension zbc?",
        "Zbc: Carry-less multiplication",
        false,
    );
    let _has_zbs = setting.add_bool(
        "has_zbs",
        "has extension zbs?",
        "Zbs: Single-bit instructions",
        false,
    );

    let has_zicsr = setting.add_bool(
        "has_zicsr",
        "has extension zicsr?",
        "Zicsr: Control and Status Register (CSR) Instructions",
        true,
    );
    let has_zifencei = setting.add_bool(
        "has_zifencei",
        "has extension zifencei?",
        "Zifencei: Instruction-Fetch Fence",
        true,
    );

    // Zvl*: Minimum Vector Length Standard Extensions
    // These extension specifiy the minimum number of bits in a vector register.
    // Since it is a minimum, Zvl64b implies Zvl32b, Zvl128b implies Zvl64b, etc.
    // The V extension supports a maximum of 64K bits in a single register.
    //
    // See: https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#181-zvl-minimum-vector-length-standard-extensions
    let (_, zvl32b) = define_zvl_ext!(setting, 32);
    let (_, zvl64b) = define_zvl_ext!(setting, 64, zvl32b);
    let (_, zvl128b) = define_zvl_ext!(setting, 128, zvl64b);
    let (_, zvl256b) = define_zvl_ext!(setting, 256, zvl128b);
    let (_, zvl512b) = define_zvl_ext!(setting, 512, zvl256b);
    let (_, zvl1024b) = define_zvl_ext!(setting, 1024, zvl512b);
    let (_, zvl2048b) = define_zvl_ext!(setting, 2048, zvl1024b);
    let (_, zvl4096b) = define_zvl_ext!(setting, 4096, zvl2048b);
    let (_, zvl8192b) = define_zvl_ext!(setting, 8192, zvl4096b);
    let (_, zvl16384b) = define_zvl_ext!(setting, 16384, zvl8192b);
    let (_, zvl32768b) = define_zvl_ext!(setting, 32768, zvl16384b);
    let (_, _zvl65536b) = define_zvl_ext!(setting, 65536, zvl32768b);

    setting.add_predicate(
        "has_g",
        predicate!(has_m && has_a && has_f && has_d && has_zicsr && has_zifencei),
    );

    TargetIsa::new("riscv64", setting.build())
}