-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesUpstreaming FAbsOp as a prerequisite for upstreaming ComplexDivOp Full diff: https://github.com/llvm/llvm-project/pull/151750.diff 10 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5ef5b60ed5a52..975a8d102d800 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3199,4 +3199,22 @@ 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 summary = "libc builtin equivalent ignoring "
+ "floating point exceptions and errno";
+ let assemblyFormat = "$src `:` type($src) attr-dict";
+
+ let llvmOp = llvmOpName;
+}
+
+def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp">;
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 6e7f3da4add3e..3a574b96340e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -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)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 9049a016b2b9b..201c119c1747f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -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 =
+ cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg);
+ return RValue::get(call->getResult(0));
+}
+
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
@@ -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()))
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 957a51ab334aa..8d18176be8218 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -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());
@@ -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>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index f339d4310ae0c..486a6b5daa563 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -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
diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp
new file mode 100644
index 0000000000000..3d43821af4e51
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtins.cpp
@@ -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 {{.*}})
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp
new file mode 100644
index 0000000000000..e494f38ef5b02
--- /dev/null
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -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) {
+ using namespace std::string_literals;
+ std::string Name = getCppClassName(Operation);
+ std::string LLVMOp = Operation->getValueAsString("llvmOp").str();
+
+ ClassDeclaration +=
+ "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";
+}
diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt
index ce759ec8548d9..14f13824e9575 100644
--- a/clang/utils/TableGen/CMakeLists.txt
+++ b/clang/utils/TableGen/CMakeLists.txt
@@ -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
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index 98c4a07a99c42..d4a383e801085 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -25,6 +25,7 @@ using namespace clang;
enum ActionType {
PrintRecords,
DumpJSON,
+ GenCIRBuiltinsLowering,
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
GenClangAttrSubjectMatchRulesParserStringSwitches,
@@ -128,6 +129,9 @@ cl::opt<ActionType> Action(
"Print all records to stdout (default)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
+ clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering",
+ "Generate lowering of ClangIR builtins to equivalent LLVM "
+ "IR builtins"),
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
"Generate clang attribute clases"),
clEnumValN(GenClangAttrParserStringSwitches,
@@ -354,6 +358,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case DumpJSON:
EmitJSON(Records, OS);
break;
+ case GenCIRBuiltinsLowering:
+ EmitCIRBuiltinsLowering(Records, OS);
+ break;
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index 79b1f66d0e49e..26d9e2c611898 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -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.
|
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesUpstreaming FAbsOp as a prerequisite for upstreaming ComplexDivOp Full diff: https://github.com/llvm/llvm-project/pull/151750.diff 10 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5ef5b60ed5a52..975a8d102d800 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3199,4 +3199,22 @@ 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 summary = "libc builtin equivalent ignoring "
+ "floating point exceptions and errno";
+ let assemblyFormat = "$src `:` type($src) attr-dict";
+
+ let llvmOp = llvmOpName;
+}
+
+def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp">;
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
index 6e7f3da4add3e..3a574b96340e7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
@@ -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)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 9049a016b2b9b..201c119c1747f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -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 =
+ cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg);
+ return RValue::get(call->getResult(0));
+}
+
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
@@ -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()))
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 957a51ab334aa..8d18176be8218 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -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());
@@ -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>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index f339d4310ae0c..486a6b5daa563 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -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
diff --git a/clang/test/CIR/CodeGen/builtins.cpp b/clang/test/CIR/CodeGen/builtins.cpp
new file mode 100644
index 0000000000000..3d43821af4e51
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtins.cpp
@@ -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 {{.*}})
diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp
new file mode 100644
index 0000000000000..e494f38ef5b02
--- /dev/null
+++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp
@@ -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) {
+ using namespace std::string_literals;
+ std::string Name = getCppClassName(Operation);
+ std::string LLVMOp = Operation->getValueAsString("llvmOp").str();
+
+ ClassDeclaration +=
+ "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";
+}
diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt
index ce759ec8548d9..14f13824e9575 100644
--- a/clang/utils/TableGen/CMakeLists.txt
+++ b/clang/utils/TableGen/CMakeLists.txt
@@ -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
diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp
index 98c4a07a99c42..d4a383e801085 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -25,6 +25,7 @@ using namespace clang;
enum ActionType {
PrintRecords,
DumpJSON,
+ GenCIRBuiltinsLowering,
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
GenClangAttrSubjectMatchRulesParserStringSwitches,
@@ -128,6 +129,9 @@ cl::opt<ActionType> Action(
"Print all records to stdout (default)"),
clEnumValN(DumpJSON, "dump-json",
"Dump all records as machine-readable JSON"),
+ clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering",
+ "Generate lowering of ClangIR builtins to equivalent LLVM "
+ "IR builtins"),
clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes",
"Generate clang attribute clases"),
clEnumValN(GenClangAttrParserStringSwitches,
@@ -354,6 +358,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) {
case DumpJSON:
EmitJSON(Records, OS);
break;
+ case GenCIRBuiltinsLowering:
+ EmitCIRBuiltinsLowering(Records, OS);
+ break;
case GenClangAttrClasses:
EmitClangAttrClass(Records, OS);
break;
diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h
index 79b1f66d0e49e..26d9e2c611898 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -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.
|
let summary = "libc builtin equivalent ignoring " | ||
"floating point exceptions and errno"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't really make sense to say that this is libc equivalent, when one of its primary characteristics is a difference from the libc function. Do we need a summary here at all? I'd prefer to see individual summaries on the operations that derive from this, even knowing that they will be very similar.
let llvmOp = llvmOpName; | ||
} | ||
|
||
def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to see a summary and description here. Something like:
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`.
}];
assert(!cir::MissingFeatures::fpConstraints()); | ||
|
||
auto call = | ||
cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cgf.getBuilder().create<Operation>(arg.getLoc(), arg.getType(), arg); | |
Operation::create(cgf.getBuilder(), (arg.getLoc(), arg.getType(), arg); |
return cppClassName.str(); | ||
} | ||
|
||
void GenerateLowering(const Record *Operation) { |
There was a problem hiding this comment.
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?
@@ -25,6 +25,7 @@ using namespace clang; | |||
enum ActionType { | |||
PrintRecords, | |||
DumpJSON, | |||
GenCIRBuiltinsLowering, |
There was a problem hiding this comment.
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.
std::string Name = getCppClassName(Operation); | ||
std::string LLVMOp = Operation->getValueAsString("llvmOp").str(); | ||
|
||
ClassDeclaration += |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 🤔
Upstreaming FAbsOp as a prerequisite for upstreaming ComplexDivOp