Skip to content

Commit

Permalink
[aievec] Move common utility code to library (1/N)
Browse files Browse the repository at this point in the history
There are several utility functions that don't have a proper place in
which to live. Some of them are defined as "inline" in a header, and one
of them is duplicated in two source files. This patch creates an
AIEVecUtils library specifically for these, and starts the migration
process by moving the duplicated function to this library.
  • Loading branch information
jsetoain committed Aug 16, 2023
1 parent 6ad105d commit 59f6ba2
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 93 deletions.
40 changes: 40 additions & 0 deletions include/aie/Dialect/AIEVec/Utils/Utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===- Utils.h - Utilities to support AIE vectorization ---------*- 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
//
// (c) Copyright 2023, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//

#ifndef AIE_DIALECT_AIEVEC_UTILS_UTILS_H
#define AIE_DIALECT_AIEVEC_UTILS_UTILS_H

#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include <cstdint>
#include <type_traits>

namespace mlir {

class AffineExpr;
class AffineForOp;
class AffineMap;

} // namespace mlir

namespace xilinx::aievec {

template <
typename TransferReadLikeOp,
typename = std::enable_if_t<
std::is_same_v<TransferReadLikeOp, mlir::vector::TransferReadOp> ||
std::is_same_v<TransferReadLikeOp,
mlir::vector::TransferReadOp::Adaptor>>>
int64_t getTransferReadAlignmentOffset(TransferReadLikeOp readOp,
mlir::VectorType vType,
int64_t alignment);

}

#endif // AIE_DIALECT_AIEVEC_UTILS_UTILS_H
1 change: 1 addition & 0 deletions lib/Dialect/AIEVec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

add_subdirectory(IR)
add_subdirectory(Transforms)
add_subdirectory(Utils)
2 changes: 2 additions & 0 deletions lib/Dialect/AIEVec/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_mlir_dialect_library(MLIRAIEVecTransforms
ADDITIONAL_HEADER_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/../../../include/aie/Dialect/AIEVec/Transforms
${CMAKE_CURRENT_SOURCE_DIR}/../../../include/aie/Dialect/AIEVec/Analysis
${CMAKE_CURRENT_SOURCE_DIR}/../../../include/aie/Dialect/AIEVec/Utils

DEPENDS
MLIRAIEVecPassIncGen
Expand All @@ -25,4 +26,5 @@ add_mlir_dialect_library(MLIRAIEVecTransforms
LINK_LIBS PUBLIC
MLIRIR
MLIRPass
MLIRAIEVecUtils
)
59 changes: 15 additions & 44 deletions lib/Dialect/AIEVec/Transforms/VectorToAIEVecConversions.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
//===-VectorToAIEVecConversions.cpp - Vector to AIEVec convs. ---*- C++ -*-===//
//
// This file is licensed 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
//
// (c) Copyright 2023, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//
// This file contains conversions from the Vector dialect into the AIEVec
// dialect. Conversions assume that the Vector dialect has been rectricted
// to ops that can be translated to a sequence of valid AIEVec ops.
//===----------------------------------------------------------------------===//

#include <algorithm>
#include <bitset>
#include <optional>
Expand All @@ -6,6 +20,7 @@
#include "aie/Dialect/AIEVec/AIEVecUtils.h"
#include "aie/Dialect/AIEVec/IR/AIEVecOps.h"
#include "aie/Dialect/AIEVec/Pipelines/Passes.h"
#include "aie/Dialect/AIEVec/Utils/Utils.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
Expand Down Expand Up @@ -34,50 +49,6 @@ using namespace xilinx::aievec;
// Utility functions
//===----------------------------------------------------------------------===//

// Return the offset of a given transfer read operation with regards to the
// specified vector type. If the read is aligned to the specified alignment
// parameter (in bits), then the offset is 0. Otherwise, the offset is the
// number of elements past the immediately preceding aligned vector length.
template <
typename TransferReadLikeOp,
typename = std::enable_if_t<
std::is_same_v<TransferReadLikeOp, vector::TransferReadOp> ||
std::is_same_v<TransferReadLikeOp, vector::TransferReadOp::Adaptor>>>
static int64_t getTransferReadAlignmentOffset(TransferReadLikeOp readOp,
VectorType vType,
int64_t alignment) {
// TODO: Add support for cases where the index is not comming from an
// TODO: `affine.apply` op or when the affine map has more than one
// TODO: dimension. We also need to address the case where the index is an
// TODO: induction variable.
auto innerMostIndex = readOp.getIndices().back();
auto vectorLength = vType.getShape().back();
auto idxDefOp = innerMostIndex.getDefiningOp();
if (!idxDefOp)
return 0L;
int64_t vectorLengthAlignmentOffset =
TypeSwitch<Operation *, int64_t>(idxDefOp)
.Case<arith::ConstantOp>([&](auto constantOp) {
return cast<IntegerAttr>(constantOp.getValue()).getInt() %
vectorLength;
})
.template Case<AffineApplyOp>([&](auto applyOp) {
if (applyOp.getAffineMap().getNumDims() == 1)
return applyOp.getAffineMap().compose(ArrayRef<int64_t>{0})[0] %
vectorLength;
return 0L;
})
.Default([&](auto) {
// XXX: If we can't determine the offset, we assume the access is
// XXX: aligned.
return 0L;
});
int64_t absoluteAlignmentOffset = alignment / getElementSizeInBits(vType);
if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
return vectorLengthAlignmentOffset;
return 0;
}

// Given the LHS and RHS of an `arith::AddIOp`, if one of them is defined by an
// `arith::MulIOp`, return a tuple with the `lhs`, `rhs`, and `acc` of the MAC
// operation that can replace them.
Expand Down
68 changes: 19 additions & 49 deletions lib/Dialect/AIEVec/Transforms/VectorToVectorConversions.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
//===-VectorToVectorConversions.cpp - Conversions within Vector -*- C++ -*-===//
//
// This file is licensed 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
//
// (c) Copyright 2023, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//
// This file contains conversions and rewrites to the Vector dialect to make
// it compatible with the available vector instructions in AIE architectures
//===----------------------------------------------------------------------===//

#include "aie/Dialect/AIEVec/AIEVecUtils.h"
#include "aie/Dialect/AIEVec/IR/AIEVecOps.h"
#include "aie/Dialect/AIEVec/Pipelines/Passes.h"
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h" // ???
#include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h" // ???
#include "aie/Dialect/AIEVec/Utils/Utils.h"
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"
#include "mlir/Dialect/Affine/Analysis/LoopAnalysis.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/Math/IR/Math.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h" // ???
#include "mlir/Dialect/SCF/IR/SCF.h" // ???
#include "mlir/Dialect/Vector/Transforms/VectorTransforms.h" // ???
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Dialect/Vector/Transforms/VectorTransforms.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/Pass/PassManager.h"
Expand All @@ -32,50 +46,6 @@ using namespace xilinx::aievec;
//================== Common AIE canonicalization analysis ====================//
//============================================================================//

// Return the offset of a given transfer read operation with regards to the
// specified vector type. If the read is aligned to the specified alignment
// parameter (in bits), then the offset is 0. Otherwise, the offset is the
// number of elements past the immediately preceding aligned vector length.
template <
typename TransferReadLikeOp,
typename = std::enable_if_t<
std::is_same_v<TransferReadLikeOp, vector::TransferReadOp> ||
std::is_same_v<TransferReadLikeOp, vector::TransferReadOp::Adaptor>>>
static int64_t getTransferReadAlignmentOffset(TransferReadLikeOp readOp,
VectorType vType,
int64_t alignment) {
// TODO: Add support for cases where the index is not comming from an
// TODO: `affine.apply` op or when the affine map has more than one
// TODO: dimension. We also need to address the case where the index is an
// TODO: induction variable.
auto innerMostIndex = readOp.getIndices().back();
auto vectorLength = vType.getShape().back();
auto idxDefOp = innerMostIndex.getDefiningOp();
if (!idxDefOp)
return 0L;
int64_t vectorLengthAlignmentOffset =
TypeSwitch<Operation *, int64_t>(idxDefOp)
.Case<arith::ConstantOp>([&](auto constantOp) {
return cast<IntegerAttr>(constantOp.getValue()).getInt() %
vectorLength;
})
.template Case<AffineApplyOp>([&](auto applyOp) {
if (applyOp.getAffineMap().getNumDims() == 1)
return applyOp.getAffineMap().compose(ArrayRef<int64_t>{0})[0] %
vectorLength;
return 0L;
})
.Default([&](auto) {
// XXX: If we can't determine the offset, we assume the access is
// XXX: aligned.
return 0L;
});
int64_t absoluteAlignmentOffset = alignment / getElementSizeInBits(vType);
if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
return vectorLengthAlignmentOffset;
return 0;
}

//============================================================================//
//============ Common AIE canonicalization conversion patterns ===============//
//============================================================================//
Expand Down
24 changes: 24 additions & 0 deletions lib/Dialect/AIEVec/Utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# This file is licensed 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
#
# (c) Copyright 2023, Advanced Micro Devices, Inc.
#

add_mlir_dialect_library(MLIRAIEVecUtils
Utils.cpp

ADDITIONAL_HEADER_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/../../../include/aie/Dialect/AIEVec

LINK_LIBS PUBLIC
MLIRAIEVec
MLIRAffineDialect
MLIRAffineAnalysis
MLIRAffineUtils
MLIRArithDialect
MLIRFuncDialect
MLIRIR
MLIRVectorDialect
)
74 changes: 74 additions & 0 deletions lib/Dialect/AIEVec/Utils/Utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===- Utils.cpp - Utilities to support AIE vectorization -----------------===//
//
// 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
//
// (c) Copyright 2023, Advanced Micro Devices, Inc.
//
//===----------------------------------------------------------------------===//
//
// This file implements utilities for the AIEVec dialect
//
//===----------------------------------------------------------------------===//

#include "aie/Dialect/AIEVec/Utils/Utils.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/Debug.h"
#include <optional>

#define DEBUG_TYPE "aievec-utils"

using namespace mlir;

namespace xilinx::aievec {
// Return the offset of a given transfer read operation with regards to the
// specified vector type. If the read is aligned to the specified alignment
// parameter (in bits), then the offset is 0. Otherwise, the offset is the
// number of elements past the immediately preceding aligned vector length.
template <typename TransferReadLikeOp, typename>
int64_t getTransferReadAlignmentOffset(TransferReadLikeOp readOp,
VectorType vType, int64_t alignment) {
// TODO: Add support for cases where the index is not comming from an
// TODO: `affine.apply` op or when the affine map has more than one
// TODO: dimension. We also need to address the case where the index is an
// TODO: induction variable.
auto innerMostIndex = readOp.getIndices().back();
auto vectorLength = vType.getShape().back();
auto idxDefOp = innerMostIndex.getDefiningOp();
if (!idxDefOp)
return 0L;
int64_t vectorLengthAlignmentOffset =
TypeSwitch<Operation *, int64_t>(idxDefOp)
.Case<arith::ConstantOp>([&](auto constantOp) {
return cast<IntegerAttr>(constantOp.getValue()).getInt() %
vectorLength;
})
.template Case<AffineApplyOp>([&](auto applyOp) {
if (applyOp.getAffineMap().getNumDims() == 1)
return applyOp.getAffineMap().compose(ArrayRef<int64_t>{0})[0] %
vectorLength;
return 0L;
})
.Default([&](auto) {
// XXX: If we can't determine the offset, we assume the access is
// XXX: aligned.
return 0L;
});
int64_t absoluteAlignmentOffset = alignment / vType.getElementTypeBitWidth();
if (vectorLengthAlignmentOffset % absoluteAlignmentOffset)
return vectorLengthAlignmentOffset;
return 0;
}

template int64_t getTransferReadAlignmentOffset(vector::TransferReadOp readOp,
VectorType vType,
int64_t alignment);
template int64_t
getTransferReadAlignmentOffset(vector::TransferReadOp::Adaptor readOp,
VectorType vType, int64_t alignment);

} // namespace xilinx::aievec

0 comments on commit 59f6ba2

Please sign in to comment.