[llvm] llvm.lround : Update verifier to support vector types. (PR #98932)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 15 09:56:57 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Sumanth Gundapaneni (sgundapa)

<details>
<summary>Changes</summary>

Both IRVerifier and Machine Verifier are updated.

---
Full diff: https://github.com/llvm/llvm-project/pull/98932.diff


4 Files Affected:

- (modified) llvm/lib/CodeGen/MachineVerifier.cpp (+11-1) 
- (modified) llvm/lib/IR/Verifier.cpp (+15-2) 
- (modified) llvm/test/MachineVerifier/test_g_lround.mir (+19-12) 
- (modified) llvm/unittests/IR/IntrinsicsTest.cpp (+64) 


``````````diff
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index d0d3af0e5e4fc..f71733f03fe7c 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2004,7 +2004,17 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
   }
   case TargetOpcode::G_LLROUND:
   case TargetOpcode::G_LROUND: {
-    verifyAllRegOpsScalar(*MI, *MRI);
+    LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
+    LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
+    if (!DstTy.isValid() || !SrcTy.isValid())
+      break;
+    if (SrcTy.isScalar()) {
+      verifyAllRegOpsScalar(*MI, *MRI);
+      break;
+    } else if (SrcTy.isVector()) {
+      verifyVectorElementMatch(SrcTy, DstTy, MI);
+      break;
+    }
     break;
   }
   case TargetOpcode::G_IS_FPCLASS: {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 75a53c1c99734..76fe759fc1f63 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5963,8 +5963,21 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
   case Intrinsic::llround: {
     Type *ValTy = Call.getArgOperand(0)->getType();
     Type *ResultTy = Call.getType();
-    Check(!ValTy->isVectorTy() && !ResultTy->isVectorTy(),
-          "Intrinsic does not support vectors", &Call);
+    Check(
+        ValTy->isFPOrFPVectorTy() && ResultTy->isIntOrIntVectorTy(),
+        "llvm.lround, llvm.llround: argument must be floating-point or vector "
+        "of floating-points, and result must be integer or vector of integers",
+        &Call);
+    Check(
+        ValTy->isVectorTy() == ResultTy->isVectorTy(),
+        "llvm.lround, llvm.llround: argument and result disagree on vector use",
+        &Call);
+    if (ValTy->isVectorTy()) {
+      Check(cast<VectorType>(ValTy)->getElementCount() ==
+                cast<VectorType>(ResultTy)->getElementCount(),
+            "llvm.lround, llvm.llround: argument must be same length as result",
+            &Call);
+    }
     break;
   }
   case Intrinsic::bswap: {
diff --git a/llvm/test/MachineVerifier/test_g_lround.mir b/llvm/test/MachineVerifier/test_g_lround.mir
index 69d5d4967de30..85ac422360a44 100644
--- a/llvm/test/MachineVerifier/test_g_lround.mir
+++ b/llvm/test/MachineVerifier/test_g_lround.mir
@@ -1,23 +1,30 @@
-#RUN: not --crash llc -mtriple=aarch64 -o - -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s
-# REQUIRES: aarch64-registered-target
+# RUN: not --crash llc -o - %s -mtriple=x86_64-- -verify-machineinstrs -run-pass=none 2>&1 | FileCheck %s
+# REQUIRES: x86-registered-target
 
 ---
-name:            test_lround
+name:            g_lround
 legalized:       true
 regBankSelected: false
 selected:        false
 tracksRegLiveness: true
+registers:
+  - { id: 0, class: _, preferred-register: '' }
 liveins:
 body:             |
   bb.0:
-    liveins: $x0, $q0
-    %ptr:_(p0) = COPY $x0
-    %vector:_(<2 x s64>) = COPY $q0
 
-    ; CHECK: Bad machine code: All register operands must have scalar types
-    ; CHECK: instruction: %no_ptrs:_(s32) = G_LROUND %ptr:_(p0)
-    %no_ptrs:_(s32) = G_LROUND %ptr:_(p0)
+    %0:_(<2 x s32>) = IMPLICIT_DEF
+    ; CHECK: Bad machine code: operand types must be all-vector or all-scalar
+    %1:_(s32) = G_LROUND %0:_(<2 x s32>)
+    ; CHECK: Bad machine code: operand types must preserve number of vector elements
+    %2:_(<3 x s32>) = G_LROUND %0:_(<2 x s32>)
+    %3:_(<2 x s32>) = G_LROUND %0:_(<2 x s32>)
 
-    ; CHECK: Bad machine code: All register operands must have scalar types
-    ; CHECK: instruction: %no_vectors:_(s32) = G_LROUND %vector:_(<2 x s64>)
-    %no_vectors:_(s32) = G_LROUND %vector:_(<2 x s64>)
+  bb.1:
+
+    ; CHECK: Bad machine code: operand types must be all-vector or all-scalar
+    %4:_(s32) = G_LLROUND %0:_(<2 x s32>)
+    ; CHECK: Bad machine code: operand types must preserve number of vector elements
+    %5:_(<3 x s32>) = G_LLROUND %0:_(<2 x s32>)
+    %6:_(<2 x s32>) = G_LLROUND %0:_(<2 x s32>)
+...
diff --git a/llvm/unittests/IR/IntrinsicsTest.cpp b/llvm/unittests/IR/IntrinsicsTest.cpp
index 6f9e724c40326..14badaa0de980 100644
--- a/llvm/unittests/IR/IntrinsicsTest.cpp
+++ b/llvm/unittests/IR/IntrinsicsTest.cpp
@@ -12,6 +12,7 @@
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -106,4 +107,67 @@ TEST_F(IntrinsicsTest, InstrProfInheritance) {
     EXPECT_TRUE(Checker(*Intr));
   }
 }
+
+TEST(IntrinsicVerifierTest, LRound) {
+  LLVMContext C;
+  std::unique_ptr<Module> M = std::make_unique<Module>("M", C);
+  IRBuilder<> Builder(C);
+
+  using TypePair = std::pair<Type *, Type *>;
+  Type *Int32Ty = Type::getInt32Ty(C);
+  Type *Int64Ty = Type::getInt64Ty(C);
+  Type *HalfTy = Type::getHalfTy(C);
+  Type *FltTy = Type::getFloatTy(C);
+  Type *DblTy = Type::getDoubleTy(C);
+  auto Vec2xTy = [&](Type *ElemTy) {
+    return VectorType::get(ElemTy, ElementCount::getFixed(2));
+  };
+  Type *Vec2xInt32Ty = Vec2xTy(Int32Ty);
+  Type *Vec2xInt64Ty = Vec2xTy(Int64Ty);
+  Type *Vec2xFltTy = Vec2xTy(FltTy);
+
+  // Test Cases
+  // Validating only a limited set of possible combinations.
+  std::vector<TypePair> ValidTypes = {
+      {Int32Ty, FltTy},          {Int32Ty, DblTy},  {Int64Ty, FltTy},
+      {Int64Ty, DblTy},          {Int32Ty, HalfTy}, {Vec2xInt32Ty, Vec2xFltTy},
+      {Vec2xInt64Ty, Vec2xFltTy}};
+
+  // CreateIntrinsic errors out on invalid argument types.
+  std::vector<TypePair> InvalidTypes = {
+      {VectorType::get(Int32Ty, ElementCount::getFixed(3)), Vec2xFltTy}};
+
+  auto testIntrinsic = [&](TypePair types, Intrinsic::ID ID, bool expectValid) {
+    Function *F =
+        Function::Create(FunctionType::get(types.first, {types.second}, false),
+                         Function::ExternalLinkage, "lround_fn", M.get());
+    BasicBlock *BB = BasicBlock::Create(C, "entry", F);
+    Builder.SetInsertPoint(BB);
+
+    Value *Arg = F->arg_begin();
+    Value *Result = Builder.CreateIntrinsic(types.first, ID, {Arg});
+    Builder.CreateRet(Result);
+
+    std::string Error;
+    raw_string_ostream ErrorOS(Error);
+    EXPECT_EQ(expectValid, !verifyFunction(*F, &ErrorOS));
+    if (!expectValid) {
+      EXPECT_TRUE(StringRef(ErrorOS.str())
+                      .contains("llvm.lround, llvm.llround: argument must be "
+                                "same length as result"));
+    }
+  };
+
+  // Run Valid Cases.
+  for (auto Types : ValidTypes) {
+    testIntrinsic(Types, Intrinsic::lround, true);
+    testIntrinsic(Types, Intrinsic::llround, true);
+  }
+
+  // Run Invalid Cases.
+  for (auto Types : InvalidTypes) {
+    testIntrinsic(Types, Intrinsic::lround, false);
+    testIntrinsic(Types, Intrinsic::llround, false);
+  }
+}
 } // end namespace

``````````

</details>


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


More information about the llvm-commits mailing list