Lowers an instruction to one of the x86 addressing modes. Note: the 32-bit offset in Cranelift has to be sign-extended, which maps x86's behavior.
(ctx: &mut Lower<Inst>, spec: InsnInput, offset: i32)
| 231 | /// |
| 232 | /// Note: the 32-bit offset in Cranelift has to be sign-extended, which maps x86's behavior. |
| 233 | fn lower_to_amode(ctx: &mut Lower<Inst>, spec: InsnInput, offset: i32) -> Amode { |
| 234 | let flags = ctx |
| 235 | .memflags(spec.insn) |
| 236 | .expect("Instruction with amode should have memflags"); |
| 237 | |
| 238 | // We now either have an add that we must materialize, or some other input; as well as the |
| 239 | // final offset. |
| 240 | if let Some(add) = matches_input(ctx, spec, Opcode::Iadd) { |
| 241 | let output_ty = ctx.output_ty(add, 0); |
| 242 | debug_assert_eq!( |
| 243 | output_ty, |
| 244 | types::I64, |
| 245 | "Address width of 64 expected, got {output_ty}" |
| 246 | ); |
| 247 | let add_inputs = &[ |
| 248 | InsnInput { |
| 249 | insn: add, |
| 250 | input: 0, |
| 251 | }, |
| 252 | InsnInput { |
| 253 | insn: add, |
| 254 | input: 1, |
| 255 | }, |
| 256 | ]; |
| 257 | |
| 258 | // TODO heap_addr legalization generates a uext64 *after* the shift, so these optimizations |
| 259 | // aren't happening in the wasm case. We could do better, given some range analysis. |
| 260 | let (base, index, shift) = if let Some((shift_input, shift_amt)) = |
| 261 | matches_small_constant_shift(ctx, add_inputs[0]) |
| 262 | { |
| 263 | ( |
| 264 | put_input_in_reg(ctx, add_inputs[1]), |
| 265 | put_input_in_reg(ctx, shift_input), |
| 266 | shift_amt, |
| 267 | ) |
| 268 | } else if let Some((shift_input, shift_amt)) = |
| 269 | matches_small_constant_shift(ctx, add_inputs[1]) |
| 270 | { |
| 271 | ( |
| 272 | put_input_in_reg(ctx, add_inputs[0]), |
| 273 | put_input_in_reg(ctx, shift_input), |
| 274 | shift_amt, |
| 275 | ) |
| 276 | } else { |
| 277 | for input in 0..=1 { |
| 278 | // Try to pierce through uextend. |
| 279 | let (inst, inst_input) = if let Some(uextend) = |
| 280 | matches_input(ctx, InsnInput { insn: add, input }, Opcode::Uextend) |
| 281 | { |
| 282 | (uextend, 0) |
| 283 | } else { |
| 284 | (add, input) |
| 285 | }; |
| 286 | |
| 287 | // If it's a constant, add it directly! |
| 288 | if let Some(cst) = ctx.get_input_as_source_or_const(inst, inst_input).constant { |
| 289 | let final_offset = (offset as i64).wrapping_add(cst as i64); |
| 290 | if let Ok(final_offset) = i32::try_from(final_offset) { |
no test coverage detected