Skip to content

Commit d96f1b7

Browse files
committed
llvm.lround: Update verifier to validate support of vector types.
(cherry picked from commit 12ed1a4)
1 parent 4502ea8 commit d96f1b7

File tree

5 files changed

+109
-11
lines changed

5 files changed

+109
-11
lines changed

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,20 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
20042004
}
20052005
case TargetOpcode::G_LLROUND:
20062006
case TargetOpcode::G_LROUND: {
2007-
verifyAllRegOpsScalar(*MI, *MRI);
2007+
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
2008+
LLT SrcTy = MRI->getType(MI->getOperand(1).getReg());
2009+
if (!DstTy.isValid() || !SrcTy.isValid())
2010+
break;
2011+
if (SrcTy.isPointer() || DstTy.isPointer()) {
2012+
std::string Op = SrcTy.isPointer() ? "Source" : "Destination";
2013+
report(Twine(Op, " operand must not be a pointer type"), MI);
2014+
} else if (SrcTy.isScalar()) {
2015+
verifyAllRegOpsScalar(*MI, *MRI);
2016+
break;
2017+
} else if (SrcTy.isVector()) {
2018+
verifyVectorElementMatch(SrcTy, DstTy, MI);
2019+
break;
2020+
}
20082021
break;
20092022
}
20102023
case TargetOpcode::G_IS_FPCLASS: {

llvm/lib/IR/Verifier.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5963,8 +5963,21 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
59635963
case Intrinsic::llround: {
59645964
Type *ValTy = Call.getArgOperand(0)->getType();
59655965
Type *ResultTy = Call.getType();
5966-
Check(!ValTy->isVectorTy() && !ResultTy->isVectorTy(),
5967-
"Intrinsic does not support vectors", &Call);
5966+
Check(
5967+
ValTy->isFPOrFPVectorTy() && ResultTy->isIntOrIntVectorTy(),
5968+
"llvm.lround, llvm.llround: argument must be floating-point or vector "
5969+
"of floating-points, and result must be integer or vector of integers",
5970+
&Call);
5971+
Check(
5972+
ValTy->isVectorTy() == ResultTy->isVectorTy(),
5973+
"llvm.lround, llvm.llround: argument and result disagree on vector use",
5974+
&Call);
5975+
if (ValTy->isVectorTy()) {
5976+
Check(cast<VectorType>(ValTy)->getElementCount() ==
5977+
cast<VectorType>(ResultTy)->getElementCount(),
5978+
"llvm.lround, llvm.llround: argument must be same length as result",
5979+
&Call);
5980+
}
59685981
break;
59695982
}
59705983
case Intrinsic::bswap: {

llvm/test/MachineVerifier/test_g_llround.mir

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ body: |
1414
%ptr:_(p0) = COPY $x0
1515
%vector:_(<2 x s64>) = COPY $q0
1616
17-
; CHECK: Bad machine code: All register operands must have scalar types
18-
; CHECK: instruction: %no_ptrs:_(s64) = G_LROUND %ptr:_(p0)
19-
%no_ptrs:_(s64) = G_LROUND %ptr:_(p0)
17+
; CHECK: Bad machine code: Source operand must not be a pointer type
18+
; CHECK: instruction: %no_ptrs:_(s32) = G_LLROUND %ptr:_(p0)
19+
%no_ptrs:_(s32) = G_LLROUND %ptr:_(p0)
2020
21-
; CHECK: Bad machine code: All register operands must have scalar types
22-
; CHECK: instruction: %no_vectors:_(s64) = G_LROUND %vector:_(<2 x s64>)
23-
%no_vectors:_(s64) = G_LROUND %vector:_(<2 x s64>)
21+
; CHECK: Bad machine code: operand types must be all-vector or all-scalar
22+
; CHECK: instruction: %no_vectors:_(s32) = G_LLROUND %vector:_(<2 x s64>)
23+
%no_vectors:_(s32) = G_LLROUND %vector:_(<2 x s64>)
24+
25+
; CHECK: Bad machine code: operand types must preserve number of vector elements
26+
; CHECK: instruction: %inv_vectors:_(<3 x s32>) = G_LLROUND %vector:_(<2 x s64>)
27+
%inv_vectors:_(<3 x s32>) = G_LLROUND %vector:_(<2 x s64>)

llvm/test/MachineVerifier/test_g_lround.mir

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ body: |
1414
%ptr:_(p0) = COPY $x0
1515
%vector:_(<2 x s64>) = COPY $q0
1616
17-
; CHECK: Bad machine code: All register operands must have scalar types
17+
; CHECK: Bad machine code: Source operand must not be a pointer type
1818
; CHECK: instruction: %no_ptrs:_(s32) = G_LROUND %ptr:_(p0)
1919
%no_ptrs:_(s32) = G_LROUND %ptr:_(p0)
2020
21-
; CHECK: Bad machine code: All register operands must have scalar types
21+
; CHECK: Bad machine code: operand types must be all-vector or all-scalar
2222
; CHECK: instruction: %no_vectors:_(s32) = G_LROUND %vector:_(<2 x s64>)
2323
%no_vectors:_(s32) = G_LROUND %vector:_(<2 x s64>)
24+
25+
; CHECK: Bad machine code: operand types must preserve number of vector elements
26+
; CHECK: instruction: %inv_vectors:_(<3 x s32>) = G_LROUND %vector:_(<2 x s64>)
27+
%inv_vectors:_(<3 x s32>) = G_LROUND %vector:_(<2 x s64>)

llvm/unittests/IR/IntrinsicsTest.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/IR/IRBuilder.h"
1313
#include "llvm/IR/IntrinsicInst.h"
1414
#include "llvm/IR/Module.h"
15+
#include "llvm/IR/Verifier.h"
1516
#include "gtest/gtest.h"
1617

1718
using namespace llvm;
@@ -106,4 +107,67 @@ TEST_F(IntrinsicsTest, InstrProfInheritance) {
106107
EXPECT_TRUE(Checker(*Intr));
107108
}
108109
}
110+
111+
TEST(IntrinsicVerifierTest, LRound) {
112+
LLVMContext C;
113+
std::unique_ptr<Module> M = std::make_unique<Module>("M", C);
114+
IRBuilder<> Builder(C);
115+
116+
using TypePair = std::pair<Type *, Type *>;
117+
Type *Int32Ty = Type::getInt32Ty(C);
118+
Type *Int64Ty = Type::getInt64Ty(C);
119+
Type *HalfTy = Type::getHalfTy(C);
120+
Type *FltTy = Type::getFloatTy(C);
121+
Type *DblTy = Type::getDoubleTy(C);
122+
auto Vec2xTy = [&](Type *ElemTy) {
123+
return VectorType::get(ElemTy, ElementCount::getFixed(2));
124+
};
125+
Type *Vec2xInt32Ty = Vec2xTy(Int32Ty);
126+
Type *Vec2xInt64Ty = Vec2xTy(Int64Ty);
127+
Type *Vec2xFltTy = Vec2xTy(FltTy);
128+
129+
// Test Cases
130+
// Validating only a limited set of possible combinations.
131+
std::vector<TypePair> ValidTypes = {
132+
{Int32Ty, FltTy}, {Int32Ty, DblTy}, {Int64Ty, FltTy},
133+
{Int64Ty, DblTy}, {Int32Ty, HalfTy}, {Vec2xInt32Ty, Vec2xFltTy},
134+
{Vec2xInt64Ty, Vec2xFltTy}};
135+
136+
// CreateIntrinsic errors out on invalid argument types.
137+
std::vector<TypePair> InvalidTypes = {
138+
{VectorType::get(Int32Ty, ElementCount::getFixed(3)), Vec2xFltTy}};
139+
140+
auto testIntrinsic = [&](TypePair types, Intrinsic::ID ID, bool expectValid) {
141+
Function *F =
142+
Function::Create(FunctionType::get(types.first, {types.second}, false),
143+
Function::ExternalLinkage, "lround_fn", M.get());
144+
BasicBlock *BB = BasicBlock::Create(C, "entry", F);
145+
Builder.SetInsertPoint(BB);
146+
147+
Value *Arg = F->arg_begin();
148+
Value *Result = Builder.CreateIntrinsic(types.first, ID, {Arg});
149+
Builder.CreateRet(Result);
150+
151+
std::string Error;
152+
raw_string_ostream ErrorOS(Error);
153+
EXPECT_EQ(expectValid, !verifyFunction(*F, &ErrorOS));
154+
if (!expectValid) {
155+
EXPECT_TRUE(StringRef(ErrorOS.str())
156+
.contains("llvm.lround, llvm.llround: argument must be "
157+
"same length as result"));
158+
}
159+
};
160+
161+
// Run Valid Cases.
162+
for (auto Types : ValidTypes) {
163+
testIntrinsic(Types, Intrinsic::lround, true);
164+
testIntrinsic(Types, Intrinsic::llround, true);
165+
}
166+
167+
// Run Invalid Cases.
168+
for (auto Types : InvalidTypes) {
169+
testIntrinsic(Types, Intrinsic::lround, false);
170+
testIntrinsic(Types, Intrinsic::llround, false);
171+
}
172+
}
109173
} // end namespace

0 commit comments

Comments
 (0)