Skip to content

Commit 6180964

Browse files
[flang]Pass to add vscale range attribute (#68103)
Add vscale range attirbute for the Scalable Vector Extension (SVE) if provided on the command-line (options in a previous commit) If no command-line option is provided, if the target-feature of SVE is specified and the architecture is AArch64, it defualts to 128-2048. in other words a vscale-min of 1, vscale-max of 16. A pass is used to add the atribute to all functions. The vectorizer will use this attribute to generate the SVE instruction to match the range specified. The attribute is harmless if there is no vectorizable operations in the function.
1 parent 5979e1d commit 6180964

File tree

8 files changed

+166
-0
lines changed

8 files changed

+166
-0
lines changed

flang/include/flang/Optimizer/Transforms/Passes.h

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ std::unique_ptr<mlir::Pass> createOMPFunctionFilteringPass();
8080
std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>>
8181
createOMPMarkDeclareTargetPass();
8282

83+
std::unique_ptr<mlir::Pass> createVScaleAttrPass();
84+
std::unique_ptr<mlir::Pass>
85+
createVScaleAttrPass(std::pair<unsigned, unsigned> vscaleAttr);
86+
8387
// declarative passes
8488
#define GEN_PASS_REGISTRATION
8589
#include "flang/Optimizer/Transforms/Passes.h.inc"

flang/include/flang/Optimizer/Transforms/Passes.td

+14
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,18 @@ def OMPFunctionFiltering : Pass<"omp-function-filtering"> {
326326
];
327327
}
328328

329+
def VScaleAttr : Pass<"vscale-attr", "mlir::func::FuncOp"> {
330+
let summary = "Add vscale_range attribute to functions";
331+
let description = [{
332+
Set an attribute for the vscale range on functions, to allow scalable
333+
vector operations to be used on processors with variable vector length.
334+
}];
335+
let options = [
336+
Option<"vscaleRange", "vscale-range",
337+
"std::pair<unsigned, unsigned>", /*default=*/"std::pair<unsigned, unsigned>{}",
338+
"vector scale range">,
339+
];
340+
let constructor = "::fir::createVScaleAttrPass()";
341+
}
342+
329343
#endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES

flang/include/flang/Tools/CLOptions.inc

+4
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ inline void createDefaultFIRCodeGenPassPipeline(
299299
fir::addTargetRewritePass(pm);
300300
fir::addExternalNameConversionPass(pm, config.Underscoring);
301301
fir::createDebugPasses(pm, config.DebugInfo);
302+
303+
if (config.VScaleMin != 0)
304+
pm.addPass(fir::createVScaleAttrPass({config.VScaleMin, config.VScaleMax}));
305+
302306
fir::addFIRToLLVMPass(pm, config.OptLevel);
303307
}
304308

flang/include/flang/Tools/CrossToolHelpers.h

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ struct MLIRToLLVMPassPipelineConfig {
4242
bool LoopVersioning = false; ///< Run the version loop pass.
4343
llvm::codegenoptions::DebugInfoKind DebugInfo =
4444
llvm::codegenoptions::NoDebugInfo; ///< Debug info generation.
45+
unsigned VScaleMin = 0; ///< SVE vector range minimum.
46+
unsigned VScaleMax = 0; ///< SVE vector range maximum.
4547
};
4648

4749
struct OffloadModuleOpts {

flang/lib/Frontend/FrontendActions.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,22 @@ void CodeGenAction::lowerHLFIRToFIR() {
695695
}
696696
}
697697

698+
// TODO: We should get this from TargetInfo. However, that depends on
699+
// too much of clang, so for now, replicate the functionality.
700+
static std::optional<std::pair<unsigned, unsigned>>
701+
getVScaleRange(CompilerInstance &ci,
702+
const Fortran::frontend::LangOptions &langOpts) {
703+
if (langOpts.VScaleMin || langOpts.VScaleMax)
704+
return std::pair<unsigned, unsigned>(
705+
langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax);
706+
707+
std::string featuresStr = getTargetFeatures(ci);
708+
if (featuresStr.find("+sve") != std::string::npos)
709+
return std::pair<unsigned, unsigned>(1, 16);
710+
711+
return std::nullopt;
712+
}
713+
698714
// Lower the previously generated MLIR module into an LLVM IR module
699715
void CodeGenAction::generateLLVMIR() {
700716
assert(mlirModule && "The MLIR module has not been generated yet.");
@@ -715,6 +731,18 @@ void CodeGenAction::generateLLVMIR() {
715731

716732
MLIRToLLVMPassPipelineConfig config(level, opts);
717733

734+
const auto targetOpts = ci.getInvocation().getTargetOpts();
735+
const llvm::Triple triple(targetOpts.triple);
736+
737+
// Only get the vscale range if AArch64.
738+
if (triple.isAArch64()) {
739+
auto langOpts = ci.getInvocation().getLangOpts();
740+
if (auto vsr = getVScaleRange(ci, langOpts)) {
741+
config.VScaleMin = vsr->first;
742+
config.VScaleMax = vsr->second;
743+
}
744+
}
745+
718746
// Create the pass pipeline
719747
fir::createMLIRToLLVMPassPipeline(pm, config);
720748
(void)mlir::applyPassManagerCLOptions(pm);

flang/lib/Optimizer/Transforms/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_flang_library(FIRTransforms
1919
OMPEarlyOutlining.cpp
2020
OMPFunctionFiltering.cpp
2121
OMPMarkDeclareTarget.cpp
22+
VScaleAttr.cpp
2223

2324
DEPENDS
2425
FIRDialect
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===- VScaleAttr.cpp -------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
//===----------------------------------------------------------------------===//
10+
/// \file
11+
/// This pass adds a `vscale_range` attribute to function definitions.
12+
/// The attribute is used for scalable vector operations on Arm processors
13+
/// and should only be run on processors that support this feature. [It is
14+
/// likely harmless to run it on something else, but it is also not valuable].
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "flang/ISO_Fortran_binding_wrapper.h"
18+
#include "flang/Optimizer/Builder/BoxValue.h"
19+
#include "flang/Optimizer/Builder/FIRBuilder.h"
20+
#include "flang/Optimizer/Builder/Runtime/Inquiry.h"
21+
#include "flang/Optimizer/Dialect/FIRDialect.h"
22+
#include "flang/Optimizer/Dialect/FIROps.h"
23+
#include "flang/Optimizer/Dialect/FIRType.h"
24+
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
25+
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
26+
#include "flang/Optimizer/Transforms/Passes.h"
27+
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
28+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
29+
#include "mlir/IR/Matchers.h"
30+
#include "mlir/IR/TypeUtilities.h"
31+
#include "mlir/Pass/Pass.h"
32+
#include "mlir/Transforms/DialectConversion.h"
33+
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
34+
#include "mlir/Transforms/RegionUtils.h"
35+
#include "llvm/Support/Debug.h"
36+
#include "llvm/Support/raw_ostream.h"
37+
38+
#include <algorithm>
39+
40+
namespace fir {
41+
#define GEN_PASS_DECL_VSCALEATTR
42+
#define GEN_PASS_DEF_VSCALEATTR
43+
#include "flang/Optimizer/Transforms/Passes.h.inc"
44+
} // namespace fir
45+
46+
#define DEBUG_TYPE "vscale-attr"
47+
48+
namespace {
49+
50+
class VScaleAttrPass : public fir::impl::VScaleAttrBase<VScaleAttrPass> {
51+
public:
52+
VScaleAttrPass(const fir::VScaleAttrOptions &options) {
53+
vscaleRange = options.vscaleRange;
54+
}
55+
VScaleAttrPass() {}
56+
void runOnOperation() override;
57+
};
58+
59+
} // namespace
60+
61+
void VScaleAttrPass::runOnOperation() {
62+
LLVM_DEBUG(llvm::dbgs() << "=== Begin " DEBUG_TYPE " ===\n");
63+
mlir::func::FuncOp func = getOperation();
64+
65+
LLVM_DEBUG(llvm::dbgs() << "Func-name:" << func.getSymName() << "\n");
66+
67+
auto context = &getContext();
68+
69+
auto intTy = mlir::IntegerType::get(context, 32);
70+
71+
assert(vscaleRange.first && "VScaleRange minimum should be non-zero");
72+
73+
func->setAttr("vscale_range",
74+
mlir::LLVM::VScaleRangeAttr::get(
75+
context, mlir::IntegerAttr::get(intTy, vscaleRange.first),
76+
mlir::IntegerAttr::get(intTy, vscaleRange.second)));
77+
78+
LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n");
79+
}
80+
81+
std::unique_ptr<mlir::Pass>
82+
fir::createVScaleAttrPass(std::pair<unsigned, unsigned> vscaleAttr) {
83+
VScaleAttrOptions opts;
84+
opts.vscaleRange = vscaleAttr;
85+
return std::make_unique<VScaleAttrPass>(opts);
86+
}
87+
88+
std::unique_ptr<mlir::Pass> fir::createVScaleAttrPass() {
89+
return std::make_unique<VScaleAttrPass>();
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1
2+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2
3+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -mvscale-max=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4
4+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -mvscale-max=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8
5+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -mvscale-max=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16
6+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1
7+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=2 -mvscale-max=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2
8+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -emit-llvm -o - %s | FileCheck %s -D#VBITS=1 --check-prefix=CHECK-NOMAX
9+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=2 -emit-llvm -o - %s | FileCheck %s -D#VBITS=2 --check-prefix=CHECK-NOMAX
10+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=4 -emit-llvm -o - %s | FileCheck %s -D#VBITS=4 --check-prefix=CHECK-NOMAX
11+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=8 -emit-llvm -o - %s | FileCheck %s -D#VBITS=8 --check-prefix=CHECK-NOMAX
12+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=16 -emit-llvm -o - %s | FileCheck %s -D#VBITS=16 --check-prefix=CHECK-NOMAX
13+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve2 -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED
14+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -mvscale-min=1 -mvscale-max=0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-UNBOUNDED
15+
! RUN: %flang_fc1 -triple aarch64-none-linux-gnu -target-feature +sve -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-NONE
16+
17+
! CHECK-LABEL: @func_() #0
18+
! CHECK: attributes #0 = {{{.*}} vscale_range([[#VBITS]],[[#VBITS]]) {{.*}}}
19+
! CHECK-NOMAX: attributes #0 = {{{.*}} vscale_range([[#VBITS]],0) {{.*}}}
20+
! CHECK-UNBOUNDED: attributes #0 = {{{.*}} vscale_range(1,0) {{.*}}}
21+
! CHECK-NONE: attributes #0 = {{{.*}} vscale_range(1,16) {{.*}}}
22+
subroutine func
23+
end subroutine func

0 commit comments

Comments
 (0)