Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/s390x/inst/args.rs
1693 views
1
//! S390x ISA definitions: instruction arguments.
2
3
use crate::ir::MemFlags;
4
use crate::ir::condcodes::{FloatCC, IntCC};
5
use crate::isa::s390x::inst::*;
6
7
//=============================================================================
8
// Instruction sub-components (memory addresses): definitions
9
10
/// A memory argument to load/store, encapsulating the possible addressing modes.
11
#[derive(Clone, Debug)]
12
pub enum MemArg {
13
//
14
// Real IBM Z addressing modes:
15
//
16
/// Base register, index register, and 12-bit unsigned displacement.
17
BXD12 {
18
base: Reg,
19
index: Reg,
20
disp: UImm12,
21
flags: MemFlags,
22
},
23
24
/// Base register, index register, and 20-bit signed displacement.
25
BXD20 {
26
base: Reg,
27
index: Reg,
28
disp: SImm20,
29
flags: MemFlags,
30
},
31
32
/// PC-relative Reference to a label.
33
Label { target: MachLabel },
34
35
/// PC-relative Reference to a constant pool entry.
36
Constant { constant: VCodeConstant },
37
38
/// PC-relative Reference to a near symbol.
39
Symbol {
40
name: Box<ExternalName>,
41
offset: i32,
42
flags: MemFlags,
43
},
44
45
//
46
// Virtual addressing modes that are lowered at emission time:
47
//
48
/// Arbitrary offset from a register. Converted to generation of large
49
/// offsets with multiple instructions as necessary during code emission.
50
RegOffset { reg: Reg, off: i64, flags: MemFlags },
51
52
/// Offset from the stack pointer at function entry.
53
InitialSPOffset { off: i64 },
54
55
/// Offset from the top of the incoming argument area.
56
IncomingArgOffset { off: i64 },
57
58
/// Offset from the bottom of the outgoing argument area.
59
OutgoingArgOffset { off: i64 },
60
61
/// Offset into the slot area of the stack, which lies just above the
62
/// outgoing argument area that's setup by the function prologue.
63
/// At emission time, this is converted to `SPOffset` with a fixup added to
64
/// the offset constant. The fixup is a running value that is tracked as
65
/// emission iterates through instructions in linear order, and can be
66
/// adjusted up and down with [Inst::VirtualSPOffsetAdj].
67
///
68
/// The standard ABI is in charge of handling this (by emitting the
69
/// adjustment meta-instructions). See the diagram in the documentation
70
/// for [crate::isa::aarch64::abi](the ABI module) for more details.
71
SlotOffset { off: i64 },
72
73
/// Offset into the spill area of the stack.
74
SpillOffset { off: i64 },
75
}
76
77
impl MemArg {
78
/// Memory reference using an address in a register.
79
pub fn reg(reg: Reg, flags: MemFlags) -> MemArg {
80
MemArg::BXD12 {
81
base: reg,
82
index: zero_reg(),
83
disp: UImm12::zero(),
84
flags,
85
}
86
}
87
88
/// Memory reference using the sum of two registers as an address.
89
pub fn reg_plus_reg(reg1: Reg, reg2: Reg, flags: MemFlags) -> MemArg {
90
MemArg::BXD12 {
91
base: reg1,
92
index: reg2,
93
disp: UImm12::zero(),
94
flags,
95
}
96
}
97
98
/// Memory reference using the sum of a register an offset as address.
99
pub fn reg_plus_off(reg: Reg, off: i64, flags: MemFlags) -> MemArg {
100
MemArg::RegOffset { reg, off, flags }
101
}
102
103
pub(crate) fn get_flags(&self) -> MemFlags {
104
match self {
105
MemArg::BXD12 { flags, .. } => *flags,
106
MemArg::BXD20 { flags, .. } => *flags,
107
MemArg::RegOffset { flags, .. } => *flags,
108
MemArg::Label { .. } => MemFlags::trusted(),
109
MemArg::Constant { .. } => MemFlags::trusted(),
110
MemArg::Symbol { flags, .. } => *flags,
111
MemArg::InitialSPOffset { .. } => MemFlags::trusted(),
112
MemArg::IncomingArgOffset { .. } => MemFlags::trusted(),
113
MemArg::OutgoingArgOffset { .. } => MemFlags::trusted(),
114
MemArg::SlotOffset { .. } => MemFlags::trusted(),
115
MemArg::SpillOffset { .. } => MemFlags::trusted(),
116
}
117
}
118
}
119
120
//=============================================================================
121
// Instruction sub-components (conditions, branches and branch targets):
122
// definitions
123
124
/// Condition for conditional branches.
125
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126
pub struct Cond {
127
mask: u8,
128
}
129
130
impl Cond {
131
pub fn from_mask(mask: u8) -> Cond {
132
assert!(mask >= 1 && mask <= 14);
133
Cond { mask }
134
}
135
136
pub fn from_intcc(cc: IntCC) -> Cond {
137
let mask = match cc {
138
IntCC::Equal => 8,
139
IntCC::NotEqual => 4 | 2,
140
IntCC::SignedGreaterThanOrEqual => 8 | 2,
141
IntCC::SignedGreaterThan => 2,
142
IntCC::SignedLessThanOrEqual => 8 | 4,
143
IntCC::SignedLessThan => 4,
144
IntCC::UnsignedGreaterThanOrEqual => 8 | 2,
145
IntCC::UnsignedGreaterThan => 2,
146
IntCC::UnsignedLessThanOrEqual => 8 | 4,
147
IntCC::UnsignedLessThan => 4,
148
};
149
Cond { mask }
150
}
151
152
pub fn from_floatcc(cc: FloatCC) -> Cond {
153
let mask = match cc {
154
FloatCC::Ordered => 8 | 4 | 2,
155
FloatCC::Unordered => 1,
156
FloatCC::Equal => 8,
157
FloatCC::NotEqual => 4 | 2 | 1,
158
FloatCC::OrderedNotEqual => 4 | 2,
159
FloatCC::UnorderedOrEqual => 8 | 1,
160
FloatCC::LessThan => 4,
161
FloatCC::LessThanOrEqual => 8 | 4,
162
FloatCC::GreaterThan => 2,
163
FloatCC::GreaterThanOrEqual => 8 | 2,
164
FloatCC::UnorderedOrLessThan => 4 | 1,
165
FloatCC::UnorderedOrLessThanOrEqual => 8 | 4 | 1,
166
FloatCC::UnorderedOrGreaterThan => 2 | 1,
167
FloatCC::UnorderedOrGreaterThanOrEqual => 8 | 2 | 1,
168
};
169
Cond { mask }
170
}
171
172
/// Return the inverted condition.
173
pub fn invert(self) -> Cond {
174
Cond {
175
mask: !self.mask & 15,
176
}
177
}
178
179
/// Return the machine encoding of this condition.
180
pub fn bits(self) -> u8 {
181
self.mask
182
}
183
}
184
185
impl PrettyPrint for MemArg {
186
fn pretty_print(&self, _: u8) -> String {
187
match self {
188
&MemArg::BXD12 {
189
base, index, disp, ..
190
} => {
191
if base != zero_reg() {
192
if index != zero_reg() {
193
format!(
194
"{}({},{})",
195
disp.pretty_print_default(),
196
show_reg(index),
197
show_reg(base),
198
)
199
} else {
200
format!("{}({})", disp.pretty_print_default(), show_reg(base))
201
}
202
} else {
203
if index != zero_reg() {
204
format!("{}({},)", disp.pretty_print_default(), show_reg(index))
205
} else {
206
format!("{}", disp.pretty_print_default())
207
}
208
}
209
}
210
&MemArg::BXD20 {
211
base, index, disp, ..
212
} => {
213
if base != zero_reg() {
214
if index != zero_reg() {
215
format!(
216
"{}({},{})",
217
disp.pretty_print_default(),
218
show_reg(index),
219
show_reg(base),
220
)
221
} else {
222
format!("{}({})", disp.pretty_print_default(), show_reg(base))
223
}
224
} else {
225
if index != zero_reg() {
226
format!("{}({},)", disp.pretty_print_default(), show_reg(index))
227
} else {
228
format!("{}", disp.pretty_print_default())
229
}
230
}
231
}
232
&MemArg::Label { target } => target.to_string(),
233
&MemArg::Constant { constant } => format!("[const({})]", constant.as_u32()),
234
&MemArg::Symbol {
235
ref name, offset, ..
236
} => format!("{} + {}", name.display(None), offset),
237
// Eliminated by `mem_finalize()`.
238
&MemArg::InitialSPOffset { .. }
239
| &MemArg::IncomingArgOffset { .. }
240
| &MemArg::OutgoingArgOffset { .. }
241
| &MemArg::SlotOffset { .. }
242
| &MemArg::SpillOffset { .. }
243
| &MemArg::RegOffset { .. } => {
244
panic!("Unexpected pseudo mem-arg mode (stack-offset or generic reg-offset)!")
245
}
246
}
247
}
248
}
249
250
impl PrettyPrint for Cond {
251
fn pretty_print(&self, _: u8) -> String {
252
let s = match self.mask {
253
1 => "o",
254
2 => "h",
255
3 => "nle",
256
4 => "l",
257
5 => "nhe",
258
6 => "lh",
259
7 => "ne",
260
8 => "e",
261
9 => "nlh",
262
10 => "he",
263
11 => "nl",
264
12 => "le",
265
13 => "nh",
266
14 => "no",
267
_ => unreachable!(),
268
};
269
s.to_string()
270
}
271
}
272
273