Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
18 changes: 8 additions & 10 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
}

cgm.errorNYI(e->getSourceRange(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is now handled in CIRGenBuiltinX86, so we can return empty values without triggering the NYI error

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's right. That will only report the error for missing X86 builtins. This was a backstop for everything else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I caught missing builtins for other targets in emitTargetArchBuiltinExpr

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about __builtin_constant_p? This was also handling missing builtins that are not target-specific?

std::string("unimplemented builtin call: ") +
getContext().BuiltinInfo.getName(builtinID));
return getUndefRValue(e->getType());
}

Expand Down Expand Up @@ -1303,9 +1300,7 @@ static mlir::Value emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
case llvm::Triple::aarch64_be:
case llvm::Triple::bpfeb:
case llvm::Triple::bpfel:
// These are actually NYI, but that will be reported by emitBuiltinExpr.
// At this point, we don't even know that the builtin is target-specific.
return nullptr;
break;

case llvm::Triple::x86:
case llvm::Triple::x86_64:
Expand All @@ -1325,12 +1320,15 @@ static mlir::Value emitTargetArchBuiltinExpr(CIRGenFunction *cgf,
case llvm::Triple::hexagon:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
// These are actually NYI, but that will be reported by emitBuiltinExpr.
// At this point, we don't even know that the builtin is target-specific.
return {};
default:
return {};
break;
}

cgf->cgm.errorNYI(
e->getSourceRange(),
"target-specific builtin not implemented on this architecture: " +
cgf->getContext().BuiltinInfo.getName(builtinID));
return {};
}

mlir::Value
Expand Down
39 changes: 39 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@

#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/CIR/MissingFeatures.h"

using namespace clang;
using namespace clang::CIRGen;

/// Get integer from a mlir::Value that is an int constant or a constant op.
static int64_t getIntValueFromConstOp(mlir::Value val) {
return val.getDefiningOp<cir::ConstantOp>().getIntValue().getSExtValue();
}

template <typename... Operands>
static mlir::Value emitIntrinsicCallOp(CIRGenFunction &cgf, const CallExpr *e,
const std::string &str,
Expand Down Expand Up @@ -68,6 +74,33 @@ static mlir::Value emitVectorFCmp(CIRGenBuilderTy &builder,
return bitCast;
}

static mlir::Value emitPrefetch(CIRGenFunction &cgf, unsigned builtinID,
const CallExpr *e,
const llvm::SmallVector<mlir::Value> &ops) {

assert(builtinID == X86::BI_mm_prefetch || builtinID == X86::BI_m_prefetchw ||
builtinID == X86::BI_m_prefetch && "Expected prefetch builtin");
CIRGenBuilderTy &builder = cgf.getBuilder();
mlir::Location location = cgf.getLoc(e->getExprLoc());
mlir::Type voidTy = builder.getVoidTy();
mlir::Value addr = ops[0];
mlir::Value address = builder.createPtrBitcast(addr, voidTy);
bool isWrite{};
int locality{};

if (builtinID == X86::BI_mm_prefetch) {
int64_t hint = getIntValueFromConstOp(ops[1]);
isWrite = (hint >> 2) & 0x1;
locality = hint & 0x3;
} else {
isWrite = (builtinID == X86::BI_m_prefetchw);
locality = 0x3;
}

cir::PrefetchOp::create(builder, location, address, locality, isWrite);
return {};
}

mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
const CallExpr *expr) {
if (builtinID == Builtin::BI__builtin_cpu_is) {
Expand Down Expand Up @@ -108,6 +141,9 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,

switch (builtinID) {
default:
cgm.errorNYI(expr->getSourceRange(),
std::string("unimplemented X86 builtin call: ") +
getContext().BuiltinInfo.getName(builtinID));
return {};
case X86::BI_mm_clflush:
return emitIntrinsicCallOp(*this, expr, "x86.sse2.clflush", voidTy, ops[0]);
Expand All @@ -120,6 +156,9 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
case X86::BI_mm_sfence:
return emitIntrinsicCallOp(*this, expr, "x86.sse.sfence", voidTy);
case X86::BI_mm_prefetch:
case X86::BI_m_prefetch:
case X86::BI_m_prefetchw:
return emitPrefetch(*this, builtinID, expr, ops);
case X86::BI__rdtsc:
case X86::BI__builtin_ia32_rdtscp: {
cgm.errorNYI(expr->getSourceRange(),
Expand Down
35 changes: 35 additions & 0 deletions clang/test/CIR/CodeGen/X86/prefetchw-builtin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-cir -o %t.cir -Wall -Werror
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s

// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -fclangir -emit-llvm -o %t.ll -Wall -Werror
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s

// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG
// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +sse -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG


#include <x86intrin.h>

void test_m_prefetch_w(void *p) {
// CIR-LABEL: test_m_prefetch_w
// LLVM-LABEL: test_m_prefetch_w
// OGCG-LABEL: test_m_prefetch_w
return _m_prefetchw(p);
// CIR: cir.prefetch write locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
}

void test_m_prefetch(void *p) {
// CIR-LABEL: test_m_prefetch
// LLVM-LABEL: test_m_prefetch
// OGCG-LABEL: test_m_prefetch
return _m_prefetch(p);
// CIR: cir.prefetch read locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: 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)
}
28 changes: 28 additions & 0 deletions clang/test/CIR/CodeGen/X86/sse-builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,31 @@ __m128 test_mm_undefined_ps(void) {
// OGCG: ret <4 x float> zeroinitializer
return _mm_undefined_ps();
}

void test_mm_prefetch(char const* p) {
// CIR-LABEL: test_mm_prefetch
// LLVM-LABEL: test_mm_prefetch
_mm_prefetch(p, 0);
// CIR: cir.prefetch read locality(0) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 0, i32 0, i32 1)
}

void test_mm_prefetch_local(char const* p) {
// CIR-LABEL: test_mm_prefetch_local
// LLVM-LABEL: test_mm_prefetch_local
_mm_prefetch(p, 3);
// CIR: cir.prefetch read locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: 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)
}

void test_mm_prefetch_write(char const* p) {
// CIR-LABEL: test_mm_prefetch_write
// LLVM-LABEL: test_mm_prefetch_write
// OGCG-LABEL: test_mm_prefetch_write
_mm_prefetch(p, 7);
// CIR: cir.prefetch write locality(3) %{{.*}} : !cir.ptr<!void>
// LLVM: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
// OGCG: call void @llvm.prefetch.p0(ptr {{.*}}, i32 1, i32 3, i32 1)
}