Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/condcodes.rs
1693 views
1
//! Condition codes for the Cranelift code generator.
2
//!
3
//! A condition code here is an enumerated type that determined how to compare two numbers. There
4
//! are different rules for comparing integers and floating point numbers, so they use different
5
//! condition codes.
6
7
use core::fmt::{self, Display, Formatter};
8
use core::str::FromStr;
9
10
#[cfg(feature = "enable-serde")]
11
use serde_derive::{Deserialize, Serialize};
12
13
/// Common traits of condition codes.
14
pub trait CondCode: Copy {
15
/// Get the complemented condition code of `self`.
16
///
17
/// The complemented condition code produces the opposite result for all comparisons.
18
/// That is, `cmp CC, x, y` is true if and only if `cmp CC.complement(), x, y` is false.
19
#[must_use]
20
fn complement(self) -> Self;
21
22
/// Get the swapped args condition code for `self`.
23
///
24
/// The swapped args condition code produces the same result as swapping `x` and `y` in the
25
/// comparison. That is, `cmp CC, x, y` is the same as `cmp CC.swap_args(), y, x`.
26
#[must_use]
27
fn swap_args(self) -> Self;
28
}
29
30
/// Condition code for comparing integers.
31
///
32
/// This condition code is used by the `icmp` instruction to compare integer values. There are
33
/// separate codes for comparing the integers as signed or unsigned numbers where it makes a
34
/// difference.
35
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
36
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
37
pub enum IntCC {
38
/// `==`.
39
Equal,
40
/// `!=`.
41
NotEqual,
42
/// Signed `<`.
43
SignedLessThan,
44
/// Signed `>=`.
45
SignedGreaterThanOrEqual,
46
/// Signed `>`.
47
SignedGreaterThan,
48
/// Signed `<=`.
49
SignedLessThanOrEqual,
50
/// Unsigned `<`.
51
UnsignedLessThan,
52
/// Unsigned `>=`.
53
UnsignedGreaterThanOrEqual,
54
/// Unsigned `>`.
55
UnsignedGreaterThan,
56
/// Unsigned `<=`.
57
UnsignedLessThanOrEqual,
58
}
59
60
impl CondCode for IntCC {
61
fn complement(self) -> Self {
62
use self::IntCC::*;
63
match self {
64
Equal => NotEqual,
65
NotEqual => Equal,
66
SignedLessThan => SignedGreaterThanOrEqual,
67
SignedGreaterThanOrEqual => SignedLessThan,
68
SignedGreaterThan => SignedLessThanOrEqual,
69
SignedLessThanOrEqual => SignedGreaterThan,
70
UnsignedLessThan => UnsignedGreaterThanOrEqual,
71
UnsignedGreaterThanOrEqual => UnsignedLessThan,
72
UnsignedGreaterThan => UnsignedLessThanOrEqual,
73
UnsignedLessThanOrEqual => UnsignedGreaterThan,
74
}
75
}
76
77
fn swap_args(self) -> Self {
78
use self::IntCC::*;
79
match self {
80
Equal => Equal,
81
NotEqual => NotEqual,
82
SignedGreaterThan => SignedLessThan,
83
SignedGreaterThanOrEqual => SignedLessThanOrEqual,
84
SignedLessThan => SignedGreaterThan,
85
SignedLessThanOrEqual => SignedGreaterThanOrEqual,
86
UnsignedGreaterThan => UnsignedLessThan,
87
UnsignedGreaterThanOrEqual => UnsignedLessThanOrEqual,
88
UnsignedLessThan => UnsignedGreaterThan,
89
UnsignedLessThanOrEqual => UnsignedGreaterThanOrEqual,
90
}
91
}
92
}
93
94
impl IntCC {
95
/// Returns a slice with all possible [IntCC] values.
96
pub fn all() -> &'static [IntCC] {
97
&[
98
IntCC::Equal,
99
IntCC::NotEqual,
100
IntCC::SignedLessThan,
101
IntCC::SignedGreaterThanOrEqual,
102
IntCC::SignedGreaterThan,
103
IntCC::SignedLessThanOrEqual,
104
IntCC::UnsignedLessThan,
105
IntCC::UnsignedGreaterThanOrEqual,
106
IntCC::UnsignedGreaterThan,
107
IntCC::UnsignedLessThanOrEqual,
108
]
109
}
110
111
/// Get the corresponding IntCC with the equal component removed.
112
/// For conditions without a zero component, this is a no-op.
113
pub fn without_equal(self) -> Self {
114
use self::IntCC::*;
115
match self {
116
SignedGreaterThan | SignedGreaterThanOrEqual => SignedGreaterThan,
117
SignedLessThan | SignedLessThanOrEqual => SignedLessThan,
118
UnsignedGreaterThan | UnsignedGreaterThanOrEqual => UnsignedGreaterThan,
119
UnsignedLessThan | UnsignedLessThanOrEqual => UnsignedLessThan,
120
_ => self,
121
}
122
}
123
124
/// Get the corresponding IntCC with the signed component removed.
125
/// For conditions without a signed component, this is a no-op.
126
pub fn unsigned(self) -> Self {
127
use self::IntCC::*;
128
match self {
129
SignedGreaterThan | UnsignedGreaterThan => UnsignedGreaterThan,
130
SignedGreaterThanOrEqual | UnsignedGreaterThanOrEqual => UnsignedGreaterThanOrEqual,
131
SignedLessThan | UnsignedLessThan => UnsignedLessThan,
132
SignedLessThanOrEqual | UnsignedLessThanOrEqual => UnsignedLessThanOrEqual,
133
_ => self,
134
}
135
}
136
137
/// Get the corresponding string condition code for the IntCC object.
138
pub fn to_static_str(self) -> &'static str {
139
use self::IntCC::*;
140
match self {
141
Equal => "eq",
142
NotEqual => "ne",
143
SignedGreaterThan => "sgt",
144
SignedGreaterThanOrEqual => "sge",
145
SignedLessThan => "slt",
146
SignedLessThanOrEqual => "sle",
147
UnsignedGreaterThan => "ugt",
148
UnsignedGreaterThanOrEqual => "uge",
149
UnsignedLessThan => "ult",
150
UnsignedLessThanOrEqual => "ule",
151
}
152
}
153
}
154
155
impl Display for IntCC {
156
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
157
f.write_str(self.to_static_str())
158
}
159
}
160
161
impl FromStr for IntCC {
162
type Err = ();
163
164
fn from_str(s: &str) -> Result<Self, Self::Err> {
165
use self::IntCC::*;
166
match s {
167
"eq" => Ok(Equal),
168
"ne" => Ok(NotEqual),
169
"sge" => Ok(SignedGreaterThanOrEqual),
170
"sgt" => Ok(SignedGreaterThan),
171
"sle" => Ok(SignedLessThanOrEqual),
172
"slt" => Ok(SignedLessThan),
173
"uge" => Ok(UnsignedGreaterThanOrEqual),
174
"ugt" => Ok(UnsignedGreaterThan),
175
"ule" => Ok(UnsignedLessThanOrEqual),
176
"ult" => Ok(UnsignedLessThan),
177
_ => Err(()),
178
}
179
}
180
}
181
182
/// Condition code for comparing floating point numbers.
183
///
184
/// This condition code is used by the `fcmp` instruction to compare floating point values. Two
185
/// IEEE floating point values relate in exactly one of four ways:
186
///
187
/// 1. `UN` - unordered when either value is NaN.
188
/// 2. `EQ` - equal numerical value.
189
/// 3. `LT` - `x` is less than `y`.
190
/// 4. `GT` - `x` is greater than `y`.
191
///
192
/// Note that `0.0` and `-0.0` relate as `EQ` because they both represent the number 0.
193
///
194
/// The condition codes described here are used to produce a single boolean value from the
195
/// comparison. The 14 condition codes here cover every possible combination of the relation above
196
/// except the impossible `!UN & !EQ & !LT & !GT` and the always true `UN | EQ | LT | GT`.
197
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
198
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
199
pub enum FloatCC {
200
/// EQ | LT | GT
201
Ordered,
202
/// UN
203
Unordered,
204
205
/// EQ
206
Equal,
207
/// The C '!=' operator is the inverse of '==': `NotEqual`.
208
/// UN | LT | GT
209
NotEqual,
210
/// LT | GT
211
OrderedNotEqual,
212
/// UN | EQ
213
UnorderedOrEqual,
214
215
/// LT
216
LessThan,
217
/// LT | EQ
218
LessThanOrEqual,
219
/// GT
220
GreaterThan,
221
/// GT | EQ
222
GreaterThanOrEqual,
223
224
/// UN | LT
225
UnorderedOrLessThan,
226
/// UN | LT | EQ
227
UnorderedOrLessThanOrEqual,
228
/// UN | GT
229
UnorderedOrGreaterThan,
230
/// UN | GT | EQ
231
UnorderedOrGreaterThanOrEqual,
232
}
233
234
impl FloatCC {
235
/// Returns a slice with all possible [FloatCC] values.
236
pub fn all() -> &'static [FloatCC] {
237
&[
238
FloatCC::Ordered,
239
FloatCC::Unordered,
240
FloatCC::Equal,
241
FloatCC::NotEqual,
242
FloatCC::OrderedNotEqual,
243
FloatCC::UnorderedOrEqual,
244
FloatCC::LessThan,
245
FloatCC::LessThanOrEqual,
246
FloatCC::GreaterThan,
247
FloatCC::GreaterThanOrEqual,
248
FloatCC::UnorderedOrLessThan,
249
FloatCC::UnorderedOrLessThanOrEqual,
250
FloatCC::UnorderedOrGreaterThan,
251
FloatCC::UnorderedOrGreaterThanOrEqual,
252
]
253
}
254
}
255
256
impl CondCode for FloatCC {
257
fn complement(self) -> Self {
258
use self::FloatCC::*;
259
match self {
260
Ordered => Unordered,
261
Unordered => Ordered,
262
Equal => NotEqual,
263
NotEqual => Equal,
264
OrderedNotEqual => UnorderedOrEqual,
265
UnorderedOrEqual => OrderedNotEqual,
266
LessThan => UnorderedOrGreaterThanOrEqual,
267
LessThanOrEqual => UnorderedOrGreaterThan,
268
GreaterThan => UnorderedOrLessThanOrEqual,
269
GreaterThanOrEqual => UnorderedOrLessThan,
270
UnorderedOrLessThan => GreaterThanOrEqual,
271
UnorderedOrLessThanOrEqual => GreaterThan,
272
UnorderedOrGreaterThan => LessThanOrEqual,
273
UnorderedOrGreaterThanOrEqual => LessThan,
274
}
275
}
276
fn swap_args(self) -> Self {
277
use self::FloatCC::*;
278
match self {
279
Ordered => Ordered,
280
Unordered => Unordered,
281
Equal => Equal,
282
NotEqual => NotEqual,
283
OrderedNotEqual => OrderedNotEqual,
284
UnorderedOrEqual => UnorderedOrEqual,
285
LessThan => GreaterThan,
286
LessThanOrEqual => GreaterThanOrEqual,
287
GreaterThan => LessThan,
288
GreaterThanOrEqual => LessThanOrEqual,
289
UnorderedOrLessThan => UnorderedOrGreaterThan,
290
UnorderedOrLessThanOrEqual => UnorderedOrGreaterThanOrEqual,
291
UnorderedOrGreaterThan => UnorderedOrLessThan,
292
UnorderedOrGreaterThanOrEqual => UnorderedOrLessThanOrEqual,
293
}
294
}
295
}
296
297
impl Display for FloatCC {
298
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
299
use self::FloatCC::*;
300
f.write_str(match *self {
301
Ordered => "ord",
302
Unordered => "uno",
303
Equal => "eq",
304
NotEqual => "ne",
305
OrderedNotEqual => "one",
306
UnorderedOrEqual => "ueq",
307
LessThan => "lt",
308
LessThanOrEqual => "le",
309
GreaterThan => "gt",
310
GreaterThanOrEqual => "ge",
311
UnorderedOrLessThan => "ult",
312
UnorderedOrLessThanOrEqual => "ule",
313
UnorderedOrGreaterThan => "ugt",
314
UnorderedOrGreaterThanOrEqual => "uge",
315
})
316
}
317
}
318
319
impl FromStr for FloatCC {
320
type Err = ();
321
322
fn from_str(s: &str) -> Result<Self, Self::Err> {
323
use self::FloatCC::*;
324
match s {
325
"ord" => Ok(Ordered),
326
"uno" => Ok(Unordered),
327
"eq" => Ok(Equal),
328
"ne" => Ok(NotEqual),
329
"one" => Ok(OrderedNotEqual),
330
"ueq" => Ok(UnorderedOrEqual),
331
"lt" => Ok(LessThan),
332
"le" => Ok(LessThanOrEqual),
333
"gt" => Ok(GreaterThan),
334
"ge" => Ok(GreaterThanOrEqual),
335
"ult" => Ok(UnorderedOrLessThan),
336
"ule" => Ok(UnorderedOrLessThanOrEqual),
337
"ugt" => Ok(UnorderedOrGreaterThan),
338
"uge" => Ok(UnorderedOrGreaterThanOrEqual),
339
_ => Err(()),
340
}
341
}
342
}
343
344
#[cfg(test)]
345
mod tests {
346
use super::*;
347
use std::string::ToString;
348
349
#[test]
350
fn int_complement() {
351
for r in IntCC::all() {
352
let cc = *r;
353
let inv = cc.complement();
354
assert!(cc != inv);
355
assert_eq!(inv.complement(), cc);
356
}
357
}
358
359
#[test]
360
fn int_swap_args() {
361
for r in IntCC::all() {
362
let cc = *r;
363
let rev = cc.swap_args();
364
assert_eq!(rev.swap_args(), cc);
365
}
366
}
367
368
#[test]
369
fn int_display() {
370
for r in IntCC::all() {
371
let cc = *r;
372
assert_eq!(cc.to_string().parse(), Ok(cc));
373
}
374
assert_eq!("bogus".parse::<IntCC>(), Err(()));
375
}
376
377
#[test]
378
fn float_complement() {
379
for r in FloatCC::all() {
380
let cc = *r;
381
let inv = cc.complement();
382
assert!(cc != inv);
383
assert_eq!(inv.complement(), cc);
384
}
385
}
386
387
#[test]
388
fn float_swap_args() {
389
for r in FloatCC::all() {
390
let cc = *r;
391
let rev = cc.swap_args();
392
assert_eq!(rev.swap_args(), cc);
393
}
394
}
395
396
#[test]
397
fn float_display() {
398
for r in FloatCC::all() {
399
let cc = *r;
400
assert_eq!(cc.to_string().parse(), Ok(cc));
401
}
402
assert_eq!("bogus".parse::<FloatCC>(), Err(()));
403
}
404
}
405
406