diff --git a/flang/include/flang/Evaluate/target.h b/flang/include/flang/Evaluate/target.h --- a/flang/include/flang/Evaluate/target.h +++ b/flang/include/flang/Evaluate/target.h @@ -91,15 +91,25 @@ return *this; } + TargetCharacteristics &set_targetFeatures(std::string x) { + targetFeaturesString_ = x; + return *this; + } + bool hasFeature(std::string x); + bool isPPC() const { return isPPC_; } void set_isPPC(bool isPPC = false); + bool isRISCV64() const { return isRISCV64_; } + void set_isRISCV64(bool isRISCV64 = false); + private: static constexpr int maxKind{32}; std::uint8_t byteSize_[common::TypeCategory_enumSize][maxKind]{}; std::uint8_t align_[common::TypeCategory_enumSize][maxKind]{}; bool isBigEndian_{false}; bool isPPC_{false}; + bool isRISCV64_{false}; bool areSubnormalsFlushedToZero_{false}; Rounding roundingMode_{defaultRounding}; std::size_t procedurePointerByteSize_{8}; @@ -109,6 +119,7 @@ std::size_t maxAlignment_{8 /*at least*/}; std::string compilerOptionsString_; std::string compilerVersionString_; + std::string targetFeaturesString_; }; } // namespace Fortran::evaluate diff --git a/flang/include/flang/Optimizer/Builder/RISCVIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/RISCVIntrinsicCall.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/RISCVIntrinsicCall.h @@ -0,0 +1,32 @@ +//==-- Builder/RISCVIntrinsicCall.h - lowering of RISCV intrinsics -*-C++-*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_RISCVINTRINSICCALL_H +#define FORTRAN_LOWER_RISCVINTRINSICCALL_H + +#include "flang/Common/static-multimap-view.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "mlir/Dialect/Math/IR/Math.h" + +namespace fir { + +struct RISCVIntrinsicLibrary : IntrinsicLibrary { + + // Constructors. + explicit RISCVIntrinsicLibrary(fir::FirOpBuilder &builder, mlir::Location loc) + : IntrinsicLibrary(builder, loc) {} + RISCVIntrinsicLibrary() = delete; + RISCVIntrinsicLibrary(const RISCVIntrinsicLibrary &) = delete; +}; + +std::pair +checkRISCVMathOperationsRange(llvm::StringRef name); + +} // namespace fir + +#endif // FORTRAN_LOWER_RISCVINTRINSICCALL_H diff --git a/flang/include/flang/Semantics/riscv-ext-with-intrinsics.def b/flang/include/flang/Semantics/riscv-ext-with-intrinsics.def new file mode 100644 --- /dev/null +++ b/flang/include/flang/Semantics/riscv-ext-with-intrinsics.def @@ -0,0 +1,17 @@ +//===-- include/flang/Semantics/riscv-ext-with-intrinsics.def ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef RISCV_EXTENSION +#error Define extensions with intrinsics in RISC-V +#endif + +RISCV_EXTENSION(Zbb) +RISCV_EXTENSION(Zbc) +RISCV_EXTENSION(Zbkb) +RISCV_EXTENSION(Zbkc) +RISCV_EXTENSION(Zbkx) diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h --- a/flang/include/flang/Semantics/semantics.h +++ b/flang/include/flang/Semantics/semantics.h @@ -221,6 +221,14 @@ Scope *GetPPCBuiltinTypesScope() { return ppcBuiltinTypesScope_; } const Scope *GetPPCBuiltinsScope() const { return ppcBuiltinsScope_; } +#define RISCV_EXTENSION(F) \ + void UseRISCV64##F##BuiltinsModule(); \ + const Scope *GetRISCV64##F##BuiltinsScope() const { \ + return riscv64##F##BuiltinsScope_; \ + } +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION + // Saves a module file's parse tree so that it remains available // during semantics. parser::Program &SaveParseTree(parser::Program &&); @@ -284,6 +292,12 @@ Scope *ppcBuiltinTypesScope_{nullptr}; // module __Fortran_PPC_types std::optional cudaBuiltinsScope_; // module __CUDA_builtins const Scope *ppcBuiltinsScope_{nullptr}; // module __ppc_intrinsics + + // module __RISCV64_##F##_intrinsics +#define RISCV_EXTENSION(F) const Scope *riscv64##F##BuiltinsScope_{nullptr}; +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION + std::list modFileParseTrees_; std::unique_ptr commonBlockMap_; bool anyDefinedIntrinsicOperator_{false}; diff --git a/flang/lib/Evaluate/target.cpp b/flang/lib/Evaluate/target.cpp --- a/flang/lib/Evaluate/target.cpp +++ b/flang/lib/Evaluate/target.cpp @@ -10,6 +10,7 @@ #include "flang/Common/template.h" #include "flang/Evaluate/common.h" #include "flang/Evaluate/type.h" +#include "flang/Parser/characters.h" namespace Fortran::evaluate { @@ -102,7 +103,21 @@ isBigEndian_ = isBig; } +bool TargetCharacteristics::hasFeature(std::string x) { + for (auto &c : x) { + c = parser::ToLowerCaseLetter(c); + } + std::string features = targetFeaturesString_ + ","; + if (features.find("+" + x + ",") != std::string::npos) { + return true; + } + return false; +} + void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; } +void TargetCharacteristics::set_isRISCV64(bool isRISCV64) { + isRISCV64_ = isRISCV64; +} void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) { areSubnormalsFlushedToZero_ = yes; diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -1114,6 +1114,13 @@ if (targetTriple.isPPC()) semanticsContext->targetCharacteristics().set_isPPC(true); + if (targetTriple.isRISCV64()) + semanticsContext->targetCharacteristics().set_isRISCV64(true); + + std::vector targetFeatures{this->targetOpts.featuresAsWritten}; + std::string featuresString = + llvm::join(targetFeatures.begin(), targetFeatures.end(), ","); + semanticsContext->targetCharacteristics().set_targetFeatures(featuresString); } /// Set \p loweringOptions controlling lowering behavior based diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -12,6 +12,7 @@ LowLevelIntrinsics.cpp MutableBox.cpp PPCIntrinsicCall.cpp + RISCVIntrinsicCall.cpp Runtime/Allocatable.cpp Runtime/ArrayConstructor.cpp Runtime/Assign.cpp diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -21,6 +21,7 @@ #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/MutableBox.h" #include "flang/Optimizer/Builder/PPCIntrinsicCall.h" +#include "flang/Optimizer/Builder/RISCVIntrinsicCall.h" #include "flang/Optimizer/Builder/Runtime/Allocatable.h" #include "flang/Optimizer/Builder/Runtime/Character.h" #include "flang/Optimizer/Builder/Runtime/Command.h" @@ -1200,6 +1201,10 @@ if (fir::getTargetTriple(mod).isPPC() && range.first == range.second) { range = checkPPCMathOperationsRange(name); } + // Search riscvMathOps only if targetting RISCV arch + if (fir::getTargetTriple(mod).isRISCV() && range.first == range.second) { + range = checkRISCVMathOperationsRange(name); + } for (auto iter = range.first; iter != range.second && iter; ++iter) { const auto &impl = *iter; auto implType = impl.typeGenerator(builder.getContext(), builder); @@ -1329,7 +1334,8 @@ static bool isIntrinsicModuleProcedure(llvm::StringRef name) { return name.startswith("c_") || name.startswith("compiler_") || - name.startswith("ieee_") || name.startswith("__ppc_"); + name.startswith("ieee_") || name.startswith("__ppc_") || + name.startswith("__riscv_"); } /// Return the generic name of an intrinsic module procedure specific name. @@ -1340,6 +1346,11 @@ llvm::StringRef name = specificName.startswith(builtin) ? specificName.drop_front(builtin.size()) : specificName; + if (name.startswith("__riscv_")) { + if (name.ends_with("_i4") || name.ends_with("_i8")) + return name.drop_back(3); + return name; + } size_t size = name.size(); if (isIntrinsicModuleProcedure(name)) while (isdigit(name[size - 1])) diff --git a/flang/lib/Optimizer/Builder/RISCVIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/RISCVIntrinsicCall.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/RISCVIntrinsicCall.cpp @@ -0,0 +1,68 @@ +//===-- RISCVIntrinsicCall.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helper routines for constructing the FIR dialect of MLIR for RISC-V +// intrinsics. Extensive use of MLIR interfaces and MLIR's coding style +// (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this +// module. +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/RISCVIntrinsicCall.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "flang/Optimizer/Builder/MutableBox.h" + +namespace fir { + +// RISC-V specific intrinsic handlers. +static constexpr MathOperation riscvMathOperations[] = { + {"__riscv_brev8", "llvm.riscv.brev8.i32", + genFuncType, Ty::Integer<4>>, genLibCall}, + {"__riscv_brev8", "llvm.riscv.brev8.i64", + genFuncType, Ty::Integer<8>>, genLibCall}, + {"__riscv_clmul", "llvm.riscv.clmul.i32", + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, genLibCall}, + {"__riscv_clmul", "llvm.riscv.clmul.i64", + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, genLibCall}, + {"__riscv_clmulh", "llvm.riscv.clmulh.i32", + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, genLibCall}, + {"__riscv_clmulh", "llvm.riscv.clmulh.i64", + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, genLibCall}, + {"__riscv_clmulr", "llvm.riscv.clmulr.i32", + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, genLibCall}, + {"__riscv_clmulr", "llvm.riscv.clmulr.i64", + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, genLibCall}, + {"__riscv_orc_b", "llvm.riscv.orc.b.i32", + genFuncType, Ty::Integer<4>>, genLibCall}, + {"__riscv_orc_b", "llvm.riscv.orc.b.i64", + genFuncType, Ty::Integer<8>>, genLibCall}, + {"__riscv_unzip", "llvm.riscv.unzip.i32", + genFuncType, Ty::Integer<4>>, genLibCall}, + {"__riscv_xperm4", "llvm.riscv.xperm4.i32", + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, genLibCall}, + {"__riscv_xperm4", "llvm.riscv.xperm4.i64", + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, genLibCall}, + {"__riscv_xperm8", "llvm.riscv.xperm8.i32", + genFuncType, Ty::Integer<4>, Ty::Integer<4>>, genLibCall}, + {"__riscv_xperm8", "llvm.riscv.xperm8.i64", + genFuncType, Ty::Integer<8>, Ty::Integer<8>>, genLibCall}, + {"__riscv_zip", "llvm.riscv.zip.i32", + genFuncType, Ty::Integer<4>>, genLibCall}, +}; + +using RtMap = Fortran::common::StaticMultimapView; +static constexpr RtMap riscvMathOps(riscvMathOperations); +static_assert(riscvMathOps.Verify() && "map must be sorted"); + +std::pair +checkRISCVMathOperationsRange(llvm::StringRef name) { + return riscvMathOps.equal_range(name); +} + +} // namespace fir diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -7492,7 +7492,21 @@ symbol = FindSymbol(*ppcBuiltinScope, name); if (!symbol) symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{}); - } else { + } + // clang-format off + // Check if it is a RISC-V builtin from the predefined module +#define RISCV_EXTENSION(F) \ + else if (const auto *riscv64##F##BuiltinScope = \ + currScope().context().GetRISCV64##F##BuiltinsScope()) { \ + symbol = FindSymbol(*riscv64##F##BuiltinScope, name); \ + if (!symbol) { \ + symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{}); \ + } \ + } +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION + // clang-format on + else { symbol = &MakeSymbol(context().globalScope(), name.source, Attrs{}); } Resolve(name, *symbol); diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp --- a/flang/lib/Semantics/semantics.cpp +++ b/flang/lib/Semantics/semantics.cpp @@ -37,6 +37,7 @@ #include "resolve-names.h" #include "rewrite-parse-tree.h" #include "flang/Common/default-kinds.h" +#include "flang/Parser/characters.h" #include "flang/Parser/parse-tree-visitor.h" #include "flang/Parser/tools.h" #include "flang/Semantics/expression.h" @@ -499,6 +500,26 @@ } } +std::string GetRISCVIntrinsicName(const char *bit, const char *name) { + std::string lowerName = name; + for (auto &c : lowerName) { + c = parser::ToLowerCaseLetter(c); + } + return lowerName = "__riscv"s + bit + "_" + lowerName + "_intrinsics"; +} + +// clang-format off +#define RISCV_EXTENSION(F) \ +void SemanticsContext::UseRISCV64##F##BuiltinsModule() { \ + if (riscv64##F##BuiltinsScope_ == nullptr) { \ + riscv64##F##BuiltinsScope_ = \ + GetBuiltinModule(GetRISCVIntrinsicName("64", #F).c_str()); \ + } \ +} +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION +// clang-format on + parser::Program &SemanticsContext::SaveParseTree(parser::Program &&tree) { return modFileParseTrees_.emplace_back(std::move(tree)); } @@ -522,7 +543,18 @@ .statement.v.source == "__ppc_intrinsics") { // The derived type definition for the vectors is needed. context_.UsePPCBuiltinTypesModule(); - } else { + } + // clang-format off +#define RISCV_EXTENSION(F) \ + else if (frontModule && \ + std::get>(frontModule->value().t) \ + .statement.v.source == GetRISCVIntrinsicName("64", #F)) { \ + context_.UseRISCV64##F##BuiltinsModule(); \ + } +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION + // clang-format on + else { context_.UseFortranBuiltinsModule(); llvm::Triple targetTriple{llvm::Triple( llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))}; @@ -531,6 +563,16 @@ context_.UsePPCBuiltinTypesModule(); context_.UsePPCBuiltinsModule(); } + if (context_.targetCharacteristics().isRISCV64()) { + // clang-format off +#define RISCV_EXTENSION(F) \ + if (context_.targetCharacteristics().hasFeature(#F)) { \ + context_.UseRISCV64##F##BuiltinsModule(); \ + } +#include "flang/Semantics/riscv-ext-with-intrinsics.def" +#undef RISCV_EXTENSION + // clang-format on + } } } return ValidateLabels(context_, program_) && diff --git a/flang/module/__riscv64_zbb_intrinsics.f90 b/flang/module/__riscv64_zbb_intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/module/__riscv64_zbb_intrinsics.f90 @@ -0,0 +1,31 @@ +!===-- module/__riscv64_zbb_intrinsics.f90 ---------------------------------===! +! +! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +! See https://llvm.org/LICENSE.txt for license information. +! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +! +!===------------------------------------------------------------------------===! + +module __RISCV64_Zbb_intrinsics + + private + + abstract interface + elemental integer(4) function func_i4i4(x) + integer, intent(in) :: x + end function func_i4i4 + elemental integer(8) function func_i8i8(x) + integer(8), intent(in) :: x + end function func_i8i8 + end interface + + ! orc.b + procedure(func_i4i4) :: __riscv_orc_b_i4 + procedure(func_i8i8) :: __riscv_orc_b_i8 + interface orc_b + procedure :: __riscv_orc_b_i4 + procedure :: __riscv_orc_b_i8 + end interface orc_b + public :: orc_b + +end module __RISCV64_Zbb_intrinsics diff --git a/flang/module/__riscv64_zbc_intrinsics.f90 b/flang/module/__riscv64_zbc_intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/module/__riscv64_zbc_intrinsics.f90 @@ -0,0 +1,49 @@ +!===-- module/__riscv64_zbc_intrinsics.f90 ---------------------------------===! +! +! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +! See https://llvm.org/LICENSE.txt for license information. +! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +! +!===------------------------------------------------------------------------===! + +module __RISCV64_Zbc_intrinsics + + private + + abstract interface + elemental integer(4) function func_i4i4i4(x, y) + integer, intent(in) :: x, y + end function func_i4i4i4 + elemental integer(8) function func_i8i8i8(x, y) + integer(8), intent(in) :: x, y + end function func_i8i8i8 + end interface + + ! clmul + procedure(func_i4i4i4) :: __riscv_clmul_i4 + procedure(func_i8i8i8) :: __riscv_clmul_i8 + interface clmul + procedure :: __riscv_clmul_i4 + procedure :: __riscv_clmul_i8 + end interface clmul + public :: clmul + + ! clmulh + procedure(func_i4i4i4) :: __riscv_clmulh_i4 + procedure(func_i8i8i8) :: __riscv_clmulh_i8 + interface clmulh + procedure :: __riscv_clmulh_i4 + procedure :: __riscv_clmulh_i8 + end interface clmulh + public :: clmulh + + ! clmulr + procedure(func_i4i4i4) :: __riscv_clmulr_i4 + procedure(func_i8i8i8) :: __riscv_clmulr_i8 + interface clmulr + procedure :: __riscv_clmulr_i4 + procedure :: __riscv_clmulr_i8 + end interface clmulr + public :: clmulr + +end module __RISCV64_Zbc_intrinsics diff --git a/flang/module/__riscv64_zbkb_intrinsics.f90 b/flang/module/__riscv64_zbkb_intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/module/__riscv64_zbkb_intrinsics.f90 @@ -0,0 +1,31 @@ +!===-- module/__riscv64_zbkb_intrinsics.f90 --------------------------------===! +! +! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +! See https://llvm.org/LICENSE.txt for license information. +! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +! +!===------------------------------------------------------------------------===! + +module __RISCV64_Zbkb_intrinsics + + private + + abstract interface + elemental integer(4) function func_i4i4(x) + integer, intent(in) :: x + end function func_i4i4 + elemental integer(8) function func_i8i8(x) + integer(8), intent(in) :: x + end function func_i8i8 + end interface + + ! brev8 + procedure(func_i4i4) :: __riscv_brev8_i4 + procedure(func_i8i8) :: __riscv_brev8_i8 + interface brev8 + procedure :: __riscv_brev8_i4 + procedure :: __riscv_brev8_i8 + end interface brev8 + public :: brev8 + +end module __RISCV64_Zbkb_intrinsics diff --git a/flang/module/__riscv64_zbkc_intrinsics.f90 b/flang/module/__riscv64_zbkc_intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/module/__riscv64_zbkc_intrinsics.f90 @@ -0,0 +1,40 @@ +!===-- module/__riscv64_zbkc_intrinsics.f90 --------------------------------===! +! +! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +! See https://llvm.org/LICENSE.txt for license information. +! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +! +!===------------------------------------------------------------------------===! + +module __RISCV64_Zbkc_intrinsics + + private + + abstract interface + elemental integer(4) function func_i4i4i4(x, y) + integer, intent(in) :: x, y + end function func_i4i4i4 + elemental integer(8) function func_i8i8i8(x, y) + integer(8), intent(in) :: x, y + end function func_i8i8i8 + end interface + + ! clmul + procedure(func_i4i4i4) :: __riscv_clmul_i4 + procedure(func_i8i8i8) :: __riscv_clmul_i8 + interface clmul + procedure :: __riscv_clmul_i4 + procedure :: __riscv_clmul_i8 + end interface clmul + public :: clmul + + ! clmulh + procedure(func_i4i4i4) :: __riscv_clmulh_i4 + procedure(func_i8i8i8) :: __riscv_clmulh_i8 + interface clmulh + procedure :: __riscv_clmulh_i4 + procedure :: __riscv_clmulh_i8 + end interface clmulh + public :: clmulh + +end module __RISCV64_Zbkc_intrinsics diff --git a/flang/module/__riscv64_zbkx_intrinsics.f90 b/flang/module/__riscv64_zbkx_intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/module/__riscv64_zbkx_intrinsics.f90 @@ -0,0 +1,40 @@ +!===-- module/__riscv64_zbkx_intrinsics.f90 --------------------------------===! +! +! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +! See https://llvm.org/LICENSE.txt for license information. +! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +! +!===------------------------------------------------------------------------===! + +module __RISCV64_Zbkx_intrinsics + + private + + abstract interface + elemental integer(4) function func_i4i4i4(x, y) + integer, intent(in) :: x, y + end function func_i4i4i4 + elemental integer(8) function func_i8i8i8(x, y) + integer(8), intent(in) :: x, y + end function func_i8i8i8 + end interface + + ! xperm4 + procedure(func_i4i4i4) :: __riscv_xperm4_i4 + procedure(func_i8i8i8) :: __riscv_xperm4_i8 + interface xperm4 + procedure :: __riscv_xperm4_i4 + procedure :: __riscv_xperm4_i8 + end interface xperm4 + public :: xperm4 + + ! xperm8 + procedure(func_i4i4i4) :: __riscv_xperm8_i4 + procedure(func_i8i8i8) :: __riscv_xperm8_i8 + interface xperm8 + procedure :: __riscv_xperm8_i4 + procedure :: __riscv_xperm8_i8 + end interface xperm8 + public :: xperm8 + +end module __RISCV64_Zbkx_intrinsics diff --git a/flang/test/Lower/RISCV/riscv64-zbb-intrinsics.f90 b/flang/test/Lower/RISCV/riscv64-zbb-intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/RISCV/riscv64-zbb-intrinsics.f90 @@ -0,0 +1,16 @@ +! RUN: %flang_fc1 -triple riscv64-unknown-linux-gnu -target-feature +zbb \ +! RUN: -emit-llvm %s -o - | FileCheck --check-prefix="CHECK-LLVMIR" %s + +! CHECK-LABEL: orc_b_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.orc.b.i32(i32 %{{[0-9]}}) +subroutine orc_b_i32_test(x) + integer :: x, r + r = orc_b(x) +end + +! CHECK-LABEL: orc_b_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.orc.b.i64(i64 %{{[0-9]}}) +subroutine orc_b_i64_test(x) + integer(8) :: x, r + r = orc_b(x) +end diff --git a/flang/test/Lower/RISCV/riscv64-zbc-intrinsics.f90 b/flang/test/Lower/RISCV/riscv64-zbc-intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/RISCV/riscv64-zbc-intrinsics.f90 @@ -0,0 +1,44 @@ +! RUN: %flang_fc1 -triple riscv64-unknown-linux-gnu -target-feature +zbc \ +! RUN: -emit-llvm %s -o - | FileCheck --check-prefix="CHECK-LLVMIR" %s + +! CHECK-LABEL: clmul_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.clmul.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine clmul_i32_test(x, y) + integer :: x, y, r + r = clmul(x, y) +end + +! CHECK-LABEL: clmul_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.clmul.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine clmul_i64_test(x, y) + integer(8) :: x, y, r + r = clmul(x, y) +end + +! CHECK-LABEL: clmulh_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.clmulh.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine clmulh_i32_test(x, y) + integer :: x, y, r + r = clmulh(x, y) +end + +! CHECK-LABEL: clmulh_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.clmulh.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine clmulh_i64_test(x, y) + integer(8) :: x, y, r + r = clmulh(x, y) +end + +! CHECK-LABEL: clmulr_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.clmulr.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine clmulr_i32_test(x, y) + integer :: x, y, r + r = clmulr(x, y) +end + +! CHECK-LABEL: clmulr_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.clmulr.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine clmulr_i64_test(x, y) + integer(8) :: x, y, r + r = clmulr(x, y) +end diff --git a/flang/test/Lower/RISCV/riscv64-zbkb-intrinsics.f90 b/flang/test/Lower/RISCV/riscv64-zbkb-intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/RISCV/riscv64-zbkb-intrinsics.f90 @@ -0,0 +1,16 @@ +! RUN: %flang_fc1 -triple riscv64-unknown-linux-gnu -target-feature +zbkb \ +! RUN: -emit-llvm %s -o - | FileCheck --check-prefix="CHECK-LLVMIR" %s + +! CHECK-LABEL: brev8_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.brev8.i32(i32 %{{[0-9]}}) +subroutine brev8_i32_test(x) + integer :: x, r + r = brev8(x) +end + +! CHECK-LABEL: brev8_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.brev8.i64(i64 %{{[0-9]}}) +subroutine brev8_i64_test(x) + integer(8) :: x, r + r = brev8(x) +end diff --git a/flang/test/Lower/RISCV/riscv64-zbkc-intrinsics.f90 b/flang/test/Lower/RISCV/riscv64-zbkc-intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/RISCV/riscv64-zbkc-intrinsics.f90 @@ -0,0 +1,30 @@ +! RUN: %flang_fc1 -triple riscv64-unknown-linux-gnu -target-feature +zbkc \ +! RUN: -emit-llvm %s -o - | FileCheck --check-prefix="CHECK-LLVMIR" %s + +! CHECK-LABEL: clmul_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.clmul.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine clmul_i32_test(x, y) + integer :: x, y, r + r = clmul(x, y) +end + +! CHECK-LABEL: clmul_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.clmul.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine clmul_i64_test(x, y) + integer(8) :: x, y, r + r = clmul(x, y) +end + +! CHECK-LABEL: clmulh_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.clmulh.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine clmulh_i32_test(x, y) + integer :: x, y, r + r = clmulh(x, y) +end + +! CHECK-LABEL: clmulh_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.clmulh.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine clmulh_i64_test(x, y) + integer(8) :: x, y, r + r = clmulh(x, y) +end diff --git a/flang/test/Lower/RISCV/riscv64-zbkx-intrinsics.f90 b/flang/test/Lower/RISCV/riscv64-zbkx-intrinsics.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/RISCV/riscv64-zbkx-intrinsics.f90 @@ -0,0 +1,30 @@ +! RUN: %flang_fc1 -triple riscv64-unknown-linux-gnu -target-feature +zbkx \ +! RUN: -emit-llvm %s -o - | FileCheck --check-prefix="CHECK-LLVMIR" %s + +! CHECK-LABEL: xperm4_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.xperm4.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine xperm4_i32_test(x, y) + integer :: x, y, r + r = xperm4(x, y) +end + +! CHECK-LABEL: xperm4_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.xperm4.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine xperm4_i64_test(x, y) + integer(8) :: x, y, r + r = xperm4(x, y) +end + +! CHECK-LABEL: xperm8_i32_test +! CHECK-LLVMIR: call i32 @llvm.riscv.xperm8.i32(i32 %{{[0-9]}}, i32 %{{[0-9]}}) +subroutine xperm8_i32_test(x, y) + integer :: x, y, r + r = xperm8(x, y) +end + +! CHECK-LABEL: xperm8_i64_test +! CHECK-LLVMIR: call i64 @llvm.riscv.xperm8.i64(i64 %{{[0-9]}}, i64 %{{[0-9]}}) +subroutine xperm8_i64_test(x, y) + integer(8) :: x, y, r + r = xperm8(x, y) +end diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -423,6 +423,8 @@ } if (targetTriple.isPPC()) semanticsContext.targetCharacteristics().set_isPPC(true); + if (targetTriple.isRISCV64()) + semanticsContext.targetCharacteristics().set_isRISCV64(true); return mlir::failed(convertFortranSourceToMLIR( inputFilename, options, programPrefix, semanticsContext, passPipe)); diff --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt --- a/flang/tools/f18/CMakeLists.txt +++ b/flang/tools/f18/CMakeLists.txt @@ -10,6 +10,11 @@ "__fortran_type_info" "__ppc_types" "__ppc_intrinsics" + "__riscv64_zbb_intrinsics" + "__riscv64_zbc_intrinsics" + "__riscv64_zbkb_intrinsics" + "__riscv64_zbkc_intrinsics" + "__riscv64_zbkx_intrinsics" "__cuda_builtins" "ieee_arithmetic" "ieee_exceptions" @@ -34,6 +39,16 @@ set(depends "") elseif(${filename} STREQUAL "__ppc_intrinsics") set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__ppc_types.mod) + elseif(${filename} STREQUAL "__riscv64_zbb_intrinsics") + set(depends "") + elseif(${filename} STREQUAL "__riscv64_zbc_intrinsics") + set(depends "") + elseif(${filename} STREQUAL "__riscv64_zbkb_intrinsics") + set(depends "") + elseif(${filename} STREQUAL "__riscv64_zbkc_intrinsics") + set(depends "") + elseif(${filename} STREQUAL "__riscv64_zbkx_intrinsics") + set(depends "") else() set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_builtins.mod) if(NOT ${filename} STREQUAL "__fortran_type_info")