Skip to content

[CIR] Upstream builtin lowering emitter & FAbs op #151750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
24 changes: 24 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -3199,4 +3199,28 @@ def CIR_ExpectOp : CIR_Op<"expect", [
}];
}

//===----------------------------------------------------------------------===//
// Floating Point Ops
//===----------------------------------------------------------------------===//

class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
{
let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src);
let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);

let assemblyFormat = "$src `:` type($src) attr-dict";

let llvmOp = llvmOpName;
}

def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
let summary = "Computes the floating-point absolute value";
let description = [{
`cir.fabs` computes the absolute value of a floating-point operand
and returns a result of the same type, ignoring floating-point
exceptions. It does not set `errno`.
}];
}

#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
4 changes: 4 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ mlir_tablegen(CIROpsAttributes.h.inc -gen-attrdef-decls)
mlir_tablegen(CIROpsAttributes.cpp.inc -gen-attrdef-defs)
add_public_tablegen_target(MLIRCIREnumsGen)

clang_tablegen(CIRBuiltinsLowering.inc -gen-cir-builtins-lowering
SOURCE CIROps.td
TARGET CIRBuiltinsLowering)

set(LLVM_TARGET_DEFINITIONS CIRTypeConstraints.td)
mlir_tablegen(CIRTypeConstraints.h.inc -gen-type-constraint-decls)
mlir_tablegen(CIRTypeConstraints.cpp.inc -gen-type-constraint-defs)
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) {
return RValue::get(r);
}

template <class Operation>
static RValue emitUnaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
const CallExpr &e) {
mlir::Value arg = cgf.emitScalarExpr(e.getArg(0));

assert(!cir::MissingFeatures::cgFPOptionsRAII());
assert(!cir::MissingFeatures::fpConstraints());

auto call =
Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(), arg);
return RValue::get(call->getResult(0));
}

RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
Expand Down Expand Up @@ -111,6 +124,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
default:
break;

case Builtin::BIfabs:
case Builtin::BIfabsf:
case Builtin::BIfabsl:
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:
case Builtin::BI__builtin_fabsf16:
case Builtin::BI__builtin_fabsl:
case Builtin::BI__builtin_fabsf128:
return emitUnaryMaybeConstrainedFPBuiltin<cir::FAbsOp>(*this, *e);

case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (e->getArg(0)->HasSideEffects(getContext()))
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2215,6 +2215,9 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecSplatOpLowering,
CIRToLLVMVecTernaryOpLowering
#define GET_BUILTIN_LOWERING_LIST
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
#undef GET_BUILTIN_LOWERING_LIST
// clang-format on
>(converter, patterns.getContext());

Expand Down Expand Up @@ -2792,6 +2795,10 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}

#define GET_BUILTIN_LOWERING_CLASSES_DEF
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
#undef GET_BUILTIN_LOWERING_CLASSES_DEF

std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@ class CIRToLLVMGetBitfieldOpLowering
mlir::ConversionPatternRewriter &) const override;
};

#define GET_BUILTIN_LOWERING_CLASSES_DECLARE
#include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc"
#undef GET_BUILTIN_LOWERING_CLASSES_DECLARE

} // namespace direct
} // namespace cir

Expand Down
14 changes: 14 additions & 0 deletions clang/test/CIR/CodeGen/builtins.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG

double fabs(double x) {
return __builtin_fabs(x);
}

// CIR: {{.*}} = cir.fabs {{.*}} : !cir.double
// LLVM: {{.*}} = call double @llvm.fabs.f64(double {{.*}})
// OGCG: {{.*}} = call double @llvm.fabs.f64(double {{.*}})
43 changes: 43 additions & 0 deletions clang/test/TableGen/emit-cir-builtins-lowering.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: clang-tblgen -gen-cir-builtins-lowering -I%S %s -o - 2>&1 | \
// RUN: FileCheck --strict-whitespace %s
// REQUIRES: clangir

def ins;
def outs;

class OpBase {
dag arguments = (ins);
dag results = (outs);
}

class LLVMLoweringInfo {
string llvmOp = "";
}

class CIR_Op : LLVMLoweringInfo, OpBase;

def CIR_FAbsOp : CIR_Op {
let arguments = (ins);
let results = (outs);

let llvmOp = "FAbsOp";
}

// CHECK: #ifdef GET_BUILTIN_LOWERING_CLASSES_DECLARE
// CHECK: class CIRFAbsOpLowering : public mlir::OpConversionPattern<cir::FAbsOp> {
// CHECK: public:
// CHECK: using OpConversionPattern<cir::FAbsOp>::OpConversionPattern;
// CHECK: mlir::LogicalResult
// CHECK: matchAndRewrite(cir::FAbsOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override;
// CHECK: };
// CHECK: #endif
// CHECK: #ifdef GET_BUILTIN_LOWERING_CLASSES_DEF
// CHECK: mlir::LogicalResult
// CHECK: CIRFAbsOpLowering::matchAndRewrite(cir::FAbsOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {
// CHECK: rewriter.replaceOpWithNewOp<mlir::LLVM::FAbsOp>(op);
// CHECK: return mlir::success();
// CHECK: }
// CHECK: #endif
// CHECK: #ifdef GET_BUILTIN_LOWERING_LIST
// CHECK: , CIRFAbsOpLowering
// CHECK: #endif
4 changes: 4 additions & 0 deletions clang/test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,7 @@ def calculate_arch_features(arch_string):
# possibly be present in system and user configuration files, so disable
# default configs for the test runs.
config.environment["CLANG_NO_DEFAULT_CONFIG"] = "1"

# Check if clangir is enabled.
if config.clang_enable_cir:
config.available_features.add("clangir")
108 changes: 108 additions & 0 deletions clang/utils/TableGen/CIRLoweringEmitter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//===- CIRLoweringEmitter.cpp - Generate lowering of builtins --=-*- C++ -*--=//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "TableGenBackends.h"
#include "llvm/TableGen/TableGenBackend.h"

using namespace llvm;

namespace {
std::string ClassDeclaration;
std::string ClassDefinitions;
std::string ClassList;

// Adapted from mlir/lib/TableGen/Operator.cpp
// Returns the C++ class name of the operation, which is the name of the
// operation with the dialect prefix removed and the first underscore removed.
// If the operation name starts with an underscore, the underscore is considered
// part of the class name.
std::string getCppClassName(const Record *Operation) {
StringRef Name = Operation->getName();
auto [prefix, cppClassName] = Name.split('_');
if (prefix.empty()) {
// Class name with a leading underscore and without dialect prefix
return Name.str();
}

if (cppClassName.empty()) {
// Class name without dialect prefix
return prefix.str();
}

return cppClassName.str();
}

void GenerateLowering(const Record *Operation) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a test for the tablegen handling in this file? There are some examples in clang/test/TableGen/ of clang-tablegen testing in general. What is the minimum .td file needed to make this work?

using namespace std::string_literals;
std::string Name = getCppClassName(Operation);
std::string LLVMOp = Operation->getValueAsString("llvmOp").str();

ClassDeclaration +=
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it even necessary to use tablegen for this? Could we not have a single CIRToLLVMUnaryFPToFPBuiltinOpLowering class that handled all the operations derived from UnaryFPToFPBuiltinOp in the same way using the llvmOp member?

Copy link
Member Author

Choose a reason for hiding this comment

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

It should be possiable yes, i will try it :D

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can't create lowering for the table gen class CIR_ UnaryFPToFPBuiltinOp, I will try to create an interface or see how it can be handled without using emitter 🤔

"class CIR" + Name +
"Lowering : public mlir::OpConversionPattern<cir::" + Name +
R"C++(> {
public:
using OpConversionPattern<cir::)C++" +
Name + R"C++(>::OpConversionPattern;

mlir::LogicalResult
matchAndRewrite(cir::)C++" +
Name +
" op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) "
"const "
"override;" +
R"C++(
};
)C++";

ClassDefinitions +=
R"C++(mlir::LogicalResult
CIR)C++" +
Name + "Lowering::matchAndRewrite(cir::" + Name +
R"C++( op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const {)C++";

auto ResultCount = Operation->getValueAsDag("results")->getNumArgs();
if (ResultCount > 0)
ClassDefinitions += R"C++(
auto resTy = this->getTypeConverter()->convertType(op.getType());)C++";

ClassDefinitions += R"C++(
rewriter.replaceOpWithNewOp<mlir::LLVM::)C++" +
LLVMOp + ">(op";

if (ResultCount > 0)
ClassDefinitions += ", resTy";

size_t ArgCount = Operation->getValueAsDag("arguments")->getNumArgs();
for (size_t i = 0; i != ArgCount; ++i)
ClassDefinitions += ", adaptor.getOperands()[" + std::to_string(i) + ']';

ClassDefinitions += R"C++();
return mlir::success();
}
)C++";

ClassList += ", CIR" + Name + "Lowering\n";
}
} // namespace

void clang::EmitCIRBuiltinsLowering(const RecordKeeper &Records,
raw_ostream &OS) {
emitSourceFileHeader("Lowering of ClangIR builtins to LLVM IR builtins", OS);
for (const auto *Builtin :
Records.getAllDerivedDefinitions("LLVMLoweringInfo")) {
if (!Builtin->getValueAsString("llvmOp").empty())
GenerateLowering(Builtin);
}

OS << "#ifdef GET_BUILTIN_LOWERING_CLASSES_DECLARE\n"
<< ClassDeclaration << "\n#endif\n";
OS << "#ifdef GET_BUILTIN_LOWERING_CLASSES_DEF\n"
<< ClassDefinitions << "\n#endif\n";
OS << "#ifdef GET_BUILTIN_LOWERING_LIST\n" << ClassList << "\n#endif\n";
}
1 change: 1 addition & 0 deletions clang/utils/TableGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_tablegen(clang-tblgen CLANG
DESTINATION "${CLANG_TOOLS_INSTALL_DIR}"
EXPORT Clang
ASTTableGen.cpp
CIRLoweringEmitter.cpp
ClangASTNodesEmitter.cpp
ClangASTPropertiesEmitter.cpp
ClangAttrEmitter.cpp
Expand Down
16 changes: 15 additions & 1 deletion clang/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "ASTTableGen.h"
#include "TableGenBackends.h" // Declares all backends.
#include "clang/Config/config.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
Expand All @@ -25,6 +26,9 @@ using namespace clang;
enum ActionType {
PrintRecords,
DumpJSON,
#if CLANG_ENABLE_CIR
GenCIRBuiltinsLowering,
Copy link
Contributor

Choose a reason for hiding this comment

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

All of the changes in this directory need to be guarded by a CLANG_ENABLE_CIR preprocessor check, and we'll need approval from the regular clang maintainers.

#endif // CLANG_ENABLE_CIR
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
GenClangAttrSubjectMatchRulesParserStringSwitches,
Expand Down Expand Up @@ -128,6 +132,11 @@ cl::opt<ActionType> Action(
"Print all records to stdout (default)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
#if CLANG_ENABLE_CIR
clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering",
"Generate lowering of ClangIR builtins to equivalent LLVM "
"IR builtins"),
#endif // CLANG_ENABLE_CIR
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
"Generate clang attribute clases"),
clEnumValN(GenClangAttrParserStringSwitches,
Expand Down Expand Up @@ -354,6 +363,11 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case DumpJSON:
EmitJSON(Records, OS);
break;
#if CLANG_ENABLE_CIR
case GenCIRBuiltinsLowering:
EmitCIRBuiltinsLowering(Records, OS);
break;
#endif // CLANG_ENABLE_CIR
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
Expand Down Expand Up @@ -639,7 +653,7 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {

return false;
}
}
} // namespace

int main(int argc, char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
Expand Down
3 changes: 3 additions & 0 deletions clang/utils/TableGen/TableGenBackends.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class RecordKeeper;

namespace clang {

void EmitCIRBuiltinsLowering(const llvm::RecordKeeper &RK,
llvm::raw_ostream &OS);

void EmitClangDeclContext(const llvm::RecordKeeper &RK, llvm::raw_ostream &OS);
/**
@param PriorizeIfSubclassOf These classes should be prioritized in the output.
Expand Down