Skip to content

Commit 1b7342b

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 009280c commit 1b7342b

File tree

13 files changed

+53
-57
lines changed

13 files changed

+53
-57
lines changed

Diff for: compiler/rustc_codegen_llvm/src/abi.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ impl LlvmType for CastTarget {
150150
// Simplify to a single unit or an array if there's no prefix.
151151
// This produces the same layout, but using a simpler type.
152152
if self.prefix.iter().all(|x| x.is_none()) {
153-
if rest_count == 1 && !self.rest.force_array {
153+
// We can't do this if is_consecutive is set and the unit would get
154+
// split on the target. Currently, this is only relevant for i128
155+
// registers.
156+
if rest_count == 1 && (!self.rest.is_consecutive || self.rest.unit != Reg::i128()) {
154157
return rest_ll_unit;
155158
}
156159

Diff for: 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
}

Diff for: 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>)

Diff for: 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
}

Diff for: 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;

Diff for: 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
}

Diff for: 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,

Diff for: 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
/// this size will be rounded up to the nearest multiple of `unit.size`.
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`.

Diff for: compiler/rustc_target/src/abi/call/nvptx64.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ 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::new(unit, Size::from_bytes(2 * align_bytes)));
3939
} else {
4040
// FIXME: find a better way to do this. See https://github.com/rust-lang/rust/issues/117271.
4141
arg.make_direct_deprecated();

Diff for: 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

Diff for: compiler/rustc_target/src/abi/call/riscv.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,7 @@ where
201201
if total.bits() <= xlen {
202202
arg.cast_to(xlen_reg);
203203
} else {
204-
arg.cast_to(Uniform {
205-
unit: xlen_reg,
206-
total: Size::from_bits(xlen * 2),
207-
force_array: false,
208-
});
204+
arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2)));
209205
}
210206
return false;
211207
}
@@ -288,11 +284,10 @@ fn classify_arg<'a, Ty, C>(
288284
if total.bits() > xlen {
289285
let align_regs = align > xlen;
290286
if is_riscv_aggregate(arg) {
291-
arg.cast_to(Uniform {
292-
unit: if align_regs { double_xlen_reg } else { xlen_reg },
293-
total: Size::from_bits(xlen * 2),
294-
force_array: false,
295-
});
287+
arg.cast_to(Uniform::new(
288+
if align_regs { double_xlen_reg } else { xlen_reg },
289+
Size::from_bits(xlen * 2),
290+
));
296291
}
297292
if align_regs && is_vararg {
298293
*avail_gprs -= *avail_gprs % 2;

Diff for: compiler/rustc_target/src/abi/call/sparc.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
}

Diff for: 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::new(Reg::i64(), rest_size),
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::new(Reg::i64(), total));
209209
}
210210

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

0 commit comments

Comments
 (0)