Skip to content

Commit 74ef47e

Browse files
make CastTarget::size and CastTarget::llvm_type consistent, remove
special case that's not present in Clang Making the methods consistent doesn't require much justification. It's required for us to generate correct code. The special case was present near the end of `CastTarget::llvm_type`, and resulted in the final integer component of the ABI type being shrunk to the smallest integer that fits. You can see this in action here (https://godbolt.org/z/Pe73cr91d), where, for a struct with 5 u16 elements, rustc generates `{ i64, i16 }`, while Clang generates `[2 x i64]`. This special case was added a long time ago, when the function was originally written [1]. That commit consolidated logic from many backends, and in some of the code it deleted, sparc64 [2] and powerpc64 [3] had similar special cases. However, looking at Clang today, it doesn't have this special case for sparc64 (https://godbolt.org/z/YaafvYWdf) or powerpc64 (https://godbolt.org/z/5c3YePTje), so this change just removes it. [1]: f0636b6#diff-183c4dadf10704bd1f521b71f71d89bf755c9603a93f894d66c03bb1effc6021R231 [2]: f0636b6#diff-2d8f87ea6db6d7f0a6fbeb1d5549adc07e93331278d951a1e051a40f92914436L163-L166 [3]: f0636b6#diff-88af4a9df9ead503a5c7774a0455d270dea3ba60e9b0ec1ce550b4c53d3bce3bL172-L175
1 parent 41c6fa8 commit 74ef47e

File tree

2 files changed

+38
-39
lines changed
  • compiler

2 files changed

+38
-39
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
1616
use rustc_middle::ty::Ty;
1717
use rustc_session::config;
1818
pub use rustc_target::abi::call::*;
19-
use rustc_target::abi::{self, HasDataLayout, Int};
19+
use rustc_target::abi::{self, HasDataLayout, Int, Size};
2020
pub use rustc_target::spec::abi::Abi;
2121
use rustc_target::spec::SanitizerSet;
2222

2323
use libc::c_uint;
2424
use smallvec::SmallVec;
2525

26+
use std::cmp;
27+
2628
pub trait ArgAttributesExt {
2729
fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value);
2830
fn apply_attrs_to_callsite(
@@ -130,42 +132,36 @@ impl LlvmType for Reg {
130132
impl LlvmType for CastTarget {
131133
fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
132134
let rest_ll_unit = self.rest.unit.llvm_type(cx);
133-
let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
134-
(0, 0)
135+
let rest_count = if self.rest.total == Size::ZERO {
136+
0
135137
} else {
136-
(
137-
self.rest.total.bytes() / self.rest.unit.size.bytes(),
138-
self.rest.total.bytes() % self.rest.unit.size.bytes(),
139-
)
138+
assert_ne!(
139+
self.rest.unit.size,
140+
Size::ZERO,
141+
"total size {:?} cannot be divided into units of zero size",
142+
self.rest.total
143+
);
144+
if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 {
145+
assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split");
146+
}
147+
self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes())
140148
};
141149

150+
// Simplify to a single unit or an array if there's no prefix.
151+
// This produces the same layout, but using a simpler type.
142152
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 {
153+
if rest_count == 1 {
145154
return rest_ll_unit;
146155
}
147156

148-
// Simplify to array when all chunks are the same size and type
149-
if rem_bytes == 0 {
150-
return cx.type_array(rest_ll_unit, rest_count);
151-
}
152-
}
153-
154-
// Create list of fields in the main structure
155-
let mut args: Vec<_> = self
156-
.prefix
157-
.iter()
158-
.flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
159-
.chain((0..rest_count).map(|_| rest_ll_unit))
160-
.collect();
161-
162-
// Append final integer
163-
if rem_bytes != 0 {
164-
// Only integers can be really split further.
165-
assert_eq!(self.rest.unit.kind, RegKind::Integer);
166-
args.push(cx.type_ix(rem_bytes * 8));
157+
return cx.type_array(rest_ll_unit, rest_count);
167158
}
168159

160+
// Generate a struct type with the prefix and the "rest" arguments.
161+
let prefix_args =
162+
self.prefix.iter().flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)));
163+
let rest_args = (0..rest_count).map(|_| rest_ll_unit);
164+
let args: Vec<_> = prefix_args.chain(rest_args).collect();
169165
cx.type_struct(&args, false)
170166
}
171167
}

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,9 @@ pub struct Uniform {
251251
/// The total size of the argument, which can be:
252252
/// * equal to `unit.size` (one scalar/vector),
253253
/// * a multiple of `unit.size` (an array of scalar/vectors),
254-
/// * if `unit.kind` is `Integer`, the last element
255-
/// can be shorter, i.e., `{ i64, i64, i32 }` for
256-
/// 64-bit integers with a total size of 20 bytes.
254+
/// * if `unit.kind` is `Integer`, the last element can be shorter, i.e., `{ i64, i64, i32 }`
255+
/// for 64-bit integers with a total size of 20 bytes. When the argument is actually passed,
256+
/// this size will be rounded up to the nearest multiple of `unit.size`.
257257
pub total: Size,
258258
}
259259

@@ -319,14 +319,17 @@ impl CastTarget {
319319
}
320320

321321
pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
322-
let mut size = self.rest.total;
323-
for i in 0..self.prefix.iter().count() {
324-
match self.prefix[i] {
325-
Some(v) => size += v.size,
326-
None => {}
327-
}
328-
}
329-
return size;
322+
// Prefix arguments are passed in specific designated registers
323+
let prefix_size = self
324+
.prefix
325+
.iter()
326+
.filter_map(|x| x.map(|reg| reg.size))
327+
.fold(Size::ZERO, |acc, size| acc + size);
328+
// Remaining arguments are passed in chunks of the unit size
329+
let rest_size =
330+
self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
331+
332+
prefix_size + rest_size
330333
}
331334

332335
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {

0 commit comments

Comments
 (0)