├── .clang-format ├── .clang-tidy ├── .github └── workflows │ ├── build.yml │ └── deploy-docs.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── COPYING ├── LICENSE-Apache ├── LICENSE-FDL ├── README.md ├── cmake ├── FindGCCJIT.cmake ├── FindLLVM.cmake └── FindMLIR.cmake ├── include ├── CMakeLists.txt └── mlir-gccjit │ ├── CMakeLists.txt │ ├── Conversion │ ├── Conversions.h │ └── TypeConverter.h │ ├── IR │ ├── CMakeLists.txt │ ├── GCCJITAttrs.h │ ├── GCCJITAttrs.td │ ├── GCCJITDialect.h │ ├── GCCJITDialect.td │ ├── GCCJITOps.h │ ├── GCCJITOps.td │ ├── GCCJITOpsEnums.h │ ├── GCCJITTypes.h │ ├── GCCJITTypes.td │ └── Interfaces │ │ ├── CMakeLists.txt │ │ ├── GCCJITRecordTypeInterface.h │ │ └── GCCJITRecordTypeInterface.td │ ├── Passes.h │ ├── Passes.td │ └── Translation │ └── TranslateToGCCJIT.h ├── logo.png ├── run-lit.py ├── src ├── CMakeLists.txt ├── Conversion │ ├── CMakeLists.txt │ ├── ConvertArithToGCCJIT.cpp │ ├── ConvertFuncToGCCJIT.cpp │ ├── ConvertMemrefToGCCJIT.cpp │ └── TypeConverter.cpp ├── GCCJITAttrs.cpp ├── GCCJITDialect.cpp ├── GCCJITOps.cpp ├── GCCJITTypes.cpp ├── Interfaces │ ├── CMakeLists.txt │ └── GCCJITRecordTypeInterface.cpp └── Translation │ ├── CMakeLists.txt │ ├── Registration.cpp │ ├── TranslateToGCCJIT.cpp │ └── TypeTranslation.cpp ├── test ├── CMakeLists.txt ├── compile │ ├── atomic.mlir │ ├── bitfield.mlir │ ├── deref_chain.mlir │ ├── expression.mlir │ ├── global.mlir │ ├── hello_world.mlir │ ├── lazy_evaluation.mlir │ ├── unary.mlir │ ├── union.mlir │ └── vector.mlir ├── lit.cfg.py ├── lit.site.cfg.py.in ├── lowering │ ├── alloc.mlir │ ├── alloca.mlir │ ├── alloca_sum.c │ ├── alloca_sum.mlir │ ├── assume_aligned.mlir │ ├── dealloc.mlir │ ├── gemm.c │ ├── gemm.mlir │ └── global.mlir └── syntax │ ├── basic.mlir │ ├── branch.mlir │ ├── extened_asm.mlir │ ├── floating_point.mlir │ ├── function_attrs.mlir │ ├── hello_world.mlir │ ├── record.mlir │ └── variables.mlir ├── tools ├── CMakeLists.txt ├── gccjit-opt │ ├── CMakeLists.txt │ └── main.cpp └── gccjit-translate │ ├── CMakeLists.txt │ └── main.cpp └── www ├── .gitignore ├── archetypes ├── attrs.md ├── default.md ├── dialect.md ├── ops.md ├── passes.md └── types.md ├── content ├── _index.md └── development │ ├── _index.md │ ├── build.md │ └── compatibility.md ├── hugo.toml ├── link-docs.sh └── static └── logo.png /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveAssignments: 8 | Enabled: false 9 | AcrossEmptyLines: false 10 | AcrossComments: false 11 | AlignCompound: false 12 | AlignFunctionPointers: false 13 | PadOperators: true 14 | AlignConsecutiveBitFields: 15 | Enabled: false 16 | AcrossEmptyLines: false 17 | AcrossComments: false 18 | AlignCompound: false 19 | AlignFunctionPointers: false 20 | PadOperators: false 21 | AlignConsecutiveDeclarations: 22 | Enabled: false 23 | AcrossEmptyLines: false 24 | AcrossComments: false 25 | AlignCompound: false 26 | AlignFunctionPointers: false 27 | PadOperators: false 28 | AlignConsecutiveMacros: 29 | Enabled: false 30 | AcrossEmptyLines: false 31 | AcrossComments: false 32 | AlignCompound: false 33 | AlignFunctionPointers: false 34 | PadOperators: false 35 | AlignConsecutiveShortCaseStatements: 36 | Enabled: false 37 | AcrossEmptyLines: false 38 | AcrossComments: false 39 | AlignCaseColons: false 40 | AlignEscapedNewlines: Right 41 | AlignOperands: Align 42 | AlignTrailingComments: 43 | Kind: Always 44 | OverEmptyLines: 0 45 | AllowAllArgumentsOnNextLine: true 46 | AllowAllParametersOfDeclarationOnNextLine: true 47 | AllowBreakBeforeNoexceptSpecifier: Never 48 | AllowShortBlocksOnASingleLine: Never 49 | AllowShortCaseLabelsOnASingleLine: false 50 | AllowShortCompoundRequirementOnASingleLine: true 51 | AllowShortEnumsOnASingleLine: true 52 | AllowShortFunctionsOnASingleLine: All 53 | AllowShortIfStatementsOnASingleLine: Never 54 | AllowShortLambdasOnASingleLine: All 55 | AllowShortLoopsOnASingleLine: false 56 | AlwaysBreakAfterDefinitionReturnType: None 57 | AlwaysBreakAfterReturnType: None 58 | AlwaysBreakBeforeMultilineStrings: false 59 | AlwaysBreakTemplateDeclarations: MultiLine 60 | AttributeMacros: 61 | - __capability 62 | BinPackArguments: true 63 | BinPackParameters: true 64 | BitFieldColonSpacing: Both 65 | BraceWrapping: 66 | AfterCaseLabel: false 67 | AfterClass: false 68 | AfterControlStatement: Never 69 | AfterEnum: false 70 | AfterExternBlock: false 71 | AfterFunction: false 72 | AfterNamespace: false 73 | AfterObjCDeclaration: false 74 | AfterStruct: false 75 | AfterUnion: false 76 | BeforeCatch: false 77 | BeforeElse: false 78 | BeforeLambdaBody: false 79 | BeforeWhile: false 80 | IndentBraces: false 81 | SplitEmptyFunction: true 82 | SplitEmptyRecord: true 83 | SplitEmptyNamespace: true 84 | BreakAdjacentStringLiterals: true 85 | BreakAfterAttributes: Leave 86 | BreakAfterJavaFieldAnnotations: false 87 | BreakArrays: true 88 | BreakBeforeBinaryOperators: None 89 | BreakBeforeConceptDeclarations: Always 90 | BreakBeforeBraces: Attach 91 | BreakBeforeInlineASMColon: OnlyMultiline 92 | BreakBeforeTernaryOperators: true 93 | BreakConstructorInitializers: BeforeColon 94 | BreakInheritanceList: BeforeColon 95 | BreakStringLiterals: true 96 | ColumnLimit: 80 97 | CommentPragmas: '^ IWYU pragma:' 98 | CompactNamespaces: false 99 | ConstructorInitializerIndentWidth: 4 100 | ContinuationIndentWidth: 4 101 | Cpp11BracedListStyle: true 102 | DerivePointerAlignment: false 103 | DisableFormat: false 104 | EmptyLineAfterAccessModifier: Never 105 | EmptyLineBeforeAccessModifier: LogicalBlock 106 | ExperimentalAutoDetectBinPacking: false 107 | FixNamespaceComments: true 108 | ForEachMacros: 109 | - foreach 110 | - Q_FOREACH 111 | - BOOST_FOREACH 112 | IfMacros: 113 | - KJ_IF_MAYBE 114 | IncludeBlocks: Preserve 115 | IncludeCategories: 116 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 117 | Priority: 2 118 | SortPriority: 0 119 | CaseSensitive: false 120 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 121 | Priority: 3 122 | SortPriority: 0 123 | CaseSensitive: false 124 | - Regex: '.*' 125 | Priority: 1 126 | SortPriority: 0 127 | CaseSensitive: false 128 | IncludeIsMainRegex: '(Test)?$' 129 | IncludeIsMainSourceRegex: '' 130 | IndentAccessModifiers: false 131 | IndentCaseBlocks: false 132 | IndentCaseLabels: false 133 | IndentExternBlock: AfterExternBlock 134 | IndentGotoLabels: true 135 | IndentPPDirectives: None 136 | IndentRequiresClause: true 137 | IndentWidth: 2 138 | IndentWrappedFunctionNames: false 139 | InsertBraces: false 140 | InsertNewlineAtEOF: false 141 | InsertTrailingCommas: None 142 | IntegerLiteralSeparator: 143 | Binary: 0 144 | BinaryMinDigits: 0 145 | Decimal: 0 146 | DecimalMinDigits: 0 147 | Hex: 0 148 | HexMinDigits: 0 149 | JavaScriptQuotes: Leave 150 | JavaScriptWrapImports: true 151 | KeepEmptyLinesAtTheStartOfBlocks: true 152 | KeepEmptyLinesAtEOF: false 153 | LambdaBodyIndentation: Signature 154 | LineEnding: DeriveLF 155 | MacroBlockBegin: '' 156 | MacroBlockEnd: '' 157 | MaxEmptyLinesToKeep: 1 158 | NamespaceIndentation: None 159 | ObjCBinPackProtocolList: Auto 160 | ObjCBlockIndentWidth: 2 161 | ObjCBreakBeforeNestedBlockParam: true 162 | ObjCSpaceAfterProperty: false 163 | ObjCSpaceBeforeProtocolList: true 164 | PackConstructorInitializers: BinPack 165 | PenaltyBreakAssignment: 2 166 | PenaltyBreakBeforeFirstCallParameter: 19 167 | PenaltyBreakComment: 300 168 | PenaltyBreakFirstLessLess: 120 169 | PenaltyBreakOpenParenthesis: 0 170 | PenaltyBreakScopeResolution: 500 171 | PenaltyBreakString: 1000 172 | PenaltyBreakTemplateDeclaration: 10 173 | PenaltyExcessCharacter: 1000000 174 | PenaltyIndentedWhitespace: 0 175 | PenaltyReturnTypeOnItsOwnLine: 60 176 | PointerAlignment: Right 177 | PPIndentWidth: -1 178 | QualifierAlignment: Leave 179 | ReferenceAlignment: Pointer 180 | ReflowComments: true 181 | RemoveBracesLLVM: false 182 | RemoveParentheses: Leave 183 | RemoveSemicolon: false 184 | RequiresClausePosition: OwnLine 185 | RequiresExpressionIndentation: OuterScope 186 | SeparateDefinitionBlocks: Leave 187 | ShortNamespaceLines: 1 188 | SkipMacroDefinitionBody: false 189 | SortIncludes: CaseSensitive 190 | SortJavaStaticImport: Before 191 | SortUsingDeclarations: LexicographicNumeric 192 | SpaceAfterCStyleCast: false 193 | SpaceAfterLogicalNot: false 194 | SpaceAfterTemplateKeyword: true 195 | SpaceAroundPointerQualifiers: Default 196 | SpaceBeforeAssignmentOperators: true 197 | SpaceBeforeCaseColon: false 198 | SpaceBeforeCpp11BracedList: false 199 | SpaceBeforeCtorInitializerColon: true 200 | SpaceBeforeInheritanceColon: true 201 | SpaceBeforeJsonColon: false 202 | SpaceBeforeParens: ControlStatements 203 | SpaceBeforeParensOptions: 204 | AfterControlStatements: true 205 | AfterForeachMacros: true 206 | AfterFunctionDefinitionName: false 207 | AfterFunctionDeclarationName: false 208 | AfterIfMacros: true 209 | AfterOverloadedOperator: false 210 | AfterPlacementOperator: true 211 | AfterRequiresInClause: false 212 | AfterRequiresInExpression: false 213 | BeforeNonEmptyParentheses: false 214 | SpaceBeforeRangeBasedForLoopColon: true 215 | SpaceBeforeSquareBrackets: false 216 | SpaceInEmptyBlock: false 217 | SpacesBeforeTrailingComments: 1 218 | SpacesInAngles: Never 219 | SpacesInContainerLiterals: true 220 | SpacesInLineCommentPrefix: 221 | Minimum: 1 222 | Maximum: -1 223 | SpacesInParens: Never 224 | SpacesInParensOptions: 225 | InCStyleCasts: false 226 | InConditionalStatements: false 227 | InEmptyParentheses: false 228 | Other: false 229 | SpacesInSquareBrackets: false 230 | Standard: Latest 231 | StatementAttributeLikeMacros: 232 | - Q_EMIT 233 | StatementMacros: 234 | - Q_UNUSED 235 | - QT_REQUIRE_VERSION 236 | TabWidth: 8 237 | UseTab: Never 238 | VerilogBreakBetweenInstancePorts: true 239 | WhitespaceSensitiveMacros: 240 | - BOOST_PP_STRINGIZE 241 | - CF_SWIFT_NAME 242 | - NS_SWIFT_NAME 243 | - PP_STRINGIZE 244 | - STRINGIZE 245 | ... 246 | 247 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # Copied from llvm/llvm-project 2 | Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,readability-identifier-naming,-misc-include-cleaner' 3 | CheckOptions: 4 | - key: readability-identifier-naming.ClassCase 5 | value: CamelCase 6 | - key: readability-identifier-naming.EnumCase 7 | value: CamelCase 8 | - key: readability-identifier-naming.FunctionCase 9 | value: camelBack 10 | # Exclude from scanning as this is an exported symbol used for fuzzing 11 | # throughout the code base. 12 | - key: readability-identifier-naming.FunctionIgnoredRegexp 13 | value: "LLVMFuzzerTestOneInput" 14 | - key: readability-identifier-naming.MemberCase 15 | value: camelBack 16 | - key: readability-identifier-naming.ParameterCase 17 | value: camelBack 18 | - key: readability-identifier-naming.UnionCase 19 | value: CamelCase 20 | - key: readability-identifier-naming.VariableCase 21 | value: camelBack 22 | - key: readability-identifier-naming.IgnoreMainLikeFunctions 23 | value: 1 24 | - key: readability-redundant-member-init.IgnoreBaseInCopyConstructors 25 | value: 1 26 | - key: modernize-use-default-member-init.UseAssignment 27 | value: 1 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-24.04 7 | env: 8 | LLVM_DIR: /usr/lib/llvm-18/cmake 9 | steps: 10 | - uses: actions/checkout@v4 11 | 12 | - name: Install build tools and libraries 13 | run: | 14 | sudo apt-get update 15 | sudo apt-get install -y gcc-14 g++-14 cmake ninja-build llvm-18-dev llvm-18-tools \ 16 | libmlir-18-dev libgccjit-14-dev mlir-18-tools python3 python3-pip 17 | pip install lit 18 | 19 | - name: Build 20 | run: | 21 | cmake -B build -G Ninja -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 . 22 | cmake --build build 23 | cmake --build build --target gccjit-tools 24 | 25 | - name: Run tests 26 | run: | 27 | cmake --build build --target check 28 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Documentation Pages 2 | on: 3 | push: 4 | branches: [main] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-24.04 9 | env: 10 | LLVM_DIR: /usr/lib/llvm-18/cmake 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | submodules: recursive 15 | 16 | - name: Install build tools and libraries 17 | run: | 18 | sudo apt-get update 19 | sudo apt-get install -y gcc-14 g++-14 cmake hugo ninja-build llvm-18-dev llvm-18-tools \ 20 | libmlir-18-dev libgccjit-14-dev mlir-18-tools 21 | 22 | - name: Build and link MLIR documentation 23 | run: | 24 | cmake -B build -G Ninja -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 . 25 | cmake --build build --target mlir-doc 26 | cmake --build build --target link-mlir-docs 27 | 28 | - name: Build hugo site 29 | run: | 30 | cd www 31 | hugo 32 | 33 | - name: Upload hugo site artifacts 34 | id: deployment 35 | uses: actions/upload-pages-artifact@v3 36 | with: 37 | path: www/public 38 | 39 | deploy: 40 | needs: build 41 | runs-on: ubuntu-latest 42 | environment: 43 | name: github-pages 44 | url: ${{ steps.deployment.outputs.page_url }} 45 | permissions: 46 | pages: write 47 | id-token: write 48 | steps: 49 | - name: Deploy hugo site to GitHub pages 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS specific files 2 | .DS_Store 3 | 4 | # Build directories 5 | /build* 6 | /cmake-build* 7 | 8 | # Temp files created by most editors 9 | *~ 10 | 11 | # vim swap files 12 | .*.sw? 13 | 14 | # JetBrains IDE files 15 | .idea 16 | 17 | # Visual Studio and vscode files 18 | .vs 19 | .vscode 20 | 21 | # clangd index and compilation databases 22 | .clangd 23 | .cache 24 | compile_commands.json 25 | compile_flags.txt 26 | 27 | # CMake user presets 28 | CMakeUserPresets.json 29 | 30 | # Python virtual environments. 31 | /venv* 32 | 33 | mlir-gccjit-* 34 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "www/themes/hugo-theme-techdoc"] 2 | path = www/themes/hugo-theme-techdoc 3 | url = https://github.com/thingsym/hugo-theme-techdoc.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.22) 2 | project(mlir-gccjit 3 | LANGUAGES C CXX 4 | ) 5 | 6 | option(MLIR_GCCJIT_BUILD_TOOLS "Build mlir-gccjit tools" ON) 7 | option(MLIR_GCCJIT_ENABLE_TEST "Enable test targets in build" ON) 8 | 9 | set(LLVM_BUILD_TOOLS ${MLIR_GCCJIT_BUILD_TOOLS}) 10 | 11 | include(cmake/FindLLVM.cmake) 12 | include(cmake/FindMLIR.cmake) 13 | include(cmake/FindGCCJIT.cmake) 14 | 15 | set(CMAKE_CXX_STANDARD 17) 16 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 20 | include_directories( 21 | ${CMAKE_SOURCE_DIR}/include 22 | ${CMAKE_BINARY_DIR}/include 23 | ${MLIR_INCLUDE_DIRS} 24 | ${LLVM_INCLUDE_DIRS} 25 | ) 26 | link_directories(${LLVM_BUILD_LIBRARY_DIR}) 27 | add_definitions(${LLVM_DEFINITIONS}) 28 | 29 | add_subdirectory(include) 30 | add_subdirectory(src) 31 | 32 | add_subdirectory(tools) 33 | 34 | if (MLIR_GCCJIT_ENABLE_TEST) 35 | add_subdirectory(test) 36 | endif () 37 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | # Copying Information 2 | 3 | - The logo of the project is licensed under GNU Free Documentation License v1.3. It is modified from the original GCC logo, which is licensed under GNU Free Documentation License v1.2. 4 | - Other contents of the project are licensed under Apache License 2.0, if not otherwise specified. 5 | -------------------------------------------------------------------------------- /LICENSE-Apache: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > "There is one who could unite them, one who could reclaim the throne of Gondor." (Gandalf) 2 | 3 | 4 | 5 | # mlir-gccjit 6 | 7 | MLIR dialect for [`libgccjit`](https://gcc.gnu.org/onlinedocs/jit/). 8 | 9 | ## Discussion 10 | 11 | If you have any questions about this project, check out the 12 | [discussion area](https://github.com/Lancern/mlir-gccjit/discussions). 13 | If you couldn't find satisfying answers there, feel free to 14 | [open a new discussion](https://github.com/Lancern/mlir-gccjit/discussions/new/choose). 15 | 16 | ## Contribution 17 | 18 | We warmly welcome any kind of contributions including but not restricted to bug 19 | reports, feature requests, and pull requests. Please 20 | [open an issue](https://github.com/Lancern/mlir-gccjit/issues/new) if you have 21 | found a bug or want to request a new feature. Feel free to open a pull request 22 | if you have made any improvements to the project! 23 | 24 | ## License 25 | 26 | Please refer to [COPYING](COPYING) for more information. 27 | -------------------------------------------------------------------------------- /cmake/FindGCCJIT.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | set(GCCJIT_ROOT "" CACHE PATH "Path to GCCJIT installation") 4 | set(GCCJIT_INCLUDE_DIR "" CACHE PATH "Path to GCCJIT include directory") 5 | 6 | if (GCCJIT_ROOT) 7 | message(STATUS "Using GCCJIT from ${GCCJIT_ROOT}") 8 | 9 | if (NOT GCCJIT_INCLUDE_DIR) 10 | set(GCCJIT_INCLUDE_DIR ${GCCJIT_ROOT}/include) 11 | endif () 12 | 13 | set(GCCJIT_LIB_DIRS ${GCCJIT_ROOT}) 14 | if (EXISTS ${GCCJIT_ROOT}/lib) 15 | list(APPEND GCCJIT_LIB_DIRS ${GCCJIT_ROOT}/lib) 16 | endif() 17 | if (EXISTS ${GCCJIT_ROOT}/lib/gcc/current) 18 | list(APPEND GCCJIT_LIB_DIRS ${GCCJIT_ROOT}/lib/gcc/current) 19 | endif () 20 | endif () 21 | 22 | if (GCCJIT_INCLUDE_DIR) 23 | list(APPEND CMAKE_REQUIRED_INCLUDES ${GCCJIT_INCLUDE_DIR}) 24 | endif () 25 | 26 | include(CheckIncludeFileCXX) 27 | CHECK_INCLUDE_FILE_CXX(libgccjit.h LIBGCCJIT_H_EXIST) 28 | if (NOT LIBGCCJIT_H_EXIST) 29 | message(FATAL_ERROR "could not find libgccjit.h in system headers (CMAKE_REQUIRED_INCLUDES: ${CMAKE_REQUIRED_INCLUDES})") 30 | endif () 31 | 32 | if (GCCJIT_LIB_DIRS OR GCCJIT_LIBRARY) 33 | find_library(GCCJIT_LIBRARY NAMES gccjit PATHS ${GCCJIT_LIB_DIRS}) 34 | if (NOT GCCJIT_LIBRARY) 35 | message(FATAL_ERROR "could not find gccjit library file at ${GCCJIT_LIB_DIRS}") 36 | elseif (NOT EXISTS ${GCCJIT_LIBRARY}) 37 | message(FATAL_ERROR "could not find gccjit library file at ${GCCJIT_LIBRARY}") 38 | endif() 39 | 40 | add_library(libgccjit SHARED IMPORTED) 41 | set_target_properties(libgccjit PROPERTIES 42 | IMPORTED_LOCATION ${GCCJIT_LIBRARY} 43 | ) 44 | else () 45 | add_library(libgccjit INTERFACE) 46 | target_link_libraries(libgccjit INTERFACE gccjit) 47 | endif () 48 | 49 | if (GCCJIT_INCLUDE_DIR) 50 | target_include_directories(libgccjit INTERFACE ${GCCJIT_INCLUDE_DIR}) 51 | endif () 52 | -------------------------------------------------------------------------------- /cmake/FindLLVM.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | find_package(LLVM REQUIRED CONFIG) 4 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION} at ${LLVM_DIR}") 5 | 6 | include(${LLVM_DIR}/AddLLVM.cmake) 7 | include(${LLVM_DIR}/TableGen.cmake) 8 | include(${LLVM_DIR}/HandleLLVMOptions.cmake) 9 | 10 | # Try to find the FileCheck utility. 11 | if (TARGET FileCheck) 12 | get_target_property(LLVM_FILE_CHECK_EXE FileCheck IMPORTED_LOCATION) 13 | endif () 14 | 15 | if (NOT LLVM_FILE_CHECK_EXE) 16 | unset(LLVM_FILE_CHECK_EXE) 17 | if (MLIR_GCCJIT_ENABLE_TEST) 18 | set(filecheck_required_param REQUIRED) 19 | endif () 20 | find_program(LLVM_FILE_CHECK_EXE 21 | FileCheck 22 | NAMES FileCheck-${LLVM_VERSION_MAJOR} 23 | HINTS 24 | "${LLVM_DIR}/../../../bin" 25 | "${LLVM_DIR}/../bin" 26 | ${filecheck_required_param} 27 | ) 28 | endif () 29 | 30 | if (LLVM_FILE_CHECK_EXE) 31 | message(STATUS "Found FileCheck utility at ${LLVM_FILE_CHECK_EXE}") 32 | elseif (MLIR_GCCJIT_ENABLE_TEST) 33 | message(FATAL_ERROR "Could not find FileCheck utility") 34 | endif () 35 | -------------------------------------------------------------------------------- /cmake/FindMLIR.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | set(find_mlir_hints) 4 | if (LLVM_DIR) 5 | list(APPEND find_mlir_hints "${LLVM_DIR}/..") 6 | endif () 7 | 8 | find_package(MLIR 9 | REQUIRED CONFIG 10 | HINTS ${find_mlir_hints} 11 | ) 12 | message(STATUS "Found MLIR ${MLIR_PACKAGE_VERSION} at ${MLIR_DIR}") 13 | 14 | include(${MLIR_DIR}/AddMLIR.cmake) 15 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(mlir-gccjit) 2 | -------------------------------------------------------------------------------- /include/mlir-gccjit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function(add_mlir_gccjit_doc doc_filename output_file output_directory command) 2 | set(LLVM_TARGET_DEFINITIONS ${doc_filename}.td) 3 | tablegen(MLIR ${output_file}.md ${command} ${ARGN}) 4 | set(GEN_DOC_FILE ${PROJECT_BINARY_DIR}/docs/${output_directory}${output_file}.md) 5 | add_custom_command( 6 | OUTPUT ${GEN_DOC_FILE} 7 | COMMAND ${CMAKE_COMMAND} -E copy 8 | ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md 9 | ${GEN_DOC_FILE} 10 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md) 11 | add_custom_target(${output_file}DocGen DEPENDS ${GEN_DOC_FILE}) 12 | add_dependencies(mlir-doc ${output_file}DocGen) 13 | endfunction() 14 | 15 | add_subdirectory(IR) 16 | 17 | set(LLVM_TARGET_DEFINITIONS Passes.td) 18 | mlir_tablegen(Passes.h.inc -gen-pass-decls -name GCCJIT) 19 | mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix GCCJIT) 20 | mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix GCCJIT) 21 | add_public_tablegen_target(MLIRGCCJITPassIncGen) 22 | 23 | add_mlir_gccjit_doc(Passes GCCJITPasses gccjit/ -gen-pass-doc) 24 | 25 | add_custom_target(link-mlir-docs 26 | COMMAND ${PROJECT_SOURCE_DIR}/www/link-docs.sh ${PROJECT_BINARY_DIR} 27 | DEPENDS mlir-doc 28 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/www 29 | ) 30 | -------------------------------------------------------------------------------- /include/mlir-gccjit/Conversion/Conversions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_CONVERSION_CONVERTIONS_H 16 | #define MLIR_GCCJIT_CONVERSION_CONVERTIONS_H 17 | 18 | #include 19 | 20 | #include "mlir-gccjit/Conversion/TypeConverter.h" 21 | 22 | namespace mlir::gccjit { 23 | void populateFuncToGCCJITPatterns(MLIRContext *context, 24 | GCCJITTypeConverter &typeConverter, 25 | RewritePatternSet &patterns, 26 | SymbolTable &symbolTable); 27 | } // namespace mlir::gccjit 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/mlir-gccjit/Conversion/TypeConverter.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_CONVERSION_TYPECONVERTER_H 16 | #define MLIR_GCCJIT_CONVERSION_TYPECONVERTER_H 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 25 | #include "mlir-gccjit/IR/GCCJITTypes.h" 26 | 27 | namespace mlir::gccjit { 28 | class GCCJITTypeConverter : public TypeConverter { 29 | 30 | public: 31 | GCCJITTypeConverter(); 32 | ~GCCJITTypeConverter(); 33 | // integral types 34 | gccjit::IntType convertIndexType(mlir::IndexType type) const; 35 | gccjit::IntType makeSigned(gccjit::IntType type) const; 36 | gccjit::IntType makeUnsigned(gccjit::IntType type) const; 37 | bool isSigned(gccjit::IntType type) const; 38 | gccjit::IntType convertIntegerType(mlir::IntegerType type) const; 39 | gccjit::IntAttr convertIntegerAttr(mlir::IntegerAttr attr) const; 40 | 41 | // floating point types 42 | gccjit::FloatType convertFloatType(mlir::FloatType type) const; 43 | gccjit::FloatAttr convertFloatAttr(mlir::FloatAttr attr) const; 44 | 45 | // special composite types 46 | gccjit::ComplexType convertComplexType(mlir::ComplexType type) const; 47 | gccjit::VectorType convertVectorType(mlir::VectorType type) const; 48 | 49 | // function prototype 50 | gccjit::FuncType convertFunctionType(mlir::FunctionType type, 51 | bool isVarArg) const; 52 | 53 | // function type to function pointer 54 | gccjit::PointerType convertFunctionTypeAsPtr(mlir::FunctionType type, 55 | bool isVarArg) const; 56 | 57 | // memref type 58 | gccjit::StructType getMemrefDescriptorType(mlir::MemRefType type) const; 59 | gccjit::StructType 60 | getUnrankedMemrefDescriptorType(mlir::UnrankedMemRefType type) const; 61 | 62 | Type convertAndPackTypesIfNonSingleton(TypeRange types, MLIRContext *) const; 63 | }; 64 | } // namespace mlir::gccjit 65 | #endif // MLIR_GCCJIT_CONVERSION_TYPECONVERTER_H 66 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect(GCCJITOps gccjit) 2 | 3 | # Generate extra headers for custom enum and attrs. 4 | set(LLVM_TARGET_DEFINITIONS GCCJITOps.td) 5 | mlir_tablegen(GCCJITOpsEnums.h.inc -gen-enum-decls) 6 | mlir_tablegen(GCCJITOpsEnums.cpp.inc -gen-enum-defs) 7 | mlir_tablegen(GCCJITOpsAttributes.h.inc -gen-attrdef-decls) 8 | mlir_tablegen(GCCJITOpsAttributes.cpp.inc -gen-attrdef-defs) 9 | add_public_tablegen_target(MLIRGCCJITEnumsGen) 10 | add_dependencies(mlir-headers MLIRGCCJITEnumsGen) 11 | 12 | add_mlir_gccjit_doc(GCCJITDialect GCCJITDialect gccjit/ -gen-dialect-doc) 13 | add_mlir_gccjit_doc(GCCJITOps GCCJITOps gccjit/ -gen-op-doc) 14 | add_mlir_gccjit_doc(GCCJITAttrs GCCJITAttrs gccjit/ -gen-attrdef-doc) 15 | add_mlir_gccjit_doc(GCCJITTypes GCCJITTypes gccjit/ -gen-typedef-doc) 16 | 17 | add_subdirectory(Interfaces) 18 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITAttrs.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_IR_GCCJIT_OPS_ATTRS_H 16 | #define MLIR_GCCJIT_IR_GCCJIT_OPS_ATTRS_H 17 | 18 | #include "mlir-gccjit/IR/GCCJITOpsEnums.h" 19 | 20 | namespace mlir::gccjit { 21 | class IntType; 22 | class FloatType; 23 | class PointerType; 24 | } // namespace mlir::gccjit 25 | 26 | #define GET_ATTRDEF_CLASSES 27 | #include "mlir-gccjit/IR/GCCJITOpsAttributes.h.inc" 28 | 29 | namespace mlir::gccjit { 30 | inline bool isUnitFnAttr(FnAttrEnum attr) { 31 | switch (attr) { 32 | case FnAttrEnum::AlwaysInline: 33 | case FnAttrEnum::Inline: 34 | case FnAttrEnum::NoInline: 35 | case FnAttrEnum::Used: 36 | case FnAttrEnum::Cold: 37 | case FnAttrEnum::ReturnsTwice: 38 | case FnAttrEnum::Pure: 39 | case FnAttrEnum::Const: 40 | case FnAttrEnum::Weak: 41 | return true; 42 | default: 43 | return false; 44 | } 45 | } 46 | inline bool isStringFnAttr(FnAttrEnum attr) { 47 | switch (attr) { 48 | case FnAttrEnum::Alias: 49 | case FnAttrEnum::Target: 50 | return true; 51 | default: 52 | return false; 53 | } 54 | } 55 | 56 | inline bool isIntArrayFnAttr(FnAttrEnum attr) { 57 | switch (attr) { 58 | case FnAttrEnum::Nonnull: 59 | return true; 60 | default: 61 | return false; 62 | } 63 | } 64 | } // namespace mlir::gccjit 65 | 66 | #endif // MLIR_GCCJIT_IR_GCCJIT_OPS_ATTRS_H 67 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITAttrs.td: -------------------------------------------------------------------------------- 1 | #ifndef MLIR_GCCJIT_IR_GCCJIT_ATTRS 2 | #define MLIR_GCCJIT_IR_GCCJIT_ATTRS 3 | 4 | include "mlir/IR/BuiltinAttributeInterfaces.td" 5 | include "mlir/IR/EnumAttr.td" 6 | include "mlir-gccjit/IR/GCCJITDialect.td" 7 | 8 | //===----------------------------------------------------------------------===// 9 | // GCCJIT Attrs 10 | //===----------------------------------------------------------------------===// 11 | 12 | class GCCJIT_Attr traits = []> 13 | : AttrDef { 14 | let mnemonic = attrMnemonic; 15 | } 16 | 17 | class GCCJIT_UnitAttr traits = []> 18 | : GCCJIT_Attr { 19 | let returnType = "bool"; 20 | let defaultValue = "false"; 21 | let valueType = NoneType; 22 | let isOptional = 1; 23 | } 24 | 25 | //===----------------------------------------------------------------------===// 26 | // TLS Model Attrs 27 | //===----------------------------------------------------------------------===// 28 | 29 | def TLSModel_None : I32EnumAttrCase<"None", 0, "none">; 30 | def TLSModel_GlobalDynamic : I32EnumAttrCase<"GlobalDynamic", 1, 31 | "global_dynamic">; 32 | def TLSModel_LocalDynamic : I32EnumAttrCase<"LocalDynamic", 2, "local_dynamic">; 33 | def TLSModel_InitialExec : I32EnumAttrCase<"InitialExec", 3, "initial_exec">; 34 | def TLSModel_LocalExec : I32EnumAttrCase<"LocalExec", 4, "local_exec">; 35 | 36 | def TLSModelEnum : I32EnumAttr<"TLSModelEnum", "TLS model", 37 | [TLSModel_None, TLSModel_GlobalDynamic, 38 | TLSModel_LocalDynamic, TLSModel_InitialExec, 39 | TLSModel_LocalExec]> { 40 | let cppNamespace = "mlir::gccjit"; 41 | } 42 | 43 | def TLSModelAttr : GCCJIT_Attr<"TLSModel", "tls_model"> { 44 | let summary = "Thread Local Storage model"; 45 | let parameters = (ins "TLSModelEnumAttr":$model); 46 | let description = [{ 47 | Represents the Thread Local Storage model for the lvalue. 48 | }]; 49 | let hasCustomAssemblyFormat = 1; 50 | let extraClassDeclaration = [{ 51 | bool isNone() const { return getModel().getValue() == TLSModelEnum::None; } 52 | bool isGlobalDynamic() const { 53 | return getModel().getValue() == TLSModelEnum::GlobalDynamic; 54 | } 55 | bool isLocalDynamic() const { 56 | return getModel().getValue() == TLSModelEnum::LocalDynamic; 57 | } 58 | bool isInitialExec() const { 59 | return getModel().getValue() == TLSModelEnum::InitialExec; 60 | } 61 | bool isLocalExec() const { 62 | return getModel().getValue() == TLSModelEnum::LocalExec; 63 | } 64 | }]; 65 | let genVerifyDecl = 0; 66 | } 67 | 68 | //===----------------------------------------------------------------------===// 69 | // Integer Attrs 70 | //===----------------------------------------------------------------------===// 71 | def IntAttr : GCCJIT_Attr<"Int", "int", [TypedAttrInterface]> { 72 | let summary = "An attribute containing a integer value"; 73 | let description = [{ 74 | An `#gccjit.int` attribute represents a constant integer value of some 75 | libgccjit integer type. 76 | 77 | Example: 78 | ```mlir 79 | #gccjit.int<42> 80 | ``` 81 | }]; 82 | let parameters = (ins 83 | AttributeSelfTypeParameter<"", "mlir::gccjit::IntType">:$type, 84 | "::mlir::APInt":$value 85 | ); 86 | let hasCustomAssemblyFormat = 1; 87 | } 88 | 89 | //===----------------------------------------------------------------------===// 90 | // Floating-point Attrs 91 | //===----------------------------------------------------------------------===// 92 | def FloatAttr : GCCJIT_Attr<"Float", "float", [TypedAttrInterface]> { 93 | let summary = "An attribute containing a constant floating-point value"; 94 | let description = [{ 95 | A `#gccjit.float` attribute represents a constant floating-point value of 96 | some libgccjit floating-point type. 97 | 98 | Example: 99 | ```mlir 100 | #gccjit.float<42.0> 101 | ``` 102 | }]; 103 | 104 | let parameters = (ins 105 | AttributeSelfTypeParameter<"", "mlir::gccjit::FloatType">:$type, 106 | "::mlir::APFloat":$value 107 | ); 108 | let hasCustomAssemblyFormat = 1; 109 | } 110 | 111 | //===----------------------------------------------------------------------===// 112 | // Special constant attributes 113 | //===----------------------------------------------------------------------===// 114 | 115 | def ZeroAttr : GCCJIT_Attr<"Zero", "zero", [TypedAttrInterface]> { 116 | let summary = "An attribute containing a constant zero"; 117 | let description = [{ 118 | A `#gccjit.zero` attribute represents a constant zero value of some 119 | libgccjit integer or floating-point type. 120 | }]; 121 | 122 | let parameters = (ins AttributeSelfTypeParameter<"">:$type); 123 | 124 | let assemblyFormat = ""; 125 | let genVerifyDecl = 1; 126 | } 127 | 128 | def OneAttr : GCCJIT_Attr<"One", "one", [TypedAttrInterface]> { 129 | let summary = "An attribute containing a constant one"; 130 | let description = [{ 131 | A `#gccjit.one` attribute represents a constant one value of some 132 | libgccjit integer or floating-point type. 133 | }]; 134 | 135 | let parameters = (ins AttributeSelfTypeParameter<"">:$type); 136 | 137 | let assemblyFormat = ""; 138 | let genVerifyDecl = 1; 139 | } 140 | 141 | def NullAttr : GCCJIT_Attr<"Null", "null", [TypedAttrInterface]> { 142 | let summary = "An attribute containing a null pointer constant"; 143 | let description = [{ 144 | A `#gccjit.null` attribute represents a constant null pointer value of some 145 | libgccjit pointer type. 146 | }]; 147 | 148 | let parameters = (ins 149 | AttributeSelfTypeParameter<"", "mlir::gccjit::PointerType">:$type); 150 | 151 | let assemblyFormat = ""; 152 | } 153 | 154 | //===----------------------------------------------------------------------===// 155 | // SourceLoc Attr 156 | //===----------------------------------------------------------------------===// 157 | 158 | def SourceLocAttr : GCCJIT_Attr<"SourceLoc", "loc"> { 159 | let summary = "Source location"; 160 | let description = [{ 161 | Represent a source location in GCCJIT. 162 | }]; 163 | let parameters = (ins "mlir::StringAttr":$filename, "int":$line, 164 | "int":$column); 165 | let assemblyFormat = [{ 166 | `<` $filename `:` $line `:` $column `>` 167 | }]; 168 | } 169 | 170 | //===----------------------------------------------------------------------===// 171 | // Record field attribute 172 | //===----------------------------------------------------------------------===// 173 | 174 | def FieldAttr : GCCJIT_Attr<"Field", "field"> { 175 | let summary = "A field within a struct or a union"; 176 | let description = [{ 177 | The `#gccjit.field` attribute represents a field within a record (i.e. a 178 | record or a union). 179 | 180 | When the `bitWidth` parameter is present, the attribute represents a 181 | bitfield. The `bitWidth` parameter gives the width of the bitfield. 182 | }]; 183 | 184 | let parameters = (ins 185 | "mlir::StringAttr":$name, "mlir::Type":$type, 186 | OptionalParameter<"std::optional">:$bitWidth, 187 | OptionalParameter<"std::optional">:$loc 188 | ); 189 | 190 | let builders = [ 191 | AttrBuilder<(ins "mlir::StringAttr":$name, "mlir::Type":$type), [{ 192 | return get($_ctxt, name, type, std::nullopt, std::nullopt); 193 | }]>, 194 | AttrBuilder<(ins "mlir::StringAttr":$name, "mlir::Type":$type, 195 | "unsigned":$bitWidth), [{ 196 | return get($_ctxt, name, type, bitWidth, std::nullopt); 197 | }]>, 198 | AttrBuilder<(ins "mlir::StringAttr":$name, "mlir::Type":$type, 199 | "mlir::gccjit::SourceLocAttr":$loc), [{ 200 | return get($_ctxt, name, type, std::nullopt, loc); 201 | }]>, 202 | ]; 203 | 204 | // attribute can eat up the `:` separator, so we need to move the name to the 205 | // front 206 | let assemblyFormat = [{ 207 | `<` $name $type (`:` $bitWidth^)? ($loc^)? `>` 208 | }]; 209 | } 210 | 211 | //===----------------------------------------------------------------------===// 212 | // OptLevel Attr 213 | //===----------------------------------------------------------------------===// 214 | 215 | def OptLevel_0 : I32EnumAttrCase<"O0", 0, "O0">; 216 | def OptLevel_1 : I32EnumAttrCase<"O1", 1, "O1">; 217 | def OptLevel_2 : I32EnumAttrCase<"O2", 2, "O2">; 218 | def OptLevel_3 : I32EnumAttrCase<"O3", 3, "O3">; 219 | def OptLevelEnum : I32EnumAttr<"OptLevelEnum", "Optimization level", 220 | [OptLevel_0, OptLevel_1, OptLevel_2, OptLevel_3]> { 221 | let cppNamespace = "mlir::gccjit"; 222 | } 223 | def OptLevelAttr : GCCJIT_Attr<"OptLevel", "opt_level"> { 224 | let summary = "Optimization level"; 225 | let parameters = (ins "OptLevelEnumAttr":$level); 226 | let description = [{ 227 | Represents the optimization level. 228 | }]; 229 | let hasCustomAssemblyFormat = 1; 230 | let extraClassDeclaration = [{ 231 | bool isO0() const { return getLevel().getValue() == OptLevelEnum::O0; } 232 | bool isO1() const { return getLevel().getValue() == OptLevelEnum::O1; } 233 | bool isO2() const { return getLevel().getValue() == OptLevelEnum::O2; } 234 | bool isO3() const { return getLevel().getValue() == OptLevelEnum::O3; } 235 | }]; 236 | let genVerifyDecl = 0; 237 | } 238 | 239 | //===----------------------------------------------------------------------===// 240 | // Function Attributes 241 | //===----------------------------------------------------------------------===// 242 | def FnAttr_Alias : I32EnumAttrCase<"Alias", 0, "alias">; 243 | def FnAttr_AlwaysInline : I32EnumAttrCase<"AlwaysInline", 1, "always_inline">; 244 | def FnAttr_Inline : I32EnumAttrCase<"Inline", 2, "inline">; 245 | def FnAttr_NoInline : I32EnumAttrCase<"NoInline", 3, "noinline">; 246 | def FnAttr_Target : I32EnumAttrCase<"Target", 4, "target">; 247 | def FnAttr_Used : I32EnumAttrCase<"Used", 5, "used">; 248 | def FnAttr_Visibility : I32EnumAttrCase<"Visibility", 6, "visibility">; 249 | def FnAttr_Cold : I32EnumAttrCase<"Cold", 7, "cold">; 250 | def FnAttr_ReturnsTwice : I32EnumAttrCase<"ReturnsTwice", 8, "returns_twice">; 251 | def FnAttr_Pure : I32EnumAttrCase<"Pure", 9, "pure">; 252 | def FnAttr_Const : I32EnumAttrCase<"Const", 10, "const">; 253 | def FnAttr_Weak : I32EnumAttrCase<"Weak", 11, "weak">; 254 | def FnAttr_Nonnull : I32EnumAttrCase<"Nonnull", 12, "nonnull">; 255 | def FnAttrEnum : I32EnumAttr<"FnAttrEnum", "Function attribute", 256 | [FnAttr_Alias, FnAttr_AlwaysInline, FnAttr_Inline, 257 | FnAttr_NoInline, FnAttr_Target, FnAttr_Used, 258 | FnAttr_Visibility, FnAttr_Cold, FnAttr_ReturnsTwice, 259 | FnAttr_Pure, FnAttr_Const, FnAttr_Weak, 260 | FnAttr_Nonnull]> { 261 | let cppNamespace = "mlir::gccjit"; 262 | } 263 | 264 | def FnAttr : GCCJIT_Attr<"Function", "fn_attr"> { 265 | let summary = "Function Attribute"; 266 | let description = [{ 267 | A `#gccjit.fn_attr` attribute represents a function attribute. 268 | There three types of function attributes: 269 | - unit attributes: those without a value. 270 | - string attributes: those with a string value. 271 | - integer array attributes: those with an array of integers. 272 | }]; 273 | 274 | let parameters = (ins 275 | "FnAttrEnumAttr":$attr, 276 | OptionalParameter<"std::optional">:$strValue, 277 | OptionalParameter<"std::optional">:$intArrayValue 278 | ); 279 | 280 | let hasCustomAssemblyFormat = 1; 281 | let genVerifyDecl = 0; 282 | } 283 | 284 | //===----------------------------------------------------------------------===// 285 | // ByteArrayInitializer Attr 286 | //===----------------------------------------------------------------------===// 287 | def ByteArrayInitializerAttr : GCCJIT_Attr<"ByteArrayInitializer", 288 | "byte_array"> { 289 | let summary = "Byte array initializer"; 290 | let parameters = (ins "DenseI8ArrayAttr":$initializer); 291 | let description = [{ 292 | Represents the byte array initializer. 293 | }]; 294 | let assemblyFormat = [{ 295 | `<` $initializer `>` 296 | }]; 297 | } 298 | #endif // MLIR_GCCJIT_IR_GCCJIT_ATTRS 299 | 300 | 301 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITDialect.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_IR_GCCJIT_DIALECT_H 16 | #define MLIR_GCCJIT_IR_GCCJIT_DIALECT_H 17 | 18 | #include 19 | 20 | #include "mlir-gccjit/IR/GCCJITOpsDialect.h.inc" 21 | 22 | #endif // MLIR_GCCJIT_IR_GCCJIT_DIALECT_H 23 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITDialect.td: -------------------------------------------------------------------------------- 1 | #ifndef GCCJIT_DIALECT 2 | #define GCCJIT_DIALECT 3 | 4 | include "mlir/IR/OpBase.td" 5 | 6 | def GCCJIT_Dialect : Dialect { 7 | let name = "gccjit"; 8 | 9 | let summary = "Dialect for libgccjit"; 10 | let description = [{ 11 | The gccjit dialect allows you to generate code with libgccjit through MLIR. 12 | }]; 13 | 14 | let cppNamespace = "::mlir::gccjit"; 15 | 16 | let useDefaultAttributePrinterParser = 0; 17 | let useDefaultTypePrinterParser = 0; 18 | 19 | let dependentDialects = [ 20 | "::mlir::BuiltinDialect", 21 | "::mlir::func::FuncDialect", 22 | ]; 23 | 24 | let extraClassDeclaration = [{ 25 | void registerTypes(); 26 | void registerAttributes(); 27 | Type parseType(DialectAsmParser &parser) const override; 28 | void printType(Type type, DialectAsmPrinter &printer) const override; 29 | Attribute parseAttribute(DialectAsmParser &parser, 30 | Type type) const override; 31 | 32 | void printAttribute(Attribute attr, DialectAsmPrinter &os) const override; 33 | }]; 34 | } 35 | 36 | class GCCJIT_Op traits = []> 37 | : Op; 38 | 39 | #endif // GCCJIT_DIALECT 40 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITOps.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_IR_GCCJIT_OPS_H 16 | #define MLIR_GCCJIT_IR_GCCJIT_OPS_H 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 32 | #include "mlir-gccjit/IR/GCCJITOpsEnums.h" 33 | #include "mlir-gccjit/IR/GCCJITTypes.h" 34 | 35 | #define GET_OP_CLASSES 36 | #include "mlir-gccjit/IR/GCCJITOps.h.inc" 37 | 38 | #endif // MLIR_GCCJIT_IR_GCCJIT_OPS_H 39 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITOpsEnums.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_IR_GCCJIT_OPS_ENUMS_H 16 | #define MLIR_GCCJIT_IR_GCCJIT_OPS_ENUMS_H 17 | 18 | #include 19 | 20 | #include "mlir-gccjit/IR/GCCJITOpsEnums.h.inc" 21 | 22 | #endif // MLIR_GCCJIT_IR_GCCJIT_OPS_ENUMS_H 23 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITTypes.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_IR_GCCJIT_TYPES_H 16 | #define MLIR_GCCJIT_IR_GCCJIT_TYPES_H 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 23 | #include "mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.h" 24 | 25 | namespace mlir::gccjit { 26 | class FieldAttr; 27 | class SourceLocAttr; 28 | } // namespace mlir::gccjit 29 | 30 | #define GET_TYPEDEF_CLASSES 31 | #include "mlir-gccjit/IR/GCCJITOpsTypes.h.inc" 32 | 33 | //===----------------------------------------------------------------------===// 34 | // GCCJIT Custom Parser/Printer Signatures 35 | //===----------------------------------------------------------------------===// 36 | namespace mlir::gccjit { 37 | mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, 38 | llvm::SmallVector ¶ms, 39 | bool &isVarArg); 40 | void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef params, 41 | bool isVarArg); 42 | 43 | inline bool isIntegral(mlir::Type type) { 44 | if (auto qualified = dyn_cast(type)) 45 | return isIntegral(qualified.getElementType()); 46 | 47 | return isa(type); 48 | } 49 | 50 | inline bool isIntegralOrPointer(mlir::Type type) { 51 | if (auto qualified = dyn_cast(type)) 52 | return isIntegralOrPointer(qualified.getElementType()); 53 | return isa(type) || isa(type); 54 | } 55 | 56 | inline bool isPointer(mlir::Type type) { 57 | if (auto qualified = dyn_cast(type)) 58 | return isPointer(qualified.getElementType()); 59 | return isa(type); 60 | } 61 | 62 | inline bool isArithmetc(mlir::Type type) { 63 | if (auto qualified = dyn_cast(type)) 64 | return isArithmetc(qualified.getElementType()); 65 | return isa(type) || isa(type); 66 | } 67 | 68 | inline bool isArithmetcOrPointer(mlir::Type type) { 69 | if (auto qualified = dyn_cast(type)) 70 | return isArithmetcOrPointer(qualified.getElementType()); 71 | return isa(type) || isa(type) || isa(type); 72 | } 73 | } // namespace mlir::gccjit 74 | 75 | #endif // MLIR_GCCJIT_IR_GCCJIT_TYPES_H 76 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/GCCJITTypes.td: -------------------------------------------------------------------------------- 1 | #ifndef GCCJIT_TYPES 2 | #define GCCJIT_TYPES 3 | 4 | include "mlir/IR/AttrTypeBase.td" 5 | 6 | include "mlir-gccjit/IR/GCCJITDialect.td" 7 | include "mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.td" 8 | 9 | class GCCJIT_Type traits = []> 10 | : TypeDef { 11 | let mnemonic = typeMnemonic; 12 | } 13 | 14 | def GCCJIT_LValueType : GCCJIT_Type<"LValue", "lvalue"> { 15 | let summary = "LValue type"; 16 | let description = [{ 17 | `gccjit.lvalue` represents a lvalue in the meaning of C. It behaves 18 | like a reference to a mutable memory location. Lvalues are addressable, 19 | so one can get a pointer from them. Lvalue's subfield can be projected as 20 | a new lvalue, while rvalue's subfield can be projected as a new rvalue. 21 | There are generally three ways to obtain an lvalue: 22 | 1. create a local lvalue with respect to current function 23 | 2. create a global lvalue with respect to current module 24 | 3. function parameters in gimple are also lvalues 25 | 26 | See also [`gccjit::lvalue`](https://gcc.gnu.org/onlinedocs/jit/cp/topics/expressions.html#_CPPv4N6gccjit6lvalueE). 27 | }]; 28 | let parameters = (ins "mlir::Type":$innerType); 29 | let assemblyFormat = [{ 30 | `<` $innerType `>` 31 | }]; 32 | } 33 | 34 | //===----------------------------------------------------------------------===// 35 | // FuncType 36 | //===----------------------------------------------------------------------===// 37 | 38 | def GCCJIT_FuncType : GCCJIT_Type<"Func", "func"> { 39 | let summary = "GCCJIT function type"; 40 | let description = [{ 41 | The `!gccjit.func` is a function type. It consists of a single return type, 42 | a list of parameter types and can optionally be variadic. 43 | }]; 44 | 45 | let parameters = (ins ArrayRefParameter<"Type">:$inputs, "Type":$returnType, 46 | "bool":$varArg); 47 | let assemblyFormat = [{ 48 | `<` $returnType ` ` `(` custom($inputs, $varArg) `>` 49 | }]; 50 | 51 | let builders = [ 52 | TypeBuilderWithInferredContext<(ins 53 | "ArrayRef":$inputs, "Type":$returnType, 54 | CArg<"bool", "false">:$isVarArg), [{ 55 | return $_get(returnType.getContext(), inputs, returnType, isVarArg); 56 | }]> 57 | ]; 58 | 59 | let extraClassDeclaration = [{ 60 | /// Returns whether the function is variadic. 61 | bool isVarArg() const { return getVarArg(); } 62 | 63 | /// Returns the `i`th input operand type. Asserts if out of bounds. 64 | Type getInput(unsigned i) const { return getInputs()[i]; } 65 | 66 | /// Returns the number of arguments to the function. 67 | unsigned getNumInputs() const { return getInputs().size(); } 68 | 69 | /// Returns the result type of the function as an ArrayRef, enabling better 70 | /// integration with generic MLIR utilities. 71 | ArrayRef getReturnTypes() const; 72 | 73 | /// Returns whether the function is returns void. 74 | bool isVoid() const; 75 | 76 | /// Returns a clone of this function type with the given argument 77 | /// and result types. 78 | FuncType clone(TypeRange inputs, TypeRange results) const; 79 | }]; 80 | } 81 | 82 | //===----------------------------------------------------------------------===// 83 | // Void type 84 | //===----------------------------------------------------------------------===// 85 | 86 | def GCCJIT_VoidType : GCCJIT_Type<"Void", "void"> { 87 | let summary = "GCCJIT void type"; 88 | let description = [{ 89 | The `!gccjit.void` type represents the C/C++ `void` type. 90 | }]; 91 | let extraClassDeclaration = [{ 92 | /// Returns a clone of this type with the given context. 93 | std::string getAlias() const { return "void"; }; 94 | }]; 95 | } 96 | 97 | //===----------------------------------------------------------------------===// 98 | // Pointer type 99 | //===----------------------------------------------------------------------===// 100 | 101 | def GCCJIT_PointerType : GCCJIT_Type<"Pointer", "ptr"> { 102 | let summary = "GCCJIT pointer type"; 103 | let description = [{ 104 | The `!gccjit.ptr` type represents a pointer type. It consists of a single 105 | element type. 106 | }]; 107 | let parameters = (ins "mlir::Type":$elementType); 108 | let assemblyFormat = [{ 109 | `<` $elementType `>` 110 | }]; 111 | } 112 | 113 | //===----------------------------------------------------------------------===// 114 | // Qualified type 115 | //===----------------------------------------------------------------------===// 116 | 117 | def GCCJIT_QualifiedType : GCCJIT_Type<"Qualified", "qualified"> { 118 | let summary = "GCCJIT qualified type"; 119 | let description = [{ 120 | GCCJIT type can be qualified with `const`, `restrict`, `volatile`. 121 | }]; 122 | let parameters = (ins "mlir::Type":$elementType, "bool":$isConst, 123 | "bool":$isRestrict, "bool":$isVolatile); 124 | let hasCustomAssemblyFormat = 1; 125 | } 126 | 127 | //===----------------------------------------------------------------------===// 128 | // Integer type 129 | //===----------------------------------------------------------------------===// 130 | 131 | def GCCJIT_IntType : GCCJIT_Type<"Int", "int"> { 132 | let summary = "Integer type"; 133 | let description = [{ 134 | GCCJIT type that represents integer types with arbitrary precision: 135 | - GCCJIT type can be either explicitly sized or not. 136 | - GCCJIT type can be either signed or unsigned. 137 | }]; 138 | 139 | let parameters = (ins "::gcc_jit_types":$kind); 140 | let hasCustomAssemblyFormat = 1; 141 | } 142 | 143 | class SpecificInt 144 | : Type($_self)">, 146 | CPred<"::mlir::cast<::mlir::gccjit::IntType>($_self).getKind() == " 147 | # enumValue> 148 | ]>, "integer with " #enumValue, "::mlir::gccjit::IntType">, 149 | BuildableType< 150 | "mlir::gccjit::IntType::get($_builder.getContext(), " 151 | # enumValue # ")"> { 152 | } 153 | 154 | def GCCJIT_BoolType : SpecificInt<"GCC_JIT_TYPE_BOOL">; 155 | 156 | //===----------------------------------------------------------------------===// 157 | // Float type 158 | //===----------------------------------------------------------------------===// 159 | 160 | def GCCJIT_FloatType : GCCJIT_Type<"Float", "fp"> { 161 | let summary = "Floating point type"; 162 | let description = [{ 163 | GCCJIT type that represents floating point types 164 | }]; 165 | 166 | let parameters = (ins "::gcc_jit_types":$kind); 167 | let hasCustomAssemblyFormat = 1; 168 | } 169 | 170 | //===----------------------------------------------------------------------===// 171 | // Complex type 172 | //===----------------------------------------------------------------------===// 173 | 174 | def GCCJIT_ComplexType : GCCJIT_Type<"Complex", "complex"> { 175 | let summary = "Complex type"; 176 | let description = [{ 177 | GCCJIT type that represents complex types 178 | }]; 179 | 180 | let parameters = (ins "::gcc_jit_types":$kind); 181 | let hasCustomAssemblyFormat = 1; 182 | } 183 | 184 | //===----------------------------------------------------------------------===// 185 | // Array type 186 | //===----------------------------------------------------------------------===// 187 | def GCCJIT_ArrayType : GCCJIT_Type<"Array", "array"> { 188 | let summary = "GCCJIT array type"; 189 | let description = [{ 190 | The `!gccjit.array` type represents an array type. It consists of a single 191 | element type and a constant length. 192 | }]; 193 | let parameters = (ins "mlir::Type":$elementType, "unsigned":$size); 194 | let assemblyFormat = [{ 195 | `<` $elementType `,` $size `>` 196 | }]; 197 | } 198 | 199 | //===----------------------------------------------------------------------===// 200 | // Vector type 201 | //===----------------------------------------------------------------------===// 202 | def GCCJIT_VectorType : GCCJIT_Type<"Vector", "vector"> { 203 | let summary = "GCCJIT vector type"; 204 | let description = [{ 205 | The `!gccjit.vector` type represents a vector type. It consists of a single 206 | element type and a constant length. 207 | }]; 208 | let parameters = (ins "mlir::Type":$elementType, "unsigned":$numUnits); 209 | let assemblyFormat = [{ 210 | `<` $elementType `,` $numUnits `>` 211 | }]; 212 | } 213 | 214 | //===----------------------------------------------------------------------===// 215 | // Struct and union type 216 | //===----------------------------------------------------------------------===// 217 | class GCCJIT_RecordType 218 | : GCCJIT_Type 220 | ]> { 221 | let parameters = (ins 222 | "mlir::StringAttr":$name, 223 | "mlir::ArrayAttr":$fields, 224 | OptionalParameter<"std::optional">:$loc 225 | ); 226 | let assemblyFormat = [{ 227 | `<` custom($name, $fields, $loc) `>` 228 | }]; 229 | 230 | let builders = [ 231 | TypeBuilder<(ins "mlir::StringAttr":$name, 232 | "mlir::ArrayAttr":$fields), [{ 233 | return get($_ctxt, name, fields, std::nullopt); 234 | }]>, 235 | TypeBuilder<(ins "llvm::StringRef":$name, 236 | "llvm::ArrayRef":$fields), [{ 237 | auto nameAttr = StringAttr::get($_ctxt, name); 238 | auto fieldsAttr = ArrayAttr::get( 239 | $_ctxt, llvm::SmallVector(fields.begin(), fields.end())); 240 | return get($_ctxt, nameAttr, fieldsAttr); 241 | }]>, 242 | TypeBuilder<(ins "llvm::StringRef":$name, 243 | "llvm::ArrayRef":$fields, 244 | "mlir::gccjit::SourceLocAttr":$loc), [{ 245 | auto nameAttr = StringAttr::get($_ctxt, name); 246 | auto fieldsAttr = ArrayAttr::get( 247 | $_ctxt, llvm::SmallVector(fields.begin(), fields.end())); 248 | return get($_ctxt, nameAttr, fieldsAttr, loc); 249 | }]> 250 | ]; 251 | 252 | let genVerifyDecl = 1; 253 | } 254 | 255 | def GCCJIT_StructType : GCCJIT_RecordType<"Struct", "struct"> { 256 | let summary = "GCCJIT struct type"; 257 | let description = [{ 258 | The `!gccjit.struct` type represents a GCCJIT struct type. 259 | }]; 260 | } 261 | 262 | def GCCJIT_UnionType : GCCJIT_RecordType<"Union", "union"> { 263 | let summary = "GCCJIT union type"; 264 | let description = [{ 265 | The `!gccjit.union` type represents a GCCJIT union type. 266 | }]; 267 | } 268 | 269 | #endif // GCCJIT_TYPES 270 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/Interfaces/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function(add_gccjit_mlir_attr_interface interface) 2 | set(LLVM_TARGET_DEFINITIONS ${interface}.td) 3 | mlir_tablegen(${interface}.h.inc -gen-attr-interface-decls) 4 | mlir_tablegen(${interface}.cpp.inc -gen-attr-interface-defs) 5 | add_public_tablegen_target(MLIRCIR${interface}IncGen) 6 | add_dependencies(mlir-headers MLIRCIR${interface}IncGen) 7 | endfunction() 8 | 9 | function(add_gccjit_mlir_op_interface interface) 10 | set(LLVM_TARGET_DEFINITIONS ${interface}.td) 11 | mlir_tablegen(${interface}.h.inc -gen-op-interface-decls) 12 | mlir_tablegen(${interface}.cpp.inc -gen-op-interface-defs) 13 | add_public_tablegen_target(MLIR${interface}IncGen) 14 | add_dependencies(mlir-headers MLIR${interface}IncGen) 15 | endfunction() 16 | 17 | function(add_gccjit_mlir_type_interface interface) 18 | set(LLVM_TARGET_DEFINITIONS ${interface}.td) 19 | mlir_tablegen(${interface}.h.inc -gen-type-interface-decls) 20 | mlir_tablegen(${interface}.cpp.inc -gen-type-interface-defs) 21 | add_public_tablegen_target(MLIR${interface}IncGen) 22 | add_dependencies(mlir-headers MLIR${interface}IncGen) 23 | endfunction() 24 | 25 | add_gccjit_mlir_type_interface(GCCJITRecordTypeInterface) 26 | -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef CLANG_INTERFACES_CIR_CIR_FPTYPEINTERFACE_H 16 | #define CLANG_INTERFACES_CIR_CIR_FPTYPEINTERFACE_H 17 | 18 | #include 19 | #include 20 | 21 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 22 | 23 | /// Include the tablegen'd interface declarations. 24 | #include "mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.h.inc" 25 | 26 | #endif // CLANG_INTERFACES_CIR_CIR_FPTYPEINTERFACE_H -------------------------------------------------------------------------------- /include/mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.td: -------------------------------------------------------------------------------- 1 | #ifndef MLIR_GCCJIT_IR_INTERFACES_GCCJIT_RECORD_TYPE_INTERFACE 2 | #define MLIR_GCCJIT_IR_INTERFACES_GCCJIT_RECORD_TYPE_INTERFACE 3 | 4 | include "mlir/IR/OpBase.td" 5 | 6 | def GCCJITRecordTypeInterface : TypeInterface<"GCCJITRecordTypeInterface"> { 7 | let description = [{ 8 | Contains helper functions to query properties about a GCCJIT record type. 9 | 10 | A record type is either a struct type or a union type. 11 | }]; 12 | let cppNamespace = "::mlir::gccjit"; 13 | 14 | let methods = [ 15 | InterfaceMethod< 16 | "Determine whether this record is a union", 17 | /*retTy=*/"bool", 18 | /*methodName=*/"isUnion" 19 | >, 20 | InterfaceMethod< 21 | "Get the name of this record", 22 | /*retTy=*/"llvm::StringRef", 23 | /*methodName=*/"getRecordName" 24 | >, 25 | InterfaceMethod< 26 | [{ 27 | Get the fields in this record, as an ArrayAttr attribute whose elements 28 | are FieldAttr attributes. 29 | }], 30 | /*retTy=*/"ArrayAttr", 31 | /*methodName=*/"getRecordFields" 32 | >, 33 | InterfaceMethod< 34 | [{ 35 | Get the source location of this record. 36 | }], 37 | /*retTy=*/"mlir::gccjit::SourceLocAttr", 38 | /*methodName=*/"getRecordLoc" 39 | > 40 | ]; 41 | } 42 | 43 | #endif // MLIR_GCCJIT_IR_INTERFACES_GCCJIT_RECORD_TYPE_INTERFACE 44 | -------------------------------------------------------------------------------- /include/mlir-gccjit/Passes.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_PASSES_H 16 | #define MLIR_GCCJIT_PASSES_H 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "mlir-gccjit/IR/GCCJITDialect.h" 27 | 28 | namespace mlir::gccjit { 29 | 30 | std::unique_ptr createConvertFuncToGCCJITPass(); 31 | std::unique_ptr createConvertArithToGCCJITPass(); 32 | std::unique_ptr createConvertMemrefToGCCJITPass(); 33 | 34 | #define GEN_PASS_CLASSES 35 | #define GEN_PASS_REGISTRATION 36 | #define GEN_PASS_DECL 37 | #include "mlir-gccjit/Passes.h.inc" 38 | 39 | } // namespace mlir::gccjit 40 | 41 | #endif // MLIR_GCCJIT_PASSES_H 42 | -------------------------------------------------------------------------------- /include/mlir-gccjit/Passes.td: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_PASSES 16 | #define MLIR_GCCJIT_PASSES 17 | 18 | include "mlir/Pass/PassBase.td" 19 | 20 | def ConvertFuncToGCCJIT : Pass<"convert-func-to-gccjit", "::mlir::ModuleOp"> { 21 | let summary = "Convert Functions and control flows to GCCJIT Dialect"; 22 | let description = [{ 23 | This pass converts function operations and control flow operations to GCCJIT 24 | dialect. 25 | }]; 26 | let constructor = "::mlir::gccjit::createConvertFuncToGCCJITPass()"; 27 | let dependentDialects = [ 28 | "::mlir::gccjit::GCCJITDialect", 29 | "::mlir::func::FuncDialect", 30 | "::mlir::BuiltinDialect", 31 | "::mlir::cf::ControlFlowDialect" 32 | ]; 33 | } 34 | 35 | def ConvertArithToGCCJIT : Pass<"convert-arith-to-gccjit", "::mlir::ModuleOp"> { 36 | let summary = "Convert Arithmetic Operations to GCCJIT Dialect"; 37 | let description = [{ 38 | `-convert-arith-to-gccjit` converts arithmetic operations to GCCJIT dialect. 39 | }]; 40 | let constructor = "::mlir::gccjit::createConvertArithToGCCJITPass()"; 41 | let dependentDialects = [ 42 | "::mlir::gccjit::GCCJITDialect", 43 | "::mlir::arith::ArithDialect" 44 | ]; 45 | } 46 | 47 | def ConvertMemrefToGCCJIT : Pass<"convert-memref-to-gccjit", 48 | "::mlir::ModuleOp"> { 49 | let summary = "Convert Memref Operations to GCCJIT Dialect"; 50 | let description = [{ 51 | `-convert-memref-to-gccjit` converts memref operations to GCCJIT dialect. 52 | }]; 53 | let constructor = "::mlir::gccjit::createConvertMemrefToGCCJITPass()"; 54 | let dependentDialects = [ 55 | "::mlir::gccjit::GCCJITDialect", 56 | "::mlir::memref::MemRefDialect" 57 | ]; 58 | } 59 | 60 | #endif // MLIR_GCCJIT_PASSES 61 | -------------------------------------------------------------------------------- /include/mlir-gccjit/Translation/TranslateToGCCJIT.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef MLIR_GCCJIT_TRANSLATION_TRANSLATETOGCCJIT_H 16 | #define MLIR_GCCJIT_TRANSLATION_TRANSLATETOGCCJIT_H 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 29 | #include "mlir-gccjit/IR/GCCJITTypes.h" 30 | 31 | namespace mlir::gccjit { 32 | 33 | void registerToGCCJITGimpleTranslation(); 34 | void registerToGCCJITReproducerTranslation(); 35 | void registerToGCCJITAssemblyTranslation(); 36 | void registerToGCCJITObjectTranslation(); 37 | void registerToGCCJITExecutableTranslation(); 38 | void registerToGCCJITDylibTranslation(); 39 | 40 | struct GCCJITContextDeleter { 41 | void operator()(gcc_jit_context *ctxt) const; 42 | }; 43 | using GCCJITContext = std::unique_ptr; 44 | 45 | class GCCJITTranslation { 46 | class FunctionEntry; 47 | class StructEntry; 48 | class UnionEntry; 49 | 50 | public: 51 | GCCJITTranslation(); 52 | ~GCCJITTranslation(); 53 | 54 | gcc_jit_context *getContext() const; 55 | GCCJITContext takeContext(); 56 | 57 | MLIRContext *getMLIRContext() const { return moduleOp->getContext(); } 58 | 59 | void translateModuleToGCCJIT(ModuleOp op); 60 | 61 | size_t getTypeSize(Type type); 62 | 63 | gcc_jit_type *convertType(Type type); 64 | void convertTypes(TypeRange types, llvm::SmallVector &result); 65 | 66 | gcc_jit_location *getLocation(LocationAttr loc); 67 | gcc_jit_location *convertLocation(SourceLocAttr loc); 68 | 69 | gcc_jit_lvalue *getGlobalLValue(SymbolRefAttr symbol); 70 | FunctionEntry getFunction(SymbolRefAttr symbol); 71 | 72 | private: 73 | class FunctionEntry { 74 | gcc_jit_function *fnHandle; 75 | 76 | public: 77 | FunctionEntry() : fnHandle(nullptr) {} 78 | FunctionEntry(gcc_jit_function *fnHandle) : fnHandle(fnHandle) {} 79 | operator gcc_jit_function *() const { return fnHandle; } 80 | size_t getParamCount() const { 81 | assert(fnHandle); 82 | return gcc_jit_function_get_param_count(fnHandle); 83 | } 84 | gcc_jit_param *operator[](size_t index) const { 85 | assert(fnHandle); 86 | return gcc_jit_function_get_param(fnHandle, index); 87 | } 88 | }; 89 | 90 | class StructEntry { 91 | gcc_jit_struct *structHandle; 92 | 93 | public: 94 | StructEntry(gcc_jit_struct *structHandle) : structHandle(structHandle) {} 95 | gcc_jit_struct *getRawHandle() const { return structHandle; } 96 | size_t getFieldCount() const { 97 | return gcc_jit_struct_get_field_count(structHandle); 98 | } 99 | gcc_jit_field *operator[](size_t index) const { 100 | return gcc_jit_struct_get_field(structHandle, index); 101 | } 102 | gcc_jit_type *getTypeHandle() const { 103 | return gcc_jit_struct_as_type(structHandle); 104 | } 105 | }; 106 | 107 | class UnionEntry { 108 | gcc_jit_type *unionHandle; 109 | llvm::SmallVector fields; 110 | 111 | public: 112 | UnionEntry(gcc_jit_type *unionHandle, ArrayRef fields) 113 | : unionHandle(unionHandle), fields(fields) {} 114 | gcc_jit_type *getRawHandle() const { return unionHandle; } 115 | size_t getFieldCount() const { return fields.size(); } 116 | gcc_jit_field *operator[](size_t index) const { return fields[index]; } 117 | gcc_jit_type *getTypeHandle() const { return unionHandle; } 118 | }; 119 | 120 | class GCCJITRecord : public llvm::PointerUnion { 121 | public: 122 | using PointerUnion::PointerUnion; 123 | gcc_jit_struct *getAsStruct() const { 124 | return this->get()->getRawHandle(); 125 | } 126 | gcc_jit_type *getAsType() const { 127 | return this->is() ? get()->getTypeHandle() 128 | : get()->getRawHandle(); 129 | } 130 | gcc_jit_field *operator[](size_t index) const { 131 | if (this->is()) 132 | return get()->operator[](index); 133 | return get()->operator[](index); 134 | } 135 | size_t getFieldCount() const { 136 | return this->is() ? get()->getFieldCount() 137 | : get()->getFieldCount(); 138 | } 139 | bool isStruct() const { return this->is(); } 140 | bool isUnion() const { return this->is(); } 141 | }; 142 | 143 | gcc_jit_context *ctxt; 144 | ModuleOp moduleOp; 145 | llvm::DenseMap functionMap; 146 | llvm::DenseMap globalMap; 147 | llvm::DenseMap typeMap; 148 | llvm::DenseMap structMap; 149 | llvm::DenseMap unionMap; 150 | 151 | void populateGCCJITModuleOptions(); 152 | void declareAllFunctionAndGlobals(); 153 | void translateGlobalInitializers(); 154 | void translateFunctions(); 155 | 156 | private: 157 | StructEntry &getOrCreateStructEntry(StructType type); 158 | UnionEntry &getOrCreateUnionEntry(UnionType type); 159 | 160 | public: 161 | GCCJITRecord getOrCreateRecordEntry(Type type); 162 | }; 163 | 164 | llvm::Expected translateModuleToGCCJIT(ModuleOp op); 165 | 166 | } // namespace mlir::gccjit 167 | 168 | #endif // MLIR_GCCJIT_TRANSLATION_TRANSLATETOGCCJIT_H 169 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lancern/mlir-gccjit/f981c8510688f2152c26882c95858d2ff039a2fd/logo.png -------------------------------------------------------------------------------- /run-lit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from lit.main import main 4 | 5 | if __name__ == "__main__": 6 | main() 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect_library(MLIRGCCJIT 2 | GCCJITAttrs.cpp 3 | GCCJITDialect.cpp 4 | GCCJITOps.cpp 5 | GCCJITTypes.cpp 6 | 7 | ADDITIONAL_HEADER_DIRS 8 | ${PROJECT_SOURCE_DIR}/include/mlir-gccjit 9 | 10 | DEPENDS 11 | MLIRGCCJITOpsIncGen 12 | MLIRGCCJITEnumsGen 13 | 14 | LINK_LIBS PUBLIC 15 | MLIRIR 16 | libgccjit 17 | 18 | LINK_COMPONENTS 19 | Core 20 | ) 21 | 22 | add_subdirectory(Interfaces) 23 | add_subdirectory(Translation) 24 | add_subdirectory(Conversion) 25 | -------------------------------------------------------------------------------- /src/Conversion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_conversion_library(MLIRGCCJITConversion 2 | TypeConverter.cpp 3 | ConvertFuncToGCCJIT.cpp 4 | ConvertArithToGCCJIT.cpp 5 | ConvertMemrefToGCCJIT.cpp 6 | 7 | DEPENDS 8 | MLIRGCCJIT 9 | MLIRGCCJITPassIncGen 10 | 11 | LINK_LIBS PUBLIC 12 | MLIRIR 13 | MLIRGCCJIT 14 | libgccjit 15 | 16 | LINK_COMPONENTS 17 | Core 18 | ) 19 | -------------------------------------------------------------------------------- /src/Conversion/ConvertArithToGCCJIT.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "mlir-gccjit/Conversion/Conversions.h" 21 | #include "mlir-gccjit/Conversion/TypeConverter.h" 22 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 23 | #include "mlir-gccjit/IR/GCCJITOps.h" 24 | #include "mlir-gccjit/IR/GCCJITOpsEnums.h" 25 | #include "mlir-gccjit/IR/GCCJITTypes.h" 26 | #include "mlir-gccjit/Passes.h" 27 | 28 | using namespace mlir; 29 | using namespace mlir::gccjit; 30 | 31 | namespace { 32 | struct ConvertArithToGCCJITPass 33 | : public ConvertArithToGCCJITBase { 34 | using ConvertArithToGCCJITBase::ConvertArithToGCCJITBase; 35 | void runOnOperation() override final; 36 | }; 37 | 38 | template 39 | class GCCJITLoweringPattern : public mlir::OpConversionPattern { 40 | protected: 41 | const GCCJITTypeConverter *getTypeConverter() const { 42 | return static_cast(this->typeConverter); 43 | } 44 | 45 | public: 46 | using OpConversionPattern::OpConversionPattern; 47 | }; 48 | 49 | class ConstantOpLowering : public GCCJITLoweringPattern { 50 | public: 51 | using GCCJITLoweringPattern::GCCJITLoweringPattern; 52 | mlir::LogicalResult 53 | matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor, 54 | mlir::ConversionPatternRewriter &rewriter) const override { 55 | auto attr = op.getValue(); 56 | 57 | if (auto value = dyn_cast(attr)) { 58 | rewriter.replaceOpWithNewOp( 59 | op, getTypeConverter()->convertIntegerAttr(value)); 60 | return mlir::success(); 61 | } 62 | 63 | if (auto value = dyn_cast(attr)) { 64 | rewriter.replaceOpWithNewOp( 65 | op, getTypeConverter()->convertFloatAttr(value)); 66 | return mlir::success(); 67 | } 68 | 69 | return mlir::failure(); 70 | } 71 | }; 72 | 73 | class CmpIOpLowering : public GCCJITLoweringPattern { 74 | void getComparison(gccjit::CmpOp &kind, bool &signedness, 75 | arith::CmpIPredicate pred) const { 76 | signedness = false; 77 | switch (pred) { 78 | case arith::CmpIPredicate::eq: 79 | kind = gccjit::CmpOp::Eq; 80 | break; 81 | case arith::CmpIPredicate::ne: 82 | kind = gccjit::CmpOp::Ne; 83 | break; 84 | 85 | case arith::CmpIPredicate::slt: 86 | signedness = true; 87 | [[fallthrough]]; 88 | case arith::CmpIPredicate::ult: 89 | kind = gccjit::CmpOp::Lt; 90 | break; 91 | 92 | case arith::CmpIPredicate::sle: 93 | signedness = true; 94 | [[fallthrough]]; 95 | case arith::CmpIPredicate::ule: 96 | kind = gccjit::CmpOp::Le; 97 | break; 98 | 99 | case arith::CmpIPredicate::sgt: 100 | signedness = true; 101 | [[fallthrough]]; 102 | case arith::CmpIPredicate::ugt: 103 | kind = gccjit::CmpOp::Gt; 104 | break; 105 | 106 | case arith::CmpIPredicate::sge: 107 | signedness = true; 108 | [[fallthrough]]; 109 | case arith::CmpIPredicate::uge: 110 | kind = gccjit::CmpOp::Ge; 111 | break; 112 | } 113 | } 114 | 115 | public: 116 | using GCCJITLoweringPattern::GCCJITLoweringPattern; 117 | mlir::LogicalResult 118 | matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor, 119 | mlir::ConversionPatternRewriter &rewriter) const override { 120 | auto lhs = adaptor.getLhs(); 121 | auto rhs = adaptor.getRhs(); 122 | auto inputTy = cast(lhs.getType()); 123 | auto pred = adaptor.getPredicate(); 124 | gccjit::CmpOp kind; 125 | bool signedness; 126 | getComparison(kind, signedness, pred); 127 | auto i1 = getTypeConverter()->convertType(op.getResult().getType()); 128 | if (signedness && !getTypeConverter()->isSigned(inputTy)) { 129 | auto signedType = getTypeConverter()->makeSigned(inputTy); 130 | lhs = rewriter.create(op.getLoc(), signedType, lhs); 131 | rhs = rewriter.create(op.getLoc(), signedType, rhs); 132 | } 133 | auto cmpAttr = CmpOpAttr::get(op.getContext(), kind); 134 | rewriter.replaceOpWithNewOp(op, i1, cmpAttr, lhs, rhs); 135 | return mlir::success(); 136 | } 137 | }; 138 | template 139 | class TrivialBinOpConversion : public GCCJITLoweringPattern { 140 | using GCCJITLoweringPattern::GCCJITLoweringPattern; 141 | mlir::LogicalResult 142 | matchAndRewrite(Op op, typename GCCJITLoweringPattern::OpAdaptor adaptor, 143 | mlir::ConversionPatternRewriter &rewriter) const override { 144 | auto lhs = adaptor.getLhs(); 145 | auto rhs = adaptor.getRhs(); 146 | auto resultTy = lhs.getType(); 147 | auto kind = BOpAttr::get(op.getContext(), Kind); 148 | rewriter.replaceOpWithNewOp(op, resultTy, kind, lhs, rhs); 149 | return mlir::success(); 150 | } 151 | }; 152 | 153 | using AddIOpLowering = TrivialBinOpConversion; 154 | using AddFOpLowering = TrivialBinOpConversion; 155 | using MulFOpLowering = TrivialBinOpConversion; 156 | 157 | void ConvertArithToGCCJITPass::runOnOperation() { 158 | auto moduleOp = getOperation(); 159 | auto typeConverter = GCCJITTypeConverter(); 160 | // unrealized conversions 161 | auto materializeAsUnrealizedCast = [](OpBuilder &builder, Type resultType, 162 | ValueRange inputs, 163 | Location loc) -> Value { 164 | if (inputs.size() != 1) 165 | return Value(); 166 | 167 | return builder.create(loc, resultType, inputs) 168 | .getResult(0); 169 | }; 170 | typeConverter.addTargetMaterialization(materializeAsUnrealizedCast); 171 | typeConverter.addSourceMaterialization(materializeAsUnrealizedCast); 172 | mlir::RewritePatternSet patterns(&getContext()); 173 | patterns.add(typeConverter, &getContext()); 175 | mlir::ConversionTarget target(getContext()); 176 | target.addLegalDialect(); 177 | target.addIllegalDialect(); 178 | llvm::SmallVector ops; 179 | for (auto func : moduleOp.getOps()) 180 | ops.push_back(func); 181 | for (auto func : moduleOp.getOps()) 182 | ops.push_back(func); 183 | if (failed(applyPartialConversion(ops, target, std::move(patterns)))) 184 | signalPassFailure(); 185 | } 186 | } // namespace 187 | 188 | std::unique_ptr mlir::gccjit::createConvertArithToGCCJITPass() { 189 | return std::make_unique(); 190 | } 191 | -------------------------------------------------------------------------------- /src/Conversion/TypeConverter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "mlir-gccjit/Conversion/TypeConverter.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 24 | #include "mlir-gccjit/IR/GCCJITTypes.h" 25 | 26 | using namespace mlir; 27 | using namespace mlir::gccjit; 28 | 29 | GCCJITTypeConverter::GCCJITTypeConverter() : TypeConverter() { 30 | addConversion([&](mlir::IndexType type) { return convertIndexType(type); }); 31 | addConversion( 32 | [&](mlir::IntegerType type) { return convertIntegerType(type); }); 33 | addConversion([&](mlir::FloatType type) { return convertFloatType(type); }); 34 | addConversion( 35 | [&](mlir::ComplexType type) { return convertComplexType(type); }); 36 | addConversion([&](mlir::VectorType type) { return convertVectorType(type); }); 37 | addConversion([&](mlir::FunctionType type) { 38 | return convertFunctionTypeAsPtr(type, false); 39 | }); 40 | addConversion( 41 | [&](mlir::MemRefType type) { return getMemrefDescriptorType(type); }); 42 | } 43 | 44 | // Nothing to do for now 45 | GCCJITTypeConverter::~GCCJITTypeConverter() {} 46 | 47 | gccjit::IntType 48 | GCCJITTypeConverter::convertIndexType(mlir::IndexType type) const { 49 | return IntType::get(type.getContext(), GCC_JIT_TYPE_SIZE_T); 50 | } 51 | 52 | gccjit::IntType 53 | GCCJITTypeConverter::convertIntegerType(mlir::IntegerType type) const { 54 | // gccjit always translates bitwidth to specific types 55 | // https://github.com/gcc-mirror/gcc/blob/ae0dbea896b77686fcd1c890e5b7c5fed6197767/gcc/jit/jit-recording.cc#L796 56 | switch (type.getWidth()) { 57 | case 1: 58 | return IntType::get(type.getContext(), GCC_JIT_TYPE_BOOL); 59 | case 8: 60 | return IntType::get(type.getContext(), type.isSigned() 61 | ? GCC_JIT_TYPE_INT8_T 62 | : GCC_JIT_TYPE_UINT8_T); 63 | case 16: 64 | return IntType::get(type.getContext(), type.isSigned() 65 | ? GCC_JIT_TYPE_INT16_T 66 | : GCC_JIT_TYPE_UINT16_T); 67 | case 32: 68 | return IntType::get(type.getContext(), type.isSigned() 69 | ? GCC_JIT_TYPE_INT32_T 70 | : GCC_JIT_TYPE_UINT32_T); 71 | case 64: 72 | return IntType::get(type.getContext(), type.isSigned() 73 | ? GCC_JIT_TYPE_INT64_T 74 | : GCC_JIT_TYPE_UINT64_T); 75 | case 128: 76 | return IntType::get(type.getContext(), type.isSigned() 77 | ? GCC_JIT_TYPE_INT128_T 78 | : GCC_JIT_TYPE_UINT128_T); 79 | default: 80 | return {}; 81 | } 82 | } 83 | 84 | gccjit::IntAttr 85 | GCCJITTypeConverter::convertIntegerAttr(mlir::IntegerAttr attr) const { 86 | auto value = attr.getValue(); 87 | if (auto intType = dyn_cast(attr.getType())) { 88 | auto type = convertIntegerType(intType); 89 | return IntAttr::get(attr.getContext(), type, value); 90 | } 91 | 92 | if (auto indexType = dyn_cast(attr.getType())) { 93 | auto type = convertIndexType(indexType); 94 | return IntAttr::get(attr.getContext(), type, value); 95 | } 96 | 97 | return {}; 98 | } 99 | 100 | gccjit::FloatType 101 | GCCJITTypeConverter::convertFloatType(mlir::FloatType type) const { 102 | if (type.isF32()) 103 | return FloatType::get(type.getContext(), GCC_JIT_TYPE_FLOAT); 104 | if (type.isF64()) 105 | return FloatType::get(type.getContext(), GCC_JIT_TYPE_DOUBLE); 106 | 107 | // FIXME: we cannot really distinguish between f80 and f128 for GCCJIT, maybe 108 | // we need target information. 109 | if (type.isF80() || type.isF128()) 110 | return FloatType::get(type.getContext(), GCC_JIT_TYPE_LONG_DOUBLE); 111 | 112 | return {}; 113 | } 114 | 115 | gccjit::FloatAttr 116 | GCCJITTypeConverter::convertFloatAttr(mlir::FloatAttr attr) const { 117 | auto value = attr.getValue(); 118 | auto type = convertFloatType(cast(attr.getType())); 119 | return FloatAttr::get(attr.getContext(), type, value); 120 | } 121 | 122 | gccjit::ComplexType 123 | GCCJITTypeConverter::convertComplexType(mlir::ComplexType type) const { 124 | auto elementType = type.getElementType(); 125 | if (elementType.isF32()) 126 | return ComplexType::get(type.getContext(), GCC_JIT_TYPE_COMPLEX_FLOAT); 127 | if (elementType.isF64()) 128 | return ComplexType::get(type.getContext(), GCC_JIT_TYPE_COMPLEX_DOUBLE); 129 | if (elementType.isF80() || elementType.isF128()) 130 | return ComplexType::get(type.getContext(), 131 | GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); 132 | return {}; 133 | } 134 | 135 | gccjit::VectorType 136 | GCCJITTypeConverter::convertVectorType(mlir::VectorType type) const { 137 | auto elementType = convertType(type.getElementType()); 138 | auto size = type.getNumElements(); 139 | return VectorType::get(type.getContext(), elementType, size); 140 | } 141 | 142 | gccjit::FuncType 143 | GCCJITTypeConverter::convertFunctionType(mlir::FunctionType type, 144 | bool isVarArg) const { 145 | llvm::SmallVector argTypes; 146 | argTypes.reserve(type.getNumInputs()); 147 | if (convertTypes(type.getInputs(), argTypes).failed()) 148 | return {}; 149 | auto resultType = 150 | convertAndPackTypesIfNonSingleton(type.getResults(), type.getContext()); 151 | return FuncType::get(type.getContext(), argTypes, resultType, isVarArg); 152 | } 153 | 154 | gccjit::PointerType 155 | GCCJITTypeConverter::convertFunctionTypeAsPtr(mlir::FunctionType type, 156 | bool isVarArg) const { 157 | auto funcType = convertFunctionType(type, isVarArg); 158 | return PointerType::get(type.getContext(), funcType); 159 | } 160 | 161 | gccjit::StructType 162 | GCCJITTypeConverter::getMemrefDescriptorType(mlir::MemRefType type) const { 163 | std::string name; 164 | llvm::raw_string_ostream os(name); 165 | type.print(os); 166 | os.flush(); 167 | auto nameAttr = StringAttr::get(type.getContext(), name); 168 | auto elementType = convertType(type.getElementType()); 169 | auto elementPtrType = PointerType::get(type.getContext(), elementType); 170 | auto indexType = IntType::get(type.getContext(), GCC_JIT_TYPE_SIZE_T); 171 | auto rank = type.getRank(); 172 | auto dimOrStrideType = 173 | gccjit::ArrayType::get(type.getContext(), indexType, rank); 174 | SmallVector fields; 175 | llvm::StringRef names[]{ 176 | "base", "aligned", "offset", "sizes", "strides", 177 | }; 178 | for (auto [idx, field] : 179 | llvm::enumerate(ArrayRef{elementPtrType, elementPtrType, indexType, 180 | dimOrStrideType, dimOrStrideType})) { 181 | auto nameAttr = StringAttr::get(type.getContext(), names[idx]); 182 | fields.push_back(FieldAttr::get(type.getContext(), nameAttr, field)); 183 | } 184 | auto fieldsAttr = ArrayAttr::get(type.getContext(), fields); 185 | return StructType::get(type.getContext(), nameAttr, fieldsAttr); 186 | } 187 | 188 | gccjit::StructType GCCJITTypeConverter::getUnrankedMemrefDescriptorType( 189 | mlir::UnrankedMemRefType type) const { 190 | 191 | auto name = 192 | Twine("__unranked_memref_") 193 | .concat(Twine(reinterpret_cast(type.getAsOpaquePointer()))) 194 | .str(); 195 | auto nameAttr = StringAttr::get(type.getContext(), name); 196 | auto indexType = IntType::get(type.getContext(), GCC_JIT_TYPE_SIZE_T); 197 | auto opaquePtrType = PointerType::get( 198 | type.getContext(), IntType::get(type.getContext(), GCC_JIT_TYPE_VOID)); 199 | SmallVector fields; 200 | for (auto [idx, field] : 201 | llvm::enumerate(ArrayRef{indexType, opaquePtrType})) { 202 | auto name = Twine("__field_").concat(Twine(idx)).str(); 203 | auto nameAttr = StringAttr::get(type.getContext(), name); 204 | fields.push_back(FieldAttr::get(type.getContext(), nameAttr, field)); 205 | } 206 | auto fieldsAttr = ArrayAttr::get(type.getContext(), fields); 207 | return StructType::get(type.getContext(), nameAttr, fieldsAttr); 208 | } 209 | 210 | Type GCCJITTypeConverter::convertAndPackTypesIfNonSingleton( 211 | TypeRange types, MLIRContext *ctx) const { 212 | if (types.size() == 0) 213 | return VoidType::get(ctx); 214 | if (types.size() == 1) 215 | return convertType(types.front()); 216 | 217 | auto *name = "__return_pack"; 218 | SmallVector fields; 219 | for (auto [idx, type] : llvm::enumerate(types)) { 220 | auto name = Twine("__field_").concat(Twine(idx)).str(); 221 | auto nameAttr = StringAttr::get(ctx, name); 222 | fields.push_back(FieldAttr::get(type.getContext(), nameAttr, type)); 223 | } 224 | auto nameAttr = StringAttr::get(ctx, name); 225 | auto fieldsAttr = ArrayAttr::get(ctx, fields); 226 | return StructType::get(ctx, nameAttr, fieldsAttr); 227 | } 228 | 229 | bool GCCJITTypeConverter::isSigned(gccjit::IntType type) const { 230 | switch (type.getKind()) { 231 | case GCC_JIT_TYPE_UNSIGNED_INT: 232 | case GCC_JIT_TYPE_UNSIGNED_LONG: 233 | case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: 234 | case GCC_JIT_TYPE_UINT8_T: 235 | case GCC_JIT_TYPE_UINT16_T: 236 | case GCC_JIT_TYPE_UINT32_T: 237 | case GCC_JIT_TYPE_UINT64_T: 238 | case GCC_JIT_TYPE_UINT128_T: 239 | return false; 240 | default: 241 | return true; 242 | } 243 | } 244 | 245 | gccjit::IntType GCCJITTypeConverter::makeSigned(gccjit::IntType type) const { 246 | switch (type.getKind()) { 247 | case GCC_JIT_TYPE_UNSIGNED_INT: 248 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT); 249 | case GCC_JIT_TYPE_UNSIGNED_LONG: 250 | return IntType::get(type.getContext(), GCC_JIT_TYPE_LONG); 251 | case GCC_JIT_TYPE_UNSIGNED_LONG_LONG: 252 | return IntType::get(type.getContext(), GCC_JIT_TYPE_LONG_LONG); 253 | case GCC_JIT_TYPE_UINT8_T: 254 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT8_T); 255 | case GCC_JIT_TYPE_UINT16_T: 256 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT16_T); 257 | case GCC_JIT_TYPE_UINT32_T: 258 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT32_T); 259 | case GCC_JIT_TYPE_UINT64_T: 260 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT64_T); 261 | case GCC_JIT_TYPE_UINT128_T: 262 | return IntType::get(type.getContext(), GCC_JIT_TYPE_INT128_T); 263 | default: 264 | return type; 265 | } 266 | } 267 | 268 | // the counterpart of makeSigned 269 | gccjit::IntType GCCJITTypeConverter::makeUnsigned(gccjit::IntType type) const { 270 | switch (type.getKind()) { 271 | case GCC_JIT_TYPE_INT: 272 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UNSIGNED_INT); 273 | case GCC_JIT_TYPE_LONG: 274 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UNSIGNED_LONG); 275 | case GCC_JIT_TYPE_LONG_LONG: 276 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UNSIGNED_LONG_LONG); 277 | case GCC_JIT_TYPE_INT8_T: 278 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UINT8_T); 279 | case GCC_JIT_TYPE_INT16_T: 280 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UINT16_T); 281 | case GCC_JIT_TYPE_INT32_T: 282 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UINT32_T); 283 | case GCC_JIT_TYPE_INT64_T: 284 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UINT64_T); 285 | case GCC_JIT_TYPE_INT128_T: 286 | return IntType::get(type.getContext(), GCC_JIT_TYPE_UINT128_T); 287 | default: 288 | return type; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /src/GCCJITAttrs.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "mlir-gccjit/IR/GCCJITAttrs.h" 28 | #include "mlir-gccjit/IR/GCCJITDialect.h" 29 | #include "mlir-gccjit/IR/GCCJITOpsEnums.h" 30 | #include "mlir-gccjit/IR/GCCJITTypes.h" 31 | 32 | #include "mlir-gccjit/IR/GCCJITOpsEnums.cpp.inc" 33 | 34 | #define GET_ATTRDEF_CLASSES 35 | #include "mlir-gccjit/IR/GCCJITOpsAttributes.cpp.inc" 36 | 37 | namespace mlir::gccjit { 38 | //===----------------------------------------------------------------------===// 39 | // General GCCJIT parsing / printing 40 | //===----------------------------------------------------------------------===// 41 | Attribute GCCJITDialect::parseAttribute(DialectAsmParser &parser, 42 | Type type) const { 43 | llvm::SMLoc typeLoc = parser.getCurrentLocation(); 44 | StringRef mnemonic; 45 | Attribute genAttr; 46 | OptionalParseResult parseResult = 47 | generatedAttributeParser(parser, &mnemonic, type, genAttr); 48 | if (parseResult.has_value()) 49 | return genAttr; 50 | parser.emitError(typeLoc, "unknown attribute in GCCJIT dialect"); 51 | return Attribute(); 52 | } 53 | 54 | void GCCJITDialect::printAttribute(Attribute attr, 55 | DialectAsmPrinter &os) const { 56 | if (failed(generatedAttributePrinter(attr, os))) 57 | llvm_unreachable("unexpected GCCJIT attribute"); 58 | } 59 | 60 | //===----------------------------------------------------------------------===// 61 | // TLSModelAttr definitions 62 | //===----------------------------------------------------------------------===// 63 | 64 | Attribute TLSModelAttr::parse(AsmParser &parser, Type odsType) { 65 | auto loc = parser.getCurrentLocation(); 66 | if (parser.parseLess()) 67 | return {}; 68 | 69 | // Parse variable 'lang'. 70 | llvm::StringRef model; 71 | if (parser.parseKeyword(&model)) 72 | return {}; 73 | 74 | // Check if parsed value is a valid language. 75 | auto modelEnum = symbolizeTLSModelEnum(model); 76 | if (!modelEnum.has_value()) { 77 | parser.emitError(loc) << "invalid TLS model keyword '" << model << "'"; 78 | return {}; 79 | } 80 | 81 | if (parser.parseGreater()) 82 | return {}; 83 | 84 | return get(parser.getContext(), 85 | TLSModelEnumAttr::get(parser.getContext(), modelEnum.value())); 86 | } 87 | 88 | void TLSModelAttr::print(AsmPrinter &printer) const { 89 | printer << "<" << getModel().getValue() << '>'; 90 | } 91 | 92 | //===----------------------------------------------------------------------===// 93 | // IntAttr definitions 94 | //===----------------------------------------------------------------------===// 95 | 96 | Attribute IntAttr::parse(AsmParser &parser, Type odsType) { 97 | auto intType = mlir::dyn_cast_if_present(odsType); 98 | 99 | if (!intType) { 100 | parser.emitError(parser.getCurrentLocation(), 101 | "expected integer type for #gccjit.int attribute"); 102 | return {}; 103 | } 104 | 105 | // Consume the '<' symbol. 106 | if (parser.parseLess()) 107 | return {}; 108 | 109 | // Fetch arbitrary precision integer value. 110 | long value; 111 | if (parser.parseInteger(value)) 112 | parser.emitError(parser.getCurrentLocation(), "expected integer value"); 113 | mlir::APInt storage(sizeof(long) * 8, value, true); 114 | if (storage.getSExtValue() != value) 115 | parser.emitError(parser.getCurrentLocation(), 116 | "integer value too large for the given type"); 117 | 118 | // Consume the '>' symbol. 119 | if (parser.parseGreater()) 120 | return {}; 121 | 122 | return IntAttr::get(parser.getContext(), intType, storage); 123 | } 124 | 125 | void IntAttr::print(AsmPrinter &printer) const { 126 | printer << '<' << getValue() << '>'; 127 | } 128 | 129 | //===----------------------------------------------------------------------===// 130 | // FloatAttr definitions 131 | //===----------------------------------------------------------------------===// 132 | 133 | Attribute FloatAttr::parse(AsmParser &parser, Type odsType) { 134 | auto floatType = mlir::dyn_cast_if_present(odsType); 135 | if (!floatType) { 136 | parser.emitError( 137 | parser.getCurrentLocation(), 138 | "expected floating-point type for #gccjit.float attribute"); 139 | return {}; 140 | } 141 | 142 | // Consume the '<' symbol. 143 | if (parser.parseLess()) 144 | return {}; 145 | 146 | // Fetch floating-point value. 147 | double value; 148 | if (parser.parseFloat(value)) 149 | parser.emitError(parser.getCurrentLocation(), 150 | "expected floating-point value"); 151 | 152 | // Consume the '>' symbol. 153 | if (parser.parseGreater()) 154 | return {}; 155 | 156 | return FloatAttr::get(parser.getContext(), floatType, mlir::APFloat(value)); 157 | } 158 | 159 | void FloatAttr::print(AsmPrinter &printer) const { 160 | printer << '<' << getValue() << '>'; 161 | } 162 | 163 | //===----------------------------------------------------------------------===// 164 | // Special value attribute definitions 165 | //===----------------------------------------------------------------------===// 166 | 167 | LogicalResult 168 | ZeroAttr::verify(llvm::function_ref emitError, 169 | Type type) { 170 | if (!mlir::isa(type)) 171 | return emitError() 172 | << "#gccjit.zero must be of integer or floating-point type"; 173 | return success(); 174 | } 175 | 176 | LogicalResult 177 | OneAttr::verify(llvm::function_ref emitError, Type type) { 178 | if (!mlir::isa(type)) 179 | return emitError() 180 | << "#gccjit.one must be of integer or floating-point type"; 181 | return success(); 182 | } 183 | 184 | //===----------------------------------------------------------------------===// 185 | // OptLevelAttr definitions 186 | //===----------------------------------------------------------------------===// 187 | Attribute OptLevelAttr::parse(AsmParser &parser, Type odsType) { 188 | llvm::SMLoc loc = parser.getCurrentLocation(); 189 | if (parser.parseLess()) 190 | return {}; 191 | 192 | // Parse variable 'level'. 193 | llvm::StringRef level; 194 | if (parser.parseKeyword(&level)) 195 | return {}; 196 | 197 | // Check if parsed value is a valid optimization level. 198 | auto optLevelEnum = symbolizeOptLevelEnum(level); 199 | if (!optLevelEnum.has_value()) { 200 | parser.emitError(loc) << "invalid optimization level keyword '" << level 201 | << "'"; 202 | return {}; 203 | } 204 | 205 | if (parser.parseGreater()) 206 | return {}; 207 | 208 | return get(parser.getContext(), 209 | OptLevelEnumAttr::get(parser.getContext(), optLevelEnum.value())); 210 | } 211 | 212 | void OptLevelAttr::print(AsmPrinter &printer) const { 213 | printer << "<" << getLevel().getValue() << '>'; 214 | } 215 | 216 | //===----------------------------------------------------------------------===// 217 | // FunctionAttr definitions 218 | //===----------------------------------------------------------------------===// 219 | Attribute FunctionAttr::parse(AsmParser &parser, Type odsType) { 220 | llvm::SMLoc loc = parser.getCurrentLocation(); 221 | if (parser.parseLess()) 222 | return {}; 223 | 224 | std::string keyword; 225 | if (parser.parseKeywordOrString(&keyword)) { 226 | parser.emitError(loc) << "expected attribute kind"; 227 | return {}; 228 | } 229 | 230 | std::optional kind = symbolizeFnAttrEnum(keyword); 231 | if (!kind.has_value()) { 232 | parser.emitError(loc) << "unknown function attribute kind: " << keyword; 233 | return {}; 234 | } 235 | 236 | auto kindAttr = FnAttrEnumAttr::get(parser.getContext(), kind.value()); 237 | 238 | if (isUnitFnAttr(kindAttr.getValue())) { 239 | if (parser.parseGreater()) 240 | return {}; 241 | return FunctionAttr::get(parser.getContext(), kindAttr, {}, {}); 242 | } 243 | 244 | if (parser.parseComma()) 245 | return {}; 246 | 247 | if (isStringFnAttr(kindAttr.getValue())) { 248 | StringAttr strValue; 249 | if (parser.parseAttribute(strValue)) 250 | return {}; 251 | if (parser.parseGreater()) 252 | return {}; 253 | return FunctionAttr::get(parser.getContext(), kindAttr, strValue, {}); 254 | } 255 | 256 | assert(isIntArrayFnAttr(kindAttr.getValue())); 257 | DenseI32ArrayAttr intArrayValue; 258 | if (parser.parseAttribute(intArrayValue)) 259 | return {}; 260 | if (parser.parseGreater()) 261 | return {}; 262 | return FunctionAttr::get(parser.getContext(), kindAttr, {}, intArrayValue); 263 | } 264 | 265 | void FunctionAttr::print(AsmPrinter &printer) const { 266 | printer << "<" << getAttr().getValue(); 267 | if (isStringFnAttr(getAttr().getValue())) { 268 | printer << ", "; 269 | printer.printAttribute(getStrValue().value()); 270 | } else if (isIntArrayFnAttr(getAttr().getValue())) { 271 | printer << ", "; 272 | printer.printAttribute(getIntArrayValue().value()); 273 | } 274 | printer << ">"; 275 | } 276 | 277 | //===----------------------------------------------------------------------===// 278 | // GCCJIT Dialect 279 | //===----------------------------------------------------------------------===// 280 | 281 | void GCCJITDialect::registerAttributes() { 282 | addAttributes< 283 | #define GET_ATTRDEF_LIST 284 | #include "mlir-gccjit/IR/GCCJITOpsAttributes.cpp.inc" 285 | >(); 286 | } 287 | 288 | } // namespace mlir::gccjit 289 | -------------------------------------------------------------------------------- /src/GCCJITDialect.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "mlir-gccjit/IR/GCCJITDialect.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "mlir-gccjit/IR/GCCJITOps.h" 38 | #include "mlir-gccjit/IR/GCCJITTypes.h" 39 | 40 | using namespace mlir; 41 | using namespace mlir::gccjit; 42 | 43 | #include "mlir-gccjit/IR/GCCJITOpsDialect.cpp.inc" 44 | 45 | void GCCJITDialect::initialize() { 46 | registerTypes(); 47 | registerAttributes(); 48 | addOperations< 49 | #define GET_OP_LIST 50 | #include "mlir-gccjit/IR/GCCJITOps.cpp.inc" 51 | >(); 52 | } 53 | -------------------------------------------------------------------------------- /src/Interfaces/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect_library(MLIRGCCJITInterfaces 2 | GCCJITRecordTypeInterface.cpp 3 | DEPENDS 4 | MLIRGCCJIT 5 | MLIRGCCJITRecordTypeInterfaceIncGen 6 | LINK_COMPONENTS 7 | Core 8 | LINK_LIBS PUBLIC 9 | MLIRGCCJIT 10 | ) 11 | -------------------------------------------------------------------------------- /src/Interfaces/GCCJITRecordTypeInterface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Sirui Mu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.h" 16 | 17 | using namespace mlir; 18 | using namespace mlir::gccjit; 19 | 20 | #include "mlir-gccjit/IR/Interfaces/GCCJITRecordTypeInterface.cpp.inc" 21 | -------------------------------------------------------------------------------- /src/Translation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_mlir_dialect_library(MLIRTranslateToGCCJIT 2 | TranslateToGCCJIT.cpp 3 | Registration.cpp 4 | TypeTranslation.cpp 5 | 6 | DEPENDS 7 | MLIRGCCJIT 8 | MLIRGCCJITInterfaces 9 | 10 | LINK_LIBS PUBLIC 11 | MLIRIR 12 | MLIRGCCJIT 13 | MLIRGCCJITInterfaces 14 | libgccjit 15 | 16 | LINK_COMPONENTS 17 | Core 18 | ) 19 | -------------------------------------------------------------------------------- /src/Translation/Registration.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "mlir-gccjit/IR/GCCJITDialect.h" 27 | #include "mlir-gccjit/Translation/TranslateToGCCJIT.h" 28 | 29 | namespace mlir::gccjit { 30 | namespace { 31 | enum class OutputType { 32 | Gimple, 33 | Reproducer, 34 | Assembly, 35 | Object, 36 | Executable, 37 | Dylib 38 | }; 39 | 40 | llvm::Expected> 41 | dumpContextToTempfile(gcc_jit_context *ctxt, OutputType type) { 42 | StringRef suffix; 43 | llvm::SmallString<128> path; 44 | switch (type) { 45 | case OutputType::Gimple: 46 | suffix = ".gimple"; 47 | break; 48 | case OutputType::Reproducer: 49 | suffix = ".c"; 50 | break; 51 | case OutputType::Assembly: 52 | suffix = ".s"; 53 | break; 54 | case OutputType::Object: 55 | suffix = ".o"; 56 | break; 57 | case OutputType::Executable: 58 | suffix = ".exe"; 59 | break; 60 | case OutputType::Dylib: 61 | suffix = ".so"; 62 | break; 63 | } 64 | auto err = llvm::sys::fs::createTemporaryFile("mlir-gccjit", suffix, path); 65 | if (err) 66 | return llvm::createStringError(err, "failed to create temporary file"); 67 | switch (type) { 68 | case OutputType::Gimple: 69 | gcc_jit_context_dump_to_file(ctxt, path.c_str(), false); 70 | break; 71 | case OutputType::Reproducer: 72 | gcc_jit_context_dump_reproducer_to_file(ctxt, path.c_str()); 73 | break; 74 | case OutputType::Assembly: 75 | gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_ASSEMBLER, 76 | path.c_str()); 77 | break; 78 | case OutputType::Object: 79 | gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_OBJECT_FILE, 80 | path.c_str()); 81 | break; 82 | case OutputType::Executable: 83 | gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_EXECUTABLE, 84 | path.c_str()); 85 | break; 86 | case OutputType::Dylib: 87 | gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY, 88 | path.c_str()); 89 | break; 90 | } 91 | if (const char *err = gcc_jit_context_get_last_error(ctxt)) 92 | return llvm::createStringError(llvm::inconvertibleErrorCode(), err); 93 | return path; 94 | } 95 | 96 | LogicalResult copyFileToStream(const llvm::SmallString<128> &path, 97 | llvm::raw_ostream &os) { 98 | os.flush(); 99 | llvm::ErrorOr> buffer = 100 | llvm::MemoryBuffer::getFile(path); 101 | if (!buffer) 102 | return failure(); 103 | os << buffer.get()->getBuffer(); 104 | return success(); 105 | } 106 | 107 | void registerTranslation(llvm::StringRef name, llvm::StringRef desc, 108 | OutputType type) { 109 | TranslateFromMLIRRegistration registration( 110 | name, desc, 111 | [type](Operation *op, raw_ostream &output) { 112 | auto module = dyn_cast(op); 113 | if (!module) { 114 | op->emitError("expected 'module' operation"); 115 | return failure(); 116 | } 117 | auto context = translateModuleToGCCJIT(module); 118 | if (!context) { 119 | op->emitError("failed to translate to GCCJIT context"); 120 | return failure(); 121 | } 122 | auto file = dumpContextToTempfile(context.get().get(), type); 123 | if (!file) { 124 | op->emitError("failed to dump GCCJIT context to tempfile"); 125 | return failure(); 126 | } 127 | return copyFileToStream(std::move(*file), output); 128 | }, 129 | [](DialectRegistry ®istry) { 130 | registry.insert(); 131 | }); 132 | } 133 | 134 | } // namespace 135 | 136 | void registerToGCCJITGimpleTranslation() { 137 | registerTranslation("mlir-to-gccjit-gimple", 138 | "Translate MLIR to GCCJIT's GIMPLE format", 139 | OutputType::Gimple); 140 | } 141 | 142 | void registerToGCCJITReproducerTranslation() { 143 | registerTranslation("mlir-to-gccjit-reproducer", 144 | "Translate MLIR to GCCJIT's reproducer format", 145 | OutputType::Reproducer); 146 | } 147 | 148 | void registerToGCCJITAssemblyTranslation() { 149 | registerTranslation("mlir-to-gccjit-assembly", 150 | "Translate MLIR to GCCJIT's assembly format", 151 | OutputType::Assembly); 152 | } 153 | 154 | void registerToGCCJITObjectTranslation() { 155 | registerTranslation("mlir-to-gccjit-object", 156 | "Translate MLIR to GCCJIT's object file format", 157 | OutputType::Object); 158 | } 159 | 160 | void registerToGCCJITExecutableTranslation() { 161 | registerTranslation("mlir-to-gccjit-executable", 162 | "Translate MLIR to GCCJIT's executable format", 163 | OutputType::Executable); 164 | } 165 | void registerToGCCJITDylibTranslation() { 166 | registerTranslation("mlir-to-gccjit-dylib", 167 | "Translate MLIR to GCCJIT's dynamic library format", 168 | OutputType::Dylib); 169 | } 170 | } // namespace mlir::gccjit 171 | -------------------------------------------------------------------------------- /src/Translation/TypeTranslation.cpp: -------------------------------------------------------------------------------- 1 | #include "mlir-gccjit/Translation/TranslateToGCCJIT.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "mlir-gccjit/IR/GCCJITTypes.h" 12 | #include "llvm/Support/ErrorHandling.h" 13 | 14 | namespace mlir::gccjit { 15 | 16 | size_t GCCJITTranslation::getTypeSize(Type type) { 17 | // gcc_jit_type_get_size only works for integer types now. 18 | if (mlir::isa(type)) 19 | return gcc_jit_type_get_size(convertType(type)); 20 | 21 | if (mlir::isa(type)) { 22 | // Let's pray size_t and pointers have the same size on users' machines. 23 | gcc_jit_type *sizeType = 24 | gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_SIZE_T); 25 | return gcc_jit_type_get_size(sizeType); 26 | } 27 | 28 | if (auto floatTy = mlir::dyn_cast(type)) { 29 | switch (floatTy.getKind()) { 30 | case GCC_JIT_TYPE_FLOAT: 31 | return 4; 32 | case GCC_JIT_TYPE_DOUBLE: 33 | return 8; 34 | // TODO: add getTypeSize support for long double type. 35 | default: 36 | llvm_unreachable("unsupported gccjit float type"); 37 | } 38 | } 39 | if (mlir::isa(type)) 40 | return 2; 41 | if (mlir::isa(type)) 42 | return 4; 43 | if (mlir::isa(type)) 44 | return 8; 45 | 46 | // TODO: add getTypeSize support for struct type and union type. 47 | 48 | llvm_unreachable("unsupported gccjit object type"); 49 | } 50 | 51 | void GCCJITTranslation::convertTypes( 52 | mlir::TypeRange types, llvm::SmallVector &result) { 53 | for (auto type : types) 54 | result.push_back(convertType(type)); 55 | } 56 | 57 | gcc_jit_type *GCCJITTranslation::convertType(mlir::Type type) { 58 | if (auto it = typeMap.find(type); it != typeMap.end()) 59 | return it->second; 60 | auto *res = 61 | llvm::TypeSwitch(type) 62 | .Case([&](gccjit::LValueType t) { 63 | return convertType(t.getInnerType()); 64 | }) 65 | .Case([&](gccjit::PointerType t) { 66 | auto *pointee = convertType(t.getElementType()); 67 | if (isa(t.getElementType())) 68 | return pointee; 69 | if (auto qualified = 70 | dyn_cast(t.getElementType())) { 71 | if (qualified.getIsConst()) 72 | if (auto intType = 73 | dyn_cast(qualified.getElementType())) 74 | if (intType.getKind() == GCC_JIT_TYPE_CHAR) 75 | return gcc_jit_context_get_type( 76 | ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); 77 | } 78 | return gcc_jit_type_get_pointer(pointee); 79 | }) 80 | .Case([&](gccjit::FuncType t) { 81 | llvm::SmallVector paramTypes; 82 | convertTypes(t.getInputs(), paramTypes); 83 | auto *returnType = convertType(t.getReturnType()); 84 | return gcc_jit_context_new_function_ptr_type( 85 | ctxt, nullptr, returnType, paramTypes.size(), paramTypes.data(), 86 | t.isVarArg()); 87 | }) 88 | .Case([&](gccjit::QualifiedType t) { 89 | auto *res = convertType(t.getElementType()); 90 | if (t.getIsConst()) 91 | res = gcc_jit_type_get_const(res); 92 | if (t.getIsRestrict()) 93 | res = gcc_jit_type_get_restrict(res); 94 | if (t.getIsVolatile()) 95 | res = gcc_jit_type_get_volatile(res); 96 | return res; 97 | }) 98 | .Case([&](gccjit::IntType t) { 99 | auto kind = t.getKind(); 100 | return gcc_jit_context_get_type(ctxt, kind); 101 | }) 102 | .Case([&](mlir::IntegerType t) { 103 | assert(!t.isSignless() && "signless integer type is not supported"); 104 | return gcc_jit_context_get_int_type(ctxt, t.getWidth() / CHAR_BIT, 105 | t.isSigned()); 106 | }) 107 | .Case([&](mlir::IndexType) { 108 | return gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_SIZE_T); 109 | }) 110 | .Case([&](gccjit::FloatType t) { 111 | auto kind = t.getKind(); 112 | return gcc_jit_context_get_type(ctxt, kind); 113 | }) 114 | .Case([&](mlir::Float32Type) { 115 | return gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_FLOAT); 116 | }) 117 | .Case([&](mlir::Float64Type) { 118 | return gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_DOUBLE); 119 | }) 120 | .Case([&](gccjit::ComplexType t) { 121 | auto kind = t.getKind(); 122 | return gcc_jit_context_get_type(ctxt, kind); 123 | }) 124 | .Case([&](mlir::ComplexType t) { 125 | mlir::Type elementTy = t.getElementType(); 126 | if (mlir::isa(elementTy)) 127 | return gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_COMPLEX_FLOAT); 128 | if (mlir::isa(elementTy)) 129 | return gcc_jit_context_get_type(ctxt, 130 | GCC_JIT_TYPE_COMPLEX_DOUBLE); 131 | if (auto floatTy = mlir::dyn_cast(elementTy)) { 132 | switch (floatTy.getKind()) { 133 | case GCC_JIT_TYPE_FLOAT: 134 | return gcc_jit_context_get_type(ctxt, 135 | GCC_JIT_TYPE_COMPLEX_FLOAT); 136 | case GCC_JIT_TYPE_DOUBLE: 137 | return gcc_jit_context_get_type(ctxt, 138 | GCC_JIT_TYPE_COMPLEX_DOUBLE); 139 | default: 140 | break; 141 | } 142 | } 143 | llvm_unreachable("unsupported complex element type"); 144 | }) 145 | .Case([&](gccjit::VoidType t) { 146 | return gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_VOID); 147 | }) 148 | .Case([&](gccjit::ArrayType t) { 149 | auto *elemType = convertType(t.getElementType()); 150 | auto size = t.getSize(); 151 | return gcc_jit_context_new_array_type(ctxt, nullptr, elemType, 152 | size); 153 | }) 154 | .Case([&](gccjit::VectorType t) { 155 | auto *elemType = convertType(t.getElementType()); 156 | auto size = t.getNumUnits(); 157 | return gcc_jit_type_get_vector(elemType, size); 158 | }) 159 | .Case([&](mlir::VectorType t) { 160 | assert(!t.isScalable() && 161 | "scalable vector types are not supported"); 162 | auto *elemType = convertType(t.getElementType()); 163 | auto size = t.getNumElements(); 164 | return gcc_jit_type_get_vector(elemType, size); 165 | }) 166 | .Case([&](gccjit::StructType t) -> gcc_jit_type * { 167 | gcc_jit_struct *rawType = getOrCreateStructEntry(t).getRawHandle(); 168 | return gcc_jit_struct_as_type(rawType); 169 | }) 170 | .Case([&](gccjit::UnionType t) -> gcc_jit_type * { 171 | return getOrCreateUnionEntry(t).getRawHandle(); 172 | }) 173 | .Default([](mlir::Type) -> gcc_jit_type * { 174 | llvm_unreachable("unsupported type for gccjit translation"); 175 | }); 176 | typeMap[type] = res; 177 | return res; 178 | } 179 | 180 | template 181 | static auto 182 | convertRecordType(GCCJITTranslation &translation, 183 | GCCJITRecordTypeInterface type, 184 | llvm::SmallVector &convertedFields, 185 | RawCreator &&rawHandleCreator) { 186 | static_assert( 187 | std::is_invocable_v); 189 | 190 | // TODO: handle opaque struct type. 191 | 192 | convertedFields.clear(); 193 | convertedFields.reserve(type.getRecordFields().size()); 194 | for (Attribute fieldOpaqueAttr : type.getRecordFields()) { 195 | auto fieldAttr = cast(fieldOpaqueAttr); 196 | 197 | int fieldBitWidth = fieldAttr.getBitWidth().value_or(0); 198 | std::string fieldName = fieldAttr.getName().str(); 199 | gcc_jit_type *fieldType = translation.convertType(fieldAttr.getType()); 200 | 201 | gcc_jit_location *loc = nullptr; 202 | if (auto fieldLoc = fieldAttr.getLoc()) 203 | loc = translation.convertLocation(*fieldLoc); 204 | 205 | gcc_jit_field *field = 206 | fieldAttr.getBitWidth() 207 | ? gcc_jit_context_new_bitfield(translation.getContext(), loc, 208 | fieldType, fieldBitWidth, 209 | fieldName.c_str()) 210 | : gcc_jit_context_new_field(translation.getContext(), loc, 211 | fieldType, fieldName.c_str()); 212 | convertedFields.push_back(field); 213 | } 214 | 215 | std::string recordName = type.getRecordName().str(); 216 | 217 | gcc_jit_location *loc = nullptr; 218 | if (SourceLocAttr recordLoc = type.getRecordLoc()) 219 | loc = translation.convertLocation(recordLoc); 220 | 221 | return std::invoke(std::forward(rawHandleCreator), 222 | translation.getContext(), loc, recordName.c_str(), 223 | convertedFields.size(), convertedFields.data()); 224 | } 225 | 226 | GCCJITTranslation::StructEntry & 227 | GCCJITTranslation::getOrCreateStructEntry(StructType type) { 228 | auto structMapIter = structMap.find(type); 229 | if (structMapIter == structMap.end()) { 230 | llvm::SmallVector convertedFields; 231 | gcc_jit_struct *rawType = convertRecordType( 232 | *this, type, convertedFields, gcc_jit_context_new_struct_type); 233 | structMapIter = structMap.insert({type, StructEntry(rawType)}).first; 234 | } 235 | 236 | return structMapIter->second; 237 | } 238 | 239 | GCCJITTranslation::UnionEntry & 240 | GCCJITTranslation::getOrCreateUnionEntry(UnionType type) { 241 | auto unionMapIter = unionMap.find(type); 242 | if (unionMapIter == unionMap.end()) { 243 | llvm::SmallVector convertedFields; 244 | gcc_jit_type *rawType = convertRecordType(*this, type, convertedFields, 245 | gcc_jit_context_new_union_type); 246 | unionMapIter = 247 | unionMap.insert({type, UnionEntry(rawType, std::move(convertedFields))}) 248 | .first; 249 | } 250 | 251 | return unionMapIter->second; 252 | } 253 | 254 | } // namespace mlir::gccjit 255 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | configure_file(lit.site.cfg.py.in lit.site.cfg.py @ONLY) 2 | 3 | add_custom_target(check 4 | COMMAND "${PROJECT_SOURCE_DIR}/run-lit.py" -v ${CMAKE_CURRENT_BINARY_DIR} 5 | DEPENDS gccjit-tools 6 | ) 7 | -------------------------------------------------------------------------------- /test/compile/atomic.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s 3 | 4 | !bool = !gccjit.int 5 | !i32 = !gccjit.int 6 | !f32 = !gccjit.fp 7 | !pi32 = !gccjit.ptr 8 | !pf32 = !gccjit.ptr 9 | !ppi32 = !gccjit.ptr 10 | 11 | module @test attributes { 12 | gccjit.opt_level = #gccjit.opt_level, 13 | gccjit.prog_name = "test", 14 | gccjit.allow_unreachable = false, 15 | gccjit.debug_info = true 16 | } { 17 | // CHECK-LABEL: atomic_load_int 18 | gccjit.func exported @atomic_load_int(!pi32) -> !i32 { 19 | ^entry(%arg : !gccjit.lvalue): 20 | %0 = gccjit.as_rvalue %arg : !gccjit.lvalue to !pi32 21 | // CHECK: %{{.+}} = __atomic_load_4 (((volatile const void *)%{{.+}}), (int)0); 22 | %1 = gccjit.atomic.load relaxed (%0 : !pi32) : !i32 23 | gccjit.return %1 : !i32 24 | } 25 | 26 | // CHECK-LABEL: atomic_load_float 27 | gccjit.func exported @atomic_load_float(!pf32) -> !f32 { 28 | ^entry(%arg : !gccjit.lvalue): 29 | %0 = gccjit.as_rvalue %arg : !gccjit.lvalue to !pf32 30 | // CHECK: %{{.+}} = bitcast(__atomic_load_4 (((volatile const void *)%{{.+}}), (int)0), float); 31 | %1 = gccjit.atomic.load relaxed (%0 : !pf32) : !f32 32 | gccjit.return %1 : !f32 33 | } 34 | 35 | // CHECK-LABEL: atomic_load_ptr 36 | gccjit.func exported @atomic_load_ptr(!ppi32) -> !pi32 { 37 | ^entry(%arg : !gccjit.lvalue): 38 | %0 = gccjit.as_rvalue %arg : !gccjit.lvalue to !ppi32 39 | // CHECK: %{{.+}} = bitcast(__atomic_load_8 (((volatile const void *)%{{.+}}), (int)0), __int32_t *); 40 | %1 = gccjit.atomic.load relaxed (%0 : !ppi32) : !pi32 41 | gccjit.return %1 : !pi32 42 | } 43 | 44 | // CHECK-LABEL: atomic_store_int 45 | gccjit.func exported @atomic_store_int(!pi32, !i32) { 46 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 47 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pi32 48 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !i32 49 | // CHECK: (void)__atomic_store_4 (((volatile void *)%{{.+}}), %{{.+}}, (int)0); 50 | gccjit.atomic.store relaxed (%0 : !pi32, %1 : !i32) 51 | gccjit.return 52 | } 53 | 54 | // CHECK-LABEL: atomic_store_float 55 | gccjit.func exported @atomic_store_float(!pf32, !f32) { 56 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 57 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pf32 58 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !f32 59 | // CHECK: (void)__atomic_store_4 (((volatile void *)%{{.+}}), (bitcast(%{{.+}}, int)), (int)0); 60 | gccjit.atomic.store relaxed (%0 : !pf32, %1 : !f32) 61 | gccjit.return 62 | } 63 | 64 | // CHECK-LABEL: atomic_store_ptr 65 | gccjit.func exported @atomic_store_ptr(!ppi32, !pi32) { 66 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 67 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !ppi32 68 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !pi32 69 | // CHECK: (void)__atomic_store_8 (((volatile void *)%{{.+}}), (bitcast(%{{.+}}, {{long long|long}})), (int)0); 70 | gccjit.atomic.store relaxed (%0 : !ppi32, %1 : !pi32) 71 | gccjit.return 72 | } 73 | 74 | // CHECK-LABEL: atomic_rmw_int 75 | gccjit.func exported @atomic_rmw_int(!pi32, !i32) -> !i32 { 76 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 77 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pi32 78 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !i32 79 | // CHECK: %{{.+}} = __atomic_fetch_add_4 (((volatile void *)%{{.+}}), %{{.+}}, (int)0); 80 | %2 = gccjit.atomic.rmw relaxed fetch_add (%0 : !pi32, %1 : !i32) : !i32 81 | gccjit.return %2 : !i32 82 | } 83 | 84 | // CHECK-LABEL: atomic_rmw_float 85 | gccjit.func exported @atomic_rmw_float(!pf32, !f32) -> !f32 { 86 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 87 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pf32 88 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !f32 89 | // CHECK: %{{.+}} = bitcast(__atomic_fetch_add_4 (((volatile void *)%{{.+}}), (bitcast(%{{.+}}, int)), (int)0), float); 90 | %2 = gccjit.atomic.rmw relaxed fetch_add (%0 : !pf32, %1 : !f32) : !f32 91 | gccjit.return %2 : !f32 92 | } 93 | 94 | // CHECK-LABEL: atomic_rmw_ptr 95 | gccjit.func exported @atomic_rmw_ptr(!ppi32, !pi32) -> !pi32 { 96 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue): 97 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !ppi32 98 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !pi32 99 | // CHECK: %{{.+}} = bitcast(__atomic_fetch_add_8 (((volatile void *)%{{.+}}), (bitcast(%{{.+}}, {{long long|long}})), (int)0), __int32_t *); 100 | %2 = gccjit.atomic.rmw relaxed fetch_add (%0 : !ppi32, %1 : !pi32) : !pi32 101 | gccjit.return %2 : !pi32 102 | } 103 | 104 | // CHECK-LABEL: atomic_cmpxchg_int 105 | gccjit.func exported @atomic_cmpxchg_int(!pi32, !pi32, !i32) -> !bool { 106 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue, %arg2 : !gccjit.lvalue): 107 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pi32 108 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !pi32 109 | %2 = gccjit.as_rvalue %arg2 : !gccjit.lvalue to !i32 110 | // CHECK: %{{.+}} = __atomic_compare_exchange_4 (((volatile void *)%{{.+}}), ((volatile const void *)%{{.+}}), %{{.+}}, (bool)1, (int)4, (int)0); 111 | %3 = gccjit.atomic.cmpxchg weak success(acq_rel) failure(relaxed) (%0 : !pi32, %1 : !pi32, %2 : !i32) : !bool 112 | gccjit.return %3 : !bool 113 | } 114 | 115 | // CHECK-LABEL: atomic_cmpxchg_float 116 | gccjit.func exported @atomic_cmpxchg_float(!pf32, !pf32, !f32) -> !bool { 117 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue, %arg2 : !gccjit.lvalue): 118 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !pf32 119 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !pf32 120 | %2 = gccjit.as_rvalue %arg2 : !gccjit.lvalue to !f32 121 | // CHECK: %{{.+}} = __atomic_compare_exchange_4 (((volatile void *)%{{.+}}), ((volatile const void *)%{{.+}}), (bitcast(%{{.+}}, int)), (bool)1, (int)4, (int)0); 122 | %3 = gccjit.atomic.cmpxchg weak success(acq_rel) failure(relaxed) (%0 : !pf32, %1 : !pf32, %2 : !f32) : !bool 123 | gccjit.return %3 : !bool 124 | } 125 | 126 | // CHECK-LABEL: atomic_cmpxchg_ptr 127 | gccjit.func exported @atomic_cmpxchg_ptr(!ppi32, !ppi32, !pi32) -> !bool { 128 | ^entry(%arg0 : !gccjit.lvalue, %arg1 : !gccjit.lvalue, %arg2 : !gccjit.lvalue): 129 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !ppi32 130 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !ppi32 131 | %2 = gccjit.as_rvalue %arg2 : !gccjit.lvalue to !pi32 132 | // CHECK: %{{.+}} = __atomic_compare_exchange_8 (((volatile void *)%{{.+}}), ((volatile const void *)%{{.+}}), (bitcast(%{{.+}}, {{long long|long}})), (bool)1, (int)4, (int)0); 133 | %3 = gccjit.atomic.cmpxchg weak success(acq_rel) failure(relaxed) (%0 : !ppi32, %1 : !ppi32, %2 : !pi32) : !bool 134 | gccjit.return %3 : !bool 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /test/compile/bitfield.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe && %t.exe 4 | 5 | !int = !gccjit.int 6 | !ilv = !gccjit.lvalue 7 | !bool = !gccjit.int 8 | !bitfields = !gccjit.struct<"Int" { 9 | #gccjit.field<"A" !int : 17>, 10 | #gccjit.field<"B" !int : 5>, 11 | #gccjit.field<"C" !int : 10> 12 | }> 13 | 14 | 15 | module attributes { gccjit.opt_level = #gccjit.opt_level, gccjit.allow_unreachable = true } { 16 | gccjit.func exported @from_int_to_bitfield (!int, !int, !int, !int) { 17 | ^entry(%arg0: !ilv, %arg1: !ilv, %arg2: !ilv, %arg3: !ilv): 18 | %0 = gccjit.as_rvalue %arg0 : !ilv to !int 19 | %1 = gccjit.as_rvalue %arg1 : !ilv to !int 20 | %2 = gccjit.as_rvalue %arg2 : !ilv to !int 21 | %3 = gccjit.as_rvalue %arg3 : !ilv to !int 22 | // CHECK: %[[V:[0-9]+]] = bitcast(%{{[0-9]+}}, struct Int); 23 | // CHECK: %{{[0-9]+}} = %[[V]].A:17; 24 | // CHECK: %{{[0-9]+}} = %[[V]].B:5; 25 | // CHECK: %{{[0-9]+}} = %[[V]].C:10; 26 | %4 = gccjit.bitcast %0 : !int to !bitfields 27 | %5 = gccjit.access_field %4[0] : !bitfields -> !int 28 | %6 = gccjit.access_field %4[1] : !bitfields -> !int 29 | %7 = gccjit.access_field %4[2] : !bitfields -> !int 30 | %eq0 = gccjit.compare eq (%5 : !int, %1 : !int) : !bool 31 | %eq1 = gccjit.compare eq (%6 : !int, %2 : !int) : !bool 32 | %eq2 = gccjit.compare eq (%7 : !int, %3 : !int) : !bool 33 | %and0 = gccjit.binary logical_and (%eq0 : !bool, %eq1 : !bool) : !bool 34 | %and1 = gccjit.binary logical_and (%and0 : !bool, %eq2 : !bool) : !bool 35 | gccjit.conditional (%and1 : !bool), ^return, ^trap 36 | 37 | ^return: 38 | gccjit.return 39 | 40 | ^trap: 41 | gccjit.call builtin @__builtin_trap() : () -> !gccjit.void 42 | gccjit.jump ^trap 43 | } 44 | gccjit.func exported @func_bitfield_to_int(!int, !int, !int, !int) { 45 | ^entry(%arg0: !ilv, %arg1: !ilv, %arg2: !ilv, %arg3: !ilv): 46 | %0 = gccjit.as_rvalue %arg0 : !ilv to !int 47 | %1 = gccjit.as_rvalue %arg1 : !ilv to !int 48 | %2 = gccjit.as_rvalue %arg2 : !ilv to !int 49 | %3 = gccjit.as_rvalue %arg3 : !ilv to !int 50 | // CHECK: (struct Int) {.A:17=%{{[0-9]+}}, .B:5=%{{[0-9]+}}, .C:10=%{{[0-9]+}}}; 51 | %4 = gccjit.new_struct [0, 1, 2] [%0, %1, %2] : (!int, !int, !int) -> !bitfields 52 | %5 = gccjit.bitcast %4 : !bitfields to !int 53 | %eq = gccjit.compare eq (%5 : !int, %3 : !int) : !bool 54 | gccjit.conditional (%eq : !bool), ^return, ^trap 55 | 56 | ^return: 57 | gccjit.return 58 | 59 | ^trap: 60 | gccjit.call builtin @__builtin_trap() : () -> !gccjit.void 61 | gccjit.jump ^trap 62 | } 63 | 64 | gccjit.func exported @main() -> !int { 65 | ^entry: 66 | %0 = gccjit.const #gccjit.int<-559038737> : !int 67 | %1 = gccjit.const #gccjit.int<-16657> : !int 68 | %2 = gccjit.const #gccjit.int<-10> : !int 69 | %3 = gccjit.const #gccjit.int<-134> : !int 70 | gccjit.call @from_int_to_bitfield(%0, %1, %2, %3) : (!int, !int, !int, !int) -> () 71 | gccjit.call @func_bitfield_to_int(%1, %2, %3, %0) : (!int, !int, !int, !int) -> () 72 | 73 | %ret = gccjit.const #gccjit.zero : !int 74 | gccjit.return %ret : !int 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/compile/deref_chain.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe 4 | // RUN: %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 5 | 6 | !int = !gccjit.int 7 | !bool = !gccjit.int 8 | !ilv = !gccjit.lvalue 9 | !vptr = !gccjit.ptr 10 | !size_t = !gccjit.int 11 | !cell = !gccjit.struct<"Cell" { 12 | #gccjit.field<"prev" !vptr>, 13 | #gccjit.field<"next" !vptr>, 14 | #gccjit.field<"data" !int> 15 | }> 16 | !str = !gccjit.ptr, const>> 17 | 18 | !list = !gccjit.struct<"List" {#gccjit.field<"dummy" !cell>}> 19 | 20 | !cptr = !gccjit.ptr 21 | !lptr = !gccjit.ptr 22 | !visitor = !gccjit.ptr> 23 | 24 | // CHECK-OUTPUT: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 25 | module @test attributes { 26 | gccjit.opt_level = #gccjit.opt_level, gccjit.debug_info = true, gccjit.cmdline_options = ["-fsanitize=address"], gccjit.driver_options = ["-fsanitize=address"] 27 | } { 28 | gccjit.func internal @push_back(!lptr, !int) { 29 | ^entry(%arg0: !gccjit.lvalue, %arg1: !ilv): 30 | %0 = gccjit.sizeof !cell : !size_t 31 | %1 = gccjit.call builtin @__builtin_malloc(%0) : (!size_t) -> !vptr 32 | %2 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !lptr 33 | %3 = gccjit.as_rvalue %arg1 : !ilv to !int 34 | 35 | // fields of newly allocated cell 36 | // CHECK-GIMPLE: %[[NEW:[0-9]+]] = bitcast(%{{[0-9]+}}, struct Cell *); 37 | %4 = gccjit.bitcast %1 : !vptr to !cptr 38 | %5 = gccjit.deref_field %4[0] : !cptr -> !gccjit.lvalue 39 | %6 = gccjit.deref_field %4[1] : !cptr -> !gccjit.lvalue 40 | %7 = gccjit.deref_field %4[2] : !cptr -> !gccjit.lvalue 41 | 42 | // fields of dummy cell (prev) 43 | %8 = gccjit.deref_field %2[0] : !lptr -> !gccjit.lvalue 44 | %9 = gccjit.access_field %8[0] : !gccjit.lvalue -> !gccjit.lvalue 45 | // CHECK-GIMPLE: %[[TAIL:[0-9]+]] = %[[LIST:[0-9]+]]->dummy.prev; 46 | %10 = gccjit.as_rvalue %9 : !gccjit.lvalue to !vptr 47 | 48 | // fields of dummys's prev cell (next) 49 | // CHECK-GIMPLE: %[[CASTED_TAIL:[0-9]+]] = bitcast(%[[TAIL]], struct Cell *); 50 | %11 = gccjit.bitcast %10 : !vptr to !cptr 51 | // CHECK-GIMPLE: %[[DUMMY:[0-9]+]] = %[[CASTED_TAIL]]->next; 52 | %12 = gccjit.deref_field %11[1] : !cptr -> !gccjit.lvalue 53 | %13 = gccjit.as_rvalue %12 : !gccjit.lvalue to !vptr 54 | 55 | // update newly allocated cell 56 | // CHECK-GIMPLE: %[[NEW]]->data = %{{[0-9]+}}; 57 | gccjit.assign %3 to %7 : !int, !ilv 58 | // CHECK-GIMPLE: %[[NEW]]->prev = %[[TAIL]]; 59 | gccjit.assign %10 to %5 : !vptr, !gccjit.lvalue 60 | // CHECK-GIMPLE: %[[NEW]]->next = %[[DUMMY]]; 61 | gccjit.assign %13 to %6 : !vptr, !gccjit.lvalue 62 | 63 | // update dummy cell 64 | // %[[LIST]]->dummy.prev = %[[NEW]]; 65 | gccjit.assign %1 to %9 : !vptr, !gccjit.lvalue 66 | 67 | // update previous tail 68 | // %[[CASTED_TAIL]]->next = %[[NEW]]; 69 | gccjit.assign %1 to %12 : !vptr, !gccjit.lvalue 70 | 71 | gccjit.return 72 | } 73 | 74 | gccjit.func internal @new_list() -> !lptr { 75 | %0 = gccjit.sizeof !list : !size_t 76 | %1 = gccjit.call builtin @__builtin_malloc(%0) : (!size_t) -> !vptr 77 | %2 = gccjit.bitcast %1 : !vptr to !lptr 78 | 79 | // initialize dummy 80 | %3 = gccjit.deref_field %2[0] : !lptr -> !gccjit.lvalue 81 | %4 = gccjit.access_field %3[0] : !gccjit.lvalue -> !gccjit.lvalue 82 | %5 = gccjit.access_field %3[1] : !gccjit.lvalue -> !gccjit.lvalue 83 | %6 = gccjit.access_field %3[2] : !gccjit.lvalue -> !gccjit.lvalue 84 | %8 = gccjit.const #gccjit.zero : !int 85 | gccjit.assign %1 to %4 : !vptr, !gccjit.lvalue 86 | gccjit.assign %1 to %5 : !vptr, !gccjit.lvalue 87 | gccjit.assign %8 to %6 : !int, !ilv 88 | 89 | gccjit.return %2 : !lptr 90 | } 91 | 92 | gccjit.func internal @_delete(!cptr) { 93 | ^entry(%arg0: !gccjit.lvalue): 94 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !cptr 95 | %1 = gccjit.bitcast %0 : !cptr to !vptr 96 | gccjit.call builtin @__builtin_free(%1) : (!vptr) -> () 97 | gccjit.return 98 | } 99 | 100 | gccjit.func imported @printf(!str, ...) -> !int 101 | 102 | gccjit.func internal @_print(!cptr) { 103 | ^entry(%arg0: !gccjit.lvalue): 104 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !cptr 105 | %1 = gccjit.deref_field %0[2] : !cptr -> !gccjit.lvalue 106 | %2 = gccjit.as_rvalue %1 : !gccjit.lvalue to !int 107 | %3 = gccjit.literal "%d " : !str 108 | gccjit.call @printf(%3, %2) : (!str, !int) -> !int 109 | gccjit.return 110 | } 111 | 112 | gccjit.func internal @foreach(!lptr, !visitor) { 113 | ^entry(%arg0: !gccjit.lvalue, %arg1: !gccjit.lvalue): 114 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !lptr 115 | %1 = gccjit.as_rvalue %arg1 : !gccjit.lvalue to !visitor 116 | 117 | // get dummy's address 118 | // CHECK-GIMPLE: %[[ADDR:[0-9]+]] = &%[[LIST:[0-9]+]]->dummy; 119 | %2 = gccjit.deref_field %0[0] : !lptr -> !gccjit.lvalue 120 | %3 = gccjit.addr (%2 : !gccjit.lvalue) : !gccjit.ptr 121 | 122 | // get dummy's next 123 | // CHECK-GIMPLE: %[[NEXT:[0-9]+]] = %[[LIST]]->dummy.next; 124 | %4 = gccjit.access_field %2[1] : !gccjit.lvalue -> !gccjit.lvalue 125 | %5 = gccjit.as_rvalue %4 : !gccjit.lvalue to !vptr 126 | %6 = gccjit.bitcast %5 : !vptr to !cptr 127 | 128 | // initialize iterator 129 | %7 = gccjit.local : !gccjit.lvalue 130 | gccjit.assign %6 to %7 : !cptr, !gccjit.lvalue 131 | gccjit.jump ^loop.head 132 | 133 | ^loop.head: 134 | // check if iterator is dummy 135 | %8 = gccjit.compare eq (%7 : !gccjit.lvalue, %3 : !cptr) : !bool 136 | gccjit.conditional (%8 : !bool), ^loop.end, ^loop.body 137 | 138 | ^loop.body: 139 | // first load next 140 | %9 = gccjit.as_rvalue %7 : !gccjit.lvalue to !cptr 141 | %10 = gccjit.deref_field %9[1] : !cptr -> !gccjit.lvalue 142 | %11 = gccjit.as_rvalue %10 : !gccjit.lvalue to !vptr 143 | %12 = gccjit.bitcast %11 : !vptr to !cptr 144 | 145 | // then apply visitor 146 | gccjit.ptr_call %1(%9) : (!visitor, !cptr) -> !gccjit.void 147 | 148 | // then update iterator 149 | gccjit.assign %12 to %7 : !cptr, !gccjit.lvalue 150 | gccjit.jump ^loop.head 151 | 152 | ^loop.end: 153 | gccjit.return 154 | } 155 | 156 | gccjit.func internal @delete_list(!lptr) { 157 | ^entry(%arg0: !gccjit.lvalue): 158 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !lptr 159 | %1 = gccjit.fn_addr @_delete : !visitor 160 | gccjit.call @foreach(%0, %1) : (!lptr, !visitor) -> !gccjit.void 161 | %2 = gccjit.bitcast %0 : !lptr to !vptr 162 | gccjit.call builtin @__builtin_free(%2) : (!vptr) -> () 163 | gccjit.return 164 | } 165 | 166 | gccjit.func internal @print_list(!lptr) { 167 | ^entry(%arg0: !gccjit.lvalue): 168 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !lptr 169 | // CHECK-GIMPLE: %{{[0-9]+}} = _print; 170 | %1 = gccjit.fn_addr @_print : !visitor 171 | gccjit.call @foreach(%0, %1) : (!lptr, !visitor) -> !gccjit.void 172 | %2 = gccjit.literal "\n" : !str 173 | gccjit.call @printf(%2) : (!str) -> !gccjit.void 174 | gccjit.return 175 | } 176 | 177 | gccjit.func exported @main() -> !int { 178 | %zero = gccjit.expr lazy { 179 | %x = gccjit.const #gccjit.zero : !int 180 | gccjit.return %x : !int 181 | } : !int 182 | %0 = gccjit.call @new_list() : () -> !lptr 183 | %1 = gccjit.local : !ilv 184 | gccjit.assign %zero to %1 : !int, !ilv 185 | %2 = gccjit.const #gccjit.int<100> : !int 186 | gccjit.jump ^while.head 187 | 188 | ^while.head: 189 | %3 = gccjit.compare lt (%1 : !ilv, %2 : !int) : !bool 190 | gccjit.conditional (%3 : !bool), ^while.body, ^while.end 191 | 192 | ^while.body: 193 | %5 = gccjit.as_rvalue %1 : !ilv to !int 194 | gccjit.call @push_back(%0, %5) : (!lptr, !int) -> !gccjit.void 195 | %6 = gccjit.const #gccjit.one : !int 196 | // CHECK-GIMPLE: %{{[0-9]+}} += %{{[0-9]+}}; 197 | gccjit.update plus %6 to %1 : !int, !ilv 198 | gccjit.jump ^while.head 199 | 200 | ^while.end: 201 | gccjit.call @print_list(%0) : (!lptr) -> !gccjit.void 202 | gccjit.call @delete_list(%0) : (!lptr) -> !gccjit.void 203 | gccjit.return %zero : !int 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /test/compile/expression.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe 4 | // RUN: echo 10 | %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 5 | 6 | !i32 = !gccjit.int 7 | !var32 = !gccjit.lvalue 8 | !char = !gccjit.int 9 | !const_char = !gccjit.qualified 10 | !str = !gccjit.ptr 11 | module @test attributes { 12 | gccjit.opt_level = #gccjit.opt_level, 13 | gccjit.prog_name = "test", 14 | gccjit.allow_unreachable = false, 15 | gccjit.debug_info = true 16 | } { 17 | gccjit.func imported @printf(!str, ...) -> !i32 18 | gccjit.func imported @scanf(!str, ...) -> !i32 19 | 20 | gccjit.func internal @fib(!i32 ) -> !i32 { 21 | ^entry(%arg : !var32): 22 | %0 = gccjit.as_rvalue %arg : !var32 to !i32 23 | gccjit.switch (%0 : !i32) { 24 | default -> ^bb1, 25 | #gccjit.int<0> : !i32 ... #gccjit.int<1> : !i32 -> ^bb0 26 | } 27 | ^bb0: 28 | %1 = gccjit.const #gccjit.one : !i32 29 | gccjit.return %1 : !i32 30 | ^bb1: 31 | // CHECK-GIMPLE: %2 = fib ((%0 - (__int32_t)1)) + fib ((%0 - (__int32_t)2)); 32 | %9 = gccjit.expr { 33 | %2 = gccjit.const #gccjit.one : !i32 34 | %3 = gccjit.const #gccjit.int<2> : !i32 35 | %4 = gccjit.binary minus (%0 : !i32, %2 : !i32) : !i32 36 | %5 = gccjit.binary minus (%0 : !i32, %3 : !i32) : !i32 37 | %6 = gccjit.call @fib(%4) : (!i32) -> !i32 38 | %7 = gccjit.call @fib(%5) : (!i32) -> !i32 39 | %8 = gccjit.binary plus (%6 : !i32, %7 : !i32) : !i32 40 | gccjit.return %8 : !i32 41 | } : !i32 42 | gccjit.return %9 : !i32 43 | } 44 | 45 | // CHECK-OUTPUT: fib(10) = 89 46 | gccjit.func exported @main() -> !i32 { 47 | %var = gccjit.local : !var32 48 | %addr = gccjit.addr (%var : !var32) : !gccjit.ptr 49 | %scanformat = gccjit.literal "%d" : !str 50 | %discard = gccjit.call @scanf(%scanformat, %addr) : (!str, !gccjit.ptr) -> !i32 51 | %val = gccjit.as_rvalue %var : !var32 to !i32 52 | %1 = gccjit.call @fib(%val) : (!i32) -> !i32 53 | %2 = gccjit.literal "fib(%d) = %d\n" : !str 54 | // CHECK-GIMPLE: %{{[0-9]}} = printf (%{{[0-9]}}, %{{[0-9]}}, %{{[0-9]}}); 55 | %3 = gccjit.call @printf(%2, %val, %1) : (!str, !i32, !i32) -> !i32 56 | %4 = gccjit.const #gccjit.zero : !i32 57 | gccjit.return %4 : !i32 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /test/compile/global.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe 4 | // RUN: %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 5 | !i32 = !gccjit.int 6 | !var32 = !gccjit.lvalue 7 | !char = !gccjit.int 8 | !const_char = !gccjit.qualified 9 | !str = !gccjit.ptr 10 | !i32_ptr = !gccjit.ptr 11 | !i32_arr10 = !gccjit.array 12 | !void_ptr = !gccjit.ptr 13 | !varptr = !gccjit.lvalue 14 | !size_t = !gccjit.int 15 | !i1 = !gccjit.int 16 | module @test attributes { 17 | gccjit.opt_level = #gccjit.opt_level, 18 | gccjit.prog_name = "test", 19 | gccjit.allow_unreachable = false, 20 | gccjit.debug_info = true 21 | } { 22 | gccjit.func imported @printf(!str, ...) -> !i32 23 | 24 | gccjit.global internal @integer_array link_section("rodata") array(#gccjit.byte_array<[ 25 | 0,0,0,0, 26 | 1,0,0,0, 27 | 2,0,0,0, 28 | 3,0,0,0, 29 | 4,0,0,0, 30 | 5,0,0,0, 31 | 6,0,0,0, 32 | 7,0,0,0, 33 | 8,0,0,0, 34 | 9,0,0,0 35 | ]>) : !gccjit.lvalue 36 | 37 | gccjit.func internal @sum(!i32) -> !i32 { 38 | ^entry(%arg0: !var32): 39 | // here we use alloca on purpose to test the alloca lowering 40 | %0 = gccjit.as_rvalue %arg0 : !var32 to !i32 41 | %1 = gccjit.cast %0 : !i32 to !size_t 42 | %2 = gccjit.call builtin @__builtin_alloca(%1) : (!size_t) -> !void_ptr 43 | %3 = gccjit.bitcast %2 : !void_ptr to !i32_ptr 44 | %4 = gccjit.deref (%3 : !i32_ptr) : !var32 // acc 45 | %5 = gccjit.local : !var32 // ivar 46 | gccjit.jump ^loop_start 47 | 48 | ^loop_start: 49 | %6 = gccjit.as_rvalue %5 : !var32 to !i32 50 | %7 = gccjit.compare eq (%6 : !i32, %0 : !i32) : !i1 51 | gccjit.conditional (%7 : !i1), ^loop_end, ^loop_body 52 | 53 | ^loop_body: 54 | // CHECK-GIMPLE: %8 = (bitcast(&integer_array, __int32_t *))[%5]; 55 | %8 = gccjit.expr { 56 | %10 = gccjit.as_rvalue %5 : !var32 to !i32 57 | %11 = gccjit.get_global @integer_array : !gccjit.lvalue 58 | %12 = gccjit.addr (%11 : !gccjit.lvalue) : !gccjit.ptr 59 | %13 = gccjit.bitcast %12 : !gccjit.ptr to !i32_ptr 60 | %14 = gccjit.deref (%13 : !i32_ptr, %10 : !i32) : !var32 61 | %15 = gccjit.as_rvalue %14 : !var32 to !i32 62 | gccjit.return %15 : !i32 63 | } : !i32 64 | // CHECK-GIMPLE: *%3 += %8; 65 | gccjit.update plus %8 to %4 : !i32, !var32 66 | %9 = gccjit.const #gccjit.one : !i32 67 | // CHECK-GIMPLE: %5 += %9; 68 | gccjit.update plus %9 to %5 : !i32, !var32 69 | gccjit.jump ^loop_start 70 | 71 | ^loop_end: 72 | %10 = gccjit.as_rvalue %4 : !var32 to !i32 73 | gccjit.return %10 : !i32 74 | } 75 | 76 | // CHECK-OUTPUT: sum = 45 77 | gccjit.func exported @main() -> !i32 { 78 | %0 = gccjit.const #gccjit.int<10> : !i32 79 | %1 = gccjit.call @sum(%0) : (!i32) -> !i32 80 | %2 = gccjit.literal "sum = %d\n" : !str 81 | %3 = gccjit.call @printf(%2, %1) : (!str, !i32) -> !i32 82 | %4 = gccjit.const #gccjit.zero : !i32 83 | gccjit.return %4 : !i32 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /test/compile/hello_world.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe 4 | // RUN: %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 5 | 6 | !i32 = !gccjit.int 7 | !char = !gccjit.int 8 | !const_char = !gccjit.qualified 9 | !str = !gccjit.ptr 10 | module @test attributes { 11 | gccjit.opt_level = #gccjit.opt_level, 12 | gccjit.prog_name = "test", 13 | gccjit.allow_unreachable = false, 14 | gccjit.debug_info = true 15 | } { 16 | gccjit.func imported @puts(!str) -> !i32 17 | 18 | gccjit.func exported @main() -> !i32 { 19 | // CHECK-GIMPLE: %0 = "hello, world!\n"; 20 | %0 = gccjit.literal "hello, world!\n" : !str 21 | // CHECK-GIMPLE: puts (%0); 22 | // CHECK-OUTPUT: hello, world! 23 | %1 = gccjit.call @puts(%0) : (!str) -> !i32 24 | // CHECK-GIMPLE: %2 = (__int32_t)0; 25 | %2 = gccjit.const #gccjit.zero : !i32 26 | // CHECK-GIMPLE: return %2; 27 | gccjit.return %2 : !i32 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/compile/lazy_evaluation.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | 4 | !i32 = !gccjit.int 5 | !i1 = !gccjit.int 6 | !var32 = !gccjit.lvalue 7 | !char = !gccjit.int 8 | !const_char = !gccjit.qualified 9 | !str = !gccjit.ptr 10 | module @test attributes { 11 | gccjit.opt_level = #gccjit.opt_level, 12 | gccjit.prog_name = "test", 13 | gccjit.allow_unreachable = false, 14 | gccjit.debug_info = true 15 | } { 16 | // fuse expr into return 17 | gccjit.func exported @add(!i32, !i32) -> !i32 { 18 | ^body(%arg0: !var32, %arg1: !var32): 19 | %res = gccjit.expr lazy { 20 | %0 = gccjit.as_rvalue %arg0 : !var32 to !i32 21 | %1 = gccjit.as_rvalue %arg1 : !var32 to !i32 22 | %2 = gccjit.binary plus (%0 : !i32, %1 : !i32) : !i32 23 | gccjit.return %2 : !i32 24 | } : !i32 25 | // CHECK-GIMPLE: return %arg0 + %arg1; 26 | gccjit.return %res : !i32 27 | } 28 | 29 | // fuse expr into conditional 30 | gccjit.func exported @max(!i32, !i32) -> !i32 { 31 | ^body(%arg0: !var32, %arg1: !var32): 32 | %0 = gccjit.as_rvalue %arg0 : !var32 to !i32 33 | %1 = gccjit.as_rvalue %arg1 : !var32 to !i32 34 | %3 = gccjit.expr lazy { 35 | %2 = gccjit.compare gt (%0 : !i32, %1 : !i32) : !i1 36 | gccjit.return %2 : !i1 37 | } : !i1 38 | // CHECK-GIMPLE: if (%0 > %1) goto bb1; else goto bb2; 39 | gccjit.conditional (%3 : !i1), ^bb1, ^bb2 40 | ^bb1: 41 | gccjit.return %0 : !i32 42 | ^bb2: 43 | gccjit.return %1 : !i32 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/compile/unary.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | !i32 = !gccjit.int 4 | !var32 = !gccjit.lvalue 5 | !bool = !gccjit.int 6 | !varbool = !gccjit.lvalue 7 | !float = !gccjit.fp 8 | !varfloat = !gccjit.lvalue 9 | module @unary_testing { 10 | gccjit.func exported @unary_minus(!i32) -> !i32 { 11 | ^body(%arg0: !var32): 12 | // CHECK-GIMPLE: %[[LOAD:[0-9]+]] = %arg0; 13 | %0 = gccjit.as_rvalue %arg0 : !var32 to !i32 14 | // CHECK-GIMPLE: %[[RET:[0-9]+]] = -(%[[LOAD]]); 15 | %1 = gccjit.unary minus (%0 : !i32) : !i32 16 | // CHECK-GIMPLE: return %[[RET]]; 17 | gccjit.return %1 : !i32 18 | } 19 | gccjit.func exported @unary_minus_lv(!i32) -> !i32 { 20 | ^body(%arg0: !var32): 21 | // CHECK-GIMPLE: %[[RET:[0-9]+]] = -(%arg0); 22 | // CHECK-GIMPLE: return %[[RET]]; 23 | %0 = gccjit.unary minus (%arg0 : !var32) : !i32 24 | gccjit.return %0 : !i32 25 | } 26 | gccjit.func exported @unary_bitwise_negate(!i32) -> !i32 { 27 | ^body(%arg0: !var32): 28 | // CHECK: return ~(%arg0); 29 | %0 = gccjit.expr lazy { 30 | %1 = gccjit.unary bitwise_negate (%arg0 : !var32) : !i32 31 | gccjit.return %1 : !i32 32 | } : !i32 33 | gccjit.return %0 : !i32 34 | } 35 | gccjit.func exported @unary_logical_negate(!bool) -> !bool { 36 | ^body(%arg0: !varbool): 37 | // CHECK: return !(%arg0); 38 | %0 = gccjit.expr lazy { 39 | %1 = gccjit.unary logical_negate (%arg0 : !varbool) : !bool 40 | gccjit.return %1 : !bool 41 | } : !bool 42 | gccjit.return %0 : !bool 43 | } 44 | gccjit.func exported @unary_abs(!float) -> !float { 45 | ^body(%arg0: !varfloat): 46 | // CHECK: return abs (%arg0); 47 | %0 = gccjit.expr lazy { 48 | %1 = gccjit.unary abs (%arg0 : !varfloat) : !float 49 | gccjit.return %1 : !float 50 | } : !float 51 | gccjit.return %0 : !float 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/compile/union.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe && %t.exe 4 | !struct0 = !gccjit.struct<"Lancern" { 5 | #gccjit.field<"professional" !gccjit.fp>, 6 | #gccjit.field<"genius" !gccjit.int> 7 | }> 8 | 9 | !struct1 = !gccjit.struct<"QuarticCat" { 10 | #gccjit.field<"excellent" !gccjit.fp>, 11 | #gccjit.field<"magnificent" !gccjit.int> 12 | }> 13 | 14 | !union = !gccjit.union<"Union" { 15 | #gccjit.field<"professional" !struct0>, 16 | #gccjit.field<"genius" !struct1>, 17 | #gccjit.field<"data" !gccjit.int> 18 | }> 19 | 20 | #float = #gccjit.float<0.15625> : !gccjit.fp 21 | #int = #gccjit.int<-1> : !gccjit.int 22 | module attributes { gccjit.opt_level = #gccjit.opt_level, gccjit.allow_unreachable = true } { 23 | 24 | gccjit.global internal @union_data init { 25 | %e = gccjit.const #float 26 | %m = gccjit.const #int 27 | %qc = gccjit.new_struct [0, 1] [%e , %m] : (!gccjit.fp, !gccjit.int) -> !struct1 28 | %un = gccjit.new_union %qc at 1 : !struct1, !union 29 | gccjit.return %un : !union 30 | } : !gccjit.lvalue 31 | 32 | gccjit.func exported @main() -> !gccjit.int { 33 | ^entry: 34 | %0 = gccjit.get_global @union_data : !gccjit.lvalue 35 | // CHECK: %{{[0-9]+}} = union_data.professional.genius; 36 | %1 = gccjit.access_field %0[0] : !gccjit.lvalue -> !gccjit.lvalue 37 | %2 = gccjit.access_field %1[1] : !gccjit.lvalue -> !gccjit.lvalue> 38 | %3 = gccjit.as_rvalue %2 : !gccjit.lvalue> to !gccjit.int 39 | %max = gccjit.const #gccjit.int<0xffffffffffffffff> : !gccjit.int 40 | %eq0 = gccjit.compare eq (%3 : !gccjit.int, %max : !gccjit.int) : !gccjit.int 41 | gccjit.conditional (%eq0 : !gccjit.int), ^next, ^abort 42 | 43 | ^next: 44 | // CHECK: %[[RV:[0-9]+]] = union_data.data; 45 | %4 = gccjit.access_field %0[2] : !gccjit.lvalue -> !gccjit.lvalue> 46 | %5 = gccjit.as_rvalue %4 : !gccjit.lvalue> to !gccjit.int 47 | %target = gccjit.const #gccjit.int<1042284544> : !gccjit.int 48 | %eq1 = gccjit.compare eq (%5 : !gccjit.int, %target : !gccjit.int) : !gccjit.int 49 | gccjit.conditional (%eq1 : !gccjit.int), ^return, ^abort 50 | 51 | ^abort: 52 | gccjit.call builtin @__builtin_trap() : () -> !gccjit.void 53 | gccjit.jump ^abort 54 | 55 | ^return: 56 | %ret = gccjit.const #gccjit.zero : !gccjit.int 57 | gccjit.return %ret : !gccjit.int 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /test/compile/vector.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-translate -o %t.gimple %s -mlir-to-gccjit-gimple 2 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 3 | // RUN: %gccjit-translate -o %t.exe %s -mlir-to-gccjit-executable && chmod +x %t.exe 4 | // RUN: %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 5 | 6 | !char = !gccjit.int 7 | !charptr = !gccjit.ptr 8 | !char_vector = !gccjit.vector 9 | !size_t = !gccjit.int 10 | !bool = !gccjit.int 11 | !str = !gccjit.ptr> 12 | 13 | // CHECK-OUTPUT: abcABCEFLJASDVKMFsdadasjlfdjfldSDASFKSDAFNKDASFJasdasdadsdKLFDSFNSDLKFNASDKFKNagjrwtoDSADASDASD 14 | module @vector attributes { 15 | gccjit.opt_level = #gccjit.opt_level, 16 | gccjit.prog_name = "test/compile/vector.mlir" 17 | } { 18 | 19 | gccjit.func always_inline @alpha_flipcase_small(!charptr, !size_t) { 20 | ^entry(%0: !gccjit.lvalue, %1: !gccjit.lvalue): 21 | %c32 = gccjit.expr lazy { 22 | %a = gccjit.const #gccjit.int<32> : !char 23 | gccjit.return %a : !char 24 | } : !char 25 | %zero = gccjit.expr lazy { 26 | %b = gccjit.const #gccjit.zero : !size_t 27 | gccjit.return %b : !size_t 28 | } : !size_t 29 | %one = gccjit.expr lazy { 30 | %c = gccjit.const #gccjit.one : !size_t 31 | gccjit.return %c : !size_t 32 | } : !size_t 33 | %iter = gccjit.local : !gccjit.lvalue 34 | gccjit.assign %zero to %iter : !size_t, !gccjit.lvalue 35 | gccjit.jump ^loop.header 36 | 37 | ^loop.header: 38 | %cond = gccjit.expr lazy { 39 | %flag = gccjit.compare eq ( 40 | %iter : !gccjit.lvalue, %1 : !gccjit.lvalue) : !bool 41 | gccjit.return %flag : !bool 42 | } : !bool 43 | gccjit.conditional (%cond : !bool), ^loop.exit, ^loop.body 44 | 45 | ^loop.body: 46 | %lv = gccjit.deref (%0 : !gccjit.lvalue, %iter: !gccjit.lvalue) 47 | : !gccjit.lvalue 48 | gccjit.update bitwise_xor %c32 to %lv : !char, !gccjit.lvalue 49 | gccjit.update plus %one to %iter : !size_t, !gccjit.lvalue 50 | gccjit.jump ^loop.header 51 | 52 | ^loop.exit: 53 | gccjit.return 54 | } 55 | 56 | gccjit.func exported @alpha_flipcase(!charptr, !size_t) { 57 | // CHECK-GIMPLE: char __attribute__((vector_size(sizeof (char) * 16))) %[[VEC:[0-9]+]]; 58 | ^entry(%0: !gccjit.lvalue, %1: !gccjit.lvalue): 59 | %c32 = gccjit.expr lazy { 60 | %a = gccjit.const #gccjit.int<32> : !char 61 | gccjit.return %a : !char 62 | } : !char 63 | // CHECK-GIMPLE: %[[VEC]] = {(char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32, (char)32}; 64 | %vec = gccjit.new_vector !char_vector [ 65 | %c32, %c32, %c32, %c32, %c32, %c32, %c32, %c32, 66 | %c32, %c32, %c32, %c32, %c32, %c32, %c32, %c32 67 | ] 68 | %zero = gccjit.expr lazy { 69 | %b = gccjit.const #gccjit.zero : !size_t 70 | gccjit.return %b : !size_t 71 | } : !size_t 72 | %c16 = gccjit.expr lazy { 73 | %c = gccjit.const #gccjit.int<16> : !size_t 74 | gccjit.return %c : !size_t 75 | } : !size_t 76 | 77 | %iter = gccjit.local : !gccjit.lvalue 78 | gccjit.assign %zero to %iter : !size_t, !gccjit.lvalue 79 | gccjit.jump ^loop.header 80 | 81 | ^loop.header: 82 | %cond = gccjit.expr lazy { 83 | %diff = gccjit.binary minus (%1 : !gccjit.lvalue, %iter : !gccjit.lvalue) : !size_t 84 | %flag = gccjit.compare lt (%diff : !size_t, %c16 : !size_t) : !bool 85 | gccjit.return %flag : !bool 86 | } : !bool 87 | gccjit.conditional (%cond : !bool), ^loop.exit, ^loop.body 88 | 89 | ^loop.body: 90 | // CHECK-GIMPLE: %[[ADDR:[0-9]+]] = &%arg0[%{{[0-9]+}}]; 91 | // CHECK-GIMPLE: %{{[0-9]+}} = (char __attribute__((vector_size(sizeof (char) * 16))) *)%[[ADDR]]; 92 | %cursor = gccjit.deref (%0 : !gccjit.lvalue, %iter: !gccjit.lvalue) 93 | : !gccjit.lvalue 94 | %cursor_addr = gccjit.addr (%cursor : !gccjit.lvalue) : !gccjit.ptr 95 | %cast = gccjit.cast %cursor_addr : !gccjit.ptr to !gccjit.ptr 96 | %deref = gccjit.deref (%cast : !gccjit.ptr) 97 | : !gccjit.lvalue 98 | gccjit.update bitwise_xor %vec to %deref : !char_vector, !gccjit.lvalue 99 | gccjit.update plus %c16 to %iter : !size_t, !gccjit.lvalue 100 | gccjit.jump ^loop.header 101 | 102 | ^loop.exit: 103 | %new_start = gccjit.deref (%0 : !gccjit.lvalue, %iter: !gccjit.lvalue) 104 | : !gccjit.lvalue 105 | %new_addr = gccjit.addr (%new_start : !gccjit.lvalue) : !gccjit.ptr 106 | %new_size = gccjit.binary minus (%1 : !gccjit.lvalue, %iter : !gccjit.lvalue) 107 | : !size_t 108 | gccjit.call @alpha_flipcase_small(%new_addr, %new_size) : (!gccjit.ptr, !size_t) -> () 109 | gccjit.return 110 | } 111 | 112 | gccjit.func exported @main () -> !gccjit.int { 113 | %data = gccjit.literal "ABCabcefljasdvkmfSDADASJLFDJFLDsdasfksdafnkdasfjASDASDADSDklfdsfnsdlkfnasdkfknAGJRWTOdsadasdasd" : !str 114 | %one = gccjit.const #gccjit.one : !size_t 115 | %len = gccjit.call builtin @strlen(%data) : (!str) -> !size_t 116 | %len_plus_one = gccjit.binary plus (%len : !size_t, %one : !size_t) : !size_t 117 | %alloca = gccjit.call builtin @alloca (%len_plus_one) : (!size_t) -> !gccjit.ptr 118 | %voidptr = gccjit.bitcast %data : !str to !gccjit.ptr> 119 | gccjit.call builtin @memcpy (%alloca, %voidptr, %len_plus_one) : (!gccjit.ptr, !gccjit.ptr>, !size_t) -> !gccjit.ptr 120 | %charptr = gccjit.cast %alloca : !gccjit.ptr to !gccjit.ptr 121 | gccjit.call @alpha_flipcase(%charptr, %len) : (!gccjit.ptr, !size_t) -> () 122 | %cast_str = gccjit.cast %charptr : !gccjit.ptr to !str 123 | gccjit.call builtin @puts(%cast_str) : (!str) -> !gccjit.int 124 | %zero = gccjit.const #gccjit.zero : !gccjit.int 125 | gccjit.return %zero : !gccjit.int 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/lit.cfg.py: -------------------------------------------------------------------------------- 1 | import os 2 | from lit.formats import ShTest 3 | 4 | config.name = "MLIR GCCJIT Dialect" 5 | config.test_format = ShTest(True) 6 | 7 | config.suffixes = [".mlir"] 8 | 9 | config.test_source_root = os.path.dirname(__file__) 10 | config.test_exec_root = os.path.join(config.mlir_gccjit_build_root, "test") 11 | 12 | config.substitutions.append((r"%filecheck", config.file_check_exe)) 13 | config.substitutions.append( 14 | (r"%gccjit-opt", os.path.join(config.mlir_gccjit_build_root, "bin/gccjit-opt")) 15 | ) 16 | config.substitutions.append( 17 | ( 18 | r"%gccjit-translate", 19 | os.path.join(config.mlir_gccjit_build_root, "bin/gccjit-translate"), 20 | ) 21 | ) 22 | -------------------------------------------------------------------------------- /test/lit.site.cfg.py.in: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | config.mlir_gccjit_src_root = r'@PROJECT_SOURCE_DIR@' 4 | config.mlir_gccjit_build_root = r'@PROJECT_BINARY_DIR@' 5 | config.file_check_exe = r'@LLVM_FILE_CHECK_EXE@' 6 | 7 | lit_cfg_file = os.path.join( 8 | config.mlir_gccjit_src_root, "test/lit.cfg.py") 9 | lit_config.load_config(config, lit_cfg_file) 10 | -------------------------------------------------------------------------------- /test/lowering/alloc.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s -o %t.mlir -convert-memref-to-gccjit 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | module @test attributes { 4 | gccjit.opt_level = #gccjit.opt_level, 5 | gccjit.debug_info = false 6 | } 7 | { 8 | 9 | func.func @foo() -> memref<100x100xf32> { 10 | // CHECK: gccjit.call builtin @aligned_alloc(%{{[0-9]+}}, %{{[0-9]+}}) : (!gccjit.int, !gccjit.int) -> !gccjit.ptr 11 | %a = memref.alloc () : memref<100x100xf32> 12 | return %a : memref<100x100xf32> 13 | } 14 | 15 | func.func @bar(%arg0 : index, %arg1: index) -> memref { 16 | // CHECK: gccjit.call builtin @aligned_alloc(%{{[0-9]+}}, %{{[0-9]+}}) : (!gccjit.int, !gccjit.int) -> !gccjit.ptr 17 | %a = memref.alloc (%arg0, %arg1) : memref 18 | return %a : memref 19 | } 20 | 21 | func.func @baz() -> memref<133x723x1xi128> { 22 | // CHECK: gccjit.call builtin @aligned_alloc(%{{[0-9]+}}, %{{[0-9]+}}) : (!gccjit.int, !gccjit.int) -> !gccjit.ptr 23 | %a = memref.alloc () {alignment = 128} : memref<133x723x1xi128> 24 | return %a : memref<133x723x1xi128> 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/lowering/alloca.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s -o %t.mlir -convert-memref-to-gccjit 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | module @test 4 | { 5 | 6 | func.func @foo() { 7 | // CHECK: gccjit.call builtin @__builtin_alloca(%{{[0-9]+}}) : (!gccjit.int) -> !gccjit.ptr 8 | %a = memref.alloca () : memref<100x100xf32> 9 | return 10 | } 11 | 12 | func.func @bar(%arg0 : index) { 13 | // // CHECK: gccjit.call builtin @__builtin_alloca(%{{[0-9]+}}) : (!gccjit.int) -> !gccjit.ptr 14 | %a = memref.alloca (%arg0) : memref<133x723x?xf32> 15 | return 16 | } 17 | 18 | func.func @baz(%arg0 : index) { 19 | // CHECK: gccjit.call builtin @__builtin_alloca_with_align(%{{[0-9]+}}, %{{[0-9]+}}) : (!gccjit.int, !gccjit.int) -> !gccjit.ptr 20 | %a = memref.alloca (%arg0) {alignment = 128} : memref<133x723x?xf32> 21 | return 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/lowering/alloca_sum.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | void print(int32_t x) { 6 | printf("%d\n", x); 7 | } 8 | 9 | int32_t read() { 10 | int32_t x; 11 | scanf("%d", &x); 12 | return x; 13 | } 14 | -------------------------------------------------------------------------------- /test/lowering/alloca_sum.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s \ 2 | // RUN: -lower-affine \ 3 | // RUN: -convert-scf-to-cf \ 4 | // RUN: -convert-arith-to-gccjit \ 5 | // RUN: -convert-memref-to-gccjit \ 6 | // RUN: -convert-func-to-gccjit \ 7 | // RUN: -reconcile-unrealized-casts -mlir-print-debuginfo -o %t.mlir 8 | 9 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-gimple | %filecheck %s --check-prefix=CHECK-GIMPLE 10 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-dylib -o %t.so 11 | // RUN: cc -O3 %p/alloca_sum.c %t.so -Wl,-rpath,%T -o %t.exe 12 | // RUN: seq 1 100 | %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 13 | 14 | // CHECK-OUTPUT: 5050 15 | module attributes { gccjit.opt_level = #gccjit.opt_level, gccjit.debug_info = false } { 16 | // Import C standard library functions for I/O 17 | func.func private @read() -> i32 18 | func.func private @print(%val: i32) 19 | 20 | func.func @main() -> i32 { 21 | // Allocate memory for the 100 integers array and initialize sum to 0 22 | // CHECK-GIMPLE: %{{[0-9]+}} = bitcast(alloca (%{{[0-9]+}}), __uint32_t *); 23 | %array = memref.alloca() : memref<100xi32> 24 | %sum_init = arith.constant 0 : i32 25 | 26 | // Loop to read 100 integers into the array 27 | %c0 = arith.constant 0 : index 28 | %c1 = arith.constant 1 : index 29 | %c100 = arith.constant 100 : index 30 | 31 | scf.for %i = %c0 to %c100 step %c1 { 32 | // Call scanf to read an integer 33 | // CHECK-GIMPLE: %{{[0-9]+}} = read (); 34 | %read = func.call @read() : () -> i32 35 | memref.store %read, %array[%i] : memref<100xi32> 36 | } 37 | 38 | // Loop to calculate the sum using iter_args 39 | %final_sum = scf.for %i = %c0 to %c100 step %c1 iter_args(%acc = %sum_init) -> (i32) { 40 | %elem = memref.load %array[%i] : memref<100xi32> 41 | %new_sum = arith.addi %acc, %elem : i32 42 | scf.yield %new_sum : i32 43 | } 44 | 45 | // Print the result using printf 46 | // CHECK-GIMPLE: (void)print (%{{[0-9]+}}); 47 | func.call @print(%final_sum) : (i32) -> () 48 | 49 | %c0_1 = arith.constant 0 : i32 50 | return %c0_1 : i32 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/lowering/assume_aligned.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s -convert-memref-to-gccjit -convert-memref-to-gccjit -convert-func-to-gccjit -reconcile-unrealized-casts -o %t.mlir -mlir-print-debuginfo 2 | // RUN: %gccjit-translate %t.mlir -o %t.gimple -mlir-to-gccjit-gimple 3 | // RUN: %filecheck --input-file=%t.gimple %s --check-prefix=CHECK-GIMPLE 4 | module @test attributes { 5 | gccjit.opt_level = #gccjit.opt_level, 6 | gccjit.debug_info = false 7 | } 8 | { 9 | func.func @foo(%arg0: memref<100x100xf32>) -> memref<100x100xf32> { 10 | // CHECK-GIMPLE: %0 = %arg0; 11 | // CHECK-GIMPLE: %1 = (struct memref<100x100xf32>) {.base=%0.base, .aligned=bitcast(__builtin_assume_aligned ((bitcast(%0.aligned, void *)), %0.offset), float *), .offset=%0.offset, .sizes=%0.sizes, .strides=%0.strides}; 12 | // CHECK-GIMPLE: return %1; 13 | memref.assume_alignment %arg0, 128 : memref<100x100xf32> 14 | return %arg0 : memref<100x100xf32> 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/lowering/dealloc.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s \ 2 | // RUN: -lower-affine \ 3 | // RUN: -convert-scf-to-cf \ 4 | // RUN: -convert-arith-to-gccjit \ 5 | // RUN: -convert-memref-to-gccjit \ 6 | // RUN: -convert-func-to-gccjit \ 7 | // RUN: -reconcile-unrealized-casts -mlir-print-debuginfo -o %t.mlir 8 | 9 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-executable -o %t.exe && chmod +x %t.exe 10 | // RUN: %t.exe 11 | module @test attributes { 12 | gccjit.cmdline_options = ["-fsanitize=address"], 13 | gccjit.driver_options = ["-fsanitize=address"], 14 | gccjit.debug_info = true 15 | } 16 | { 17 | func.func @main() { 18 | %arg0 = arith.constant 133 : index 19 | %a = memref.alloc (%arg0) : memref<133x723x?xf32> 20 | memref.dealloc %a : memref<133x723x?xf32> 21 | return 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/lowering/gemm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define TOLERANCE 1e-5 6 | 7 | // Define the memref struct 8 | typedef struct { 9 | float *allocated; // Pointer to allocated memory 10 | float *aligned; // Pointer to aligned data (if applicable) 11 | size_t offset; // Offset from aligned pointer to actual data 12 | size_t sizes[2]; // Array to hold sizes for the 2D dimensions 13 | size_t strides[2]; // Array to hold strides for the 2D dimensions 14 | } memref_t; 15 | 16 | // External declaration of the gemm function 17 | extern void gemm(memref_t A, memref_t B, memref_t C, float alpha, float beta); 18 | 19 | void initialize_matrix(memref_t *matrix, size_t rows, size_t cols) { 20 | matrix->allocated = (float *)malloc(rows * cols * sizeof(float)); 21 | matrix->aligned = matrix->allocated; // Assume no special alignment needed 22 | matrix->offset = 0; 23 | matrix->sizes[0] = rows; 24 | matrix->sizes[1] = cols; 25 | matrix->strides[0] = cols; // Row-major layout 26 | matrix->strides[1] = 1; 27 | } 28 | 29 | void free_matrix(memref_t *matrix) { free(matrix->allocated); } 30 | 31 | // Simple C implementation of gemm for verification 32 | void gemm_verify(memref_t *A, memref_t *B, memref_t *C, float alpha, 33 | float beta) { 34 | size_t rows = C->sizes[0]; 35 | size_t cols = C->sizes[1]; 36 | size_t K = A->sizes[1]; 37 | 38 | for (size_t i = 0; i < rows; i++) { 39 | for (size_t j = 0; j < cols; j++) { 40 | float sum = 0.0f; 41 | for (size_t k = 0; k < K; k++) { 42 | float a_val = A->allocated[i * A->strides[0] + k * A->strides[1]]; 43 | float b_val = B->allocated[k * B->strides[0] + j * B->strides[1]]; 44 | sum += a_val * b_val; 45 | } 46 | float c_val = C->allocated[i * C->strides[0] + j * C->strides[1]]; 47 | C->allocated[i * C->strides[0] + j * C->strides[1]] = 48 | alpha * sum + beta * c_val; 49 | } 50 | } 51 | } 52 | 53 | // Function to check if two matrices are approximately equal 54 | int verify_result(memref_t *C, memref_t *C_ref) { 55 | size_t rows = C->sizes[0]; 56 | size_t cols = C->sizes[1]; 57 | for (size_t i = 0; i < rows; i++) { 58 | for (size_t j = 0; j < cols; j++) { 59 | float val = C->allocated[i * C->strides[0] + j * C->strides[1]]; 60 | float ref_val = 61 | C_ref->allocated[i * C_ref->strides[0] + j * C_ref->strides[1]]; 62 | if (fabs(val - ref_val) > TOLERANCE) { 63 | printf("Mismatch at C[%zu][%zu]: %f (expected %f)\n", i, j, val, 64 | ref_val); 65 | return 0; 66 | } 67 | } 68 | } 69 | return 1; 70 | } 71 | 72 | int main() { 73 | memref_t A, B, C, C_ref; 74 | float alpha = 1.0f, beta = 1.0f; 75 | size_t rows = 100, cols = 100; 76 | 77 | // Initialize matrices A, B, C, and C_ref with 100x100 dimensions 78 | initialize_matrix(&A, rows, cols); 79 | initialize_matrix(&B, rows, cols); 80 | initialize_matrix(&C, rows, cols); 81 | initialize_matrix(&C_ref, rows, cols); 82 | 83 | // Fill matrices A and B with some values and initialize C and C_ref 84 | for (size_t i = 0; i < rows; i++) { 85 | for (size_t j = 0; j < cols; j++) { 86 | A.allocated[i * A.strides[0] + j * A.strides[1]] = (float)(i + j); 87 | B.allocated[i * B.strides[0] + j * B.strides[1]] = (float)(i - j); 88 | C.allocated[i * C.strides[0] + j * C.strides[1]] = 0.0f; 89 | C_ref.allocated[i * C_ref.strides[0] + j * C_ref.strides[1]] = 0.0f; 90 | } 91 | } 92 | 93 | // Call the external gemm function 94 | gemm(A, B, C, alpha, beta); 95 | 96 | // Call the verification gemm function 97 | gemm_verify(&A, &B, &C_ref, alpha, beta); 98 | 99 | // Verify the results 100 | if (verify_result(&C, &C_ref)) { 101 | printf("Verification passed! The matrices match.\n"); 102 | } else { 103 | printf("Verification failed! The matrices do not match.\n"); 104 | } 105 | 106 | // Free allocated memory for matrices 107 | free_matrix(&A); 108 | free_matrix(&B); 109 | free_matrix(&C); 110 | free_matrix(&C_ref); 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /test/lowering/gemm.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s \ 2 | // RUN: -lower-affine \ 3 | // RUN: -convert-scf-to-cf \ 4 | // RUN: -convert-arith-to-gccjit \ 5 | // RUN: -convert-memref-to-gccjit \ 6 | // RUN: -convert-func-to-gccjit \ 7 | // RUN: -reconcile-unrealized-casts -mlir-print-debuginfo -o %t.mlir 8 | // RUN: %filecheck --input-file=%t.mlir %s 9 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-gimple | %filecheck %s --check-prefix=CHECK-GIMPLE 10 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-dylib -o %t.so 11 | // RUN: cc -O3 %p/gemm.c %t.so -Wl,-rpath,%T -o %t.exe 12 | // RUN: %t.exe | %filecheck %s --check-prefix=CHECK-OUTPUT 13 | 14 | // CHECK-OUTPUT: Verification passed! The matrices match. 15 | module @test attributes { 16 | gccjit.opt_level = #gccjit.opt_level, 17 | gccjit.debug_info = false 18 | } 19 | { 20 | // CHECK-NOT: func.func 21 | // CHECK-NOT: func.return 22 | // CHECK-NOT: cf.cond_br 23 | // CHECK-NOT: cf.br 24 | func.func @gemm(%A: memref<100x100xf32>, %B: memref<100x100xf32>, %C: memref<100x100xf32>, %alpha: f32, %beta: f32) { 25 | affine.for %i = 0 to 100 { 26 | affine.for %j = 0 to 100 { 27 | // Load the value from C and scale it by beta 28 | %c_val = affine.load %C[%i, %j] : memref<100x100xf32> 29 | %c_scaled = arith.mulf %c_val, %beta : f32 30 | 31 | // Initialize the accumulator 32 | %acc0 = arith.constant 0.0 : f32 33 | %sum = affine.for %k = 0 to 100 iter_args(%acc = %acc0) -> f32 { 34 | // Load values from A and B 35 | // CHECK-GIMPLE: %{{[0-9]+}} = %{{[0-9\.a-z]+}}[(%{{[0-9]+}} * (size_t)100 + %{{[0-9]+}})] 36 | %a_val = affine.load %A[%i, %k] : memref<100x100xf32> 37 | // CHECK-GIMPLE: %{{[0-9]+}} = %{{[0-9\.a-z]+}}[(%{{[0-9]+}} * (size_t)100 + %{{[0-9]+}})] 38 | %b_val = affine.load %B[%k, %j] : memref<100x100xf32> 39 | 40 | // Multiply and accumulate 41 | // CHECK-GIMPLE: %[[V:[0-9]+]] = %{{[0-9]+}} * %{{[0-9]+}} 42 | %prod = arith.mulf %a_val, %b_val : f32 43 | // CHECK-GIMPLE: %{{[0-9]+}} = %{{[0-9]+}} + %[[V]] 44 | %new_acc = arith.addf %acc, %prod : f32 45 | 46 | // Yield the new accumulated value 47 | affine.yield %new_acc : f32 48 | } 49 | 50 | // Multiply the sum by alpha 51 | %result = arith.mulf %sum, %alpha : f32 52 | 53 | // Add the scaled C matrix value to the result 54 | %final_val = arith.addf %c_scaled, %result : f32 55 | 56 | // Store the final result back to matrix C 57 | // CHECK-GIMPLE: %{{[0-9\.a-z]+}}[(%{{[0-9]+}} * (size_t)100 + %{{[0-9]+}})] = %{{[0-9]+}} 58 | affine.store %final_val, %C[%i, %j] : memref<100x100xf32> 59 | } 60 | } 61 | return 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/lowering/global.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt %s \ 2 | // RUN: -lower-affine \ 3 | // RUN: -convert-scf-to-cf \ 4 | // RUN: -convert-arith-to-gccjit \ 5 | // RUN: -convert-memref-to-gccjit \ 6 | // RUN: -convert-func-to-gccjit \ 7 | // RUN: -reconcile-unrealized-casts -mlir-print-debuginfo -o %t.mlir 8 | // RUN: %filecheck --input-file=%t.mlir %s 9 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-gimple | %filecheck %s --check-prefix=CHECK-GIMPLE 10 | // RUN: %gccjit-translate %t.mlir -mlir-to-gccjit-object -o %t.o 11 | // RUN: nm %t.o | %filecheck %s --check-prefix=CHECK-NM 12 | 13 | 14 | // CHECK-NM: T get_gv0 15 | // CHECK-NM: T get_splat 16 | // CHECK-NM: T get_uninit 17 | // CHECK-NM: d gv0 18 | // CHECK-NM: D gv1 19 | // CHECK-NM: d splat 20 | // CHECK-NM: T sum_uninit 21 | // CHECK-NM: b uninit 22 | 23 | module attributes { gccjit.opt_level = #gccjit.opt_level, gccjit.cmdline_options = ["-ffast-math"] } { 24 | // CHECK: gccjit.global internal @splat init 25 | // CHECK-GIMPLE: static float[4][4] splat = (float[4][4]) {(float[4]) {(float)1.000000, (float)1.000000, (float)1.000000, (float)1.000000}, (float[4]) {(float)1.000000, (float)1.000000, (float)1.000000, (float)1.000000}, (float[4]) {(float)1.000000, (float)1.000000, (float)1.000000, (float)1.000000}, (float[4]) {(float)1.000000, (float)1.000000, (float)1.000000, (float)1.000000}}; 26 | memref.global "private" @splat : memref<4x4xf32> = dense<1.0> 27 | // CHECK: gccjit.global internal @gv0 init 28 | // CHECK-GIMPLE: static float[4] gv0 = (float[4]) {(float)0.000000, (float)1.000000, (float)2.000000, (float)3.000000}; 29 | memref.global "private" @gv0 : memref<4xf32> = dense<[0.0, 1.0, 2.0, 3.0]> 30 | // CHECK: gccjit.global exported @gv1 init 31 | // CHECK-GIMPLE: __uint32_t[2][3] gv1 = (__uint32_t[2][3]) {(__uint32_t[2]) {(__uint32_t)0, (__uint32_t)1}, (__uint32_t[2]) {(__uint32_t)2, (__uint32_t)3}, (__uint32_t[2]) {(__uint32_t)4, (__uint32_t)5}}; 32 | memref.global @gv1 : memref<3x2xi32> = dense<[[0, 1],[2, 3],[4, 5]]> 33 | // CHECK: gccjit.global internal @uninit 34 | // CHECK-GIMPLE: static float[512][512] uninit; 35 | memref.global "private" @uninit : memref<512x512xf32> = uninitialized 36 | 37 | 38 | func.func @get_splat() -> memref<4x4xf32> { 39 | %0 = memref.get_global @splat : memref<4x4xf32> 40 | return %0 : memref<4x4xf32> 41 | } 42 | 43 | func.func @get_gv0() -> memref<4xf32> { 44 | %0 = memref.get_global @gv0 : memref<4xf32> 45 | return %0 : memref<4xf32> 46 | } 47 | 48 | func.func @get_uninit() -> memref<512x512xf32> { 49 | %0 = memref.get_global @uninit : memref<512x512xf32> 50 | return %0 : memref<512x512xf32> 51 | } 52 | 53 | func.func @sum_uninit() -> f32 { 54 | %0 = memref.get_global @uninit : memref<512x512xf32> 55 | 56 | %zero = arith.constant 0.000000e+00 : f32 57 | 58 | %c0 = arith.constant 0 : index 59 | %c512 = arith.constant 512 : index 60 | %c1 = arith.constant 1 : index 61 | %sum = scf.for %arg0 = %c0 to %c512 step %c1 iter_args(%arg1 = %zero) -> f32 { 62 | %inner = scf.for %arg2 = %c0 to %c512 step %c1 iter_args(%arg3 = %arg1) -> f32 { 63 | %1 = memref.load %0[%arg0, %arg2] : memref<512x512xf32> 64 | %2 = arith.addf %arg3, %1 : f32 65 | scf.yield %2 : f32 66 | } 67 | scf.yield %inner : f32 68 | } 69 | return %sum : f32 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/syntax/basic.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !i32 = !gccjit.int 5 | module @test attributes { 6 | gccjit.opt_level = #gccjit.opt_level, 7 | gccjit.prog_name = "test", 8 | gccjit.allow_unreachable = false 9 | } { 10 | gccjit.func exported @foo(!i32 , !i32) -> !i32 { 11 | ^entry(%arg0: !gccjit.lvalue, %arg1: !gccjit.lvalue): 12 | llvm.unreachable 13 | } 14 | // CHECK-LABEL: @foo 15 | // CHECK-NEXT: ^{{.+}}(%{{.+}}: !gccjit.lvalue>, %{{.+}}: !gccjit.lvalue>): 16 | // CHECK-NEXT: llvm.unreachable 17 | // CHECK-NEXT: } 18 | 19 | gccjit.func imported @bar(!gccjit.int) 20 | // CHECK-LABEL: gccjit.func imported @bar (!gccjit.int) 21 | } 22 | -------------------------------------------------------------------------------- /test/syntax/branch.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !bool = !gccjit.int 5 | !long = !gccjit.int 6 | module @test { 7 | gccjit.func exported @foo(!bool) { 8 | ^entry(%arg0: !gccjit.lvalue): 9 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !bool 10 | gccjit.conditional (%0 : !bool), ^true, ^false 11 | ^true: 12 | gccjit.return 13 | ^false: 14 | gccjit.return 15 | } 16 | // CHECK-LABEL: @foo 17 | // CHECK-NEXT: ^{{.+}}(%[[ARG0:.+]]: !gccjit.lvalue>): 18 | // CHECK-NEXT: %[[#V0:]] = gccjit.as_rvalue %[[ARG0:.+]] : > to !gccjit.int 19 | // CHECK-NEXT: gccjit.conditional(%[[#V0]] : ), ^[[BB1:.+]], ^[[BB2:.+]] 20 | // CHECK-NEXT: ^[[BB1]]: 21 | // CHECK-NEXT: gccjit.return 22 | // CHECK-NEXT: ^[[BB2]]: 23 | // CHECK-NEXT: gccjit.return 24 | // CHECK-NEXT: } 25 | 26 | gccjit.func exported @bar(!long) { 27 | ^entry(%arg0: !gccjit.lvalue): 28 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !long 29 | gccjit.switch (%0 : !long) { 30 | default -> ^default, 31 | #gccjit.int<5> : !long -> ^case1, 32 | #gccjit.int<10> : !long ...#gccjit.int<20> : !long -> ^case2 33 | } 34 | ^case1: 35 | gccjit.return 36 | ^case2: 37 | gccjit.return 38 | ^default: 39 | gccjit.return 40 | } 41 | // CHECK-LABEL: @bar 42 | // CHECK-NEXT: ^{{.+}}(%[[ARG0:.+]]: !gccjit.lvalue>): 43 | // CHECK-NEXT: %[[#V0:]] = gccjit.as_rvalue %[[ARG0]] : > to !gccjit.int 44 | // CHECK-NEXT: gccjit.switch(%[[#V0]] : ) { 45 | // CHECK-NEXT: default -> ^[[BB3:.+]], 46 | // CHECK-NEXT: #gccjit.int<5> : !gccjit.int -> ^[[BB1:.+]], 47 | // CHECK-NEXT: #gccjit.int<10> : !gccjit.int...#gccjit.int<20> : !gccjit.int -> ^[[BB2:.+]] 48 | // CHECK-NEXT: } 49 | // CHECK-NEXT: ^[[BB1]]: 50 | // CHECK-NEXT: gccjit.return 51 | // CHECK-NEXT: ^[[BB2]]: 52 | // CHECK-NEXT: gccjit.return 53 | // CHECK-NEXT: ^[[BB3]]: 54 | // CHECK-NEXT: gccjit.return 55 | // CHECK-NEXT: } 56 | } 57 | -------------------------------------------------------------------------------- /test/syntax/extened_asm.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !u64 = !gccjit.int 5 | module @test { 6 | gccjit.func exported @foo() -> !u64 { 7 | %msr = gccjit.local : !gccjit.lvalue 8 | gccjit.asm volatile ( 9 | "rdtsc\n\tshl $32, %%rdx\n\tor %%rdx, %0\n\t" 10 | : "=a" (%msr : !gccjit.lvalue) 11 | : 12 | : "rdx" 13 | ) 14 | %val = gccjit.as_rvalue %msr : !gccjit.lvalue to !u64 15 | gccjit.return %val : !u64 16 | } 17 | // CHECK-LABEL: @foo 18 | // CHECK-NEXT: %[[#V0:]] = gccjit.local : > 19 | // CHECK-NEXT: gccjit.asm volatile("rdtsc\0A\09shl $32, %%rdx\0A\09or %%rdx, %0\0A\09" : "=a"(%[[#V0]] : !gccjit.lvalue>) : : "rdx") 20 | // CHECK-NEXT: %[[#V1:]] = gccjit.as_rvalue %[[#V0]] : > to !gccjit.int 21 | // CHECK-NEXT: gccjit.return %[[#V1]] : !gccjit.int 22 | // CHECK-NEXT: } 23 | } 24 | -------------------------------------------------------------------------------- /test/syntax/floating_point.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !float = !gccjit.fp 5 | !ldb = !gccjit.fp 6 | module @test { 7 | gccjit.func exported @foo(!float , !ldb) -> !float { 8 | ^entry(%arg0: !gccjit.lvalue, %arg1: !gccjit.lvalue): 9 | %0 = gccjit.const #gccjit.zero : !float 10 | gccjit.return %0 : !float 11 | } 12 | // CHECK-LABEL: @foo 13 | // CHECK-NEXT: ^{{.+}}(%{{.+}}: !gccjit.lvalue>, %{{.+}}: !gccjit.lvalue>): 14 | // CHECK-NEXT: %[[#V0:]] = gccjit.const #gccjit.zero : !gccjit.fp 15 | // CHECK-NEXT: gccjit.return %[[#V0]] : !gccjit.fp 16 | // CHECK-NEXT: } 17 | } 18 | -------------------------------------------------------------------------------- /test/syntax/function_attrs.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !i32 = !gccjit.int 5 | !ptr_i32 = !gccjit.ptr 6 | module @test attributes { 7 | gccjit.opt_level = #gccjit.opt_level, 8 | gccjit.prog_name = "test", 9 | gccjit.allow_unreachable = false 10 | } { 11 | gccjit.func exported @foo(!ptr_i32) -> !ptr_i32 attrs([ 12 | #gccjit.fn_attr, 13 | #gccjit.fn_attr, 14 | #gccjit.fn_attr>]) 15 | { 16 | ^entry(%arg0: !gccjit.lvalue): 17 | %0 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !ptr_i32 18 | gccjit.return %0 : !ptr_i32 19 | } 20 | // CHECK-LABEL: @foo 21 | // CHECK-NEXT: ^{{.+}}(%[[ARG0:.+]]: !gccjit.lvalue>>): 22 | // CHECK-NEXT: %[[#V0:]] = gccjit.as_rvalue %[[ARG0]] : >> to !gccjit.ptr> 23 | // CHECK-NEXT: gccjit.return %[[#V0]] : !gccjit.ptr> 24 | // CHECK-NEXT: } 25 | } 26 | -------------------------------------------------------------------------------- /test/syntax/hello_world.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !i32 = !gccjit.int 5 | !char = !gccjit.int 6 | !const_char = !gccjit.qualified 7 | !str = !gccjit.ptr 8 | module @test attributes { 9 | gccjit.opt_level = #gccjit.opt_level, 10 | gccjit.prog_name = "test", 11 | gccjit.allow_unreachable = false, 12 | gccjit.debug_info = true 13 | } { 14 | gccjit.func imported @puts(!str) -> !i32 15 | // CHECK-LABEL: gccjit.func imported @puts (!gccjit.ptr, const>>) -> !gccjit.int 16 | 17 | // CHECK-LABEL: @main 18 | gccjit.func exported @main() -> !i32 { 19 | %0 = gccjit.literal "hello, world!\n" : !str 20 | %1 = gccjit.call @puts(%0) : (!str) -> !i32 21 | %2 = gccjit.const #gccjit.zero : !i32 22 | gccjit.return %2 : !i32 23 | 24 | // CHECK-NEXT: %[[#V0:]] = gccjit.literal "hello, world!\0A" : , const>> 25 | // CHECK-NEXT: %[[#V1:]] = gccjit.call @puts(%[[#V0]]) : (!gccjit.ptr, const>>) -> !gccjit.int 26 | // CHECK-NEXT: %[[#V2:]] = gccjit.const #gccjit.zero : !gccjit.int 27 | // CHECK-NEXT: gccjit.return %[[#V2]] : !gccjit.int 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/syntax/record.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | module @test { 5 | gccjit.func imported @gemm ( 6 | !gccjit.struct<"__memref_188510220862752" { 7 | #gccjit.field<"base" !gccjit.ptr>>, 8 | #gccjit.field<"aligned" !gccjit.ptr>>, 9 | #gccjit.field<"offset" !gccjit.int : 32>, 10 | #gccjit.field<"sizes" !gccjit.array, 2>>, 11 | #gccjit.field<"strides" !gccjit.array, 2>> 12 | }> 13 | ) 14 | // CHECK: @gemm 15 | // CHECK-SAME: !gccjit.struct<"__memref_188510220862752" { 16 | // CHECK-SAME: #gccjit.field<"base" !gccjit.ptr>> 17 | // CHECK-SAME: #gccjit.field<"aligned" !gccjit.ptr>> 18 | // CHECK-SAME: #gccjit.field<"offset" !gccjit.int : 32> 19 | // CHECK-SAME: #gccjit.field<"sizes" !gccjit.array, 2>> 20 | // CHECK-SAME: #gccjit.field<"strides" !gccjit.array, 2>> 21 | // CHECK-SAME: } 22 | } 23 | -------------------------------------------------------------------------------- /test/syntax/variables.mlir: -------------------------------------------------------------------------------- 1 | // RUN: %gccjit-opt -o %t.mlir %s 2 | // RUN: %filecheck --input-file=%t.mlir %s 3 | 4 | !i32 = !gccjit.int 5 | !ptr_i32 = !gccjit.ptr 6 | module @test attributes { 7 | gccjit.debug_info = true 8 | } { 9 | // CHECK-LABEL: @foo 10 | gccjit.func exported @foo(!i32) -> !i32 attrs([ 11 | #gccjit.fn_attr 12 | ]) { 13 | ^entry(%arg0: !gccjit.lvalue): 14 | %0 = gccjit.local align(16) : 15 | %1 = gccjit.const #gccjit.one : !i32 16 | gccjit.assign %1 to %0 : !i32, 17 | %2 = gccjit.as_rvalue %0 : !gccjit.lvalue to !i32 18 | %3 = gccjit.as_rvalue %arg0 : !gccjit.lvalue to !i32 19 | %4 = gccjit.binary plus (%2 : !i32, %3 : !i32) : !i32 20 | gccjit.return %4 : !i32 21 | 22 | // CHECK: ^{{.+}}(%arg0: !gccjit.lvalue>): 23 | // CHECK-NEXT: %[[#V0:]] = gccjit.local align(16) : > 24 | // CHECK-NEXT: %[[#V1:]] = gccjit.const #gccjit.one : !gccjit.int 25 | // CHECK-NEXT: gccjit.assign %[[#V1]] to %[[#V0]] : !gccjit.int, > 26 | // CHECK-NEXT: %[[#V2:]] = gccjit.as_rvalue %[[#V0]] : > to !gccjit.int 27 | // CHECK-NEXT: %[[#V3:]] = gccjit.as_rvalue %arg0 : > to !gccjit.int 28 | // CHECK-NEXT: %[[#V4:]] = gccjit.binary plus(%[[#V2]] : !gccjit.int, %[[#V3]] : !gccjit.int) : !gccjit.int 29 | // CHECK-NEXT: gccjit.return %[[#V4]] : !gccjit.int 30 | } 31 | 32 | gccjit.global imported @test : !gccjit.lvalue 33 | // CHECK-LABEL: gccjit.global imported @test : !gccjit.lvalue> 34 | 35 | gccjit.global internal @test2 array(#gccjit.byte_array<[0, 0, 0, 0]>) : !gccjit.lvalue> 36 | // CHECK-LABEL: gccjit.global internal @test2 array(<[0, 0, 0, 0]>) : !gccjit.lvalue, 1>> 37 | 38 | // CHECK-LABEL: @test3 39 | gccjit.global exported @test3 init { 40 | %0 = gccjit.const #gccjit.zero : !i32 41 | gccjit.return %0 : !i32 42 | 43 | // CHECK: %[[#V0:]] = gccjit.const #gccjit.zero : !gccjit.int 44 | // CHECK-NEXT: gccjit.return %[[#V0]] : !gccjit.int 45 | } : !gccjit.lvalue 46 | 47 | gccjit.global exported @test4 literal ("hello, world!") : !gccjit.lvalue, 14>> 48 | // CHECK-LABEL: gccjit.global exported @test4 literal("hello, world!") : !gccjit.lvalue, 14>> 49 | 50 | // CHECK-LABEL: @test5 51 | gccjit.global exported @test5 link_section(".rodata") init { 52 | %0 = gccjit.get_global @test3 : !gccjit.lvalue 53 | %addr = gccjit.addr (%0 : !gccjit.lvalue) : !gccjit.ptr 54 | gccjit.return %addr : !gccjit.ptr 55 | 56 | // CHECK: %[[#V0:]] = gccjit.get_global @test3 : > 57 | // CHECK-NEXT: %[[#V1:]] = gccjit.addr(%[[#V0]] : >) : > 58 | // CHECK-NEXT: gccjit.return %[[#V1]] : !gccjit.ptr> 59 | } : !gccjit.lvalue> 60 | } 61 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(gccjit-tools) 2 | 3 | add_subdirectory(gccjit-opt) 4 | add_subdirectory(gccjit-translate) 5 | -------------------------------------------------------------------------------- /tools/gccjit-opt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) 2 | get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) 3 | get_property(extension_libs GLOBAL PROPERTY MLIR_EXTENSION_LIBS) 4 | 5 | add_mlir_tool(gccjit-opt 6 | main.cpp 7 | DEPENDS 8 | MLIROptLib 9 | MLIRGCCJIT 10 | ${dialect_libs} 11 | ${conversion_libs} 12 | ${extension_libs} 13 | ) 14 | target_link_libraries(gccjit-opt 15 | PRIVATE 16 | MLIROptLib 17 | MLIRGCCJIT 18 | ${dialect_libs} 19 | ${conversion_libs} 20 | ${extension_libs} 21 | ) 22 | 23 | add_dependencies(gccjit-tools gccjit-opt) 24 | -------------------------------------------------------------------------------- /tools/gccjit-opt/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "mlir-gccjit/IR/GCCJITDialect.h" 22 | #include "mlir-gccjit/Passes.h" 23 | 24 | int main(int argc, char **argv) { 25 | mlir::DialectRegistry registry; 26 | mlir::registerAllDialects(registry); 27 | registry.insert(); 28 | mlir::registerAllExtensions(registry); 29 | mlir::registerAllPasses(); 30 | mlir::gccjit::registerGCCJITPasses(); 31 | return failed(mlir::MlirOptMain( 32 | argc, argv, "GCCJIT analysis and optimization driver\n", registry)); 33 | } 34 | -------------------------------------------------------------------------------- /tools/gccjit-translate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_LINK_COMPONENTS 2 | Support 3 | ) 4 | 5 | get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) 6 | get_property(translation_libs GLOBAL PROPERTY MLIR_TRANSLATION_LIBS) 7 | 8 | add_mlir_tool(gccjit-translate 9 | main.cpp 10 | ) 11 | llvm_update_compile_flags(gccjit-translate) 12 | target_link_libraries(gccjit-translate 13 | PRIVATE 14 | ${dialect_libs} 15 | ${translation_libs} 16 | MLIRIR 17 | MLIRParser 18 | MLIRPass 19 | MLIRSPIRVDialect 20 | MLIRTranslateLib 21 | MLIRSupport 22 | MLIRTranslateToGCCJIT 23 | MLIRGCCJIT 24 | ) 25 | 26 | mlir_check_link_libraries(gccjit-translate) 27 | 28 | add_dependencies(gccjit-tools gccjit-translate) 29 | -------------------------------------------------------------------------------- /tools/gccjit-translate/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Schrodinger ZHU Yifan 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "mlir-gccjit/Translation/TranslateToGCCJIT.h" 20 | 21 | using namespace mlir; 22 | 23 | int main(int argc, char **argv) { 24 | registerAllTranslations(); 25 | mlir::gccjit::registerToGCCJITGimpleTranslation(); 26 | mlir::gccjit::registerToGCCJITReproducerTranslation(); 27 | mlir::gccjit::registerToGCCJITAssemblyTranslation(); 28 | mlir::gccjit::registerToGCCJITObjectTranslation(); 29 | mlir::gccjit::registerToGCCJITExecutableTranslation(); 30 | mlir::gccjit::registerToGCCJITDylibTranslation(); 31 | return failed( 32 | mlirTranslateMain(argc, argv, "GCCJIT Translation Testing Tool")); 33 | } 34 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | /public 2 | *.lock 3 | 4 | # Pages in content/dialect are reserved for generated docs. 5 | /content/dialect 6 | -------------------------------------------------------------------------------- /www/archetypes/attrs.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Attributes' 3 | date = {{ .Date }} 4 | weight = 3 5 | +++ 6 | -------------------------------------------------------------------------------- /www/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = '{{ replace .File.ContentBaseName "-" " " | title }}' 3 | date = {{ .Date }} 4 | +++ 5 | -------------------------------------------------------------------------------- /www/archetypes/dialect.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Dialect' 3 | date = {{ .Date }} 4 | +++ 5 | -------------------------------------------------------------------------------- /www/archetypes/ops.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Operations' 3 | date = {{ .Date }} 4 | weight = 1 5 | +++ 6 | -------------------------------------------------------------------------------- /www/archetypes/passes.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Passes' 3 | date = {{ .Date }} 4 | weight = 4 5 | +++ 6 | -------------------------------------------------------------------------------- /www/archetypes/types.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Types' 3 | date = {{ .Date }} 4 | weight = 2 5 | +++ 6 | -------------------------------------------------------------------------------- /www/content/_index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'mlir-gccjit' 3 | date = 2024-11-29T16:25:51+08:00 4 | +++ 5 | 6 | 7 | 8 | ## mlir-gccjit 9 | 10 | MLIR dialect for `libgccjit`. 11 | 12 | ### Discussion 13 | 14 | If you have any questions about this project, check out the 15 | [discussion area](https://github.com/Lancern/mlir-gccjit/discussions). 16 | If you couldn't find satisfying answers there, feel free to 17 | [open a new discussion](https://github.com/Lancern/mlir-gccjit/discussions/new/choose). 18 | 19 | ### Contribution 20 | 21 | We warmly welcome any kind of contributions including but not restricted to bug 22 | reports, feature requests, and pull requests. Please 23 | [open an issue](https://github.com/Lancern/mlir-gccjit/issues/new) if you have 24 | found a bug or want to request a new feature. Feel free to open a pull request 25 | if you have made any improvements to the project! 26 | -------------------------------------------------------------------------------- /www/content/development/_index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Development' 3 | date = 2024-11-29T16:32:19+08:00 4 | weight = 2 5 | +++ 6 | -------------------------------------------------------------------------------- /www/content/development/build.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Build and Test' 3 | date = 2024-11-29T16:32:38+08:00 4 | +++ 5 | 6 | ## Prerequisites 7 | 8 | In general you need the following tools and libraries to build `mlir-gccjit`: 9 | 10 | - A working C++ compiler toolchain that supports C++17 standard. 11 | - [CMake] with minimum version 3.22. 12 | - [Ninja] build system (recommended but not mandatory). 13 | - [LLVM] libraries and development files. For now we have only tested LLVM-18. 14 | - [MLIR] libraries and development files. For now we have only tested MLIR-18. 15 | - [libgccjit] libraries and development files. For now we have only tested 16 | libgccjit-14. 17 | 18 | [CMake]: https://cmake.org/ 19 | [Ninja]: https://ninja-build.org/ 20 | [LLVM]: https://llvm.org/ 21 | [MLIR]: https://mlir.llvm.org/ 22 | [libgccjit]: https://gcc.gnu.org/onlinedocs/jit/ 23 | 24 | For Ubuntu 24.04 (noble) users: 25 | 26 | ```bash 27 | apt-get install build-essential cmake ninja-build llvm-18-dev llvm-18-tools libmlir-18-dev libgccjit-14-dev mlir-18-tools 28 | ``` 29 | 30 | Additionally, you need Python and the [`lit` tool] to run tests. You can 31 | install the tool via `pip`: 32 | 33 | ```bash 34 | pip install lit 35 | ``` 36 | 37 | [`lit` tool]: https://llvm.org/docs/CommandGuide/lit.html 38 | 39 | ## Build 40 | 41 | Clone the repository: 42 | 43 | ```bash 44 | git clone https://github.com/Lancern/mlir-gccjit.git 45 | cd mlir-gccjit 46 | ``` 47 | 48 | Create a build directory: 49 | 50 | ```bash 51 | mkdir build 52 | cd build 53 | ``` 54 | 55 | Build with CMake and `ninja`: 56 | 57 | ```bash 58 | cmake -G Ninja .. 59 | ninja 60 | ``` 61 | 62 | You can run all tests via the `check` target: 63 | 64 | ```bash 65 | ninja check 66 | ``` 67 | -------------------------------------------------------------------------------- /www/content/development/compatibility.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Compatibility' 3 | date = 2024-11-29T16:32:33+08:00 4 | +++ 5 | 6 | ## Minimum GCCJIT ABI requirement 7 | 8 | `mlir-gccjit` assumes the availability of [`LIBGCCJIT_ABI_27`](https://gcc.gnu.org/onlinedocs/jit/topics/compatibility.html#libgccjit-abi-27), which is available in GCC `14.2.0` or higher. 9 | 10 | Please refer to [ABI and API compatibility](https://gcc.gnu.org/onlinedocs/jit/topics/compatibility.html#abi-and-api-compatibility) for detailed ABI specification of `libgccjit.so`. 11 | 12 | ## Known Issues 13 | 14 | ### Polyfill of `gccjit.alignof` 15 | 16 | [`LIBGCCJIT_ABI_28`](https://gcc.gnu.org/onlinedocs/jit/topics/compatibility.html#libgccjit-abi-28) introduces `gcc_jit_context_new_alignof`. On targets before such ABI level, we calculate the alignment of a given type `T` by creating 17 | a dummy structure: 18 | ```c 19 | struct dummy { 20 | char __padding; 21 | T __field; 22 | }; 23 | ``` 24 | 25 | The alignment is then calculate as the offset to `__field` if a `dummy` struct is placed at address `NULL`: 26 | ```c 27 | bitcast(&((dummy *)NULL)->__field, size_t) 28 | ``` 29 | 30 | ### GCCJIT ICE with Aligned Alloca or Scoped Alloca 31 | 32 | When alignment is specified, our lowering pass converts `memref.alloca` to an intrinsic call to `__builtin_alloca_with_align`. Unfortunately, due to some implementation details inside GCC, `libgccjit` currently cannot identidy the type of this builtin function hence would run into an ICE. We have reported this project to upstream and will keep track of the status. Such issues also apply to 33 | `__builtin_stack_save` and `__builtin_stack_restore`, which are required to implement scoped alloca. 34 | -------------------------------------------------------------------------------- /www/hugo.toml: -------------------------------------------------------------------------------- 1 | baseURL = 'https://lancern.github.io/mlir-gccjit/' 2 | 3 | languageCode = 'en-us' 4 | title = 'mlir-gccjit' 5 | theme = 'hugo-theme-techdoc' 6 | 7 | [params] 8 | # Source Code repository section 9 | description = "An MLIR dialect for libgccjit" 10 | github_repository = "https://github.com/Lancern/mlir-gccjit" 11 | version = "" 12 | 13 | # Analytic section 14 | google_analytics_id = "" # Your Google Analytics tracking id 15 | tag_manager_container_id = "" # Your Google Tag Manager container id 16 | google_site_verification = "" # Your Google Site Verification for Search Console 17 | 18 | # Open Graph and Twitter Cards settings section 19 | # Open Graph settings for each page are set on the front matter. 20 | # See https://gohugo.io/templates/internal/#open-graph 21 | # See https://gohugo.io/templates/internal/#twitter-cards 22 | title = "mlir-gccjit" 23 | images = [] # Open graph images are placed in `static/images` 24 | 25 | # Theme settings section 26 | # Theme color 27 | # See color value reference https://developer.mozilla.org/en-US/docs/Web/CSS/color 28 | custom_font_color = "" 29 | custom_background_color = "#173559" 30 | 31 | # Documentation Menu section 32 | # Menu style settings 33 | menu_style = "slide-menu" # "open-menu" or "slide-menu" or "" blank is as no sidebar 34 | 35 | # Date format 36 | dateformat = "" # default "2 Jan 2006" 37 | # See the format reference https://gohugo.io/functions/format/#hugo-date-and-time-templating-reference 38 | 39 | # path name excluded from documentation menu 40 | menu_exclusion = [ 41 | "archives", 42 | "archive", 43 | "blog", 44 | "entry", 45 | "post", 46 | "posts", 47 | ] 48 | 49 | 50 | # Global menu section 51 | # See https://gohugo.io/content-management/menus/ 52 | [menu] 53 | [[menu.main]] 54 | name = "Repository" 55 | weight = 1 56 | url = "https://github.com/Lancern/mlir-gccjit" 57 | 58 | [[menu.main]] 59 | name = "Releases" 60 | weight = 2 61 | url = "https://github.com/Lancern/mlir-gccjit/releases" 62 | 63 | [[menu.main]] 64 | name = "Issues" 65 | weight = 3 66 | url = "https://github.com/Lancern/mlir-gccjit/issues" 67 | 68 | [[menu.main]] 69 | name = "Links" 70 | weight = 4 71 | 72 | [[menu.main]] 73 | name = "MLIR" 74 | parent = "Links" 75 | weight = 1 76 | url = "https://mlir.llvm.org/" 77 | 78 | [[menu.main]] 79 | name = "LLVM" 80 | parent = "Links" 81 | weight = 2 82 | url = "https://llvm.org/" 83 | 84 | [[menu.main]] 85 | name = "libgccjit" 86 | parent = "Links" 87 | weight = 3 88 | url = "https://gcc.gnu.org/onlinedocs/jit/" 89 | 90 | # Markup configure section 91 | # See https://gohugo.io/getting-started/configuration-markup/ 92 | [markup] 93 | defaultMarkdownHandler = "goldmark" 94 | [markup.goldmark.renderer] 95 | unsafe= true 96 | [markup.tableOfContents] 97 | startLevel = 2 98 | endLevel = 6 99 | ordered = false 100 | -------------------------------------------------------------------------------- /www/link-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | if [[ $# -ne 1 ]]; then 6 | echo "link-docs.sh requires 1 argument" 7 | exit 1 8 | fi 9 | 10 | rm -f content/dialect/*.md 11 | 12 | hugo new content --kind dialect content/dialect/_index.md 13 | hugo new content --kind ops content/dialect/ops.md 14 | hugo new content --kind types content/dialect/types.md 15 | hugo new content --kind attrs content/dialect/attrs.md 16 | hugo new content --kind passes content/dialect/passes.md 17 | 18 | cat "$1/docs/gccjit/GCCJITDialect.md" >> content/dialect/_index.md 19 | cat "$1/docs/gccjit/GCCJITOps.md" >> content/dialect/ops.md 20 | cat "$1/docs/gccjit/GCCJITTypes.md" >> content/dialect/types.md 21 | cat "$1/docs/gccjit/GCCJITAttrs.md" >> content/dialect/attrs.md 22 | cat "$1/docs/gccjit/GCCJITPasses.md" >> content/dialect/passes.md 23 | -------------------------------------------------------------------------------- /www/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lancern/mlir-gccjit/f981c8510688f2152c26882c95858d2ff039a2fd/www/static/logo.png --------------------------------------------------------------------------------