-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
[mlir] [Dialect] Add LibC dialect and printf op for CPU #92369
Conversation
@llvm/pr-subscribers-mlir Author: Menooker (Menooker) ChangesAdd a new dialect Full diff: https://github.com/llvm/llvm-project/pull/92369.diff 16 Files Affected:
diff --git a/mlir/include/mlir/Conversion/LibCToLLVM/LibCToLLVM.h b/mlir/include/mlir/Conversion/LibCToLLVM/LibCToLLVM.h
new file mode 100644
index 0000000000000..0776c2debe410
--- /dev/null
+++ b/mlir/include/mlir/Conversion/LibCToLLVM/LibCToLLVM.h
@@ -0,0 +1,27 @@
+//===- LibCToLLVM.h - Utils to convert from the libc dialect --------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef MLIR_CONVERSION_LIBCTOLLVM_LIBCTOLLVM_H_
+#define MLIR_CONVERSION_LIBCTOLLVM_LIBCTOLLVM_H_
+
+#include "mlir/IR/PatternMatch.h"
+
+namespace mlir {
+class LLVMTypeConverter;
+class RewritePatternSet;
+class Pass;
+#define GEN_PASS_DECL_CONVERTLIBCTOLLVMPASS
+#include "mlir/Conversion/Passes.h.inc"
+
+/// Populate the given list with patterns that convert from LibC to Func.
+void populateLibCToLLVMConversionPatterns(LLVMTypeConverter &converter,
+ RewritePatternSet &patterns);
+
+void registerConvertLibCToLLVMInterface(DialectRegistry ®istry);
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_LIBCTOLLVM_LIBCTOLLVM_H_
diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h
index 2179ae18ac074..b63be36f14abf 100644
--- a/mlir/include/mlir/Conversion/Passes.h
+++ b/mlir/include/mlir/Conversion/Passes.h
@@ -40,6 +40,7 @@
#include "mlir/Conversion/GPUToVulkan/ConvertGPUToVulkanPass.h"
#include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h"
#include "mlir/Conversion/IndexToSPIRV/IndexToSPIRV.h"
+#include "mlir/Conversion/LibCToLLVM/LibCToLLVM.h"
#include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h"
#include "mlir/Conversion/MathToFuncs/MathToFuncs.h"
#include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index e6d678dc1b12b..5244ba415878e 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -1356,4 +1356,17 @@ def ConvertVectorToSPIRV : Pass<"convert-vector-to-spirv"> {
let dependentDialects = ["spirv::SPIRVDialect"];
}
+
+//===----------------------------------------------------------------------===//
+// LibCToLLVM
+//===----------------------------------------------------------------------===//
+
+def ConvertLibCToLLVMPass: Pass<"convert-libc-to-llvm"> {
+ let summary = "Convert libc to LLVM dialect";
+ let description = [{
+ This pass converts supported libc ops to LLVM dialect ops.
+ }];
+ let dependentDialects = ["LLVM::LLVMDialect"];
+}
+
#endif // MLIR_CONVERSION_PASSES
diff --git a/mlir/include/mlir/Dialect/CMakeLists.txt b/mlir/include/mlir/Dialect/CMakeLists.txt
index 4bd7f12fabf7b..5589c47aa0809 100644
--- a/mlir/include/mlir/Dialect/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/CMakeLists.txt
@@ -15,6 +15,7 @@ add_subdirectory(Func)
add_subdirectory(GPU)
add_subdirectory(Index)
add_subdirectory(IRDL)
+add_subdirectory(LibC)
add_subdirectory(Linalg)
add_subdirectory(LLVMIR)
add_subdirectory(Math)
diff --git a/mlir/include/mlir/Dialect/LibC/CMakeLists.txt b/mlir/include/mlir/Dialect/LibC/CMakeLists.txt
new file mode 100644
index 0000000000000..80b2fea4aa50f
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LibC/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_mlir_dialect(LibC libc)
+add_mlir_doc(LibC LibC Dialects/ -gen-dialect-doc -dialect=libc)
\ No newline at end of file
diff --git a/mlir/include/mlir/Dialect/LibC/LibC.td b/mlir/include/mlir/Dialect/LibC/LibC.td
new file mode 100644
index 0000000000000..e27e813e5d52c
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LibC/LibC.td
@@ -0,0 +1,55 @@
+//===-- AMX.td - AMX dialect operation definitions *- tablegen -*----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the basic operations for the libc dialect.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_LIBC_LIBC
+#define MLIR_DIALECT_LIBC_LIBC
+
+include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
+include "mlir/Interfaces/SideEffectInterfaces.td"
+
+//===----------------------------------------------------------------------===//
+// LibC dialect definition.
+//===----------------------------------------------------------------------===//
+
+def LibC_Dialect : Dialect {
+ let name = "libc";
+ let cppNamespace = "::mlir::libc";
+ let description = [{
+ The dialect provides interfaces for the standard C library functions, to
+ enable users to call them in CPU environments if a valid standard C library
+ (like glibc) is linked. The dialect's ops are designed to be lowered to
+ function calls to the corresponding LibC functions.
+ }];
+}
+
+class LibC_Op<string mnemonic, list<Trait> traits = []> :
+ Op<LibC_Dialect, mnemonic, traits> {}
+
+def LibC_PrintfOp : LibC_Op<"printf", [MemoryEffects<[MemWrite]>]>,
+ Arguments<(ins StrAttr:$format,
+ Variadic<AnyTypeOf<[AnyInteger, Index, AnyFloat]>>:$args)> {
+ let summary = "C-style printf";
+ let description = [{
+ `cpuruntime.printf` takes a literal format string `format` and an arbitrary
+ number of scalar arguments that should be printed.
+
+ The format string is a C-style printf string, subject to any restrictions
+ imposed by the target platform.
+ }];
+ let assemblyFormat = [{
+ $format attr-dict ($args^ `:` type($args))?
+ }];
+}
+
+
+#endif // MLIR_DIALECT_LIBC_LIBC
diff --git a/mlir/include/mlir/Dialect/LibC/LibCDialect.h b/mlir/include/mlir/Dialect/LibC/LibCDialect.h
new file mode 100644
index 0000000000000..98baab3387dba
--- /dev/null
+++ b/mlir/include/mlir/Dialect/LibC/LibCDialect.h
@@ -0,0 +1,27 @@
+//===- LibCDialect.h - MLIR Dialect for LibC ---------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the dialect for LibC in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_LIBC_LIBCDIALECT_H_
+#define MLIR_DIALECT_LIBC_LIBCDIALECT_H_
+
+#include "mlir/Bytecode/BytecodeOpInterface.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+
+#include "mlir/Dialect/LibC/LibCDialect.h.inc"
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/LibC/LibC.h.inc"
+
+#endif // MLIR_DIALECT_LIBC_LIBCDIALECT_H_
diff --git a/mlir/include/mlir/InitAllDialects.h b/mlir/include/mlir/InitAllDialects.h
index d9db21073e15c..da36d9f9aa057 100644
--- a/mlir/include/mlir/InitAllDialects.h
+++ b/mlir/include/mlir/InitAllDialects.h
@@ -43,6 +43,7 @@
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/LLVMIR/NVVMDialect.h"
#include "mlir/Dialect/LLVMIR/ROCDLDialect.h"
+#include "mlir/Dialect/LibC/LibCDialect.h"
#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/Linalg/Transforms/AllInterfaces.h"
#include "mlir/Dialect/Linalg/Transforms/RuntimeOpVerification.h"
@@ -121,6 +122,7 @@ inline void registerAllDialects(DialectRegistry ®istry) {
gpu::GPUDialect,
index::IndexDialect,
irdl::IRDLDialect,
+ libc::LibCDialect,
linalg::LinalgDialect,
LLVM::LLVMDialect,
math::MathDialect,
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index 41ab7046b91ce..66178b122745e 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -29,6 +29,7 @@ add_subdirectory(GPUToSPIRV)
add_subdirectory(GPUToVulkan)
add_subdirectory(IndexToLLVM)
add_subdirectory(IndexToSPIRV)
+add_subdirectory(LibCToLLVM)
add_subdirectory(LinalgToStandard)
add_subdirectory(LLVMCommon)
add_subdirectory(MathToFuncs)
diff --git a/mlir/lib/Conversion/LibCToLLVM/CMakeLists.txt b/mlir/lib/Conversion/LibCToLLVM/CMakeLists.txt
new file mode 100644
index 0000000000000..f73506a22211a
--- /dev/null
+++ b/mlir/lib/Conversion/LibCToLLVM/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_mlir_conversion_library(MLIRLibCToLLVM
+ LibCToLLVM.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/LibCToLLVM
+
+ DEPENDS
+ MLIRConversionPassIncGen
+
+ LINK_COMPONENTS
+ Core
+
+ LINK_LIBS PUBLIC
+ MLIRLLVMCommonConversion
+ MLIRLLVMDialect
+ MLIRLibCDialect
+ MLIRPass
+ )
diff --git a/mlir/lib/Conversion/LibCToLLVM/LibCToLLVM.cpp b/mlir/lib/Conversion/LibCToLLVM/LibCToLLVM.cpp
new file mode 100644
index 0000000000000..29fd57e1653cd
--- /dev/null
+++ b/mlir/lib/Conversion/LibCToLLVM/LibCToLLVM.cpp
@@ -0,0 +1,155 @@
+//===-- LibCToLLVM.cpp - conversion from LibC to Func calls ---------------===//
+//
+// 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 "mlir/Conversion/LibCToLLVM/LibCToLLVM.h"
+#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
+#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
+#include "mlir/Conversion/LLVMCommon/Pattern.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LibC/LibCDialect.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/TypeUtilities.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Rewrite/FrozenRewritePatternSet.h"
+#include "mlir/Support/LogicalResult.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+
+namespace mlir {
+
+void populateLibCToLLVMConversionPatterns(LLVMTypeConverter &converter,
+ RewritePatternSet &patterns);
+
+#define GEN_PASS_DEF_CONVERTLIBCTOLLVMPASS
+#include "mlir/Conversion/Passes.h.inc"
+
+namespace {
+static const char formatStringPrefix[] = "cpuprintfFormat_";
+
+static LLVM::LLVMFuncOp getOrDefineFunction(ModuleOp &moduleOp,
+ const Location loc,
+ ConversionPatternRewriter &rewriter,
+ StringRef name,
+ LLVM::LLVMFunctionType type) {
+ LLVM::LLVMFuncOp ret;
+ if (!(ret = moduleOp.template lookupSymbol<LLVM::LLVMFuncOp>(name))) {
+ ConversionPatternRewriter::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPointToStart(moduleOp.getBody());
+ ret = rewriter.create<LLVM::LLVMFuncOp>(loc, name, type,
+ LLVM::Linkage::External);
+ }
+ return ret;
+}
+
+class PrintfRewriter : public ConvertOpToLLVMPattern<libc::PrintfOp> {
+public:
+ using ConvertOpToLLVMPattern<libc::PrintfOp>::ConvertOpToLLVMPattern;
+ LogicalResult
+ matchAndRewrite(libc::PrintfOp op, libc::PrintfOpAdaptor adaptor,
+ ConversionPatternRewriter &rewriter) const final {
+ auto moduleOp = op->getParentOfType<ModuleOp>();
+ auto loc = op->getLoc();
+ mlir::Type llvmI32 = typeConverter->convertType(rewriter.getI32Type());
+ mlir::Type llvmI64 = typeConverter->convertType(rewriter.getI64Type());
+ mlir::Type llvmI8 = typeConverter->convertType(rewriter.getI8Type());
+ mlir::Type i8Ptr = LLVM::LLVMPointerType::get(op.getContext());
+ auto printfFunc = getOrDefineFunction(
+ moduleOp, loc, rewriter, "printf",
+ LLVM::LLVMFunctionType::get(llvmI32, {i8Ptr}, /*isVarArg*/ true));
+
+ unsigned stringNumber = 0;
+ SmallString<16> stringConstName;
+ do {
+ stringConstName.clear();
+ (formatStringPrefix + Twine(stringNumber++)).toStringRef(stringConstName);
+ } while (moduleOp.lookupSymbol(stringConstName));
+
+ llvm::SmallString<20> formatString(adaptor.getFormat());
+ formatString.push_back('\0'); // Null terminate for C
+ size_t formatStringSize = formatString.size_in_bytes();
+
+ auto globalType = LLVM::LLVMArrayType::get(llvmI8, formatStringSize);
+ LLVM::GlobalOp global;
+ {
+ ConversionPatternRewriter::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPointToStart(moduleOp.getBody());
+ global = rewriter.create<LLVM::GlobalOp>(
+ loc, globalType,
+ /*isConstant=*/true, LLVM::Linkage::Internal, stringConstName,
+ rewriter.getStringAttr(formatString));
+ }
+ Value globalPtr = rewriter.create<LLVM::AddressOfOp>(
+ loc,
+ LLVM::LLVMPointerType::get(rewriter.getContext(),
+ global.getAddrSpace()),
+ global.getSymNameAttr());
+ Value stringStart = rewriter.create<LLVM::GEPOp>(
+ loc, i8Ptr, globalType, globalPtr, ArrayRef<LLVM::GEPArg>{0, 0});
+ SmallVector<Value, 5> appendFormatArgs = {stringStart};
+ for (auto arg : adaptor.getArgs()) {
+ if (auto floatType = dyn_cast<FloatType>(arg.getType())) {
+ if (!floatType.isF64())
+ arg = rewriter.create<LLVM::FPExtOp>(
+ loc, typeConverter->convertType(rewriter.getF64Type()), arg);
+ }
+ if (arg.getType().getIntOrFloatBitWidth() != 64)
+ arg = rewriter.create<LLVM::ZExtOp>(loc, llvmI64, arg);
+ appendFormatArgs.push_back(arg);
+ }
+ rewriter.create<LLVM::CallOp>(loc, printfFunc, appendFormatArgs);
+ rewriter.eraseOp(op);
+ return success();
+ }
+};
+
+class ConvertLibCToLLVMPass
+ : public impl::ConvertLibCToLLVMPassBase<ConvertLibCToLLVMPass> {
+public:
+ using Base::Base;
+ void runOnOperation() final {
+ LLVMConversionTarget target(getContext());
+ RewritePatternSet patterns(&getContext());
+ LowerToLLVMOptions options(&getContext());
+ LLVMTypeConverter converter(&getContext(), options);
+ populateLibCToLLVMConversionPatterns(converter, patterns);
+
+ if (failed(applyPartialConversion(getOperation(), target,
+ std::move(patterns))))
+ signalPassFailure();
+ }
+};
+
+/// Implement the interface to convert MemRef to LLVM.
+struct ConvertLibCToDialectInterface : public ConvertToLLVMPatternInterface {
+ using ConvertToLLVMPatternInterface::ConvertToLLVMPatternInterface;
+ void loadDependentDialects(MLIRContext *context) const final {
+ context->loadDialect<LLVM::LLVMDialect>();
+ }
+
+ /// Hook for derived dialect interface to provide conversion patterns
+ /// and mark dialect legal for the conversion target.
+ void populateConvertToLLVMConversionPatterns(
+ ConversionTarget &target, LLVMTypeConverter &typeConverter,
+ RewritePatternSet &patterns) const final {
+ populateLibCToLLVMConversionPatterns(typeConverter, patterns);
+ }
+};
+
+} // namespace
+
+void populateLibCToLLVMConversionPatterns(LLVMTypeConverter &converter,
+ RewritePatternSet &patterns) {
+ patterns.add<PrintfRewriter>(converter);
+}
+
+void registerConvertLibCToLLVMInterface(DialectRegistry ®istry) {
+ registry.addExtension(+[](MLIRContext *ctx, libc::LibCDialect *dialect) {
+ dialect->addInterfaces<ConvertLibCToDialectInterface>();
+ });
+}
+
+} // namespace mlir
diff --git a/mlir/lib/Dialect/CMakeLists.txt b/mlir/lib/Dialect/CMakeLists.txt
index a324ce7f9b19f..684bbb485f877 100644
--- a/mlir/lib/Dialect/CMakeLists.txt
+++ b/mlir/lib/Dialect/CMakeLists.txt
@@ -15,6 +15,7 @@ add_subdirectory(Func)
add_subdirectory(GPU)
add_subdirectory(Index)
add_subdirectory(IRDL)
+add_subdirectory(LibC)
add_subdirectory(Linalg)
add_subdirectory(LLVMIR)
add_subdirectory(Math)
diff --git a/mlir/lib/Dialect/LibC/CMakeLists.txt b/mlir/lib/Dialect/LibC/CMakeLists.txt
new file mode 100644
index 0000000000000..faefaba7e05cb
--- /dev/null
+++ b/mlir/lib/Dialect/LibC/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_mlir_dialect_library(MLIRLibCDialect
+ LibCDialect.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/LibC
+
+ DEPENDS
+ MLIRLibCIncGen
+
+ LINK_LIBS PUBLIC
+ MLIRIR
+ MLIRFuncDialect
+ MLIRSideEffectInterfaces
+ )
diff --git a/mlir/lib/Dialect/LibC/LibCDialect.cpp b/mlir/lib/Dialect/LibC/LibCDialect.cpp
new file mode 100644
index 0000000000000..7b6a710398879
--- /dev/null
+++ b/mlir/lib/Dialect/LibC/LibCDialect.cpp
@@ -0,0 +1,31 @@
+//===- LibCDialect.cpp - MLIR LibC ops implementation -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the LibC dialect and its operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/LibC/LibCDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/OpImplementation.h"
+#include "mlir/IR/TypeUtilities.h"
+
+using namespace mlir;
+
+#include "mlir/Dialect/LibC/LibCDialect.cpp.inc"
+
+void libc::LibCDialect::initialize() {
+ addOperations<
+#define GET_OP_LIST
+#include "mlir/Dialect/LibC/LibC.cpp.inc"
+ >();
+}
+
+#define GET_OP_CLASSES
+#include "mlir/Dialect/LibC/LibC.cpp.inc"
diff --git a/mlir/test/Conversion/LibCToLLVM/printf-run.mlir b/mlir/test/Conversion/LibCToLLVM/printf-run.mlir
new file mode 100644
index 0000000000000..0b93558f39bf0
--- /dev/null
+++ b/mlir/test/Conversion/LibCToLLVM/printf-run.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt %s --convert-libc-to-llvm --convert-func-to-llvm --convert-arith-to-llvm --convert-cf-to-llvm | mlir-cpu-runner -e main -entry-point-result=void -shared-libs=%mlir_runner_utils,%mlir_c_runner_utils | FileCheck %s
+
+module {
+ func.func @doprint(%t: f32, %t2: i32, %t3: i64) {
+ libc.printf "Hello world %f %d %lld\n" %t, %t2, %t3 : f32, i32, i64
+ return
+ }
+
+ func.func @main() {
+ %c2 = arith.constant 2.0 : f32
+ %c32i = arith.constant 2000000 : i32
+ %c64i = arith.constant 2000000 : i64
+ call @doprint(%c2, %c32i, %c64i) : (f32, i32, i64) -> ()
+ return
+ }
+ // CHECK: Hello world 2.000000 2000000 2000000
+}
\ No newline at end of file
diff --git a/mlir/test/Conversion/LibCToLLVM/printf-to-mlir.mlir b/mlir/test/Conversion/LibCToLLVM/printf-to-mlir.mlir
new file mode 100644
index 0000000000000..67cb2444849a0
--- /dev/null
+++ b/mlir/test/Conversion/LibCToLLVM/printf-to-mlir.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-opt %s --convert-libc-to-llvm | FileCheck %s
+
+module {
+ // CHECK: llvm.mlir.global internal constant @cpuprintfFormat_0("Hello world %f %d %lld\0A\00") {addr_space = 0 : i32}
+ // CHECK: llvm.func @printf(!llvm.ptr,
+ // CHECK-NEXT: func.func @doprint(%[[ARG0:.*]]: f32, %[[ARG1:.*]]: i32, %[[ARG2:.*]]: i64)
+ func.func @doprint(%t: f32, %t2: i32, %t3: i64) {
+ // CHECK-NEXT: llvm.mlir.addressof
+ // CHECK-DAG: %[[C1:.*]] = llvm.getelementptr
+ // CHECK-SAME: !llvm.ptr, !llvm.array<24 x i8>
+ // CHECK: %[[C2:.*]] = llvm.fpext %[[ARG0]]
+ // CHECK: %[[C3:.*]] = llvm.zext %[[ARG1]]
+ // CHECK-NOT: libc.printf
+ // CHECK-NEXT: llvm.call @printf(%[[C1]], %[[C2]], %[[C3]], %[[ARG2]])
+ libc.printf "Hello world %f %d %lld\n" %t, %t2, %t3 : f32, i32, i64
+ return
+ }
+
+}
\ No newline at end of file
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Maybe we can remove the some of the uses of |
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.
FWIW, we already have some printing primitives.
I don't mind adding printf
, but adding a whole dialect just for this opens a dialect discussion that is far wider than this one function.
- Can we add this to the existing primitives?
- Do we need a whole
libc
dialect? Perhaps c++ too? - Will this help Clang with CIL? Do they already have something like this?
I'd suggest you try the easy route with the current primitives and see what that gets you.
Some nits on the code. Also, your tests are not enough. You need to cover the functionality you add, including the error messages that you expect to get on a negative test.
@@ -0,0 +1,55 @@ | |||
//===-- AMX.td - AMX dialect operation definitions *- tablegen -*----------===// |
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.
Typo
Variadic<AnyTypeOf<[AnyInteger, Index, AnyFloat]>>:$args)> { | ||
let summary = "C-style printf"; | ||
let description = [{ | ||
`cpuruntime.printf` takes a literal format string `format` and an arbitrary |
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.
`cpuruntime.printf` takes a literal format string `format` and an arbitrary | |
`libc.printf` takes a literal format string `format` and an arbitrary |
Thanks for @rengolin for the view!
What I would like to do is to add the functionality of printing values in MLIR. It would be very helpful when debugging and writing tests, since users can print arithmetic values any where in the MLIR code. Also developers can use filecheck on the outputs by printf. The printing primitives you mentioned does not support formatting and need to declare the functions before using, which is not easy to use in IR.
Other interesting features in libc I know will be the ability of C++ has complex ABI issues and many of its useful features are based on templates. I don't think we need
I totally understand that it is overkill to add a dialect for a single Op. My original proposal is to add an printf op for CPU. I have found an After more searching, I found that in
Thanks for pointing out! I am an MLIR beginner here. Will improve them! :) |
Indeed, we had the same problem in the past, but decided to print tensors/memrefs as vectors.
We have added "runner" functionality in local dialects (check, perf), but never quite found the place to put them. I think there's a common trend between all these little functions and it's not
Right, I was using it to show how quickly this can escalate if we chose a tangent path. :) I do like the idea of improving the ability to print stuff in MLIR, but just a printf wrapper is too much for a new dialect. Right now, you can already lower your formatted printf into LLVM dialect call, so this should be enough for just basic printf. On the rest of the "runtime dialect", I think an RFC is in order to make sure we converge to a common design. I'd love to find a home for our |
Thanks for the contribution! Please have a look at https://mlir.llvm.org/getting_started/DeveloperGuide/#guidelines-on-contributing-a-new-dialect-or-important-components and conduct a discussion on Discourse for contributing a new dialect. |
Thanks for reminder. I have posted an RFC. We can move to that for discussion on the new dialect. |
Add a new dialect
LibC
to expose some useful features from CPU's standard C library. Currently, onlyprintf
is added.printf
is particularly useful in debugging and testing. There is agpu.printf
op, but it is missing on CPU.RFC discussion at https://discourse.llvm.org/t/rfc-new-dialect-to-expose-handy-utilities/79041