Skip to content

Commit bfd1ddc

Browse files
committed
force_array -> is_consecutive
The actual ABI implication here is that in some cases the values are required to be "consecutive", i.e. must either all be passed in registers or all on stack (without padding). Adjust the code to either use Uniform::new() or Uniform::consecutive() depending on which behavior is needed. Then, when lowering this in LLVM, skip the [1 x i128] to i128 simplification if is_consecutive is set. i128 is the only case I'm aware of where this is problematic right now. If we find other cases, we can extend this (either based on target information or possibly just by not simplifying for is_consecutive entirely).
1 parent a9815d2 commit bfd1ddc

File tree

13 files changed

+56
-47
lines changed

13 files changed

+56
-47
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ impl LlvmType for CastTarget {
140140
};
141141

142142
if self.prefix.iter().all(|x| x.is_none()) {
143-
// Simplify to a single unit when there is no prefix and size <= unit size
144-
if self.rest.total <= self.rest.unit.size && !self.rest.force_array {
143+
// Try to simplify to a single unit when there is no prefix and size <= unit size.
144+
// We can't do this if is_consecutive is set and the unit would get split on the
145+
// target. Currently, this is only relevant for i128 registers.
146+
if self.rest.total <= self.rest.unit.size
147+
&& (!self.rest.is_consecutive || self.rest.unit != Reg::i128())
148+
{
145149
return rest_ll_unit;
146150
}
147151

compiler/rustc_target/src/abi/call/aarch64.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ where
3131
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
3232
};
3333

34-
valid_unit.then_some(Uniform { unit, total: size, force_array: false })
34+
valid_unit.then_some(Uniform::consecutive(unit, size))
3535
})
3636
}
3737

@@ -60,7 +60,7 @@ where
6060
let size = ret.layout.size;
6161
let bits = size.bits();
6262
if bits <= 128 {
63-
ret.cast_to(Uniform { unit: Reg::i64(), total: size, force_array: false });
63+
ret.cast_to(Uniform::new(Reg::i64(), size));
6464
return;
6565
}
6666
ret.make_indirect();
@@ -100,9 +100,9 @@ where
100100
};
101101
if size.bits() <= 128 {
102102
if align.bits() == 128 {
103-
arg.cast_to(Uniform { unit: Reg::i128(), total: size, force_array: false });
103+
arg.cast_to(Uniform::new(Reg::i128(), size));
104104
} else {
105-
arg.cast_to(Uniform { unit: Reg::i64(), total: size, force_array: false });
105+
arg.cast_to(Uniform::new(Reg::i64(), size));
106106
}
107107
return;
108108
}

compiler/rustc_target/src/abi/call/arm.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ where
2121
RegKind::Vector => size.bits() == 64 || size.bits() == 128,
2222
};
2323

24-
valid_unit.then_some(Uniform { unit, total: size, force_array: false })
24+
valid_unit.then_some(Uniform::consecutive(unit, size))
2525
})
2626
}
2727

@@ -49,7 +49,7 @@ where
4949
let size = ret.layout.size;
5050
let bits = size.bits();
5151
if bits <= 32 {
52-
ret.cast_to(Uniform { unit: Reg::i32(), total: size, force_array: false });
52+
ret.cast_to(Uniform::new(Reg::i32(), size));
5353
return;
5454
}
5555
ret.make_indirect();
@@ -78,11 +78,7 @@ where
7878

7979
let align = arg.layout.align.abi.bytes();
8080
let total = arg.layout.size;
81-
arg.cast_to(Uniform {
82-
unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
83-
total,
84-
force_array: false,
85-
});
81+
arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total));
8682
}
8783

8884
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)

compiler/rustc_target/src/abi/call/csky.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
1818
if total.bits() > 64 {
1919
arg.make_indirect();
2020
} else if total.bits() > 32 {
21-
arg.cast_to(Uniform { unit: Reg::i32(), total, force_array: false });
21+
arg.cast_to(Uniform::new(Reg::i32(), total));
2222
} else {
2323
arg.cast_to(Reg::i32());
2424
}
@@ -38,7 +38,7 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
3838
if arg.layout.is_aggregate() {
3939
let total = arg.layout.size;
4040
if total.bits() > 32 {
41-
arg.cast_to(Uniform { unit: Reg::i32(), total, force_array: false });
41+
arg.cast_to(Uniform::new(Reg::i32(), total));
4242
} else {
4343
arg.cast_to(Reg::i32());
4444
}

compiler/rustc_target/src/abi/call/loongarch.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,7 @@ where
195195
if total.bits() <= xlen {
196196
arg.cast_to(xlen_reg);
197197
} else {
198-
arg.cast_to(Uniform {
199-
unit: xlen_reg,
200-
total: Size::from_bits(xlen * 2),
201-
force_array: false,
202-
});
198+
arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2)));
203199
}
204200
return false;
205201
}
@@ -282,11 +278,10 @@ fn classify_arg<'a, Ty, C>(
282278
if total.bits() > xlen {
283279
let align_regs = align > xlen;
284280
if is_loongarch_aggregate(arg) {
285-
arg.cast_to(Uniform {
286-
unit: if align_regs { double_xlen_reg } else { xlen_reg },
287-
total: Size::from_bits(xlen * 2),
288-
force_array: false,
289-
});
281+
arg.cast_to(Uniform::new(
282+
if align_regs { double_xlen_reg } else { xlen_reg },
283+
Size::from_bits(xlen * 2),
284+
));
290285
}
291286
if align_regs && is_vararg {
292287
*avail_gprs -= *avail_gprs % 2;

compiler/rustc_target/src/abi/call/mips.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ where
2727

2828
if arg.layout.is_aggregate() {
2929
let pad_i32 = !offset.is_aligned(align);
30-
arg.cast_to_and_pad_i32(
31-
Uniform { unit: Reg::i32(), total: size, force_array: false },
32-
pad_i32,
33-
);
30+
arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32);
3431
} else {
3532
arg.extend_integer_width_to(32);
3633
}

compiler/rustc_target/src/abi/call/mips64.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ where
6868
}
6969

7070
// Cast to a uniform int structure
71-
ret.cast_to(Uniform { unit: Reg::i64(), total: size, force_array: false });
71+
ret.cast_to(Uniform::new(Reg::i64(), size));
7272
} else {
7373
ret.make_indirect();
7474
}
@@ -139,7 +139,7 @@ where
139139
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
140140
arg.cast_to(CastTarget {
141141
prefix,
142-
rest: Uniform { unit: Reg::i64(), total: rest_size, force_array: false },
142+
rest: Uniform::new(Reg::i64(), rest_size),
143143
attrs: ArgAttributes {
144144
regular: ArgAttribute::default(),
145145
arg_ext: ArgExtension::None,

compiler/rustc_target/src/abi/call/mod.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -256,20 +256,34 @@ pub struct Uniform {
256256
/// 64-bit integers with a total size of 20 bytes.
257257
pub total: Size,
258258

259-
/// Force the use of an array, even if there is only a single element.
260-
pub force_array: bool,
259+
/// Indicate that the argument is consecutive, in the sense that either all values need to be
260+
/// passed in register, or all on the stack. If they are passed on the stack, there should be
261+
/// no additional padding between elements.
262+
pub is_consecutive: bool,
261263
}
262264

263265
impl From<Reg> for Uniform {
264266
fn from(unit: Reg) -> Uniform {
265-
Uniform { unit, total: unit.size, force_array: false }
267+
Uniform { unit, total: unit.size, is_consecutive: false }
266268
}
267269
}
268270

269271
impl Uniform {
270272
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
271273
self.unit.align(cx)
272274
}
275+
276+
/// Pass using one or more values of the given type, without requiring them to be consecutive.
277+
/// That is, some values may be passed in register and some on the stack.
278+
pub fn new(unit: Reg, total: Size) -> Self {
279+
Uniform { unit, total, is_consecutive: false }
280+
}
281+
282+
/// Pass using one or more consecutive values of the given type. Either all values will be
283+
/// passed in registers, or all on the stack.
284+
pub fn consecutive(unit: Reg, total: Size) -> Self {
285+
Uniform { unit, total, is_consecutive: true }
286+
}
273287
}
274288

275289
/// Describes the type used for `PassMode::Cast`.

compiler/rustc_target/src/abi/call/nvptx64.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ where
3535
16 => Reg::i128(),
3636
_ => unreachable!("Align is given as power of 2 no larger than 16 bytes"),
3737
};
38-
arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes), force_array: false });
38+
arg.cast_to(Uniform {
39+
unit,
40+
total: Size::from_bytes(2 * align_bytes),
41+
is_consecutive: false,
42+
});
3943
} else {
4044
// FIXME: find a better way to do this. See https://github.com/rust-lang/rust/issues/117271.
4145
arg.make_direct_deprecated();

compiler/rustc_target/src/abi/call/powerpc64.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ where
3737
RegKind::Vector => arg.layout.size.bits() == 128,
3838
};
3939

40-
valid_unit.then_some(Uniform { unit, total: arg.layout.size, force_array: false })
40+
valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size))
4141
})
4242
}
4343

@@ -81,7 +81,7 @@ where
8181
Reg::i64()
8282
};
8383

84-
ret.cast_to(Uniform { unit, total: size, force_array: false });
84+
ret.cast_to(Uniform::new(unit, size));
8585
return;
8686
}
8787

@@ -117,11 +117,10 @@ where
117117
// of i64s or i128s, depending on the aggregate alignment. Always use an array for
118118
// this, even if there is only a single element.
119119
let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() };
120-
arg.cast_to(Uniform {
121-
unit: reg,
122-
total: size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()),
123-
force_array: true,
124-
})
120+
arg.cast_to(Uniform::consecutive(
121+
reg,
122+
size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()),
123+
))
125124
};
126125
}
127126

compiler/rustc_target/src/abi/call/riscv.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ where
204204
arg.cast_to(Uniform {
205205
unit: xlen_reg,
206206
total: Size::from_bits(xlen * 2),
207-
force_array: false,
207+
is_consecutive: false,
208208
});
209209
}
210210
return false;
@@ -291,7 +291,7 @@ fn classify_arg<'a, Ty, C>(
291291
arg.cast_to(Uniform {
292292
unit: if align_regs { double_xlen_reg } else { xlen_reg },
293293
total: Size::from_bits(xlen * 2),
294-
force_array: false,
294+
is_consecutive: false,
295295
});
296296
}
297297
if align_regs && is_vararg {

compiler/rustc_target/src/abi/call/sparc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ where
2828
if arg.layout.is_aggregate() {
2929
let pad_i32 = !offset.is_aligned(align);
3030
arg.cast_to_and_pad_i32(
31-
Uniform { unit: Reg::i32(), total: size, force_array: false },
31+
Uniform { unit: Reg::i32(), total: size, is_consecutive: false },
3232
pad_i32,
3333
);
3434
} else {

compiler/rustc_target/src/abi/call/sparc64.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ where
192192

193193
arg.cast_to(CastTarget {
194194
prefix: data.prefix,
195-
rest: Uniform { unit: Reg::i64(), total: rest_size, force_array: false },
195+
rest: Uniform { unit: Reg::i64(), total: rest_size, is_consecutive: false },
196196
attrs: ArgAttributes {
197197
regular: data.arg_attribute,
198198
arg_ext: ArgExtension::None,
@@ -205,7 +205,7 @@ where
205205
}
206206
}
207207

208-
arg.cast_to(Uniform { unit: Reg::i64(), total, force_array: false });
208+
arg.cast_to(Uniform { unit: Reg::i64(), total, is_consecutive: false });
209209
}
210210

211211
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)

0 commit comments

Comments
 (0)