[CIR] Add non-floating-point builtin intrinsics (#178093)
## Summary This PR adds support for non-floating-point builtin intrinsics as a follow-up to #175233: - Integer `abs`/`labs`/`llabs` with `cir.abs` operation - `__builtin_unpredictable` handling - Integer elementwise abs support - Tests: `builtin-rotate.c`, `pred-info-builtins.c`, updates to `libc.c` and `builtins-elementwise.c` ## Dependency **This PR depends on #175233 (FP math builtins) and should be merged after it.** The non-FP builtins were split from #175233 per reviewer feedback to reduce PR size. ## Test plan - [x] All CIR codegen tests pass - [x] All CIR tests pass
This commit is contained in:
parent
f7497f784c
commit
34c28ba3d0
@ -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<!s32i x 4>
|
||||
```
|
||||
}];
|
||||
|
||||
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 = [{
|
||||
|
||||
@ -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<cir::BitPopcountOp>(*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<cir::FAbsOp>(*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<cir::ACosOp>(*this, *e);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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> {{%.*}})
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
77
clang/test/CIR/CodeGen/pred-info-builtins.c
Normal file
77
clang/test/CIR/CodeGen/pred-info-builtins.c
Normal file
@ -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()
|
||||
118
clang/test/CIR/CodeGenBuiltins/builtin-rotate.c
Normal file
118
clang/test/CIR/CodeGenBuiltins/builtin-rotate.c
Normal file
@ -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);
|
||||
}
|
||||
@ -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>, !s32i
|
||||
// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i
|
||||
// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !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>, !s32i
|
||||
// CIR-NEXT: %[[X_LONG:.+]] = cir.cast integral %[[X]] : !s32i -> !s64i
|
||||
// CIR-NEXT: %[[Y:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !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();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user