Skip to content

Commit a9e1d2e

Browse files
committed
[flang] Add PowerPC vec_add, vec_and, vec_mul, vec_sub and vec_xor intrinsics
Differential Revision: https://reviews.llvm.org/D151857
1 parent 651e5ae commit a9e1d2e

File tree

20 files changed

+1449
-6
lines changed

20 files changed

+1449
-6
lines changed

flang/include/flang/Evaluate/target.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,15 @@ class TargetCharacteristics {
9191
return *this;
9292
}
9393

94+
bool isPPC() const { return isPPC_; }
95+
void set_isPPC(bool isPPC = false);
96+
9497
private:
9598
static constexpr int maxKind{32};
9699
std::uint8_t byteSize_[common::TypeCategory_enumSize][maxKind]{};
97100
std::uint8_t align_[common::TypeCategory_enumSize][maxKind]{};
98101
bool isBigEndian_{false};
102+
bool isPPC_{false};
99103
bool areSubnormalsFlushedToZero_{false};
100104
Rounding roundingMode_{defaultRounding};
101105
std::size_t procedurePointerByteSize_{8};

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ enum class LowerIntrinsicArgAs {
8888
Inquired
8989
};
9090

91+
/// Enums used to templatize vector intrinsic function generators. Enum does
92+
/// not contain every vector intrinsic, only intrinsics that share generators.
93+
enum class VecOp { Add, And, Mul, Sub, Xor };
94+
9195
/// Define how a given intrinsic argument must be lowered.
9296
struct ArgLoweringRule {
9397
LowerIntrinsicArgAs lowerAs;
@@ -335,6 +339,11 @@ struct IntrinsicLibrary {
335339
mlir::Type resultType,
336340
llvm::ArrayRef<fir::ExtendedValue> args);
337341

342+
template <VecOp>
343+
fir::ExtendedValue
344+
genVecAddAndMulSubXor(mlir::Type resultType,
345+
llvm::ArrayRef<fir::ExtendedValue> args);
346+
338347
/// Define the different FIR generators that can be mapped to intrinsic to
339348
/// generate the related code.
340349
using ElementalGenerator = decltype(&IntrinsicLibrary::genAbs);

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,6 +2610,7 @@ def fir_ConvertOp : fir_OneResultOp<"convert", [NoMemoryEffect]> {
26102610
static bool isFloatCompatible(mlir::Type ty);
26112611
static bool isPointerCompatible(mlir::Type ty);
26122612
static bool canBeConverted(mlir::Type inType, mlir::Type outType);
2613+
static bool areVectorsCompatible(mlir::Type inTy, mlir::Type outTy);
26132614
}];
26142615
let hasCanonicalizer = 1;
26152616
}

flang/lib/Evaluate/target.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ void TargetCharacteristics::set_isBigEndian(bool isBig) {
102102
isBigEndian_ = isBig;
103103
}
104104

105+
void TargetCharacteristics::set_isPPC(bool isPowerPC) { isPPC_ = isPowerPC; }
106+
105107
void TargetCharacteristics::set_areSubnormalsFlushedToZero(bool yes) {
106108
areSubnormalsFlushedToZero_ = yes;
107109
}

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,9 @@ void CompilerInvocation::setSemanticsOpts(
11071107
semanticsContext->targetCharacteristics()
11081108
.set_compilerOptionsString(allCompilerInvocOpts)
11091109
.set_compilerVersionString(version);
1110+
1111+
if (targetTriple.isPPC())
1112+
semanticsContext->targetCharacteristics().set_isPPC(true);
11101113
}
11111114

11121115
/// Set \p loweringOptions controlling lowering behavior based

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "mlir/Dialect/Complex/IR/Complex.h"
4242
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
4343
#include "mlir/Dialect/Math/IR/Math.h"
44+
#include "mlir/Dialect/Vector/IR/VectorOps.h"
4445
#include "llvm/Support/CommandLine.h"
4546
#include "llvm/Support/Debug.h"
4647
#include "llvm/Support/MathExtras.h"
@@ -88,6 +89,84 @@ static bool isStaticallyPresent(const fir::ExtendedValue &exv) {
8889
return !isStaticallyAbsent(exv);
8990
}
9091

92+
//===----------------------------------------------------------------------===//
93+
// Helper functions for argument handling in vector intrinsics.
94+
//===----------------------------------------------------------------------===//
95+
static mlir::Type getConvertedElementType(mlir::MLIRContext *context,
96+
mlir::Type eleTy) {
97+
if (eleTy.isa<mlir::IntegerType>() && !eleTy.isSignlessInteger()) {
98+
const auto intTy{eleTy.dyn_cast<mlir::IntegerType>()};
99+
auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
100+
return newEleTy;
101+
}
102+
return eleTy;
103+
}
104+
105+
// Wrapper struct to encapsulate information for a vector type. Preserves
106+
// sign of eleTy if eleTy is signed/unsigned integer. Helps with vector type
107+
// conversions.
108+
struct VecTypeInfo {
109+
mlir::Type eleTy;
110+
uint64_t len;
111+
112+
mlir::Type toFirVectorType() { return fir::VectorType::get(len, eleTy); }
113+
114+
// We need a builder to do the signless element conversion.
115+
mlir::Type toMlirVectorType(mlir::MLIRContext *context) {
116+
// Will convert to eleTy to signless int if eleTy is signed/unsigned int.
117+
auto convEleTy{getConvertedElementType(context, eleTy)};
118+
return mlir::VectorType::get(len, convEleTy);
119+
}
120+
121+
bool isFloat32() { return mlir::isa<mlir::Float32Type>(eleTy); }
122+
123+
bool isFloat64() { return mlir::isa<mlir::Float64Type>(eleTy); }
124+
125+
bool isFloat() { return isFloat32() || isFloat64(); }
126+
};
127+
128+
static llvm::SmallVector<mlir::Value>
129+
getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
130+
llvm::SmallVector<mlir::Value, 4> baseVec;
131+
for (auto arg : args)
132+
baseVec.push_back(getBase(arg));
133+
return baseVec;
134+
}
135+
136+
static llvm::SmallVector<mlir::Type>
137+
getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
138+
llvm::SmallVector<mlir::Type, 4> typeVec;
139+
for (auto arg : args)
140+
typeVec.push_back(arg.getType());
141+
return typeVec;
142+
}
143+
144+
// Returns a VecTypeInfo with element type and length of given fir vector type.
145+
// Preserves signness of fir vector type if element type of integer.
146+
static VecTypeInfo getVecTypeFromFirType(mlir::Type firTy) {
147+
assert(firTy.isa<fir::VectorType>());
148+
VecTypeInfo vecTyInfo;
149+
vecTyInfo.eleTy = firTy.dyn_cast<fir::VectorType>().getEleTy();
150+
vecTyInfo.len = firTy.dyn_cast<fir::VectorType>().getLen();
151+
return vecTyInfo;
152+
}
153+
154+
static VecTypeInfo getVecTypeFromFir(mlir::Value firVec) {
155+
return getVecTypeFromFirType(firVec.getType());
156+
}
157+
158+
// Converts array of fir vectors to mlir vectors.
159+
static llvm::SmallVector<mlir::Value>
160+
convertVecArgs(fir::FirOpBuilder &builder, mlir::Location loc,
161+
VecTypeInfo vecTyInfo, llvm::SmallVector<mlir::Value> args) {
162+
llvm::SmallVector<mlir::Value, 4> newArgs;
163+
auto ty{vecTyInfo.toMlirVectorType(builder.getContext())};
164+
assert(ty && "unknown mlir vector type");
165+
for (size_t i = 0; i < args.size(); i++)
166+
newArgs.push_back(builder.createConvert(loc, ty, args[i]));
167+
return newArgs;
168+
}
169+
91170
constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
92171
constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
93172
constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
@@ -531,6 +610,26 @@ static constexpr IntrinsicHandler ppcHandlers[]{
531610
&I::genMtfsf<true>,
532611
{{{"bf", asValue}, {"i", asValue}}},
533612
/*isElemental=*/false},
613+
{"__ppc_vec_add",
614+
&I::genVecAddAndMulSubXor<VecOp::Add>,
615+
{{{"arg1", asValue}, {"arg2", asValue}}},
616+
/*isElemental=*/true},
617+
{"__ppc_vec_and",
618+
&I::genVecAddAndMulSubXor<VecOp::And>,
619+
{{{"arg1", asValue}, {"arg2", asValue}}},
620+
/*isElemental=*/true},
621+
{"__ppc_vec_mul",
622+
&I::genVecAddAndMulSubXor<VecOp::Mul>,
623+
{{{"arg1", asValue}, {"arg2", asValue}}},
624+
/*isElemental=*/true},
625+
{"__ppc_vec_sub",
626+
&I::genVecAddAndMulSubXor<VecOp::Sub>,
627+
{{{"arg1", asValue}, {"arg2", asValue}}},
628+
/*isElemental=*/true},
629+
{"__ppc_vec_xor",
630+
&I::genVecAddAndMulSubXor<VecOp::Xor>,
631+
{{{"arg1", asValue}, {"arg2", asValue}}},
632+
/*isElemental=*/true},
534633
};
535634

536635
static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
@@ -4505,6 +4604,73 @@ mlir::Value IntrinsicLibrary::genTrailz(mlir::Type resultType,
45054604
return builder.createConvert(loc, resultType, result);
45064605
}
45074606

4607+
// VEC_ADD, VEC_AND, VEC_SUB, VEC_MUL, VEC_XOR
4608+
template <VecOp vop>
4609+
fir::ExtendedValue IntrinsicLibrary::genVecAddAndMulSubXor(
4610+
mlir::Type resultType, llvm::ArrayRef<fir::ExtendedValue> args) {
4611+
assert(args.size() == 2);
4612+
auto argBases{getBasesForArgs(args)};
4613+
auto argsTy{getTypesForArgs(argBases)};
4614+
assert(argsTy[0].isa<fir::VectorType>() && argsTy[1].isa<fir::VectorType>());
4615+
4616+
auto vecTyInfo{getVecTypeFromFir(argBases[0])};
4617+
4618+
const auto isInteger{vecTyInfo.eleTy.isa<mlir::IntegerType>()};
4619+
const auto isFloat{vecTyInfo.eleTy.isa<mlir::FloatType>()};
4620+
assert((isInteger || isFloat) && "unknown vector type");
4621+
4622+
auto vargs{convertVecArgs(builder, loc, vecTyInfo, argBases)};
4623+
4624+
mlir::Value r{nullptr};
4625+
switch (vop) {
4626+
case VecOp::Add:
4627+
if (isInteger)
4628+
r = builder.create<mlir::arith::AddIOp>(loc, vargs[0], vargs[1]);
4629+
else if (isFloat)
4630+
r = builder.create<mlir::arith::AddFOp>(loc, vargs[0], vargs[1]);
4631+
break;
4632+
case VecOp::Mul:
4633+
if (isInteger)
4634+
r = builder.create<mlir::arith::MulIOp>(loc, vargs[0], vargs[1]);
4635+
else if (isFloat)
4636+
r = builder.create<mlir::arith::MulFOp>(loc, vargs[0], vargs[1]);
4637+
break;
4638+
case VecOp::Sub:
4639+
if (isInteger)
4640+
r = builder.create<mlir::arith::SubIOp>(loc, vargs[0], vargs[1]);
4641+
else if (isFloat)
4642+
r = builder.create<mlir::arith::SubFOp>(loc, vargs[0], vargs[1]);
4643+
break;
4644+
case VecOp::And:
4645+
case VecOp::Xor: {
4646+
mlir::Value arg1{nullptr};
4647+
mlir::Value arg2{nullptr};
4648+
if (isInteger) {
4649+
arg1 = vargs[0];
4650+
arg2 = vargs[1];
4651+
} else if (isFloat) {
4652+
// bitcast the arguments to integer
4653+
auto wd{vecTyInfo.eleTy.dyn_cast<mlir::FloatType>().getWidth()};
4654+
auto ftype{builder.getIntegerType(wd)};
4655+
auto bcVecTy{mlir::VectorType::get(vecTyInfo.len, ftype)};
4656+
arg1 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[0]);
4657+
arg2 = builder.create<mlir::vector::BitCastOp>(loc, bcVecTy, vargs[1]);
4658+
}
4659+
if (vop == VecOp::And)
4660+
r = builder.create<mlir::arith::AndIOp>(loc, arg1, arg2);
4661+
else if (vop == VecOp::Xor)
4662+
r = builder.create<mlir::arith::XOrIOp>(loc, arg1, arg2);
4663+
4664+
if (isFloat)
4665+
r = builder.create<mlir::vector::BitCastOp>(loc, vargs[0].getType(), r);
4666+
4667+
break;
4668+
}
4669+
}
4670+
4671+
return builder.createConvert(loc, argsTy[0], r);
4672+
}
4673+
45084674
static bool hasDefaultLowerBound(const fir::ExtendedValue &exv) {
45094675
return exv.match(
45104676
[](const fir::ArrayBoxValue &arr) { return arr.getLBounds().empty(); },

flang/lib/Optimizer/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_flang_library(FIRCodeGen
2727
MLIRBuiltinToLLVMIRTranslation
2828
MLIRLLVMToLLVMIRTranslation
2929
MLIRTargetLLVMIRExport
30+
MLIRVectorToLLVM
3031

3132
LINK_COMPONENTS
3233
AsmParser

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "mlir/Conversion/MathToLibm/MathToLibm.h"
3434
#include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
3535
#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
36+
#include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
3637
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
3738
#include "mlir/Dialect/OpenACC/OpenACC.h"
3839
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
@@ -3697,6 +3698,7 @@ class FIRToLLVMLowering
36973698
// to Libm.
36983699
mlir::populateMathToLibmConversionPatterns(pattern);
36993700
mlir::populateComplexToLLVMConversionPatterns(typeConverter, pattern);
3701+
mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
37003702
mlir::ConversionTarget target{*context};
37013703
target.addLegalDialect<mlir::LLVM::LLVMDialect>();
37023704
// The OpenMP dialect is legal for Operations without regions, for those

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,59 @@ bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) {
943943
fir::TypeDescType>();
944944
}
945945

946+
static std::optional<mlir::Type> getVectorElementType(mlir::Type ty) {
947+
if (mlir::isa<fir::VectorType>(ty)) {
948+
auto elemTy = mlir::dyn_cast<fir::VectorType>(ty).getEleTy();
949+
950+
// fir.vector<4:ui32> is converted to mlir.vector<4xi32>
951+
if (elemTy.isUnsignedInteger()) {
952+
elemTy = mlir::IntegerType::get(
953+
ty.getContext(),
954+
mlir::dyn_cast<mlir::IntegerType>(elemTy).getWidth());
955+
}
956+
return elemTy;
957+
} else if (mlir::isa<mlir::VectorType>(ty))
958+
return mlir::dyn_cast<mlir::VectorType>(ty).getElementType();
959+
960+
return std::nullopt;
961+
}
962+
963+
static std::optional<uint64_t> getVectorLen(mlir::Type ty) {
964+
if (mlir::isa<fir::VectorType>(ty))
965+
return mlir::dyn_cast<fir::VectorType>(ty).getLen();
966+
else if (mlir::isa<mlir::VectorType>(ty)) {
967+
// fir.vector only supports 1-D vector
968+
if (mlir::dyn_cast<mlir::VectorType>(ty).getNumScalableDims() == 0)
969+
return mlir::dyn_cast<mlir::VectorType>(ty).getShape()[0];
970+
}
971+
972+
return std::nullopt;
973+
}
974+
975+
bool fir::ConvertOp::areVectorsCompatible(mlir::Type inTy, mlir::Type outTy) {
976+
if (!(mlir::isa<fir::VectorType>(inTy) &&
977+
mlir::isa<mlir::VectorType>(outTy)) &&
978+
!(mlir::isa<mlir::VectorType>(inTy) && mlir::isa<fir::VectorType>(outTy)))
979+
return false;
980+
981+
// Only support integer, unsigned and real vector
982+
// Both vectors must have the same element type
983+
std::optional<mlir::Type> inElemTy = getVectorElementType(inTy);
984+
std::optional<mlir::Type> outElemTy = getVectorElementType(outTy);
985+
if (!inElemTy.has_value() || !outElemTy.has_value() ||
986+
inElemTy.value() != outElemTy.value())
987+
return false;
988+
989+
// Both vectors must have the same number of elements
990+
std::optional<uint64_t> inLen = getVectorLen(inTy);
991+
std::optional<uint64_t> outLen = getVectorLen(outTy);
992+
if (!inLen.has_value() || !outLen.has_value() ||
993+
inLen.value() != outLen.value())
994+
return false;
995+
996+
return true;
997+
}
998+
946999
bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
9471000
if (inType == outType)
9481001
return true;
@@ -958,7 +1011,8 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
9581011
(fir::isa_complex(inType) && fir::isa_complex(outType)) ||
9591012
(fir::isBoxedRecordType(inType) && fir::isPolymorphicType(outType)) ||
9601013
(fir::isPolymorphicType(inType) && fir::isPolymorphicType(outType)) ||
961-
(fir::isPolymorphicType(inType) && outType.isa<BoxType>());
1014+
(fir::isPolymorphicType(inType) && outType.isa<BoxType>()) ||
1015+
areVectorsCompatible(inType, outType);
9621016
}
9631017

9641018
mlir::LogicalResult fir::ConvertOp::verify() {

flang/lib/Semantics/resolve-names.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4849,6 +4849,13 @@ int DeclarationVisitor::GetVectorElementKind(
48494849
}
48504850

48514851
bool DeclarationVisitor::Pre(const parser::VectorTypeSpec &) {
4852+
// PowerPC vector types are allowed only on Power architectures.
4853+
if (!currScope().context().targetCharacteristics().isPPC()) {
4854+
Say(currStmtSource().value(),
4855+
"Vector type is only supported for PowerPC"_err_en_US);
4856+
isVectorType_ = false;
4857+
return false;
4858+
}
48524859
isVectorType_ = true;
48534860
return true;
48544861
}

flang/lib/Semantics/semantics.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,19 +513,21 @@ bool Semantics::Perform() {
513513
if (frontModule &&
514514
(std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
515515
.statement.v.source == "__fortran_builtins" ||
516-
std::get<parser::Statement<parser::ModuleStmt>>(
517-
frontModule->value().t)
518-
.statement.v.source == "__fortran_ppc_intrinsics" ||
519516
std::get<parser::Statement<parser::ModuleStmt>>(
520517
frontModule->value().t)
521518
.statement.v.source == "__fortran_ppc_types")) {
522519
// Don't try to read the builtins module when we're actually building it.
520+
} else if (frontModule &&
521+
std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
522+
.statement.v.source == "__fortran_ppc_intrinsics") {
523+
// The derived type definition for the vectors is needed.
524+
context_.UsePPCFortranBuiltinTypesModule();
523525
} else {
524526
context_.UseFortranBuiltinsModule();
525527
llvm::Triple targetTriple{llvm::Triple(
526528
llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()))};
527529
// Only use __Fortran_PPC_intrinsics module when targetting PowerPC arch
528-
if (targetTriple.isPPC()) {
530+
if (context_.targetCharacteristics().isPPC()) {
529531
context_.UsePPCFortranBuiltinTypesModule();
530532
context_.UsePPCFortranBuiltinsModule();
531533
}

0 commit comments

Comments
 (0)