diff --git a/CMakeLists.txt b/CMakeLists.txt index 37fde36ca95b..e69de29bb2d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,110 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -include(CheckCXXSourceCompiles) - -set(POLYGEIST_ENABLE_CUDA 0 CACHE BOOL "Enable CUDA compilation support") - -if(POLICY CMP0068) - cmake_policy(SET CMP0068 NEW) - set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) -endif() - -if(POLICY CMP0075) - cmake_policy(SET CMP0075 NEW) -endif() - -if(POLICY CMP0077) - cmake_policy(SET CMP0077 NEW) -endif() - -option(LLVM_INCLUDE_TOOLS "Generate build targets for the LLVM tools." ON) -option(LLVM_BUILD_TOOLS "Build the LLVM tools. If OFF, just generate build targets." ON) - -set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) -set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) - -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - project(polygeist LANGUAGES CXX C) - - set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") - - message(STATUS "Searching for MLIRConfig.cmake in: ${MLIR_DIR}") - find_package(MLIR REQUIRED CONFIG) - - set(Clang_DIR ${CLANG_DIR}) - message(STATUS "Searching for ClangConfig.cmake in: ${Clang_DIR}") - find_package(Clang REQUIRED CONFIG) - - # This is exported if we are building against a build area. If - # building against an install area, then assume we're using the - # submodule. - if(NOT LLVM_BUILD_MAIN_SRC_DIR) - set(LLVM_BUILD_MAIN_SRC_DIR ${CMAKE_SOURCE_DIR}/llvm-project/llvm) - endif() - set(LLVM_SOURCE_DIR ${LLVM_BUILD_MAIN_SRC_DIR} CACHE STRING "Location of LLVM source") - - message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - message(STATUS "Using ClangConfig.cmake in: ${CLANG_DIR}") -else () - set(LLVM_SOURCE_DIR ${LLVM_MAIN_SRC_DIR}) - set(MLIR_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../mlir) - set(MLIR_INCLUDE_DIRS ${MLIR_MAIN_SRC_DIR}/include) - set(MLIR_CMAKE_DIR ${MLIR_MAIN_SRC_DIR}/cmake/modules) - set(MLIR_TABLEGEN_EXE $) - set(MLIR_TABLEGEN_OUTPUT_DIR ${LLVM_BINARY_DIR}/tools/mlir/include) - set(PROJECT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - set(POLYGEIST_TABLEGEN_OUTPUT_DIR ${LLVM_BINARY_DIR}/tools/polygeist/include) - include_directories(${MLIR_TABLEGEN_OUTPUT_DIR}) - include_directories(${POLYGEIST_TABLEGEN_OUTPUT_DIR}) -endif() - -function(append value) - foreach(variable ${ARGN}) - set(${variable} "${${variable}} ${value}" PARENT_SCOPE) - endforeach(variable) -endfunction() - -if( POLYGEIST_USE_LINKER ) - append("-fuse-ld=${POLYGEIST_USE_LINKER}" - CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) - check_cxx_source_compiles("int main() { return 0; }" CXX_SUPPORTS_CUSTOM_LINKER) - if ( NOT CXX_SUPPORTS_CUSTOM_LINKER ) - message(FATAL_ERROR "Host compiler does not support '-fuse-ld=${LLVM_USE_LINKER}'") - endif() -endif() - -list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") -list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") -list(APPEND CMAKE_MODULE_PATH "${CLANG_CMAKE_DIR}") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") -include(TableGen) -include(AddLLVM) -include(AddMLIR) -include(AddClang) -include(HandleLLVMOptions) - -set(POLYGEIST_TOOLS_DIR ${CMAKE_BINARY_DIR}) - -include_directories(${LLVM_INCLUDE_DIRS}) -include_directories(${CLANG_INCLUDE_DIRS}) -include_directories(${MLIR_INCLUDE_DIRS}) -include_directories(${PROJECT_SOURCE_DIR}/include) -include_directories(${PROJECT_BINARY_DIR}/include) -link_directories(${LLVM_BUILD_LIBRARY_DIR}) -add_definitions(${LLVM_DEFINITIONS}) - -set(POLYGEIST_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(POLYGEIST_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(POLYGEIST_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include ) -set(POLYGEIST_TOOLS_DIR ${CMAKE_BINARY_DIR}/bin) -set(POLYGEIST_UTILS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/utils) - -set(LLVM_LIT_ARGS "-sv" CACHE STRING "lit default options") -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") -include(sanitizers) - -add_subdirectory(include) -add_subdirectory(lib) -add_subdirectory(tools) -add_subdirectory(test) diff --git a/include/sql/CMakeLists.txt b/include/sql/CMakeLists.txt index 5de01d8b95a8..8764d8eddbb4 100644 --- a/include/sql/CMakeLists.txt +++ b/include/sql/CMakeLists.txt @@ -1,3 +1,5 @@ add_mlir_dialect(SQLOps sql) # add_mlir_doc(SQLDialect -gen-dialect-doc SQLDialect SQL/) # add_mlir_doc(SQLOps -gen-op-doc SQLOps SQL/) + +add_subdirectory(Passes) \ No newline at end of file diff --git a/include/sql/Passes/CMakeLists.txt b/include/sql/Passes/CMakeLists.txt new file mode 100644 index 000000000000..298ddabf48f7 --- /dev/null +++ b/include/sql/Passes/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name sql) +add_public_tablegen_target(MLIRSQLPassIncGen) + +add_mlir_doc(Passes SQLPasses ./ -gen-pass-doc) diff --git a/include/sql/Passes/Passes.h b/include/sql/Passes/Passes.h new file mode 100644 index 000000000000..3c0861eeab4e --- /dev/null +++ b/include/sql/Passes/Passes.h @@ -0,0 +1,48 @@ +#ifndef SQL_DIALECT_SQL_PASSES_H +#define SQL_DIALECT_SQL_PASSES_H + +#include "mlir/Conversion/LLVMCommon/LoweringOptions.h" +#include "mlir/Pass/Pass.h" +#include +namespace mlir { +class PatternRewriter; +class RewritePatternSet; +class DominanceInfo; +namespace sql { + +std::unique_ptr createParallelLowerPass(); +} // namespace sql +} // namespace mlir + +namespace mlir { +// Forward declaration from Dialect.h +template +void registerDialect(DialectRegistry ®istry); + +namespace arith { +class ArithDialect; +} // end namespace arith + +namespace scf { +class SCFDialect; +} // end namespace scf + +namespace memref { +class MemRefDialect; +} // end namespace memref + +namespace func { +class FuncDialect; +} + +class AffineDialect; +namespace LLVM { +class LLVMDialect; +} + +#define GEN_PASS_REGISTRATION +#include "sql/Passes/Passes.h.inc" + +} // end namespace mlir + +#endif // SQL_DIALECT_SQL_PASSES_H diff --git a/include/sql/Passes/Passes.td b/include/sql/Passes/Passes.td new file mode 100644 index 000000000000..36faaab4a52f --- /dev/null +++ b/include/sql/Passes/Passes.td @@ -0,0 +1,14 @@ +#ifndef SQL_PASSES +#define SQL_PASSES + +include "mlir/Pass/PassBase.td" + + +def ParallelLower : Pass<"sql-lower", "mlir::ModuleOp"> { + let summary = "Lower sql op to mlir"; + let dependentDialects = + ["arith::AirthDialect", "func::FuncDialect", "LLVM::LLVMDialect"]; + let constructor = "mlir::sql::createSQLLowerPass()"; +} + +#endif // SQL_PASSES diff --git a/include/sql/Passes/Utils.h b/include/sql/Passes/Utils.h new file mode 100644 index 000000000000..b191d89ba6a6 --- /dev/null +++ b/include/sql/Passes/Utils.h @@ -0,0 +1,139 @@ +#pragma once + +#include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/SCF/IR/SCF.h" +#include "mlir/IR/BlockAndValueMapping.h" +#include "mlir/IR/IntegerSet.h" + +static inline mlir::scf::IfOp +cloneWithResults(mlir::scf::IfOp op, mlir::OpBuilder &rewriter, + mlir::BlockAndValueMapping mapping = {}) { + using namespace mlir; + return rewriter.create(op.getLoc(), op.getResultTypes(), + mapping.lookupOrDefault(op.getCondition()), + true); +} +static inline mlir::AffineIfOp +cloneWithResults(mlir::AffineIfOp op, mlir::OpBuilder &rewriter, + mlir::BlockAndValueMapping mapping = {}) { + using namespace mlir; + SmallVector lower; + for (auto o : op.getOperands()) + lower.push_back(mapping.lookupOrDefault(o)); + return rewriter.create(op.getLoc(), op.getResultTypes(), + op.getIntegerSet(), lower, true); +} + +static inline mlir::scf::IfOp +cloneWithoutResults(mlir::scf::IfOp op, mlir::OpBuilder &rewriter, + mlir::BlockAndValueMapping mapping = {}, + mlir::TypeRange types = {}) { + using namespace mlir; + return rewriter.create( + op.getLoc(), types, mapping.lookupOrDefault(op.getCondition()), true); +} +static inline mlir::AffineIfOp +cloneWithoutResults(mlir::AffineIfOp op, mlir::OpBuilder &rewriter, + mlir::BlockAndValueMapping mapping = {}, + mlir::TypeRange types = {}) { + using namespace mlir; + SmallVector lower; + for (auto o : op.getOperands()) + lower.push_back(mapping.lookupOrDefault(o)); + return rewriter.create(op.getLoc(), types, op.getIntegerSet(), + lower, true); +} + +static inline mlir::scf::ForOp +cloneWithoutResults(mlir::scf::ForOp op, mlir::PatternRewriter &rewriter, + mlir::BlockAndValueMapping mapping = {}) { + using namespace mlir; + return rewriter.create( + op.getLoc(), mapping.lookupOrDefault(op.getLowerBound()), + mapping.lookupOrDefault(op.getUpperBound()), + mapping.lookupOrDefault(op.getStep())); +} +static inline mlir::AffineForOp +cloneWithoutResults(mlir::AffineForOp op, mlir::PatternRewriter &rewriter, + mlir::BlockAndValueMapping mapping = {}) { + using namespace mlir; + SmallVector lower; + for (auto o : op.getLowerBoundOperands()) + lower.push_back(mapping.lookupOrDefault(o)); + SmallVector upper; + for (auto o : op.getUpperBoundOperands()) + upper.push_back(mapping.lookupOrDefault(o)); + return rewriter.create(op.getLoc(), lower, op.getLowerBoundMap(), + upper, op.getUpperBoundMap(), + op.getStep()); +} + +static inline void clearBlock(mlir::Block *block, + mlir::PatternRewriter &rewriter) { + for (auto &op : llvm::make_early_inc_range(llvm::reverse(*block))) { + assert(op.use_empty() && "expected 'op' to have no uses"); + rewriter.eraseOp(&op); + } +} + +static inline mlir::Block *getThenBlock(mlir::scf::IfOp op) { + return op.thenBlock(); +} +static inline mlir::Block *getThenBlock(mlir::AffineIfOp op) { + return op.getThenBlock(); +} +static inline mlir::Block *getElseBlock(mlir::scf::IfOp op) { + return op.elseBlock(); +} +static inline mlir::Block *getElseBlock(mlir::AffineIfOp op) { + if (op.hasElse()) + return op.getElseBlock(); + else + return nullptr; +} + +static inline mlir::Region &getThenRegion(mlir::scf::IfOp op) { + return op.getThenRegion(); +} +static inline mlir::Region &getThenRegion(mlir::AffineIfOp op) { + return op.getThenRegion(); +} +static inline mlir::Region &getElseRegion(mlir::scf::IfOp op) { + return op.getElseRegion(); +} +static inline mlir::Region &getElseRegion(mlir::AffineIfOp op) { + return op.getElseRegion(); +} + +static inline mlir::scf::YieldOp getThenYield(mlir::scf::IfOp op) { + return op.thenYield(); +} +static inline mlir::AffineYieldOp getThenYield(mlir::AffineIfOp op) { + return llvm::cast(op.getThenBlock()->getTerminator()); +} +static inline mlir::scf::YieldOp getElseYield(mlir::scf::IfOp op) { + return op.elseYield(); +} +static inline mlir::AffineYieldOp getElseYield(mlir::AffineIfOp op) { + return llvm::cast(op.getElseBlock()->getTerminator()); +} + +static inline bool inBound(mlir::scf::IfOp op, mlir::Value v) { + return op.getCondition() == v; +} +static inline bool inBound(mlir::AffineIfOp op, mlir::Value v) { + return llvm::any_of(op.getOperands(), [&](mlir::Value e) { return e == v; }); +} +static inline bool inBound(mlir::scf::ForOp op, mlir::Value v) { + return op.getUpperBound() == v; +} +static inline bool inBound(mlir::AffineForOp op, mlir::Value v) { + return llvm::any_of(op.getUpperBoundOperands(), + [&](mlir::Value e) { return e == v; }); +} +static inline bool hasElse(mlir::scf::IfOp op) { + return op.getElseRegion().getBlocks().size() > 0; +} +static inline bool hasElse(mlir::AffineIfOp op) { + return op.getElseRegion().getBlocks().size() > 0; +} diff --git a/lib/sql/Passes/CMakeLists.txt b/lib/sql/Passes/CMakeLists.txt new file mode 100644 index 000000000000..e2b4f46f658f --- /dev/null +++ b/lib/sql/Passes/CMakeLists.txt @@ -0,0 +1,17 @@ +add_mlir_dialect_library(MLIRSQLTransforms + SQLLower.cpp + + DEPENDS + MLIRPolygeistOpsIncGen + MLIRPolygeistPassIncGen + + LINK_LIBS PUBLIC + MLIRArithDialect + MLIRFuncDialect + MLIRFuncTransforms + MLIRIR + MLIRLLVMDialect + MLIRMathDialect + MLIRMemRefDialect + MLIRPass + ) \ No newline at end of file diff --git a/lib/sql/Passes/SQLLower.cpp b/lib/sql/Passes/SQLLower.cpp new file mode 100644 index 000000000000..d639cdf32424 --- /dev/null +++ b/lib/sql/Passes/SQLLower.cpp @@ -0,0 +1,118 @@ +//===- SQLLower.cpp - Lower gpu code to triple nested loops ------ -*-===// +// +// 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 a pass to lower gpu kernels in NVVM/gpu dialects into +// a generic SQL for representation +//===----------------------------------------------------------------------===// + +#include "PassDetails.h" +#include "mlir/Analysis/CallGraph.h" +#include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/Dialect/Async/IR/Async.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/NVVMDialect.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "mlir/Transforms/Passes.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include +#include + +#define DEBUG_TYPE "sql-opt" + +using namespace mlir; +using namespace mlir::arith; +using namespace mlir::func; +using namespace sql; + +namespace { +struct SQLLower : public SQLLowerBase { + void runOnOperation() override; +}; + +} // end anonymous namespace + +struct NumResultsOpLowering : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + + LogicalResult matchAndRewrite(sql::NumResultsOp loop, + PatternRewriter &rewriter) const final { + auto module = loop->getParentOfType(); + + // 1) make sure the postgres_getresult function is declared + auto rowsfn = dyn_cast_or_null(symbolTable.lookupSymbolIn( + module, builder.getStringAttr("PQcmdTuples"))); + + auto atoifn = dyn_cast_or_null(symbolTable.lookupSymbolIn( + module, builder.getStringAttr("atoi"))); + + // 2) convert the args to valid args to postgres_getresult abi + Value arg = loop.getHandle(); + arg = rewriter.create(loop.getLoc(), rewriter.getIntTy(64), arg); + arg = rewriter.create(loop.getLoc(), LLVM::LLVMPointerType::get(builder.getInt8Ty()), arg); + + + // 3) call and replace + Value args[] = {arg} + Value res = rewriter.create(loop.getLoc(), rowsfn, args)->getResult(0); + + Value args2[] = {res} + Value res2 = rewriter.create(loop.getLoc(), atoifn, args2)->getResult(0); + + rewriter.replaceOpWithNewOp(loop, rewriter.getIndexType(), res2); + + // 4) done + return success(); + } +}; + +void SQLLower::runOnOperation() { + auto module = getOperation(); + OpBuilder builder(module.getContext()); + builder.setInsertionPointToStart(module.getBody()); + + if (!dyn_cast_or_null(symbolTable.lookupSymbolIn( + module, builder.getStringAttr("PQcmdTuples")))) { + mlir::Type argtypes[] = {LLVM::LLVMPointerType::get(builder.getInt8Ty())}; + mlir::Type rettypes[] = {LLVM::LLVMPointerType::get(builder.getInt8Ty())}; + + auto fn = builder.create(module.getLoc(), "PQcmdTuples", builder.getFunctionType(argtys, rettys)); + SymbolTable::setSymbolVisibility(fn, SymbolTable::Private); + } + if (!dyn_cast_or_null(symbolTable.lookupSymbolIn( + module, builder.getStringAttr("atoi")))) { + mlir::Type argtypes[] = {LLVM::LLVMPointerType::get(builder.getInt8Ty())}; + + // todo use data layout + mlir::Type rettypes[] = {builder.getIntTy(sizeof(int))}; + + auto fn = builder.create(module.getLoc(), "atoi", builder.getFunctionType(argtys, rettys)); + SymbolTable::setSymbolVisibility(fn, SymbolTable::Private); + } + + RewritePatternSet patterns(&getContext()); + patterns.insert(&getContext()); + + GreedyRewriteConfig config; + (void)applyPatternsAndFoldGreedily(getOperation(), std::move(patterns), + config); +} + + + +namespace mlir { +namespace polygeist { +std::unique_ptr createSQLLowerPass() { + return std::make_unique(); +} +} // namespace polygeist +} // namespace mlir + +