@@ -334,6 +334,10 @@ struct IntrinsicLibrary {
334
334
// / is ignored because this is already reflected in the result type.
335
335
mlir::Value genConversion (mlir::Type, llvm::ArrayRef<mlir::Value>);
336
336
337
+ // PPC intrinsic handlers.
338
+ template <bool isImm>
339
+ void genMtfsf (llvm::ArrayRef<fir::ExtendedValue>);
340
+
337
341
// / In the template helper below:
338
342
// / - "FN func" is a callback to generate the related intrinsic runtime call.
339
343
// / - "FD funcDim" is a callback to generate the "dim" runtime call.
@@ -880,6 +884,18 @@ static constexpr IntrinsicHandler handlers[]{
880
884
/* isElemental=*/ true },
881
885
};
882
886
887
+ // PPC specific intrinsic handlers.
888
+ static constexpr IntrinsicHandler ppcHandlers[]{
889
+ {" __ppc_mtfsf" ,
890
+ &I::genMtfsf<false >,
891
+ {{{" mask" , asValue}, {" r" , asValue}}},
892
+ /* isElemental=*/ false },
893
+ {" __ppc_mtfsfi" ,
894
+ &I::genMtfsf<true >,
895
+ {{{" bf" , asValue}, {" i" , asValue}}},
896
+ /* isElemental=*/ false },
897
+ };
898
+
883
899
static const IntrinsicHandler *findIntrinsicHandler (llvm::StringRef name) {
884
900
auto compare = [](const IntrinsicHandler &handler, llvm::StringRef name) {
885
901
return name.compare (handler.name ) > 0 ;
@@ -889,6 +905,15 @@ static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
889
905
: nullptr ;
890
906
}
891
907
908
+ static const IntrinsicHandler *findPPCIntrinsicHandler (llvm::StringRef name) {
909
+ auto compare = [](const IntrinsicHandler &ppcHandler, llvm::StringRef name) {
910
+ return name.compare (ppcHandler.name ) > 0 ;
911
+ };
912
+ auto result = llvm::lower_bound (ppcHandlers, name, compare);
913
+ return result != std::end (ppcHandlers) && result->name == name ? result
914
+ : nullptr ;
915
+ }
916
+
892
917
// / To make fir output more readable for debug, one can outline all intrinsic
893
918
// / implementation in wrappers (overrides the IntrinsicHandler::outline flag).
894
919
static llvm::cl::opt<bool > outlineAllIntrinsics (
@@ -980,6 +1005,20 @@ static mlir::FunctionType genF64F64F64F64FuncType(mlir::MLIRContext *context) {
980
1005
return mlir::FunctionType::get (context, {t, t, t}, {t});
981
1006
}
982
1007
1008
+ template <int Bits>
1009
+ static mlir::FunctionType genVoidIntF64FuncType (mlir::MLIRContext *context) {
1010
+ auto t = mlir::IntegerType::get (context, Bits);
1011
+ auto u = mlir::FloatType::getF64 (context);
1012
+ return mlir::FunctionType::get (context, {t, u}, std::nullopt);
1013
+ }
1014
+
1015
+ template <int BitsA, int BitsB>
1016
+ static mlir::FunctionType genVoidIntIntFuncType (mlir::MLIRContext *context) {
1017
+ auto t = mlir::IntegerType::get (context, BitsA);
1018
+ auto u = mlir::IntegerType::get (context, BitsB);
1019
+ return mlir::FunctionType::get (context, {t, u}, std::nullopt);
1020
+ }
1021
+
983
1022
template <int Bits>
984
1023
static mlir::FunctionType genIntF64FuncType (mlir::MLIRContext *context) {
985
1024
auto t = mlir::FloatType::getF64 (context);
@@ -1865,15 +1904,30 @@ IntrinsicLibrary::genIntrinsicCall(llvm::StringRef specificName,
1865
1904
this ->resultMustBeFreed };
1866
1905
}
1867
1906
1868
- if (!resultType)
1869
- // Subroutine should have a handler, they are likely missing for now.
1870
- crashOnMissingIntrinsic (loc, name);
1907
+ // If targeting PowerPC, check PPC intrinsic handlers.
1908
+ auto mod = builder.getModule ();
1909
+ if (fir::getTargetTriple (mod).isPPC ()) {
1910
+ if (const IntrinsicHandler *ppcHandler = findPPCIntrinsicHandler (name)) {
1911
+ bool outline = ppcHandler->outline || outlineAllIntrinsics;
1912
+ return {std::visit (
1913
+ [&](auto &generator) -> fir::ExtendedValue {
1914
+ return invokeHandler (generator, *ppcHandler, resultType,
1915
+ args, outline , *this );
1916
+ },
1917
+ ppcHandler->generator ),
1918
+ this ->resultMustBeFreed };
1919
+ }
1920
+ }
1871
1921
1872
1922
// Try the runtime if no special handler was defined for the
1873
1923
// intrinsic being called. Maths runtime only has numerical elemental.
1874
1924
// No optional arguments are expected at this point, the code will
1875
1925
// crash if it gets absent optional.
1876
1926
1927
+ if (!resultType)
1928
+ // Subroutine should have a handler, they are likely missing for now.
1929
+ crashOnMissingIntrinsic (loc, name);
1930
+
1877
1931
// FIXME: using toValue to get the type won't work with array arguments.
1878
1932
llvm::SmallVector<mlir::Value> mlirArgs;
1879
1933
for (const fir::ExtendedValue &extendedVal : args) {
@@ -1971,12 +2025,20 @@ static std::string typeToString(mlir::Type t) {
1971
2025
// / arguments. The mangling pattern is:
1972
2026
// / fir.<generic name>.<result type>.<arg type>...
1973
2027
// / e.g ACOS(COMPLEX(4)) is mangled as fir.acos.z4.z4
2028
+ // / For subroutines no result type is return but in order to still provide
2029
+ // / a unique mangled name, we use "void" as the return type. As in:
2030
+ // / fir.<generic name>.void.<arg type>...
2031
+ // / e.g. FREE(INTEGER(4)) is mangled as fir.free.void.i4
1974
2032
static std::string mangleIntrinsicProcedure (llvm::StringRef intrinsic,
1975
2033
mlir::FunctionType funTy) {
1976
2034
std::string name = " fir." ;
1977
2035
name.append (intrinsic.str ()).append (" ." );
1978
- assert (funTy.getNumResults () == 1 && " only function mangling supported" );
1979
- name.append (typeToString (funTy.getResult (0 )));
2036
+ if (funTy.getNumResults () == 1 )
2037
+ name.append (typeToString (funTy.getResult (0 )));
2038
+ else if (funTy.getNumResults () == 0 )
2039
+ name.append (" void" );
2040
+ else
2041
+ llvm_unreachable (" more than one result value for function" );
1980
2042
unsigned e = funTy.getNumInputs ();
1981
2043
for (decltype (e) i = 0 ; i < e; ++i)
1982
2044
name.append (" ." ).append (typeToString (funTy.getInput (i)));
@@ -5520,6 +5582,31 @@ mlir::Value IntrinsicLibrary::genExtremum(mlir::Type,
5520
5582
return result;
5521
5583
}
5522
5584
5585
+ // ===----------------------------------------------------------------------===//
5586
+ // PowerPC specific intrinsic handlers.
5587
+ // ===----------------------------------------------------------------------===//
5588
+ template <bool isImm>
5589
+ void IntrinsicLibrary::genMtfsf (llvm::ArrayRef<fir::ExtendedValue> args) {
5590
+ assert (args.size () == 2 );
5591
+ llvm::SmallVector<mlir::Value> scalarArgs;
5592
+ for (const fir::ExtendedValue &arg : args)
5593
+ if (arg.getUnboxed ())
5594
+ scalarArgs.emplace_back (fir::getBase (arg));
5595
+ else
5596
+ mlir::emitError (loc, " nonscalar intrinsic argument" );
5597
+
5598
+ mlir::FunctionType libFuncType;
5599
+ mlir::func::FuncOp funcOp;
5600
+ if (isImm) {
5601
+ libFuncType = genVoidIntIntFuncType<32 , 32 >(builder.getContext ());
5602
+ funcOp = builder.addNamedFunction (loc, " llvm.ppc.mtfsfi" , libFuncType);
5603
+ } else {
5604
+ libFuncType = genVoidIntF64FuncType<32 >(builder.getContext ());
5605
+ funcOp = builder.addNamedFunction (loc, " llvm.ppc.mtfsf" , libFuncType);
5606
+ }
5607
+ builder.create <fir::CallOp>(loc, funcOp, scalarArgs);
5608
+ }
5609
+
5523
5610
// ===----------------------------------------------------------------------===//
5524
5611
// Argument lowering rules interface for intrinsic or intrinsic module
5525
5612
// procedure.
0 commit comments