blob: c4eb0267ea619aacfae330ff89ce65c830a41705 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=aarch64-unknown-linux-gnu -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefixes=CHECK,LP64 %s
; RUN: opt -mtriple=arm64_32-apple-watchos -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefixes=CHECK,ILP32 %s
; Test that @llvm.can.load.speculatively lowers to an alignment check for
; power-of-2 sizes up to the 16-byte MTE tag granule, and to false otherwise.
define i1 @size_1(ptr %ptr) {
; LP64-LABEL: @size_1(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 0
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_1(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 0
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 1)
ret i1 %can_load
}
define i1 @size_2(ptr %ptr) {
; LP64-LABEL: @size_2(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 1
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_2(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 2)
ret i1 %can_load
}
define i1 @size_4(ptr %ptr) {
; LP64-LABEL: @size_4(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 3
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_4(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 3
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 4)
ret i1 %can_load
}
define i1 @size_8(ptr %ptr) {
; LP64-LABEL: @size_8(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 7
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_8(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 7
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 8)
ret i1 %can_load
}
define i1 @size_16(ptr %ptr) {
; LP64-LABEL: @size_16(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 15
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_16(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 15
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 16)
ret i1 %can_load
}
; The alignment of the pointer operand does not change the emitted check.
define i1 @size_16_ptr_align_16(ptr align 16 %ptr) {
; LP64-LABEL: @size_16_ptr_align_16(
; LP64-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], 15
; LP64-NEXT: [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
; LP64-NEXT: ret i1 [[TMP3]]
;
; ILP32-LABEL: @size_16_ptr_align_16(
; ILP32-NEXT: [[TMP1:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 15
; ILP32-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
; ILP32-NEXT: ret i1 [[TMP3]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr align 16 %ptr, i64 16)
ret i1 %can_load
}
; Size > 16 - returns false (may cross MTE tag granule boundary)
define i1 @size_32(ptr %ptr) {
; CHECK-LABEL: @size_32(
; CHECK-NEXT: ret i1 false
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 32)
ret i1 %can_load
}
; Non-power-of-2 size: the alignment check is only valid for powers of 2.
define i1 @size_non_pow2(ptr %ptr) {
; CHECK-LABEL: @size_non_pow2(
; CHECK-NEXT: ret i1 false
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 12)
ret i1 %can_load
}
; Non-power-of-2 size larger than the tag granule.
define i1 @size_non_pow2_large(ptr %ptr) {
; CHECK-LABEL: @size_non_pow2_large(
; CHECK-NEXT: ret i1 false
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 100)
ret i1 %can_load
}
; Zero size is not a positive power of 2 either.
define i1 @size_zero(ptr %ptr) {
; CHECK-LABEL: @size_zero(
; CHECK-NEXT: ret i1 false
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 0)
ret i1 %can_load
}
; Test with address space
define i1 @addrspace1(ptr addrspace(1) %ptr) {
; CHECK-LABEL: @addrspace1(
; CHECK-NEXT: ret i1 false
;
%can_load = call i1 @llvm.can.load.speculatively.p1(ptr addrspace(1) %ptr, i64 16)
ret i1 %can_load
}
; The granule comparison must happen before the size is narrowed to the address
; type, so a size exceeding the address width is not truncated into range.
define i1 @runtime_size(ptr %ptr, i64 %size) {
; LP64-LABEL: @runtime_size(
; LP64-NEXT: [[TMP1:%.*]] = icmp ule i64 [[SIZE:%.*]], 16
; LP64-NEXT: [[TMP2:%.*]] = sub i64 [[SIZE]], 1
; LP64-NEXT: [[TMP3:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i64
; LP64-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], [[TMP2]]
; LP64-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 0
; LP64-NEXT: [[TMP6:%.*]] = and i1 [[TMP1]], [[TMP5]]
; LP64-NEXT: ret i1 [[TMP6]]
;
; ILP32-LABEL: @runtime_size(
; ILP32-NEXT: [[TMP1:%.*]] = icmp ule i64 [[SIZE:%.*]], 16
; ILP32-NEXT: [[TMP2:%.*]] = trunc i64 [[SIZE]] to i32
; ILP32-NEXT: [[TMP3:%.*]] = sub i32 [[TMP2]], 1
; ILP32-NEXT: [[TMP4:%.*]] = ptrtoaddr ptr [[PTR:%.*]] to i32
; ILP32-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], [[TMP3]]
; ILP32-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 0
; ILP32-NEXT: [[TMP7:%.*]] = and i1 [[TMP1]], [[TMP6]]
; ILP32-NEXT: ret i1 [[TMP7]]
;
%can_load = call i1 @llvm.can.load.speculatively.p0(ptr %ptr, i64 %size)
ret i1 %can_load
}
declare i1 @llvm.can.load.speculatively.p0(ptr, i64)
declare i1 @llvm.can.load.speculatively.p1(ptr addrspace(1), i64)