Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -4052,6 +4052,43 @@ def CIR_ExpectOp : CIR_Op<"expect", [
}];
}

//===----------------------------------------------------------------------===//
// PrefetchOp
//===----------------------------------------------------------------------===//

def CIR_PrefetchOp : CIR_Op<"prefetch"> {
let summary = "Prefetch operation";
let description = [{
The `cir.prefetch` operation is a hint to the code generator to insert a
prefetch instruction if supported; otherwise, it is a noop. Prefetches
have no effect on the behavior of the program but can change its
performance characteristics.

```mlir
cir.prefetch(%0 : !cir.ptr<!void>) locality(1) write
```

$locality is a temporal locality specifier ranging from (0) - no locality,
to (3) - extremely local, keep in cache. If $locality is not present, the
default value is 3.

$isWrite specifies whether the prefetch is for a 'read' or 'write'. If
$isWrite is not specified, it means that prefetch is prepared for 'read'.
}];

let arguments = (ins CIR_VoidPtrType:$addr,
DefaultValuedAttr<ConfinedAttr<I32Attr, [IntMinValue<0>, IntMaxValue<3>]>,
"3">:$locality,
UnitAttr:$isWrite);

let assemblyFormat = [{
(`write` $isWrite^) : (`read`)?
`locality` `(` $locality `)`
$addr `:` qualified(type($addr))
attr-dict
}];
}

//===----------------------------------------------------------------------===//
// PtrDiffOp
//===----------------------------------------------------------------------===//
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,27 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
assert(!cir::MissingFeatures::coroSizeBuiltinCall());
return getUndefRValue(e->getType());
}
case Builtin::BI__builtin_prefetch: {
auto evaluateOperandAsInt = [&](const Expr *arg) {
Expr::EvalResult res;
[[maybe_unused]] bool evalSucceed =
arg->EvaluateAsInt(res, cgm.getASTContext());
assert(evalSucceed && "expression should be able to evaluate as int");
return res.Val.getInt().getZExtValue();
};

bool isWrite = false;
if (e->getNumArgs() > 1)
isWrite = evaluateOperandAsInt(e->getArg(1));

int locality = 3;
if (e->getNumArgs() > 2)
locality = evaluateOperandAsInt(e->getArg(2));

mlir::Value address = emitScalarExpr(e->getArg(0));
cir::PrefetchOp::create(builder, loc, address, locality, isWrite);
return RValue::get(nullptr);
}
}

// If this is an alias for a lib function (e.g. __builtin_sin), emit
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,15 @@ static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) {
return llvm::divideCeil(layout.getTypeSizeInBits(type), 8);
}

mlir::LogicalResult CIRToLLVMPrefetchOpLowering::matchAndRewrite(
cir::PrefetchOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
rewriter.replaceOpWithNewOp<mlir::LLVM::Prefetch>(
op, adaptor.getAddr(), adaptor.getIsWrite(), adaptor.getLocality(),
/*DataCache=*/1);
return mlir::success();
}

mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite(
cir::PtrDiffOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
Expand Down
43 changes: 43 additions & 0 deletions clang/test/CIR/CodeGen/builtin_prefetech.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=OGCG

void foo(void *a) {
__builtin_prefetch(a); // rw=0, locality=3
__builtin_prefetch(a, 0); // rw=0, locality=3
__builtin_prefetch(a, 1); // rw=1, locality=3
__builtin_prefetch(a, 1, 1); // rw=1, locality=1
}

// CIR-LABEL: cir.func dso_local @foo(
// CIR: %[[ALLOCA:.*]] = cir.alloca !cir.ptr<!void>
// CIR: cir.store %arg0, %[[ALLOCA]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// CIR: %[[P1:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.prefetch read locality(3) %[[P1]] : !cir.ptr<!void>
// CIR: %[[P2:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.prefetch read locality(3) %[[P2]] : !cir.ptr<!void>
// CIR: %[[P3:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.prefetch write locality(3) %[[P3]] : !cir.ptr<!void>
// CIR: %[[P4:.*]] = cir.load{{.*}} %[[ALLOCA]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: cir.prefetch write locality(1) %[[P4]] : !cir.ptr<!void>
// CIR: cir.return

// LLVM-LABEL: define dso_local void @foo(
// LLVM: [[ALLOCA:%.*]] = alloca ptr, i64 1
// LLVM: store ptr {{.*}}, ptr [[ALLOCA]]
// LLVM: [[LP1:%.*]] = load ptr, ptr [[ALLOCA]]
// LLVM: call void @llvm.prefetch.p0(ptr [[LP1]], i32 0, i32 3, i32 1)
// LLVM: [[LP2:%.*]] = load ptr, ptr [[ALLOCA]]
// LLVM: call void @llvm.prefetch.p0(ptr [[LP2]], i32 0, i32 3, i32 1)
// LLVM: [[LP3:%.*]] = load ptr, ptr [[ALLOCA]]
// LLVM: call void @llvm.prefetch.p0(ptr [[LP3]], i32 1, i32 3, i32 1)
// LLVM: [[LP4:%.*]] = load ptr, ptr [[ALLOCA]]
// LLVM: call void @llvm.prefetch.p0(ptr [[LP4]], i32 1, i32 1, i32 1)
// LLVM: ret void

// OGCG-LABEL: define dso_local void @foo(ptr
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 1, i32 1)
// OGCG: ret void