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
#[cfg(test)]
use stdarch_test::assert_instr;

#[cfg(target_arch = "riscv32")]
extern "unadjusted" {
    #[link_name = "llvm.riscv.orc.b.i32"]
    fn _orc_b_32(rs: i32) -> i32;

    #[link_name = "llvm.riscv.clmul.i32"]
    fn _clmul_32(rs1: i32, rs2: i32) -> i32;

    #[link_name = "llvm.riscv.clmulh.i32"]
    fn _clmulh_32(rs1: i32, rs2: i32) -> i32;

    #[link_name = "llvm.riscv.clmulr.i32"]
    fn _clmulr_32(rs1: i32, rs2: i32) -> i32;
}

#[cfg(target_arch = "riscv64")]
extern "unadjusted" {
    #[link_name = "llvm.riscv.orc.b.i64"]
    fn _orc_b_64(rs1: i64) -> i64;

    #[link_name = "llvm.riscv.clmul.i64"]
    fn _clmul_64(rs1: i64, rs2: i64) -> i64;

    #[link_name = "llvm.riscv.clmulh.i64"]
    fn _clmulh_64(rs1: i64, rs2: i64) -> i64;

    #[link_name = "llvm.riscv.clmulr.i64"]
    fn _clmulr_64(rs1: i64, rs2: i64) -> i64;
}

/// Bitwise OR-Combine, byte granule
///
/// Combines the bits within every byte through a reciprocal bitwise logical OR. This sets the bits of each byte in
/// the result rd to all zeros if no bit within the respective byte of rs is set, or to all ones if any bit within the
/// respective byte of rs is set.
///
/// Source: RISC-V Bit-Manipulation ISA-extensions
///
/// Version: v1.0.0
///
/// Section: 2.24
///
/// # Safety
///
/// This function is safe to use if the `zbb` target feature is present.
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
#[target_feature(enable = "zbb")]
#[cfg_attr(test, assert_instr(orc.b))]
#[inline]
pub unsafe fn orc_b(rs: usize) -> usize {
    #[cfg(target_arch = "riscv32")]
    {
        _orc_b_32(rs as i32) as usize
    }

    #[cfg(target_arch = "riscv64")]
    {
        _orc_b_64(rs as i64) as usize
    }
}

/// Carry-less multiply (low-part)
///
/// clmul produces the lower half of the 2·XLEN carry-less product.
///
/// Source: RISC-V Bit-Manipulation ISA-extensions
///
/// Version: v1.0.0
///
/// Section: 2.11
///
/// # Safety
///
/// This function is safe to use if the `zbc` target feature is present.
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
#[target_feature(enable = "zbc")]
#[cfg_attr(test, assert_instr(clmul))]
#[inline]
pub unsafe fn clmul(rs1: usize, rs2: usize) -> usize {
    #[cfg(target_arch = "riscv32")]
    {
        _clmul_32(rs1 as i32, rs2 as i32) as usize
    }

    #[cfg(target_arch = "riscv64")]
    {
        _clmul_64(rs1 as i64, rs2 as i64) as usize
    }
}

/// Carry-less multiply (high-part)
///
/// clmulh produces the upper half of the 2·XLEN carry-less product.
///
/// Source: RISC-V Bit-Manipulation ISA-extensions
///
/// Version: v1.0.0
///
/// Section: 2.12
///
/// # Safety
///
/// This function is safe to use if the `zbc` target feature is present.
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
#[target_feature(enable = "zbc")]
#[cfg_attr(test, assert_instr(clmulh))]
#[inline]
pub unsafe fn clmulh(rs1: usize, rs2: usize) -> usize {
    #[cfg(target_arch = "riscv32")]
    {
        _clmulh_32(rs1 as i32, rs2 as i32) as usize
    }

    #[cfg(target_arch = "riscv64")]
    {
        _clmulh_64(rs1 as i64, rs2 as i64) as usize
    }
}

/// Carry-less multiply (reversed)
///
/// clmulr produces bits 2·XLEN−2:XLEN-1 of the 2·XLEN carry-less product.
///
/// Source: RISC-V Bit-Manipulation ISA-extensions
///
/// Version: v1.0.0
///
/// Section: 2.13
///
/// # Safety
///
/// This function is safe to use if the `zbc` target feature is present.
#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
#[target_feature(enable = "zbc")]
#[cfg_attr(test, assert_instr(clmulr))]
#[inline]
pub unsafe fn clmulr(rs1: usize, rs2: usize) -> usize {
    #[cfg(target_arch = "riscv32")]
    {
        _clmulr_32(rs1 as i32, rs2 as i32) as usize
    }

    #[cfg(target_arch = "riscv64")]
    {
        _clmulr_64(rs1 as i64, rs2 as i64) as usize
    }
}