std_detect/detect/os/
riscv.rs

1//! Run-time feature detection utility for RISC-V.
2//!
3//! On RISC-V, full feature detection needs a help of one or more
4//! feature detection mechanisms (usually provided by the operating system).
5//!
6//! RISC-V architecture defines many extensions and some have dependency to others.
7//! More importantly, some of them cannot be enabled without resolving such
8//! dependencies due to limited set of features that such mechanisms provide.
9//!
10//! This module provides an OS-independent utility to process such relations
11//! between RISC-V extensions.
12
13use crate::detect::{Feature, cache};
14
15/// Imply features by the given set of enabled features.
16///
17/// Note that it does not perform any consistency checks including existence of
18/// conflicting extensions and/or complicated requirements.  Eliminating such
19/// inconsistencies is the responsibility of the feature detection logic and
20/// its provider(s).
21pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initializer {
22    loop {
23        // Check convergence of the feature flags later.
24        let prev = value;
25
26        // Expect that the optimizer turns repeated operations into
27        // a fewer number of bit-manipulation operations.
28        macro_rules! imply {
29            // Regular implication:
30            // A1 => (B1[, B2...]), A2 => (B1[, B2...]) and so on.
31            ($($from: ident)|+ => $($to: ident)&+) => {
32                if [$(Feature::$from as u32),+].iter().any(|&x| value.test(x)) {
33                    $(
34                        value.set(Feature::$to as u32);
35                    )+
36                }
37            };
38            // Implication with multiple requirements:
39            // A1 && A2 ... => (B1[, B2...]).
40            ($($from: ident)&+ => $($to: ident)&+) => {
41                if [$(Feature::$from as u32),+].iter().all(|&x| value.test(x)) {
42                    $(
43                        value.set(Feature::$to as u32);
44                    )+
45                }
46            };
47        }
48        macro_rules! group {
49            ($group: ident == $($member: ident)&+) => {
50                // Forward implication as defined in the specifications.
51                imply!($group => $($member)&+);
52                // Reverse implication to "group extension" from its members.
53                // This is not a part of specifications but convenient for
54                // feature detection and implemented in e.g. LLVM.
55                imply!($($member)&+ => $group);
56            };
57        }
58
59        /*
60            If a dependency/implication is not explicitly stated in the
61            specification, it is denoted as a comment as follows:
62            "defined as subset":
63                The latter extension is described as a subset of the former
64                (but the evidence is weak).
65            "functional":
66                The former extension is functionally a superset of the latter
67                (no direct references though).
68        */
69
70        imply!(zvbb => zvkb);
71
72        // Certain set of vector cryptography extensions form a group.
73        group!(zvkn == zvkned & zvknhb & zvkb & zvkt);
74        group!(zvknc == zvkn & zvbc);
75        group!(zvkng == zvkn & zvkg);
76        group!(zvks == zvksed & zvksh & zvkb & zvkt);
77        group!(zvksc == zvks & zvbc);
78        group!(zvksg == zvks & zvkg);
79
80        imply!(zvknhb => zvknha); // functional
81
82        // For vector cryptography, Zvknhb and Zvbc require integer arithmetic
83        // with EEW=64 (Zve64x) while others not depending on them
84        // require EEW=32 (Zve32x).
85        imply!(zvknhb | zvbc => zve64x);
86        imply!(zvbb | zvkb | zvkg | zvkned | zvknha | zvksed | zvksh => zve32x);
87
88        imply!(zbc => zbkc); // defined as subset
89        group!(zkn == zbkb & zbkc & zbkx & zkne & zknd & zknh);
90        group!(zks == zbkb & zbkc & zbkx & zksed & zksh);
91        group!(zk == zkn & zkr & zkt);
92
93        imply!(zabha | zacas => zaamo);
94        group!(a == zalrsc & zaamo);
95
96        group!(b == zba & zbb & zbs);
97
98        imply!(zcf => zca & f);
99        imply!(zcd => zca & d);
100        imply!(zcmop | zcb => zca);
101
102        imply!(zhinx => zhinxmin);
103        imply!(zdinx | zhinxmin => zfinx);
104
105        imply!(zvfh => zvfhmin); // functional
106        imply!(zvfh => zve32f & zfhmin);
107        imply!(zvfhmin => zve32f);
108        imply!(zvfbfwma => zvfbfmin & zfbfmin);
109        imply!(zvfbfmin => zve32f);
110
111        imply!(v => zve64d);
112        imply!(zve64d => zve64f & d);
113        imply!(zve64f => zve64x & zve32f);
114        imply!(zve64x => zve32x);
115        imply!(zve32f => zve32x & f);
116
117        imply!(zfh => zfhmin);
118        imply!(q => d);
119        imply!(d | zfhmin | zfa => f);
120        imply!(zfbfmin => f); // and some of (not all) "Zfh" instructions.
121
122        // Relatively complex implication rules from the "C" extension.
123        imply!(c => zca);
124        imply!(c & d => zcd);
125        #[cfg(target_arch = "riscv32")]
126        imply!(c & f => zcf);
127
128        imply!(zicntr | zihpm | f | zfinx | zve32x => zicsr);
129
130        // Loop until the feature flags converge.
131        if prev == value {
132            return value;
133        }
134    }
135}
136
137#[cfg(test)]
138#[path = "riscv/tests.rs"]
139mod tests;