Skip to content

Commit 21aab62

Browse files
committed
[CIR] Implement __builtin_ia32_cmpnleps/cmpnlepd
- Add `isOrdered` UnitAttr to CIR_VecCmpOp for controlling FP comparison semantics - Add verifier to CIR_VecCmpOp to ensure isOrdered only used with floating-point vector types - Implement createVecCompare, getCIRIntOrFloatBitWidth, getVectorFCmpIR helper. - Update LLVM lowering to emit ordered vs unordered fcmp predicates (olt/ult, etc.) - Add clang/test/CIR/CodeGen/builtin-fcmp-sse.c test. - Update clang/test/CIR/Lowering/vec-cmp.cir to reflect ordered semantics of VecCmpOp
1 parent 16e2250 commit 21aab62

File tree

9 files changed

+128
-18
lines changed

9 files changed

+128
-18
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
8989
return cir::IntType::get(getContext(), N, false);
9090
}
9191

92+
unsigned getCIRIntOrFloatBitWidth(mlir::Type eltTy) const {
93+
if (auto intType = mlir::dyn_cast<cir::IntTypeInterface>(eltTy))
94+
return intType.getWidth();
95+
if (auto floatType = mlir::dyn_cast<cir::FPTypeInterface>(eltTy))
96+
return floatType.getWidth();
97+
98+
llvm_unreachable("Wrong type passed in or Non-CIR type passed in");
99+
}
92100
cir::IntType getSIntNTy(int N) {
93101
return cir::IntType::get(getContext(), N, true);
94102
}
@@ -188,6 +196,18 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
188196
return cir::CmpOp::create(*this, loc, getBoolTy(), kind, lhs, rhs);
189197
}
190198

199+
cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind,
200+
mlir::Value lhs, mlir::Value rhs,
201+
bool isOrdered) {
202+
VectorType vecCast = mlir::cast<VectorType>(lhs.getType());
203+
auto integralTy =
204+
getSIntNTy(getCIRIntOrFloatBitWidth(vecCast.getElementType()));
205+
VectorType integralVecTy =
206+
VectorType::get(context, integralTy, vecCast.getSize());
207+
return cir::VecCmpOp::create(*this, loc, integralVecTy, kind, lhs, rhs,
208+
isOrdered);
209+
}
210+
191211
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
192212
return createCompare(loc, cir::CmpOpKind::ne, operand, operand);
193213
}

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,17 +3533,19 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
35333533
let arguments = (ins
35343534
CIR_CmpOpKind:$kind,
35353535
CIR_VectorType:$lhs,
3536-
CIR_VectorType:$rhs
3536+
CIR_VectorType:$rhs,
3537+
UnitAttr:$isOrdered
35373538
);
35383539

35393540
let results = (outs CIR_VectorType:$result);
35403541

35413542
let assemblyFormat = [{
3542-
`(` $kind `,` $lhs `,` $rhs `)` `:` qualified(type($lhs)) `,`
3543+
`(` $kind `,` $lhs `,` $rhs(`,` `ordered` $isOrdered^)? `)` `:` qualified(type($lhs)) `,`
35433544
qualified(type($result)) attr-dict
35443545
}];
35453546

35463547
let hasFolder = 1;
3548+
let hasVerifier = 1;
35473549
}
35483550

35493551
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned BuiltinID,
183183
Ops.push_back(emitScalarOrConstFoldImmArg(ICEArguments, i, E));
184184
}
185185

186+
// TODO: Add isSignaling boolean once emitConstrainedFPCall implemented
187+
auto getVectorFCmpIR = [this, &Ops, &E](cir::CmpOpKind pred, bool isOrdered) {
188+
assert(!cir::MissingFeatures::CGFPOptionsRAII());
189+
assert(!cir::MissingFeatures::emitConstrainedFPCall());
190+
auto loc = getLoc(E->getExprLoc());
191+
mlir::Value cmp =
192+
builder.createVecCompare(loc, pred, Ops[0], Ops[1], isOrdered);
193+
return cmp;
194+
};
195+
186196
switch (BuiltinID) {
187197
default:
188198
return nullptr;
@@ -1411,7 +1421,7 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned BuiltinID,
14111421
llvm_unreachable("cmpnltps NYI");
14121422
case X86::BI__builtin_ia32_cmpnleps:
14131423
case X86::BI__builtin_ia32_cmpnlepd:
1414-
llvm_unreachable("cmpnleps NYI");
1424+
return getVectorFCmpIR(cir::CmpOpKind::gt, /*isOrdered=*/false);
14151425
case X86::BI__builtin_ia32_cmpordps:
14161426
case X86::BI__builtin_ia32_cmpordpd:
14171427
llvm_unreachable("cmpordps NYI");

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,18 @@ OpFoldResult cir::VecCmpOp::fold(FoldAdaptor adaptor) {
13211321
getType(), mlir::ArrayAttr::get(getContext(), elements));
13221322
}
13231323

1324+
LogicalResult cir::VecCmpOp::verify() {
1325+
// Check that isOrderedAttr attribute is emitted only with floating point
1326+
// types
1327+
if (getIsOrderedAttr()) {
1328+
cir::VectorType vecType = mlir::cast<cir::VectorType>(getLhs().getType());
1329+
if (!mlir::isa<cir::FPTypeInterface>(vecType.getElementType()))
1330+
return emitOpError("only floating point types can elect to be either "
1331+
"ordered or unordered");
1332+
}
1333+
return success();
1334+
}
1335+
13241336
//===----------------------------------------------------------------------===//
13251337
// VecExtractOp
13261338
//===----------------------------------------------------------------------===//

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ mlir::LLVM::ICmpPredicate convertCmpKindToICmpPredicate(cir::CmpOpKind kind,
116116

117117
/// Convert from a CIR comparison kind to an LLVM IR floating-point comparison
118118
/// kind.
119-
mlir::LLVM::FCmpPredicate convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {
119+
mlir::LLVM::FCmpPredicate convertCmpKindToFCmpPredicate(cir::CmpOpKind kind,
120+
bool isOrdered) {
120121
using CIR = cir::CmpOpKind;
121122
using LLVMFCmp = mlir::LLVM::FCmpPredicate;
122123
switch (kind) {
@@ -125,13 +126,13 @@ mlir::LLVM::FCmpPredicate convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {
125126
case CIR::ne:
126127
return LLVMFCmp::une;
127128
case CIR::lt:
128-
return LLVMFCmp::olt;
129+
return isOrdered ? LLVMFCmp::olt : LLVMFCmp::ult;
129130
case CIR::le:
130-
return LLVMFCmp::ole;
131+
return isOrdered ? LLVMFCmp::ole : LLVMFCmp::ule;
131132
case CIR::gt:
132-
return LLVMFCmp::ogt;
133+
return isOrdered ? LLVMFCmp::ogt : LLVMFCmp::ugt;
133134
case CIR::ge:
134-
return LLVMFCmp::oge;
135+
return isOrdered ? LLVMFCmp::oge : LLVMFCmp::uge;
135136
}
136137
llvm_unreachable("Unknown CmpOpKind");
137138
}
@@ -2069,7 +2070,8 @@ mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(
20692070
adaptor.getLhs(), adaptor.getRhs());
20702071
} else if (mlir::isa<cir::FPTypeInterface>(elementType)) {
20712072
bitResult = rewriter.create<mlir::LLVM::FCmpOp>(
2072-
op.getLoc(), convertCmpKindToFCmpPredicate(op.getKind()),
2073+
op.getLoc(),
2074+
convertCmpKindToFCmpPredicate(op.getKind(), op.getIsOrdered()),
20732075
adaptor.getLhs(), adaptor.getRhs());
20742076
} else {
20752077
return op.emitError() << "unsupported type for VecCmpOp: " << elementType;
@@ -3226,7 +3228,8 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
32263228
rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
32273229
cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
32283230
} else if (mlir::isa<cir::FPTypeInterface>(type)) {
3229-
auto kind = convertCmpKindToFCmpPredicate(cmpOp.getKind());
3231+
auto kind =
3232+
convertCmpKindToFCmpPredicate(cmpOp.getKind(), /*isOrdered=*/true);
32303233
rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(
32313234
cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
32323235
} else {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=LLVM
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=OG
4+
5+
typedef float __m128 __attribute__((__vector_size__(16), __aligned__(16)));
6+
7+
8+
__m128 test_cmpnleps(__m128 A, __m128 B) {
9+
10+
// CIR-LABEL: @test_cmpnleps
11+
// CIR: [[CMP:%.*]] = cir.vec.cmp(gt, [[A:%.*]], [[B:%.*]]) : !cir.vector<!cir.float x 4>, !cir.vector<!s32i x 4>
12+
// CIR-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[ALLOCA:%.*]] : !cir.ptr<!cir.vector<!cir.float x 4>>), !cir.ptr<!cir.vector<!s32i x 4>>
13+
// CIR-NEXT: cir.store [[CMP]], [[CAST]] : !cir.vector<!s32i x 4>, !cir.ptr<!cir.vector<!s32i x 4>>
14+
// CIR-NEXT: [[LD:%.*]] = cir.load [[ALLOCA]] :
15+
// CIR-NEXT: cir.return [[LD]] : !cir.vector<!cir.float x 4>
16+
17+
// LLVM-LABEL: test_cmpnleps
18+
// LLVM: [[CMP:%.*]] = fcmp ugt <4 x float> {{.*}}, {{.*}}
19+
// LLVM-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
20+
// LLVM-NEXT: [[CAST:%.*]] = bitcast <4 x i32> [[SEXT]] to <4 x float>
21+
// LLVM-NEXT: ret <4 x float> [[CAST]]
22+
23+
// OG-LABEL: test_cmpnleps
24+
// OG: [[CMP:%.*]] = fcmp ugt <4 x float> {{.*}}, {{.*}}
25+
// OG-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32>
26+
// OG-NEXT: [[CAST:%.*]] = bitcast <4 x i32> [[SEXT]] to <4 x float>
27+
// OG-NEXT: ret <4 x float> [[CAST]]
28+
return __builtin_ia32_cmpnleps(A, B);
29+
}
30+
31+
32+
__m128 test_cmpnlepd(__m128 A, __m128 B) {
33+
34+
// CIR-LABEL: @test_cmpnlepd
35+
// CIR: [[CMP:%.*]] = cir.vec.cmp(gt, [[A:%.*]], [[B:%.*]]) : !cir.vector<!cir.double x 2>, !cir.vector<!s64i x 2>
36+
// CIR-NEXT: [[CAST:%.*]] = cir.cast(bitcast, [[CMP]] : !cir.vector<!s64i x 2>), !cir.vector<!cir.float x 4>
37+
// CIR-NEXT: cir.store [[CAST]], [[ALLOCA:%.*]] : !cir.vector<!cir.float x 4>, !cir.ptr<!cir.vector<!cir.float x 4>>
38+
// CIR-NEXT: [[LD:%.*]] = cir.load [[ALLOCA]] :
39+
// CIR-NEXT: cir.return [[LD]] : !cir.vector<!cir.float x 4>
40+
41+
// LLVM-LABEL: test_cmpnlepd
42+
// LLVM: [[CMP:%.*]] = fcmp ugt <2 x double> {{.*}}, {{.*}}
43+
// LLVM-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64>
44+
// LLVM-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[SEXT]] to <4 x float>
45+
// LLVM-NEXT: ret <4 x float> [[CAST]]
46+
47+
// OG-LABEL: test_cmpnlepd
48+
// OG: [[CMP:%.*]] = fcmp ugt <2 x double> {{.*}}, {{.*}}
49+
// OG-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64>
50+
// OG-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[SEXT]] to <4 x float>
51+
// OG-NEXT: ret <4 x float> [[CAST]]
52+
return __builtin_ia32_cmpnlepd(A, B);
53+
}

clang/test/CIR/CodeGen/vectype-ext.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,19 +318,19 @@ void vector_double_test(int x, double y) {
318318
// LLVM-NEXT: sext <2 x i1> %[[#RES:]] to <2 x i64>
319319
vl2 q = a < b;
320320
// CIR: %{{[0-9]+}} = cir.vec.cmp(lt, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector<!cir.double x 2>, !cir.vector<!s64i x 2>
321-
// LLVM: %[[#RES:]] = fcmp olt <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
321+
// LLVM: %[[#RES:]] = fcmp ult <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
322322
// LLVM-NEXT: sext <2 x i1> %[[#RES:]] to <2 x i64>
323323
vl2 r = a > b;
324324
// CIR: %{{[0-9]+}} = cir.vec.cmp(gt, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector<!cir.double x 2>, !cir.vector<!s64i x 2>
325-
// LLVM: %[[#RES:]] = fcmp ogt <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
325+
// LLVM: %[[#RES:]] = fcmp ugt <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
326326
// LLVM-NEXT: sext <2 x i1> %[[#RES:]] to <2 x i64>
327327
vl2 s = a <= b;
328328
// CIR: %{{[0-9]+}} = cir.vec.cmp(le, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector<!cir.double x 2>, !cir.vector<!s64i x 2>
329-
// LLVM: %[[#RES:]] = fcmp ole <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
329+
// LLVM: %[[#RES:]] = fcmp ule <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
330330
// LLVM-NEXT: sext <2 x i1> %[[#RES:]] to <2 x i64>
331331
vl2 t = a >= b;
332332
// CIR: %{{[0-9]+}} = cir.vec.cmp(ge, %{{[0-9]+}}, %{{[0-9]+}}) : !cir.vector<!cir.double x 2>, !cir.vector<!s64i x 2>
333-
// LLVM: %[[#RES:]] = fcmp oge <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
333+
// LLVM: %[[#RES:]] = fcmp uge <2 x double> %{{[0-9]+}}, %{{[0-9]+}}
334334
// LLVM-NEXT: sext <2 x i1> %[[#RES:]] to <2 x i64>
335335

336336
// __builtin_convertvector

clang/test/CIR/Lowering/vec-cmp.cir

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,13 @@ cir.func @vec_cmp(%0: !cir.vector<!s16i x 16>, %1: !cir.vector<!s16i x 16>) -> (
1414
// MLIR-NEXT: %{{[0-9]+}} = llvm.icmp "slt" %arg0, %arg1 : vector<16xi16>
1515
// MLIR-NEXT: %{{[0-9]+}} = llvm.bitcast %{{[0-9]+}} : vector<16xi1> to i16
1616
// MLIR-NEXT: llvm.return
17+
18+
19+
cir.func @vec_fcmp_ordered(%0: !cir.vector<!cir.float x 4>, %1: !cir.vector<!cir.float x 4>) -> () {
20+
%2 = cir.vec.cmp(lt, %0, %1, ordered) : !cir.vector<!cir.float x 4>, !cir.vector<!cir.int<u, 1> x 4>
21+
cir.return
22+
}
23+
24+
// MLIR: llvm.func @vec_fcmp_ordered
25+
// MLIR-NEXT: %{{[0-9]+}} = llvm.fcmp "olt" %arg0, %arg1 : vector<4xf32>
26+
// MLIR-NEXT: llvm.return

clang/test/CIR/Lowering/vectype.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,25 +321,25 @@ void vector_double_test(int x, double y) {
321321
vll2 q = a < b;
322322
// CHECK: %[[#T68:]] = llvm.load %[[#T5]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
323323
// CHECK: %[[#T69:]] = llvm.load %[[#T7]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
324-
// CHECK: %[[#T70:]] = llvm.fcmp "olt" %[[#T68]], %[[#T69]] : vector<2xf64>
324+
// CHECK: %[[#T70:]] = llvm.fcmp "ult" %[[#T68]], %[[#T69]] : vector<2xf64>
325325
// CHECK: %[[#T71:]] = llvm.sext %[[#T70]] : vector<2xi1> to vector<2xi64>
326326
// CHECK: llvm.store %[[#T71]], %[[#Tq:]] {alignment = 16 : i64} : vector<2xi64>, !llvm.ptr
327327
vll2 r = a > b;
328328
// CHECK: %[[#T72:]] = llvm.load %[[#T5]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
329329
// CHECK: %[[#T73:]] = llvm.load %[[#T7]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
330-
// CHECK: %[[#T74:]] = llvm.fcmp "ogt" %[[#T72]], %[[#T73]] : vector<2xf64>
330+
// CHECK: %[[#T74:]] = llvm.fcmp "ugt" %[[#T72]], %[[#T73]] : vector<2xf64>
331331
// CHECK: %[[#T75:]] = llvm.sext %[[#T74]] : vector<2xi1> to vector<2xi64>
332332
// CHECK: llvm.store %[[#T75]], %[[#Tr:]] {alignment = 16 : i64} : vector<2xi64>, !llvm.ptr
333333
vll2 s = a <= b;
334334
// CHECK: %[[#T76:]] = llvm.load %[[#T5]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
335335
// CHECK: %[[#T77:]] = llvm.load %[[#T7]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
336-
// CHECK: %[[#T78:]] = llvm.fcmp "ole" %[[#T76]], %[[#T77]] : vector<2xf64>
336+
// CHECK: %[[#T78:]] = llvm.fcmp "ule" %[[#T76]], %[[#T77]] : vector<2xf64>
337337
// CHECK: %[[#T79:]] = llvm.sext %[[#T78]] : vector<2xi1> to vector<2xi64>
338338
// CHECK: llvm.store %[[#T79]], %[[#Ts:]] {alignment = 16 : i64} : vector<2xi64>, !llvm.ptr
339339
vll2 t = a >= b;
340340
// CHECK: %[[#T80:]] = llvm.load %[[#T5]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
341341
// CHECK: %[[#T81:]] = llvm.load %[[#T7]] {alignment = 16 : i64} : !llvm.ptr -> vector<2xf64>
342-
// CHECK: %[[#T82:]] = llvm.fcmp "oge" %[[#T80]], %[[#T81]] : vector<2xf64>
342+
// CHECK: %[[#T82:]] = llvm.fcmp "uge" %[[#T80]], %[[#T81]] : vector<2xf64>
343343
// CHECK: %[[#T83:]] = llvm.sext %[[#T82]] : vector<2xi1> to vector<2xi64>
344344
// CHECK: llvm.store %[[#T83]], %[[#Tt:]] {alignment = 16 : i64} : vector<2xi64>, !llvm.ptr
345345

0 commit comments

Comments
 (0)