diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 78d7ef751000..ebc4d78563d9 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5799,6 +5799,35 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> { }]; } +def CIR_AbsOp : CIR_Op<"abs", [Pure, SameOperandsAndResultType]> { + let summary = "Computes the absolute value of a signed integer"; + let description = [{ + `cir.abs` computes the absolute value of a signed integer or vector + of signed integers. + + The `min_is_poison` attribute indicates whether the result value is a + poison value if the argument is statically or dynamically the minimum + value for the type. + + Example: + + ```mlir + %0 = cir.const #cir.int<-42> : s32i + %1 = cir.abs %0 min_is_poison : s32i + %2 = cir.abs %3 : !cir.vector + ``` + }]; + + let arguments = (ins + CIR_AnySIntOrVecOfSIntType:$src, + UnitAttr:$min_is_poison + ); + + let results = (outs CIR_AnySIntOrVecOfSIntType:$result); + + let assemblyFormat = "$src ( `min_is_poison` $min_is_poison^ )? `:` type($src) attr-dict"; +} + def CIR_FloorOp : CIR_UnaryFPToFPBuiltinOp<"floor", "FloorOp"> { let summary = "Computes the floating-point floor value"; let description = [{ diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 87c50585c1af..85c7d2cd5c48 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -970,6 +970,34 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return {}; } + case Builtin::BIabs: + case Builtin::BIlabs: + case Builtin::BIllabs: + case Builtin::BI__builtin_abs: + case Builtin::BI__builtin_labs: + case Builtin::BI__builtin_llabs: { + bool sanitizeOverflow = sanOpts.has(SanitizerKind::SignedIntegerOverflow); + mlir::Value arg = emitScalarExpr(e->getArg(0)); + mlir::Value result; + switch (getLangOpts().getSignedOverflowBehavior()) { + case LangOptions::SOB_Defined: + result = cir::AbsOp::create(builder, loc, arg.getType(), arg, + /*minIsPoison=*/false); + break; + case LangOptions::SOB_Undefined: + if (!sanitizeOverflow) { + result = cir::AbsOp::create(builder, loc, arg.getType(), arg, + /*minIsPoison=*/true); + break; + } + [[fallthrough]]; + case LangOptions::SOB_Trapping: + cgm.errorNYI(e->getSourceRange(), "abs with overflow handling"); + return RValue::get(nullptr); + } + return RValue::get(result); + } + case Builtin::BI__assume: case Builtin::BI__builtin_assume: { if (e->getArg(0)->HasSideEffects(getContext())) @@ -1092,9 +1120,20 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_popcountg: return emitBuiltinBitOp(*this, e); + // Always return the argument of __builtin_unpredictable. LLVM does not + // have an intrinsic corresponding to this builtin. Metadata for this + // builtin should be added directly to instructions such as branches or + // switches that use it. + case Builtin::BI__builtin_unpredictable: { + return RValue::get(emitScalarExpr(e->getArg(0))); + } + case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: { mlir::Value argValue = emitScalarExpr(e->getArg(0)); + if (cgm.getCodeGenOpts().OptimizationLevel == 0) + return RValue::get(argValue); + mlir::Value expectedValue = emitScalarExpr(e->getArg(1)); mlir::FloatAttr probAttr; @@ -1386,8 +1425,10 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, bool isIntTy = cir::isIntOrVectorOfIntType(cirTy); if (!isIntTy) return emitUnaryFPBuiltin(*this, *e); - // Integer abs is not yet implemented - return errorBuiltinNYI(*this, e, builtinID); + mlir::Value arg = emitScalarExpr(e->getArg(0)); + mlir::Value result = cir::AbsOp::create(builder, getLoc(e->getExprLoc()), + arg.getType(), arg, false); + return RValue::get(result); } case Builtin::BI__builtin_elementwise_acos: return emitUnaryMaybeConstrainedFPBuiltin(*this, *e); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 2fd80d5e91e8..85f2e7952b55 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2278,6 +2278,17 @@ mlir::LogicalResult CIRToLLVMFAbsOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMAbsOpLowering::matchAndRewrite( + cir::AbsOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type resTy = typeConverter->convertType(op.getType()); + auto absOp = mlir::LLVM::AbsOp::create(rewriter, op.getLoc(), resTy, + adaptor.getOperands()[0], + adaptor.getMinIsPoison()); + rewriter.replaceOp(op, absOp); + return mlir::success(); +} + /// Convert the `cir.func` attributes to `llvm.func` attributes. /// Only retain those attributes that are not constructed by /// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out diff --git a/clang/test/CIR/CodeGen/builtins-elementwise.c b/clang/test/CIR/CodeGen/builtins-elementwise.c index 3ca46e1fe3f4..6c31ce19788d 100644 --- a/clang/test/CIR/CodeGen/builtins-elementwise.c +++ b/clang/test/CIR/CodeGen/builtins-elementwise.c @@ -10,7 +10,7 @@ typedef int vint4 __attribute__((ext_vector_type(4))); typedef float vfloat4 __attribute__((ext_vector_type(4))); typedef double vdouble4 __attribute__((ext_vector_type(4))); -void test_builtin_elementwise_abs(float f, double d, +void test_builtin_elementwise_abs(vint4 vi4, int i, float f, double d, vfloat4 vf4, vdouble4 vd4) { // CIR-LABEL: test_builtin_elementwise_abs // LLVM-LABEL: test_builtin_elementwise_abs @@ -25,6 +25,16 @@ void test_builtin_elementwise_abs(float f, double d, // OGCG: {{%.*}} = call double @llvm.fabs.f64(double {{%.*}}) d = __builtin_elementwise_abs(d); + // CIR: {{%.*}} = cir.abs {{%.*}} : !cir.vector<4 x !s32i> + // LLVM: {{%.*}} = call <4 x i32> @llvm.abs.v4i32(<4 x i32> {{%.*}}, i1 false) + // OGCG: {{%.*}} = call <4 x i32> @llvm.abs.v4i32(<4 x i32> {{%.*}}, i1 false) + vi4 = __builtin_elementwise_abs(vi4); + + // CIR: {{%.*}} = cir.abs {{%.*}} : !s32 + // LLVM: {{%.*}} = call i32 @llvm.abs.i32(i32 {{%.*}}, i1 false) + // OGCG: {{%.*}} = call i32 @llvm.abs.i32(i32 {{%.*}}, i1 false) + i = __builtin_elementwise_abs(i); + // CIR: {{%.*}} = cir.fabs {{%.*}} : !cir.vector<4 x !cir.float> // LLVM: {{%.*}} = call <4 x float> @llvm.fabs.v4f32(<4 x float> {{%.*}}) // OGCG: {{%.*}} = call <4 x float> @llvm.fabs.v4f32(<4 x float> {{%.*}}) diff --git a/clang/test/CIR/CodeGen/libc.c b/clang/test/CIR/CodeGen/libc.c index 6bd2bca33de5..e20cdc3dfbbf 100644 --- a/clang/test/CIR/CodeGen/libc.c +++ b/clang/test/CIR/CodeGen/libc.c @@ -1,5 +1,16 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-ogcg.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t-ogcg.ll %s + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -fwrapv +// RUN: FileCheck --check-prefix=CIR_NO_POISON --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -fwrapv +// RUN: FileCheck --check-prefix=LLVM_NO_POISON --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-ogcg-wrapv.ll -fwrapv +// RUN: FileCheck --check-prefix=OGCG_NO_POISON --input-file=%t-ogcg-wrapv.ll %s // Note: In the final implementation, we will want these to generate // CIR-specific libc operations. This test is just a placeholder @@ -35,3 +46,36 @@ float testFabsf(float x) { return fabsf(x); // CHECK: cir.fabs %{{.+}} : !cir.float } + +int abs(int); +int testAbs(int x) { + return abs(x); + // CHECK: cir.abs %{{.+}} min_is_poison : !s32i + // LLVM: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 true) + // OGCG: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 true) + // CIR_NO_POISON: cir.abs %{{[^ ]+}} : !s32i + // LLVM_NO_POISON: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 false) + // OGCG_NO_POISON: %{{.+}} = call i32 @llvm.abs.i32(i32 %{{.+}}, i1 false) +} + +long labs(long); +long testLabs(long x) { + return labs(x); + // CHECK: cir.abs %{{.+}} min_is_poison : !s64i + // LLVM: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true) + // OGCG: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true) + // CIR_NO_POISON: cir.abs %{{[^ ]+}} : !s64i + // LLVM_NO_POISON: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false) + // OGCG_NO_POISON: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false) +} + +long long llabs(long long); +long long testLlabs(long long x) { + return llabs(x); + // CHECK: cir.abs %{{.+}} min_is_poison : !s64i + // LLVM: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true) + // OGCG: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 true) + // CIR_NO_POISON: cir.abs %{{[^ ]+}} : !s64i + // LLVM_NO_POISON: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false) + // OGCG_NO_POISON: %{{.+}} = call i64 @llvm.abs.i64(i64 %{{.+}}, i1 false) +} diff --git a/clang/test/CIR/CodeGen/pred-info-builtins.c b/clang/test/CIR/CodeGen/pred-info-builtins.c new file mode 100644 index 000000000000..09e6b9013aee --- /dev/null +++ b/clang/test/CIR/CodeGen/pred-info-builtins.c @@ -0,0 +1,77 @@ +// Test __builtin_expect, __builtin_expect_with_probability, and __builtin_unpredictable. +// Focus: O0 vs O2 CIR output (no cir.expect at O0), and LLVM/OGCG with -O2 -disable-llvm-passes. +// Builtin call lowering is also covered by builtin_call.cpp. +// +// RUN: %clang_cc1 -O0 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR-O0 +// CIR-O0-NOT: cir.expect +// RUN: %clang_cc1 -O2 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR-O2 +// RUN: %clang_cc1 -O2 -disable-llvm-passes -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -O2 -disable-llvm-passes -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=OGCG + +extern void __attribute__((noinline)) bar(void); + +void expect(int x) { + if (__builtin_expect(x, 0)) + bar(); +} +// CIR-O0: cir.func {{.*}} @expect +// CIR-O0: cir.if {{%.*}} { +// CIR-O0: cir.call @bar() : () -> () + +// CIR-O2: cir.func {{.*}} @expect +// CIR-O2: [[EXPECT:%.*]] = cir.expect({{.*}}, {{.*}}) : !s64i +// CIR-O2: [[EXPECT_BOOL:%.*]] = cir.cast int_to_bool [[EXPECT]] : !s64i -> !cir.bool +// CIR-O2: cir.if [[EXPECT_BOOL]] +// CIR-O2: cir.call @bar() : () -> () + +// LLVM-LABEL: @expect +// LLVM: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// LLVM: [[THEN]]: +// LLVM: call void @bar() + +// OGCG-LABEL: @expect +// OGCG: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// OGCG: [[THEN]]: +// OGCG: call void @bar() + +void expect_with_probability(int x) { + if (__builtin_expect_with_probability(x, 1, 0.8)) + bar(); +} +// CIR-O0: cir.func {{.*}} @expect_with_probability +// CIR-O0: cir.if {{%.*}} { +// CIR-O0: cir.call @bar() : () -> () + +// CIR-O2: cir.func {{.*}} @expect_with_probability +// CIR-O2: [[EXPECT:%.*]] = cir.expect({{.*}}, {{.*}}, 8.000000e-01) : !s64i +// CIR-O2: [[EXPECT_BOOL:%.*]] = cir.cast int_to_bool [[EXPECT]] : !s64i -> !cir.bool +// CIR-O2: cir.if [[EXPECT_BOOL]] +// CIR-O2: cir.call @bar() : () -> () + +// LLVM-LABEL: @expect_with_probability +// LLVM: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// LLVM: [[THEN]]: +// LLVM: call void @bar() + +// OGCG-LABEL: @expect_with_probability +// OGCG: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// OGCG: [[THEN]]: +// OGCG: call void @bar() + +void unpredictable(int x) { + if (__builtin_unpredictable(x > 1)) + bar(); +} +// CIR-O0: cir.func {{.*}} @unpredictable +// CIR-O0: cir.if {{%.*}} { +// CIR-O0: cir.call @bar() : () -> () + +// LLVM-LABEL: @unpredictable +// LLVM: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// LLVM: [[THEN]]: +// LLVM: call void @bar() + +// OGCG-LABEL: @unpredictable +// OGCG: br i1 {{.*}}, label %[[THEN:.*]], label %[[END:.*]] +// OGCG: [[THEN]]: +// OGCG: call void @bar() diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-rotate.c b/clang/test/CIR/CodeGenBuiltins/builtin-rotate.c new file mode 100644 index 000000000000..0f587eb644a3 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-rotate.c @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +void f() { +// CIR-LABEL: @f +// LLVM-LABEL: @f +// OGCG-LABEL: @f + unsigned int v[4]; + unsigned int h = __builtin_rotateleft32(v[0], 1); +// CIR: %[[CONST:.*]] = cir.const #cir.int<1> : !u32i +// CIR: cir.rotate left {{.*}}, %[[CONST]] : !u32i + +// LLVM: %[[SRC:.*]] = load i32, ptr +// LLVM: call i32 @llvm.fshl.i32(i32 %[[SRC]], i32 %[[SRC]], i32 1) + +// OGCG: %[[SRC:.*]] = load i32, ptr +// OGCG: call i32 @llvm.fshl.i32(i32 %[[SRC]], i32 %[[SRC]], i32 1) +} + +unsigned char rotl8(unsigned char x, unsigned char y) { +// CIR-LABEL: rotl8 +// CIR: cir.rotate left {{.*}}, {{.*}} : !u8i + +// LLVM-LABEL: rotl8 +// LLVM: [[F:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Y:%.*]]) + +// OGCG-LABEL: rotl8 +// OGCG: call i8 @llvm.fshl.i8(i8 {{.*}}, i8 {{.*}}, i8 {{.*}}) + return __builtin_rotateleft8(x, y); +} + +short rotl16(short x, short y) { +// CIR-LABEL: rotl16 +// CIR: cir.rotate left {{.*}}, {{.*}} : !u16i + +// LLVM-LABEL: rotl16 +// LLVM: [[F:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[X]], i16 [[Y:%.*]]) + +// OGCG-LABEL: rotl16 +// OGCG: call i16 @llvm.fshl.i16(i16 {{.*}}, i16 {{.*}}, i16 {{.*}}) + return __builtin_rotateleft16(x, y); +} + +int rotl32(int x, unsigned int y) { +// CIR-LABEL: rotl32 +// CIR: cir.rotate left {{.*}}, {{.*}} : !u32i + +// LLVM-LABEL: rotl32 +// LLVM: [[F:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 [[Y:%.*]]) + +// OGCG-LABEL: rotl32 +// OGCG: call i32 @llvm.fshl.i32(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) + return __builtin_rotateleft32(x, y); +} + +unsigned long long rotl64(unsigned long long x, long long y) { +// CIR-LABEL: rotl64 +// CIR: cir.rotate left {{.*}}, {{.*}} : !u64i + +// LLVM-LABEL: rotl64 +// LLVM: [[F:%.*]] = call i64 @llvm.fshl.i64(i64 [[X:%.*]], i64 [[X]], i64 [[Y:%.*]]) + +// OGCG-LABEL: rotl64 +// OGCG: call i64 @llvm.fshl.i64(i64 {{.*}}, i64 {{.*}}, i64 {{.*}}) + return __builtin_rotateleft64(x, y); +} + +char rotr8(char x, char y) { +// CIR-LABEL: rotr8 +// CIR: cir.rotate right {{.*}}, {{.*}} : !u8i + +// LLVM-LABEL: rotr8 +// LLVM: [[F:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Y:%.*]]) + +// OGCG-LABEL: rotr8 +// OGCG: call i8 @llvm.fshr.i8(i8 {{.*}}, i8 {{.*}}, i8 {{.*}}) + return __builtin_rotateright8(x, y); +} + +unsigned short rotr16(unsigned short x, unsigned short y) { +// CIR-LABEL: rotr16 +// CIR: cir.rotate right {{.*}}, {{.*}} : !u16i + +// LLVM-LABEL: rotr16 +// LLVM: [[F:%.*]] = call i16 @llvm.fshr.i16(i16 [[X:%.*]], i16 [[X]], i16 [[Y:%.*]]) + +// OGCG-LABEL: rotr16 +// OGCG: call i16 @llvm.fshr.i16(i16 {{.*}}, i16 {{.*}}, i16 {{.*}}) + return __builtin_rotateright16(x, y); +} + +unsigned int rotr32(unsigned int x, int y) { +// CIR-LABEL: rotr32 +// CIR: cir.rotate right {{.*}}, {{.*}} : !u32i + +// LLVM-LABEL: rotr32 +// LLVM: [[F:%.*]] = call i32 @llvm.fshr.i32(i32 [[X:%.*]], i32 [[X]], i32 [[Y:%.*]]) + +// OGCG-LABEL: rotr32 +// OGCG: call i32 @llvm.fshr.i32(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) + return __builtin_rotateright32(x, y); +} + +long long rotr64(long long x, unsigned long long y) { +// CIR-LABEL: rotr64 +// CIR: cir.rotate right {{.*}}, {{.*}} : !u64i + +// LLVM-LABEL: rotr64 +// LLVM: [[F:%.*]] = call i64 @llvm.fshr.i64(i64 [[X:%.*]], i64 [[X]], i64 [[Y:%.*]]) + +// OGCG-LABEL: rotr64 +// OGCG: call i64 @llvm.fshr.i64(i64 {{.*}}, i64 {{.*}}, i64 {{.*}}) + return __builtin_rotateright64(x, y); +} diff --git a/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp b/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp index 7e1d77f6b61b..f783a2bd7e38 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtin_call.cpp @@ -164,42 +164,36 @@ void expect(int x, int y) { __builtin_expect(x, y); } +// At -O0, __builtin_expect is a passthrough (no cir.expect / llvm.expect). +// See pred-info-builtins.c for -O2 tests that verify cir.expect emission. // CIR-LABEL: cir.func{{.*}} @_Z6expectii -// CIR: %[[X:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !s32i -// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i -// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !s32i -// CIR-NEXT: %[[Y_LONG:.+]] = cir.cast integral %[[Y]] : !s32i -> !s64i -// CIR-NEXT: %{{.+}} = cir.expect(%[[X_LONG]], %[[Y_LONG]]) : !s64i +// CIR-NOT: cir.expect // CIR: } // LLVM-LABEL: define{{.*}} void @_Z6expectii -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[X_LONG:.+]] = sext i32 %[[X]] to i64 -// LLVM-NEXT: %[[Y:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[Y_LONG:.+]] = sext i32 %[[Y]] to i64 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.expect.i64(i64 %[[X_LONG]], i64 %[[Y_LONG]]) +// LLVM-NOT: call i64 @llvm.expect // LLVM: } +// OGCG-LABEL: define{{.*}} void @_Z6expectii +// OGCG-NOT: call i64 @llvm.expect +// OGCG: } + void expect_prob(int x, int y) { __builtin_expect_with_probability(x, y, 0.25); } // CIR-LABEL: cir.func{{.*}} @_Z11expect_probii -// CIR: %[[X:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !s32i -// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i -// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr, !s32i -// CIR-NEXT: %[[Y_LONG:.+]] = cir.cast integral %[[Y]] : !s32i -> !s64i -// CIR-NEXT: %{{.+}} = cir.expect(%[[X_LONG]], %[[Y_LONG]], 2.500000e-01) : !s64i +// CIR-NOT: cir.expect // CIR: } -// LLVM: define{{.*}} void @_Z11expect_probii -// LLVM: %[[X:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[X_LONG:.+]] = sext i32 %[[X]] to i64 -// LLVM-NEXT: %[[Y:.+]] = load i32, ptr %{{.+}}, align 4 -// LLVM-NEXT: %[[Y_LONG:.+]] = sext i32 %[[Y]] to i64 -// LLVM-NEXT: %{{.+}} = call i64 @llvm.expect.with.probability.i64(i64 %[[X_LONG]], i64 %[[Y_LONG]], double 2.500000e-01) +// LLVM-LABEL: define{{.*}} void @_Z11expect_probii +// LLVM-NOT: call i64 @llvm.expect // LLVM: } +// OGCG-LABEL: define{{.*}} void @_Z11expect_probii +// OGCG-NOT: call i64 @llvm.expect +// OGCG: } + void unreachable() { __builtin_unreachable(); }