[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 01:32:58 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:

Yeah, it's not very likely to come up. But even on hardware that doesn't have vector extensions, the frontends should be able to rely on LLVM transforming vector ops into scalar ops without crashing.

I simplified the tests to only cover `<2 x float>` and `<1 x double>`, to get rid of the biggest asm blocks but keep that part somewhat tested.

https://github.com/llvm/llvm-project/pull/152708


More information about the llvm-commits mailing list