[llvm] LoopIdiom/test: add negative tests for fpowi (PR #68985)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 13 05:55:57 PDT 2023


https://github.com/artagnon created https://github.com/llvm/llvm-project/pull/68985

Compiling the following program under -ffast-math results in very poor codegen due to LoopVectorize:

```c
  float fpowi(float base, int exp) {
    float result = 1.0;
    while (exp != 0) {
      result *= base;
      --exp;
    }
    return result;
  }
```

In preparation to get LoopIdiomRecognize to convert this idiom to a llvm.powi, add negative tests corresponding to variations of this program.

>From 573a6e2cd4689057cf4075d97e4ae5bd364380d1 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <Ramkumar.Ramachandra at imgtec.com>
Date: Fri, 13 Oct 2023 13:43:30 +0100
Subject: [PATCH] LoopIdiom/test: add negative tests for fpowi

Compiling the following program under -ffast-math results in very poor
codegen due to LoopVectorize:

  float fpowi(float base, int exp) {
    float result = 1.0;
    while (exp != 0) {
      result *= base;
      --exp;
    }
    return result;
  }

In preparation to get LoopIdiomRecognize to convert this idiom to a
llvm.powi, add negative tests corresponding to variations of this
program.
---
 llvm/test/Transforms/LoopIdiom/fpowi.ll | 122 ++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
 create mode 100644 llvm/test/Transforms/LoopIdiom/fpowi.ll

diff --git a/llvm/test/Transforms/LoopIdiom/fpowi.ll b/llvm/test/Transforms/LoopIdiom/fpowi.ll
new file mode 100644
index 000000000000000..640921cb8c367f3
--- /dev/null
+++ b/llvm/test/Transforms/LoopIdiom/fpowi.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=loop-idiom < %s -S | FileCheck %s
+
+; TODO: Currently, LIR doesn't recognize the fpowi idiom, but it could in the
+; future, generating llvm.powi intrinsics for the positive tests.
+
+define float @fpowi_f32(float %base, i32 %exp) {
+; CHECK-LABEL: @fpowi_f32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i32 [[EXP:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[WHILE_END:%.*]], label [[WHILE_BODY_PREHEADER:%.*]]
+; CHECK:       while.body.preheader:
+; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[RESULT:%.*]] = phi float [ [[MUL:%.*]], [[WHILE_BODY]] ], [ 1.000000e+00, [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MERGE_DEC:%.*]] = phi i32 [ [[DEC:%.*]], [[WHILE_BODY]] ], [ [[EXP]], [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MUL]] = fmul fast float [[RESULT]], [[BASE:%.*]]
+; CHECK-NEXT:    [[DEC]] = add nsw i32 [[MERGE_DEC]], -1
+; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp eq i32 [[DEC]], 0
+; CHECK-NEXT:    br i1 [[CMP_EQ]], label [[WHILE_END_LOOPEXIT:%.*]], label [[WHILE_BODY]]
+; CHECK:       while.end.loopexit:
+; CHECK-NEXT:    [[MUL_LCSSA:%.*]] = phi float [ [[MUL]], [[WHILE_BODY]] ]
+; CHECK-NEXT:    br label [[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    [[RESULT_LCSSA:%.*]] = phi float [ 1.000000e+00, [[ENTRY:%.*]] ], [ [[MUL_LCSSA]], [[WHILE_END_LOOPEXIT]] ]
+; CHECK-NEXT:    ret float [[RESULT_LCSSA]]
+;
+entry:
+  %cmp.not = icmp eq i32 %exp, 0
+  br i1 %cmp.not, label %while.end, label %while.body
+
+while.body:                                       ; preds = %entry, %while.body
+  %result = phi float [ %mul, %while.body ], [ 1.000000e+00, %entry ]
+  %merge.dec = phi i32 [ %dec, %while.body ], [ %exp, %entry ]
+  %mul = fmul fast float %result, %base
+  %dec = add nsw i32 %merge.dec, -1
+  %cmp.eq = icmp eq i32 %dec, 0
+  br i1 %cmp.eq, label %while.end, label %while.body
+
+while.end:                                        ; preds = %while.body, %entry
+  %result.lcssa = phi float [ 1.000000e+00, %entry ], [ %mul, %while.body ]
+  ret float %result.lcssa
+}
+
+define double @fpowi_f64(double %base, i32 %exp) {
+; CHECK-LABEL: @fpowi_f64(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i32 [[EXP:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[WHILE_END:%.*]], label [[WHILE_BODY_PREHEADER:%.*]]
+; CHECK:       while.body.preheader:
+; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[RESULT:%.*]] = phi double [ [[MUL:%.*]], [[WHILE_BODY]] ], [ 1.000000e+00, [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MERGE_DEC:%.*]] = phi i32 [ [[DEC:%.*]], [[WHILE_BODY]] ], [ [[EXP]], [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MUL]] = fmul fast double [[RESULT]], [[BASE:%.*]]
+; CHECK-NEXT:    [[DEC]] = add nsw i32 [[MERGE_DEC]], -1
+; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp eq i32 [[DEC]], 0
+; CHECK-NEXT:    br i1 [[CMP_EQ]], label [[WHILE_END_LOOPEXIT:%.*]], label [[WHILE_BODY]]
+; CHECK:       while.end.loopexit:
+; CHECK-NEXT:    [[MUL_LCSSA:%.*]] = phi double [ [[MUL]], [[WHILE_BODY]] ]
+; CHECK-NEXT:    br label [[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    [[RESULT_LCSSA:%.*]] = phi double [ 1.000000e+00, [[ENTRY:%.*]] ], [ [[MUL_LCSSA]], [[WHILE_END_LOOPEXIT]] ]
+; CHECK-NEXT:    ret double [[RESULT_LCSSA]]
+;
+entry:
+  %cmp.not = icmp eq i32 %exp, 0
+  br i1 %cmp.not, label %while.end, label %while.body
+
+while.body:                                       ; preds = %entry, %while.body
+  %result = phi double [ %mul, %while.body ], [ 1.000000e+00, %entry ]
+  %merge.dec = phi i32 [ %dec, %while.body ], [ %exp, %entry ]
+  %mul = fmul fast double %result, %base
+  %dec = add nsw i32 %merge.dec, -1
+  %cmp.eq = icmp eq i32 %dec, 0
+  br i1 %cmp.eq, label %while.end, label %while.body
+
+while.end:                                        ; preds = %while.body, %entry
+  %result.lcssa = phi double [ 1.000000e+00, %entry ], [ %mul, %while.body ]
+  ret double %result.lcssa
+}
+
+; Negative tests
+
+; The loop idiom is only legal in -ffast-math mode
+define float @fpowi_nofast(float %base, i32 %exp) {
+; CHECK-LABEL: @fpowi_nofast(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp eq i32 [[EXP:%.*]], 0
+; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[WHILE_END:%.*]], label [[WHILE_BODY_PREHEADER:%.*]]
+; CHECK:       while.body.preheader:
+; CHECK-NEXT:    br label [[WHILE_BODY:%.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[RESULT:%.*]] = phi float [ [[MUL:%.*]], [[WHILE_BODY]] ], [ 1.000000e+00, [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MERGE_DEC:%.*]] = phi i32 [ [[DEC:%.*]], [[WHILE_BODY]] ], [ [[EXP]], [[WHILE_BODY_PREHEADER]] ]
+; CHECK-NEXT:    [[MUL]] = fmul float [[RESULT]], [[BASE:%.*]]
+; CHECK-NEXT:    [[DEC]] = add nsw i32 [[MERGE_DEC]], -1
+; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp eq i32 [[DEC]], 0
+; CHECK-NEXT:    br i1 [[CMP_EQ]], label [[WHILE_END_LOOPEXIT:%.*]], label [[WHILE_BODY]]
+; CHECK:       while.end.loopexit:
+; CHECK-NEXT:    [[MUL_LCSSA:%.*]] = phi float [ [[MUL]], [[WHILE_BODY]] ]
+; CHECK-NEXT:    br label [[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    [[RESULT_LCSSA:%.*]] = phi float [ 1.000000e+00, [[ENTRY:%.*]] ], [ [[MUL_LCSSA]], [[WHILE_END_LOOPEXIT]] ]
+; CHECK-NEXT:    ret float [[RESULT_LCSSA]]
+;
+entry:
+  %cmp.not = icmp eq i32 %exp, 0
+  br i1 %cmp.not, label %while.end, label %while.body
+
+while.body:                                       ; preds = %entry, %while.body
+  %result = phi float [ %mul, %while.body ], [ 1.000000e+00, %entry ]
+  %merge.dec = phi i32 [ %dec, %while.body ], [ %exp, %entry ]
+  %mul = fmul float %result, %base
+  %dec = add nsw i32 %merge.dec, -1
+  %cmp.eq = icmp eq i32 %dec, 0
+  br i1 %cmp.eq, label %while.end, label %while.body
+
+while.end:                                        ; preds = %while.body, %entry
+  %result.lcssa = phi float [ 1.000000e+00, %entry ], [ %mul, %while.body ]
+  ret float %result.lcssa
+}



More information about the llvm-commits mailing list