[SelectionDAG][AVR] Add support for lrint and lround intrinsics
authorAyke van Laethem <aykevanlaethem@gmail.com>
Sun, 1 Jan 2023 18:05:35 +0000 (19:05 +0100)
committerAyke van Laethem <aykevanlaethem@gmail.com>
Sun, 8 Jan 2023 17:56:07 +0000 (18:56 +0100)
Integer legalization already supported splitting the output integer of
llround and llrint, but did not support this for lround and lrint yet.
This is not a problem for 32-bit architectures, but for 8/16-bit
architectures like AVR it results in a crash like this:

    ExpandIntegerResult #0: t7: i32 = lround t6

    LLVM ERROR: Do not know how to expand the result of this operator!

This patch simply add lrint/lround to the list of ISD opcodes to expand.

Fixes https://github.com/llvm/llvm-project/issues/59573.

Differential Revision: https://reviews.llvm.org/D140822

llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
llvm/test/CodeGen/AVR/llrint.ll [new file with mode: 0644]
llvm/test/CodeGen/AVR/llround-conv.ll [new file with mode: 0644]
llvm/test/CodeGen/AVR/lrint.ll [new file with mode: 0644]
llvm/test/CodeGen/AVR/lround-conv.ll [new file with mode: 0644]

index 2e4ccae..4e64024 100644 (file)
@@ -2435,10 +2435,14 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) {
   case ISD::FP_TO_UINT:  ExpandIntRes_FP_TO_UINT(N, Lo, Hi); break;
   case ISD::FP_TO_SINT_SAT:
   case ISD::FP_TO_UINT_SAT: ExpandIntRes_FP_TO_XINT_SAT(N, Lo, Hi); break;
+  case ISD::STRICT_LROUND:
+  case ISD::STRICT_LRINT:
+  case ISD::LROUND:
+  case ISD::LRINT:
   case ISD::STRICT_LLROUND:
   case ISD::STRICT_LLRINT:
   case ISD::LLROUND:
-  case ISD::LLRINT:      ExpandIntRes_LLROUND_LLRINT(N, Lo, Hi); break;
+  case ISD::LLRINT:      ExpandIntRes_XROUND_XRINT(N, Lo, Hi); break;
   case ISD::LOAD:        ExpandIntRes_LOAD(cast<LoadSDNode>(N), Lo, Hi); break;
   case ISD::MUL:         ExpandIntRes_MUL(N, Lo, Hi); break;
   case ISD::READCYCLECOUNTER: ExpandIntRes_READCYCLECOUNTER(N, Lo, Hi); break;
@@ -3474,8 +3478,8 @@ void DAGTypeLegalizer::ExpandIntRes_FP_TO_XINT_SAT(SDNode *N, SDValue &Lo,
   SplitInteger(Res, Lo, Hi);
 }
 
-void DAGTypeLegalizer::ExpandIntRes_LLROUND_LLRINT(SDNode *N, SDValue &Lo,
-                                                   SDValue &Hi) {
+void DAGTypeLegalizer::ExpandIntRes_XROUND_XRINT(SDNode *N, SDValue &Lo,
+                                                 SDValue &Hi) {
   SDLoc dl(N);
   bool IsStrict = N->isStrictFPOpcode();
   SDValue Op = N->getOperand(IsStrict ? 1 : 0);
@@ -3498,7 +3502,33 @@ void DAGTypeLegalizer::ExpandIntRes_LLROUND_LLRINT(SDNode *N, SDValue &Lo,
   }
 
   RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL;
-  if (N->getOpcode() == ISD::LLROUND ||
+  if (N->getOpcode() == ISD::LROUND ||
+      N->getOpcode() == ISD::STRICT_LROUND) {
+    if (VT == MVT::f32)
+      LC = RTLIB::LROUND_F32;
+    else if (VT == MVT::f64)
+      LC = RTLIB::LROUND_F64;
+    else if (VT == MVT::f80)
+      LC = RTLIB::LROUND_F80;
+    else if (VT == MVT::f128)
+      LC = RTLIB::LROUND_F128;
+    else if (VT == MVT::ppcf128)
+      LC = RTLIB::LROUND_PPCF128;
+    assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected lround input type!");
+  } else if (N->getOpcode() == ISD::LRINT ||
+             N->getOpcode() == ISD::STRICT_LRINT) {
+    if (VT == MVT::f32)
+      LC = RTLIB::LRINT_F32;
+    else if (VT == MVT::f64)
+      LC = RTLIB::LRINT_F64;
+    else if (VT == MVT::f80)
+      LC = RTLIB::LRINT_F80;
+    else if (VT == MVT::f128)
+      LC = RTLIB::LRINT_F128;
+    else if (VT == MVT::ppcf128)
+      LC = RTLIB::LRINT_PPCF128;
+    assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected lrint input type!");
+  } else if (N->getOpcode() == ISD::LLROUND ||
       N->getOpcode() == ISD::STRICT_LLROUND) {
     if (VT == MVT::f32)
       LC = RTLIB::LLROUND_F32;
index e57a030..4dea7d6 100644 (file)
@@ -441,7 +441,7 @@ private:
   void ExpandIntRes_FP_TO_SINT        (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandIntRes_FP_TO_UINT        (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandIntRes_FP_TO_XINT_SAT    (SDNode *N, SDValue &Lo, SDValue &Hi);
-  void ExpandIntRes_LLROUND_LLRINT    (SDNode *N, SDValue &Lo, SDValue &Hi);
+  void ExpandIntRes_XROUND_XRINT      (SDNode *N, SDValue &Lo, SDValue &Hi);
 
   void ExpandIntRes_Logical           (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandIntRes_ADDSUB            (SDNode *N, SDValue &Lo, SDValue &Hi);
diff --git a/llvm/test/CodeGen/AVR/llrint.ll b/llvm/test/CodeGen/AVR/llrint.ll
new file mode 100644 (file)
index 0000000..32b4c7a
--- /dev/null
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=avr -mcpu=atmega328p | FileCheck %s
+
+define i64 @testmsxs_builtin(float %x) {
+; CHECK-LABEL: testmsxs_builtin:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llrintf
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llrint.f32(float %x)
+  ret i64 %0
+}
+
+define i64 @testmsxd_builtin(double %x) {
+; CHECK-LABEL: testmsxd_builtin:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llrint
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llrint.f64(double %x)
+  ret i64 %0
+}
+
+declare i64 @llvm.llrint.f32(float) nounwind readnone
+declare i64 @llvm.llrint.f64(double) nounwind readnone
diff --git a/llvm/test/CodeGen/AVR/llround-conv.ll b/llvm/test/CodeGen/AVR/llround-conv.ll
new file mode 100644 (file)
index 0000000..3e81d08
--- /dev/null
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=avr -mcpu=atmega328p | FileCheck %s
+
+define signext i32 @testmsws(float %x) {
+; CHECK-LABEL: testmsws:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llroundf
+; CHECK-NEXT:    movw r22, r18
+; CHECK-NEXT:    movw r24, r20
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llround.i64.f32(float %x)
+  %conv = trunc i64 %0 to i32
+  ret i32 %conv
+}
+
+define i64 @testmsxs(float %x) {
+; CHECK-LABEL: testmsxs:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llroundf
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llround.i64.f32(float %x)
+  ret i64 %0
+}
+
+define signext i32 @testmswd(double %x) {
+; CHECK-LABEL: testmswd:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llround
+; CHECK-NEXT:    movw r22, r18
+; CHECK-NEXT:    movw r24, r20
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llround.i64.f64(double %x)
+  %conv = trunc i64 %0 to i32
+  ret i32 %conv
+}
+
+define i64 @testmsxd(double %x) {
+; CHECK-LABEL: testmsxd:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call llround
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i64 @llvm.llround.i64.f64(double %x)
+  ret i64 %0
+}
+
+declare i64 @llvm.llround.i64.f32(float) nounwind readnone
+declare i64 @llvm.llround.i64.f64(double) nounwind readnone
diff --git a/llvm/test/CodeGen/AVR/lrint.ll b/llvm/test/CodeGen/AVR/lrint.ll
new file mode 100644 (file)
index 0000000..d756830
--- /dev/null
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=avr -mcpu=atmega328p | FileCheck %s
+
+define i32 @testmsws_builtin(float %x) {
+; CHECK-LABEL: testmsws_builtin:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lrintf
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lrint.i32.f32(float %x)
+  ret i32 %0
+}
+
+define i32 @testmswd_builtin(double %x) {
+; CHECK-LABEL: testmswd_builtin:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lrint
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lrint.i32.f64(double %x)
+  ret i32 %0
+}
+
+declare i32 @llvm.lrint.i32.f32(float) nounwind readnone
+declare i32 @llvm.lrint.i32.f64(double) nounwind readnone
diff --git a/llvm/test/CodeGen/AVR/lround-conv.ll b/llvm/test/CodeGen/AVR/lround-conv.ll
new file mode 100644 (file)
index 0000000..aaf7af8
--- /dev/null
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=avr -mcpu=atmega328p | FileCheck %s
+
+define signext i16 @testmsws(float %x) {
+; CHECK-LABEL: testmsws:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lroundf
+; CHECK-NEXT:    movw r24, r22
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lround.i32.f32(float %x)
+  %conv = trunc i32 %0 to i16
+  ret i16 %conv
+}
+
+define i32 @testmsxs(float %x) {
+; CHECK-LABEL: testmsxs:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lroundf
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lround.i32.f32(float %x)
+  ret i32 %0
+}
+
+define signext i16 @testmswd(double %x) {
+; CHECK-LABEL: testmswd:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lround
+; CHECK-NEXT:    movw r24, r22
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lround.i32.f64(double %x)
+  %conv = trunc i32 %0 to i16
+  ret i16 %conv
+}
+
+define i32 @testmsxd(double %x) {
+; CHECK-LABEL: testmsxd:
+; CHECK:       ; %bb.0: ; %entry
+; CHECK-NEXT:    call lround
+; CHECK-NEXT:    ret
+entry:
+  %0 = tail call i32 @llvm.lround.i32.f64(double %x)
+  ret i32 %0
+}
+
+declare i32 @llvm.lround.i32.f32(float) nounwind readnone
+declare i32 @llvm.lround.i32.f64(double) nounwind readnone