Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1881,12 +1881,15 @@ unsafe extern "C" {
C: &Context,
effects: MemoryEffects,
) -> &Attribute;
pub(crate) fn LLVMRustCreateRangeAttribute(
C: &Context,
num_bits: c_uint,
lower_words: *const u64,
upper_words: *const u64,
) -> &Attribute;
/// Lower and upper bounds are each passed as a `u128` broken into low and high 64-bit parts.
pub(crate) safe fn LLVMRustCreateRangeAttribute<'ll>(
C: &'ll Context,
NumBits: c_uint,
LowerBoundLo: u64,
LowerBoundHi: u64,
UpperBoundLo: u64,
UpperBoundHi: u64,
) -> &'ll Attribute;

// Operations on functions
pub(crate) fn LLVMRustGetOrInsertFunction<'a>(
Expand Down
30 changes: 20 additions & 10 deletions compiler/rustc_codegen_llvm/src/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,27 @@ pub(crate) fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &

pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
let lower = range.start;
// LLVM treats the upper bound as exclusive, but allows wrapping.
let upper = range.end.wrapping_add(1);
let lower_words = [lower as u64, (lower >> 64) as u64];
let upper_words = [upper as u64, (upper >> 64) as u64];
unsafe {
LLVMRustCreateRangeAttribute(
llcx,
size.bits().try_into().unwrap(),
lower_words.as_ptr(),
upper_words.as_ptr(),
)
}

// Split each endpoint into a pair of u64 values to make FFI easier.
let as_lo_hi_pair = |x: u128| (x as u64, (x >> 64) as u64);
let (lower_bound_lo, lower_bound_hi) = as_lo_hi_pair(lower);
let (upper_bound_lo, upper_bound_hi) = as_lo_hi_pair(upper);

// Endpoints are given as u128, so make sure the given size isn't larger than that.
let size_bits = size.bits();
assert!(size_bits <= 128);
let size_bits = size_bits.try_into().unwrap();

LLVMRustCreateRangeAttribute(
llcx,
size_bits,
lower_bound_lo,
lower_bound_hi,
upper_bound_lo,
upper_bound_hi,
)
}

#[derive(Copy, Clone)]
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,10 +486,15 @@ LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {

extern "C" LLVMAttributeRef
LLVMRustCreateRangeAttribute(LLVMContextRef C, unsigned NumBits,
const uint64_t LowerWords[],
const uint64_t UpperWords[]) {
return LLVMCreateConstantRangeAttribute(C, Attribute::Range, NumBits,
LowerWords, UpperWords);
uint64_t LowerBoundLo, uint64_t LowerBoundHi,
uint64_t UpperBoundLo, uint64_t UpperBoundHi) {
// For both endpoints, reassemble the lo/hi parts into into APInt values.
// APInt will automatically discard any excess bits.
ConstantRange RangeValue = {
APInt(NumBits, ArrayRef{LowerBoundLo, LowerBoundHi}),
APInt(NumBits, ArrayRef{UpperBoundLo, UpperBoundHi}),
};
return wrap(Attribute::get(*unwrap(C), llvm::Attribute::Range, RangeValue));
}

// These values **must** match ffi::AllocKindFlags.
Expand Down
39 changes: 39 additions & 0 deletions tests/codegen-llvm/range-attr/edge-cases.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![feature(rustc_attrs)]
#![crate_type = "lib"]
//@ edition: 2024

// Edge-case tests for the conversion from `rustc_abi::WrappingRange` to
// LLVM range attributes.

#[rustc_layout_scalar_valid_range_start(1)]
pub struct LowNiche8(u8);
// CHECK: define void @low_niche_8(i8 noundef range(i8 1, 0) %_1)
#[unsafe(no_mangle)]
pub fn low_niche_8(_: LowNiche8) {}

#[rustc_layout_scalar_valid_range_end(254)]
pub struct HighNiche8(u8);
// CHECK: define void @high_niche_8(i8 noundef range(i8 0, -1) %_1)
#[unsafe(no_mangle)]
pub fn high_niche_8(_: HighNiche8) {}

#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_layout_scalar_valid_range_end(254)]
pub struct Niches8(u8);
// CHECK: define void @niches_8(i8 noundef range(i8 1, -1) %_1)
#[unsafe(no_mangle)]
pub fn niches_8(_: Niches8) {}

#[rustc_layout_scalar_valid_range_start(255)]
#[rustc_layout_scalar_valid_range_end(255)]
pub struct SoloHigh8(u8);
// CHECK: define void @solo_high_8(i8 noundef range(i8 -1, 0) %_1)
#[unsafe(no_mangle)]
pub fn solo_high_8(_: SoloHigh8) {}

#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_layout_scalar_valid_range_end(340282366920938463463374607431768211454)] // (u128::MAX - 1)
pub struct Niches128(u128);
// CHECK: define void @niches_128(i128 noundef range(i128 1, -1) %_1)
#[unsafe(no_mangle)]
pub fn niches_128(_: Niches128) {}
Loading