[llvm] [AVR] Add a test for half support (NFC) (PR #152708)
Trevor Gross via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 9 04:10:31 PDT 2025
================
@@ -0,0 +1,750 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc %s -o - -mtriple=avr | FileCheck %s
+
+; Tests for various operations on half precison float. Much of the test is
+; copied from test/CodeGen/X86/half.ll.
+
+define void @store(half %x, ptr %p) nounwind {
+; CHECK-LABEL: store:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r20
+; CHECK-NEXT: mov r31, r21
+; CHECK-NEXT: std Z+1, r23
+; CHECK-NEXT: st Z, r22
+; CHECK-NEXT: ret
+ store half %x, ptr %p
+ ret void
+}
+
+define half @return(ptr %p) nounwind {
+; CHECK-LABEL: return:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r22, Z
+; CHECK-NEXT: ldd r23, Z+1
+; CHECK-NEXT: ret
+ %r = load half, ptr %p
+ ret half %r
+}
+
+define dso_local double @loadd(ptr nocapture readonly %a) local_unnamed_addr nounwind {
+; CHECK-LABEL: loadd:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ldd r24, Z+2
+; CHECK-NEXT: ldd r25, Z+3
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __extendsfdf2
+; CHECK-NEXT: ret
+entry:
+ %arrayidx = getelementptr inbounds i16, ptr %a, i64 1
+ %0 = load i16, ptr %arrayidx, align 2
+ %1 = tail call double @llvm.convert.from.fp16.f64(i16 %0)
+ ret double %1
+}
+
+define dso_local float @loadf(ptr nocapture readonly %a) local_unnamed_addr nounwind {
+; CHECK-LABEL: loadf:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ldd r24, Z+2
+; CHECK-NEXT: ldd r25, Z+3
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: ret
+entry:
+ %arrayidx = getelementptr inbounds i16, ptr %a, i64 1
+ %0 = load i16, ptr %arrayidx, align 2
+ %1 = tail call float @llvm.convert.from.fp16.f32(i16 %0)
+ ret float %1
+}
+
+define dso_local void @stored(ptr nocapture %a, double %b) local_unnamed_addr nounwind {
+; CHECK-LABEL: stored:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: push r16
+; CHECK-NEXT: push r17
+; CHECK-NEXT: mov r30, r22
+; CHECK-NEXT: mov r31, r23
+; CHECK-NEXT: mov r22, r20
+; CHECK-NEXT: mov r23, r21
+; CHECK-NEXT: mov r20, r18
+; CHECK-NEXT: mov r21, r19
+; CHECK-NEXT: mov r18, r16
+; CHECK-NEXT: mov r19, r17
+; CHECK-NEXT: mov r16, r24
+; CHECK-NEXT: mov r17, r25
+; CHECK-NEXT: mov r24, r30
+; CHECK-NEXT: mov r25, r31
+; CHECK-NEXT: rcall __truncdfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: pop r17
+; CHECK-NEXT: pop r16
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i16 @llvm.convert.to.fp16.f64(double %b)
+ store i16 %0, ptr %a, align 2
+ ret void
+}
+
+define dso_local void @storef(ptr nocapture %a, float %b) local_unnamed_addr nounwind {
+; CHECK-LABEL: storef:
+; CHECK: ; %bb.0: ; %entry
+; CHECK-NEXT: push r16
+; CHECK-NEXT: push r17
+; CHECK-NEXT: mov r18, r22
+; CHECK-NEXT: mov r19, r23
+; CHECK-NEXT: mov r16, r24
+; CHECK-NEXT: mov r17, r25
+; CHECK-NEXT: mov r22, r20
+; CHECK-NEXT: mov r23, r21
+; CHECK-NEXT: mov r24, r18
+; CHECK-NEXT: mov r25, r19
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: pop r17
+; CHECK-NEXT: pop r16
+; CHECK-NEXT: ret
+entry:
+ %0 = tail call i16 @llvm.convert.to.fp16.f32(float %b)
+ store i16 %0, ptr %a, align 2
+ ret void
+}
+
+define void @test_load_store(ptr %in, ptr %out) nounwind {
+; CHECK-LABEL: test_load_store:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: push r16
+; CHECK-NEXT: push r17
+; CHECK-NEXT: mov r16, r22
+; CHECK-NEXT: mov r17, r23
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: pop r17
+; CHECK-NEXT: pop r16
+; CHECK-NEXT: ret
+ %val = load half, ptr %in
+ store half %val, ptr %out
+ ret void
+}
+
+define i16 @test_bitcast_from_half(ptr %addr) nounwind {
+; CHECK-LABEL: test_bitcast_from_half:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: ret
+ %val = load half, ptr %addr
+ %val_int = bitcast half %val to i16
+ ret i16 %val_int
+}
+
+define void @test_bitcast_to_half(ptr %addr, i16 %in) nounwind {
+; CHECK-LABEL: test_bitcast_to_half:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: std Z+1, r23
+; CHECK-NEXT: st Z, r22
+; CHECK-NEXT: ret
+ %val_fp = bitcast i16 %in to half
+ store half %val_fp, ptr %addr
+ ret void
+}
+
+define half @from_bits(i16 %x) nounwind {
+; CHECK-LABEL: from_bits:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r22, r24
+; CHECK-NEXT: mov r23, r25
+; CHECK-NEXT: ret
+ %res = bitcast i16 %x to half
+ ret half %res
+}
+
+define i16 @to_bits(half %x) nounwind {
+; CHECK-LABEL: to_bits:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r24, r22
+; CHECK-NEXT: mov r25, r23
+; CHECK-NEXT: ret
+ %res = bitcast half %x to i16
+ ret i16 %res
+}
+
+define float @test_extend32(ptr %addr) nounwind {
+; CHECK-LABEL: test_extend32:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: ret
+ %val16 = load half, ptr %addr
+ %val32 = fpext half %val16 to float
+ ret float %val32
+}
+
+define double @test_extend64(ptr %addr) nounwind {
+; CHECK-LABEL: test_extend64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __extendsfdf2
+; CHECK-NEXT: ret
+ %val16 = load half, ptr %addr
+ %val32 = fpext half %val16 to double
+ ret double %val32
+}
+
+define void @test_trunc32(float %in, ptr %addr) nounwind {
+; CHECK-LABEL: test_trunc32:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: push r16
+; CHECK-NEXT: push r17
+; CHECK-NEXT: mov r16, r20
+; CHECK-NEXT: mov r17, r21
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: pop r17
+; CHECK-NEXT: pop r16
+; CHECK-NEXT: ret
+ %val16 = fptrunc float %in to half
+ store half %val16, ptr %addr
+ ret void
+}
+
+define void @test_trunc64(double %in, ptr %addr) nounwind {
+; CHECK-LABEL: test_trunc64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: rcall __truncdfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: ret
+ %val16 = fptrunc double %in to half
+ store half %val16, ptr %addr
+ ret void
+}
+
+define i64 @test_fptosi_i64(ptr %p) nounwind {
+; CHECK-LABEL: test_fptosi_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __fixsfdi
+; CHECK-NEXT: ret
+ %a = load half, ptr %p, align 2
+ %r = fptosi half %a to i64
+ ret i64 %r
+}
+
+define void @test_sitofp_i64(i64 %a, ptr %p) nounwind {
+; CHECK-LABEL: test_sitofp_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: rcall __floatdisf
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: ret
+ %r = sitofp i64 %a to half
+ store half %r, ptr %p
+ ret void
+}
+
+define i64 @test_fptoui_i64(ptr %p) nounwind {
+; CHECK-LABEL: test_fptoui_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: mov r30, r24
+; CHECK-NEXT: mov r31, r25
+; CHECK-NEXT: ld r24, Z
+; CHECK-NEXT: ldd r25, Z+1
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __fixunssfdi
+; CHECK-NEXT: ret
+ %a = load half, ptr %p, align 2
+ %r = fptoui half %a to i64
+ ret i64 %r
+}
+
+define void @test_uitofp_i64(i64 %a, ptr %p) nounwind {
+; CHECK-LABEL: test_uitofp_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: rcall __floatundisf
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: rcall __extendhfsf2
+; CHECK-NEXT: rcall __truncsfhf2
+; CHECK-NEXT: mov r30, r16
+; CHECK-NEXT: mov r31, r17
+; CHECK-NEXT: std Z+1, r25
+; CHECK-NEXT: st Z, r24
+; CHECK-NEXT: ret
+ %r = uitofp i64 %a to half
+ store half %r, ptr %p
+ ret void
+}
+
+define <4 x float> @test_extend32_vec4(ptr %p) nounwind {
----------------
tgross35 wrote:
That's about what I was thinking - nobody is really going to use this, but it also shouldn't regress in some way or start crashing. The test just makes sure that gets noticed if it does, and can always be deleted if needed.
If you feel strongly, though, I don't mind remove them.
> For vector types, the clang front end does not supprt vector type syntax, also other language fronts should not do that either.
(somewhat off topic) For what it's worth, portable SIMD works this way: the frontend emits vector ops and it's up to LLVM to decide whether the target supports them directly, or if they should be scalarized. Not that I expect there to be much overlap between libraries using portable SIMD and libraries for AVR, but it does work pretty well on embedded targets currently.
https://github.com/llvm/llvm-project/pull/152708
More information about the llvm-commits
mailing list