let llvmBuilder = [{
$res = builder.CreateICmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
}];
- let parser = [{ return parseICmpOp(parser, result); }];
+ let parser = [{ return parseCmpOp<ICmpPredicate>(parser, result); }];
let printer = [{ printICmpOp(p, *this); }];
}
+// Predicate for float comparisons
+def FCmpPredicateFALSE : I64EnumAttrCase<"_false", 0>;
+def FCmpPredicateOEQ : I64EnumAttrCase<"oeq", 1>;
+def FCmpPredicateOGT : I64EnumAttrCase<"ogt", 2>;
+def FCmpPredicateOGE : I64EnumAttrCase<"oge", 3>;
+def FCmpPredicateOLT : I64EnumAttrCase<"olt", 4>;
+def FCmpPredicateOLE : I64EnumAttrCase<"ole", 5>;
+def FCmpPredicateONE : I64EnumAttrCase<"one", 6>;
+def FCmpPredicateORD : I64EnumAttrCase<"ord", 7>;
+def FCmpPredicateUEQ : I64EnumAttrCase<"ueq", 8>;
+def FCmpPredicateUGT : I64EnumAttrCase<"ugt", 9>;
+def FCmpPredicateUGE : I64EnumAttrCase<"uge", 10>;
+def FCmpPredicateULT : I64EnumAttrCase<"ult", 11>;
+def FCmpPredicateULE : I64EnumAttrCase<"ule", 12>;
+def FCmpPredicateUNE : I64EnumAttrCase<"une", 13>;
+def FCmpPredicateUNO : I64EnumAttrCase<"uno", 14>;
+def FCmpPredicateTRUE : I64EnumAttrCase<"_true", 15>;
+
+def FCmpPredicate : I64EnumAttr<
+ "FCmpPredicate",
+ "llvm.fcmp comparison predicate",
+ [FCmpPredicateFALSE, FCmpPredicateOEQ, FCmpPredicateOGT, FCmpPredicateOGE,
+ FCmpPredicateOLT, FCmpPredicateOLE, FCmpPredicateONE, FCmpPredicateORD,
+ FCmpPredicateUEQ, FCmpPredicateUGT, FCmpPredicateUGE, FCmpPredicateULT,
+ FCmpPredicateULE, FCmpPredicateUNE, FCmpPredicateUNO, FCmpPredicateTRUE
+ ]> {
+ let cppNamespace = "mlir::LLVM";
+
+ let returnType = "FCmpPredicate";
+ let convertFromStorage =
+ "static_cast<" # returnType # ">($_self.getValue().getZExtValue())";
+}
+
+// Other integer operations.
+def LLVM_FCmpOp : LLVM_OneResultOp<"fcmp", [NoSideEffect]>,
+ Arguments<(ins FCmpPredicate:$predicate, LLVM_Type:$lhs,
+ LLVM_Type:$rhs)> {
+ let llvmBuilder = [{
+ $res = builder.CreateFCmp(getLLVMCmpPredicate($predicate), $lhs, $rhs);
+ }];
+ let parser = [{ return parseCmpOp<FCmpPredicate>(parser, result); }];
+ let printer = [{ printFCmpOp(p, *this); }];
+}
+
// Floating point binary operations.
def LLVM_FAddOp : LLVM_ArithmeticOp<"fadd", "CreateFAdd">;
def LLVM_FSubOp : LLVM_ArithmeticOp<"fsub", "CreateFSub">;
};
/// The predicate indicates the type of the comparison to perform:
-/// (un)orderedness, (in)equality and signed less/greater than (or equal to) as
+/// (un)orderedness, (in)equality and less/greater than (or equal to) as
/// well as predicates that are always true or false.
enum class CmpFPredicate {
FirstValidValue,
}
};
-// Convert std.cmpi predicate into the LLVM dialect ICmpPredicate. The two
+// Convert std.cmp predicate into the LLVM dialect CmpPredicate. The two
// enums share the numerical values so just cast.
-static LLVM::ICmpPredicate convertCmpIPredicate(CmpIPredicate pred) {
- return static_cast<LLVM::ICmpPredicate>(pred);
+template <typename LLVMPredType, typename StdPredType>
+static LLVMPredType convertCmpPredicate(StdPredType pred) {
+ return static_cast<LLVMPredType>(pred);
}
struct CmpIOpLowering : public LLVMLegalizationPattern<CmpIOp> {
rewriter.replaceOpWithNewOp<LLVM::ICmpOp>(
op, lowering.convertType(cmpiOp.getResult()->getType()),
- rewriter.getI64IntegerAttr(
- static_cast<int64_t>(convertCmpIPredicate(cmpiOp.getPredicate()))),
+ rewriter.getI64IntegerAttr(static_cast<int64_t>(
+ convertCmpPredicate<LLVM::ICmpPredicate>(cmpiOp.getPredicate()))),
+ transformed.lhs(), transformed.rhs());
+
+ return matchSuccess();
+ }
+};
+
+struct CmpFOpLowering : public LLVMLegalizationPattern<CmpFOp> {
+ using LLVMLegalizationPattern<CmpFOp>::LLVMLegalizationPattern;
+
+ PatternMatchResult
+ matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
+ ConversionPatternRewriter &rewriter) const override {
+ auto cmpfOp = cast<CmpFOp>(op);
+ CmpFOpOperandAdaptor transformed(operands);
+
+ rewriter.replaceOpWithNewOp<LLVM::FCmpOp>(
+ op, lowering.convertType(cmpfOp.getResult()->getType()),
+ rewriter.getI64IntegerAttr(static_cast<int64_t>(
+ convertCmpPredicate<LLVM::FCmpPredicate>(cmpfOp.getPredicate()))),
transformed.lhs(), transformed.rhs());
return matchSuccess();
patterns.insert<
AddFOpLowering, AddIOpLowering, AndOpLowering, AllocOpLowering,
BranchOpLowering, CallIndirectOpLowering, CallOpLowering, CmpIOpLowering,
- CondBranchOpLowering, ConstLLVMOpLowering, DeallocOpLowering,
- DimOpLowering, DivISOpLowering, DivIUOpLowering, DivFOpLowering,
- FuncOpConversion, IndexCastOpLowering, LoadOpLowering,
+ CmpFOpLowering, CondBranchOpLowering, ConstLLVMOpLowering,
+ DeallocOpLowering, DimOpLowering, DivISOpLowering, DivIUOpLowering,
+ DivFOpLowering, FuncOpConversion, IndexCastOpLowering, LoadOpLowering,
MemRefCastOpLowering, MulFOpLowering, MulIOpLowering, OrOpLowering,
RemISOpLowering, RemIUOpLowering, RemFOpLowering, ReturnOpLowering,
SelectOpLowering, SIToFPLowering, StoreOpLowering, SubFOpLowering,
return !(!lhs && !rhs);
}
-static ValueHandle createComparisonExpr(CmpIPredicate predicate,
- ValueHandle lhs, ValueHandle rhs) {
+static ValueHandle createIComparisonExpr(CmpIPredicate predicate,
+ ValueHandle lhs, ValueHandle rhs) {
auto lhsType = lhs.getType();
auto rhsType = rhs.getType();
(void)lhsType;
return ValueHandle(op.getResult());
}
+static ValueHandle createFComparisonExpr(CmpFPredicate predicate,
+ ValueHandle lhs, ValueHandle rhs) {
+ auto lhsType = lhs.getType();
+ auto rhsType = rhs.getType();
+ (void)lhsType;
+ (void)rhsType;
+ assert(lhsType == rhsType && "cannot mix types in operators");
+ assert(lhsType.isa<FloatType>() && "only float comparisons are supported");
+
+ auto op = ScopedContext::getBuilder().create<CmpFOp>(
+ ScopedContext::getLocation(), predicate, lhs.getValue(), rhs.getValue());
+ return ValueHandle(op.getResult());
+}
+
+// All floating point comparison are ordered through EDSL
ValueHandle mlir::edsc::op::operator==(ValueHandle lhs, ValueHandle rhs) {
- return createComparisonExpr(CmpIPredicate::EQ, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::OEQ, lhs, rhs)
+ : createIComparisonExpr(CmpIPredicate::EQ, lhs, rhs);
}
ValueHandle mlir::edsc::op::operator!=(ValueHandle lhs, ValueHandle rhs) {
- return createComparisonExpr(CmpIPredicate::NE, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::ONE, lhs, rhs)
+ : createIComparisonExpr(CmpIPredicate::NE, lhs, rhs);
}
ValueHandle mlir::edsc::op::operator<(ValueHandle lhs, ValueHandle rhs) {
- // TODO(ntv,zinenko): signed by default, how about unsigned?
- return createComparisonExpr(CmpIPredicate::SLT, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::OLT, lhs, rhs)
+ :
+ // TODO(ntv,zinenko): signed by default, how about unsigned?
+ createIComparisonExpr(CmpIPredicate::SLT, lhs, rhs);
}
ValueHandle mlir::edsc::op::operator<=(ValueHandle lhs, ValueHandle rhs) {
- return createComparisonExpr(CmpIPredicate::SLE, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::OLE, lhs, rhs)
+ : createIComparisonExpr(CmpIPredicate::SLE, lhs, rhs);
}
ValueHandle mlir::edsc::op::operator>(ValueHandle lhs, ValueHandle rhs) {
- return createComparisonExpr(CmpIPredicate::SGT, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::OGT, lhs, rhs)
+ : createIComparisonExpr(CmpIPredicate::SGT, lhs, rhs);
}
ValueHandle mlir::edsc::op::operator>=(ValueHandle lhs, ValueHandle rhs) {
- return createComparisonExpr(CmpIPredicate::SGE, lhs, rhs);
+ auto type = lhs.getType();
+ return type.isa<FloatType>()
+ ? createFComparisonExpr(CmpFPredicate::OGE, lhs, rhs)
+ : createIComparisonExpr(CmpIPredicate::SGE, lhs, rhs);
}
#include "mlir/LLVMIR/LLVMOpsEnums.cpp.inc"
//===----------------------------------------------------------------------===//
-// Printing/parsing for LLVM::ICmpOp.
+// Printing/parsing for LLVM::CmpOp.
//===----------------------------------------------------------------------===//
-
static void printICmpOp(OpAsmPrinter *p, ICmpOp &op) {
*p << op.getOperationName() << " \"" << stringifyICmpPredicate(op.predicate())
<< "\" " << *op.getOperand(0) << ", " << *op.getOperand(1);
*p << " : " << op.lhs()->getType();
}
+static void printFCmpOp(OpAsmPrinter *p, FCmpOp &op) {
+ *p << op.getOperationName() << " \"" << stringifyFCmpPredicate(op.predicate())
+ << "\" " << *op.getOperand(0) << ", " << *op.getOperand(1);
+ p->printOptionalAttrDict(op.getAttrs(), {"predicate"});
+ *p << " : " << op.lhs()->getType();
+}
+
// <operation> ::= `llvm.icmp` string-literal ssa-use `,` ssa-use
// attribute-dict? `:` type
-static ParseResult parseICmpOp(OpAsmParser *parser, OperationState *result) {
+// <operation> ::= `llvm.fcmp` string-literal ssa-use `,` ssa-use
+// attribute-dict? `:` type
+template <typename CmpPredicateType>
+static ParseResult parseCmpOp(OpAsmParser *parser, OperationState *result) {
Builder &builder = parser->getBuilder();
Attribute predicate;
if (!predicateStr)
return parser->emitError(predicateLoc,
"expected 'predicate' attribute of string type");
- Optional<ICmpPredicate> predicateValue =
- symbolizeICmpPredicate(predicateStr.getValue());
- if (!predicateValue)
- return parser->emitError(predicateLoc)
- << "'" << predicateStr.getValue()
- << "' is an incorrect value of the 'predicate' attribute";
-
- attrs[0].second = parser->getBuilder().getI64IntegerAttr(
- static_cast<int64_t>(predicateValue.getValue()));
+
+ int64_t predicateValue = 0;
+ if (std::is_same<CmpPredicateType, ICmpPredicate>()) {
+ Optional<ICmpPredicate> predicate =
+ symbolizeICmpPredicate(predicateStr.getValue());
+ if (!predicate)
+ return parser->emitError(predicateLoc)
+ << "'" << predicateStr.getValue()
+ << "' is an incorrect value of the 'predicate' attribute";
+ predicateValue = static_cast<int64_t>(predicate.getValue());
+ } else {
+ Optional<FCmpPredicate> predicate =
+ symbolizeFCmpPredicate(predicateStr.getValue());
+ if (!predicate)
+ return parser->emitError(predicateLoc)
+ << "'" << predicateStr.getValue()
+ << "' is an incorrect value of the 'predicate' attribute";
+ predicateValue = static_cast<int64_t>(predicate.getValue());
+ }
+
+ attrs[0].second = parser->getBuilder().getI64IntegerAttr(predicateValue);
// The result type is either i1 or a vector type <? x i1> if the inputs are
// vectors.
}
}
+static llvm::CmpInst::Predicate getLLVMCmpPredicate(FCmpPredicate p) {
+ switch (p) {
+ case LLVM::FCmpPredicate::_false:
+ return llvm::CmpInst::Predicate::FCMP_FALSE;
+ case LLVM::FCmpPredicate::oeq:
+ return llvm::CmpInst::Predicate::FCMP_OEQ;
+ case LLVM::FCmpPredicate::ogt:
+ return llvm::CmpInst::Predicate::FCMP_OGT;
+ case LLVM::FCmpPredicate::oge:
+ return llvm::CmpInst::Predicate::FCMP_OGE;
+ case LLVM::FCmpPredicate::olt:
+ return llvm::CmpInst::Predicate::FCMP_OLT;
+ case LLVM::FCmpPredicate::ole:
+ return llvm::CmpInst::Predicate::FCMP_OLE;
+ case LLVM::FCmpPredicate::one:
+ return llvm::CmpInst::Predicate::FCMP_ONE;
+ case LLVM::FCmpPredicate::ord:
+ return llvm::CmpInst::Predicate::FCMP_ORD;
+ case LLVM::FCmpPredicate::ueq:
+ return llvm::CmpInst::Predicate::FCMP_UEQ;
+ case LLVM::FCmpPredicate::ugt:
+ return llvm::CmpInst::Predicate::FCMP_UGT;
+ case LLVM::FCmpPredicate::uge:
+ return llvm::CmpInst::Predicate::FCMP_UGE;
+ case LLVM::FCmpPredicate::ult:
+ return llvm::CmpInst::Predicate::FCMP_ULT;
+ case LLVM::FCmpPredicate::ule:
+ return llvm::CmpInst::Predicate::FCMP_ULE;
+ case LLVM::FCmpPredicate::une:
+ return llvm::CmpInst::Predicate::FCMP_UNE;
+ case LLVM::FCmpPredicate::uno:
+ return llvm::CmpInst::Predicate::FCMP_UNO;
+ case LLVM::FCmpPredicate::_true:
+ return llvm::CmpInst::Predicate::FCMP_TRUE;
+ default:
+ llvm_unreachable("incorrect comparison predicate");
+ }
+}
+
// A helper to look up remapped operands in the value remapping table.
template <typename Range>
SmallVector<llvm::Value *, 8> ModuleTranslation::lookupValues(Range &&values) {
f.erase();
}
-TEST_FUNC(select_op) {
+TEST_FUNC(select_op_i32) {
using namespace edsc;
using namespace edsc::intrinsics;
using namespace edsc::op;
f.erase();
}
+TEST_FUNC(select_op_f32) {
+ using namespace edsc;
+ using namespace edsc::intrinsics;
+ using namespace edsc::op;
+ auto f32Type = FloatType::getF32(&globalContext());
+ auto memrefType = MemRefType::get({-1, -1}, f32Type, {}, 0);
+ auto f = makeFunction("select_op", {}, {memrefType, memrefType});
+
+ OpBuilder builder(f.getBody());
+ ScopedContext scope(builder, f.getLoc());
+ // clang-format off
+ ValueHandle zero = constant_index(0), one = constant_index(1);
+ MemRefView vA(f.getArgument(0)), vB(f.getArgument(1));
+ IndexedValue A(f.getArgument(0)), B(f.getArgument(1));
+ IndexHandle i, j;
+ LoopNestBuilder({&i, &j}, {zero, zero}, {one, one}, {1, 1})([&]{
+
+ edsc::intrinsics::select(B(i, j) == B(i+one, j), *A(zero, zero), *A(i, j));
+ edsc::intrinsics::select(B(i, j) != B(i+one, j), *A(zero, zero), *A(i, j));
+ edsc::intrinsics::select(B(i, j) >= B(i+one, j), *A(zero, zero), *A(i, j));
+ edsc::intrinsics::select(B(i, j) <= B(i+one, j), *A(zero, zero), *A(i, j));
+ edsc::intrinsics::select(B(i, j) < B(i+one, j), *A(zero, zero), *A(i, j));
+ edsc::intrinsics::select(B(i, j) > B(i+one, j), *A(zero, zero), *A(i, j));
+ });
+
+ // CHECK-LABEL: @select_op
+ // CHECK: affine.for %{{.*}} = 0 to 1 {
+ // CHECK-NEXT: affine.for %{{.*}} = 0 to 1 {
+ // CHECK-DAG: cmpf "oeq"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // CHECK-DAG: cmpf "one"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // CHECK-DAG: cmpf "oge"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // CHECK-DAG: cmpf "ole"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // CHECK-DAG: cmpf "olt"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // CHECK-DAG: cmpf "ogt"
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.load
+ // CHECK-DAG: affine.apply
+ // CHECK-NEXT: select
+ // clang-format on
+ f.print(llvm::outs());
+ f.erase();
+}
+
// Inject an EDSC-constructed computation to exercise imperfectly nested 2-d
// tiling.
TEST_FUNC(tile_2d) {
// CHECK: ^[[dummyBlock]]:
// CHECK-NEXT: llvm.br ^[[origBlock]](%arg2 : !llvm.i32)
}
+
+// CHECK-LABEL: func @fcmp(%arg0: !llvm.float, %arg1: !llvm.float) {
+func @fcmp(f32, f32) -> () {
+^bb0(%arg0: f32, %arg1: f32):
+ // CHECK: llvm.fcmp "oeq" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ogt" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "oge" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "olt" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ole" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "one" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ord" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ueq" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ugt" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "uge" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ult" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "ule" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "une" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.fcmp "uno" %arg0, %arg1 : !llvm.float
+ // CHECK-NEXT: llvm.return
+ %1 = cmpf "oeq", %arg0, %arg1 : f32
+ %2 = cmpf "ogt", %arg0, %arg1 : f32
+ %3 = cmpf "oge", %arg0, %arg1 : f32
+ %4 = cmpf "olt", %arg0, %arg1 : f32
+ %5 = cmpf "ole", %arg0, %arg1 : f32
+ %6 = cmpf "one", %arg0, %arg1 : f32
+ %7 = cmpf "ord", %arg0, %arg1 : f32
+ %8 = cmpf "ueq", %arg0, %arg1 : f32
+ %9 = cmpf "ugt", %arg0, %arg1 : f32
+ %10 = cmpf "uge", %arg0, %arg1 : f32
+ %11 = cmpf "ult", %arg0, %arg1 : f32
+ %12 = cmpf "ule", %arg0, %arg1 : f32
+ %13 = cmpf "une", %arg0, %arg1 : f32
+ %14 = cmpf "uno", %arg0, %arg1 : f32
+
+ return
+}
// CHECK: unreachable
llvm.unreachable
}
+
+// CHECK-LABEL: define void @fcmp
+func @fcmp(%arg0: !llvm.float, %arg1: !llvm.float) {
+ // CHECK: fcmp oeq float %0, %1
+ // CHECK-NEXT: fcmp ogt float %0, %1
+ // CHECK-NEXT: fcmp oge float %0, %1
+ // CHECK-NEXT: fcmp olt float %0, %1
+ // CHECK-NEXT: fcmp ole float %0, %1
+ // CHECK-NEXT: fcmp one float %0, %1
+ // CHECK-NEXT: fcmp ord float %0, %1
+ // CHECK-NEXT: fcmp ueq float %0, %1
+ // CHECK-NEXT: fcmp ugt float %0, %1
+ // CHECK-NEXT: fcmp uge float %0, %1
+ // CHECK-NEXT: fcmp ult float %0, %1
+ // CHECK-NEXT: fcmp ule float %0, %1
+ // CHECK-NEXT: fcmp une float %0, %1
+ // CHECK-NEXT: fcmp uno float %0, %1
+ %0 = llvm.fcmp "oeq" %arg0, %arg1 : !llvm.float
+ %1 = llvm.fcmp "ogt" %arg0, %arg1 : !llvm.float
+ %2 = llvm.fcmp "oge" %arg0, %arg1 : !llvm.float
+ %3 = llvm.fcmp "olt" %arg0, %arg1 : !llvm.float
+ %4 = llvm.fcmp "ole" %arg0, %arg1 : !llvm.float
+ %5 = llvm.fcmp "one" %arg0, %arg1 : !llvm.float
+ %6 = llvm.fcmp "ord" %arg0, %arg1 : !llvm.float
+ %7 = llvm.fcmp "ueq" %arg0, %arg1 : !llvm.float
+ %8 = llvm.fcmp "ugt" %arg0, %arg1 : !llvm.float
+ %9 = llvm.fcmp "uge" %arg0, %arg1 : !llvm.float
+ %10 = llvm.fcmp "ult" %arg0, %arg1 : !llvm.float
+ %11 = llvm.fcmp "ule" %arg0, %arg1 : !llvm.float
+ %12 = llvm.fcmp "une" %arg0, %arg1 : !llvm.float
+ %13 = llvm.fcmp "uno" %arg0, %arg1 : !llvm.float
+ llvm.return
+}