Skip to content

Commit

Permalink
[𝘀𝗽𝗿] initial version
Browse files Browse the repository at this point in the history
Created using spr 1.3.6-beta.1
  • Loading branch information
mgehre-amd committed Feb 28, 2024
2 parents d3c90a4 + 1d95249 commit 530667f
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 25 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/merge-upstream.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Create PR to update the hooks in .pre-commit-config.yaml
name: Merge xilinx/llvm-project

on:
workflow_dispatch:
schedule:
# Start 4 am every day
- cron: '0 4 * * *'

jobs:
auto-update:
permissions:
contents: write # to push a branch

runs-on: [Ubuntu22.04]

steps:
# See https://xilinx.slack.com/archives/C03BVM6E423/p1707245513111479
- name: Clear working directory
run: find . -name . -o -prune -exec rm -rf -- {} +

- uses: actions/checkout@v4
with:
# Fetch all history to be able to check whether we are up-to-date
fetch-depth: 0
# We only need the git commits, no files in the worktree.
sparse-checkout: README.md
# Use PAT to allow pushing branches even if they affect workflow files
token: ${{ secrets.SVC_ACT_JENKINS_PAT }}

- name: Is update needed
id: uptodate
run: |
git remote add xilinx https://github.com/Xilinx/llvm-project.git
git fetch xilinx refs/heads/feature/fused-ops
git merge-base --is-ancestor xilinx/feature/fused-ops origin/feature/fused-ops
continue-on-error: true

- name: Create branch
if: ${{ steps.uptodate.outcome == 'failure' }}
id: create_branch
run: |
BRANCH=merge_feature/fused-ops_$(date +'%Y-%m-%d')
git push origin xilinx/feature/fused-ops:refs/heads/$BRANCH
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
- name: Create Pull Request
if: ${{ steps.uptodate.outcome == 'failure' }}
env:
GH_ENTERPRISE_TOKEN: ${{ secrets.SVC_ACT_JENKINS_PAT }}
GH_HOST: gitenterprise.xilinx.com
run: |
gh pr create \
--title "Merge xilinx/llvm-project feature/fused-ops" \
--body "Auto-generated by .github/workflows/merge-upstream.yml" \
--head "${{steps.create_branch.outputs.branch}}" \
--base "feature/fused-ops" \
--reviewer tinamari,mgehre
16 changes: 13 additions & 3 deletions mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,33 @@ std::unique_ptr<Pass> createBufferLoopHoistingPass();

// Options struct for BufferResultsToOutParams pass.
// Note: defined only here, not in tablegen.
struct BufferResultsToOutParamsOptions {
struct BufferResultsToOutParamsOpts {
/// Memcpy function: Generate a memcpy between two memrefs.
using MemCpyFn =
std::function<LogicalResult(OpBuilder &, Location, Value, Value)>;

// Filter function; returns true if the function should be converted.
// Defaults to true, i.e. all functions are converted.
llvm::function_ref<bool(func::FuncOp *)> filterFn = [](func::FuncOp *func) {
return true;
};

std::optional<MemCpyFn> memCpyFn;

/// If true, the pass adds a "bufferize.result" attribute to each output
/// parameter.
bool addResultAttribute = false;
};

/// Creates a pass that converts memref function results to out-params.
std::unique_ptr<Pass> createBufferResultsToOutParamsPass(
const BufferResultsToOutParamsOptions &options = {});
const BufferResultsToOutParamsOpts &options = {});

/// Replace buffers that are returned from a function with an out parameter.
/// Also update all call sites.
LogicalResult
promoteBufferResultsToOutParams(ModuleOp module,
const BufferResultsToOutParamsOptions &options);
const BufferResultsToOutParamsOpts &options);

/// Creates a pass that drops memref function results that are equivalent to a
/// function argument.
Expand Down
5 changes: 5 additions & 0 deletions mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ def BufferResultsToOutParams : Pass<"buffer-results-to-out-params", "ModuleOp">
buffers for results need to be allocated in the caller. This currently only
works for static shaped memrefs.
}];
let options = [
Option<"addResultAttribute", "add-result-attr", "bool",
/*default=*/"false",
"Add the attribute 'bufferize.result' to all output parameters.">,
];
let constructor = "mlir::bufferization::createBufferResultsToOutParamsPass()";
let dependentDialects = ["memref::MemRefDialect"];
}
Expand Down
32 changes: 32 additions & 0 deletions mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
Original file line number Diff line number Diff line change
Expand Up @@ -565,4 +565,36 @@ def EmitC_IfOp : EmitC_Op<"if",
let hasCustomAssemblyFormat = 1;
}

def EmitC_SubscriptOp : EmitC_Op<"subscript",
[TypesMatchWith<"result type matches element type of 'array'",
"array", "result",
"::llvm::cast<ArrayType>($_self).getElementType()">]> {
let summary = "Array subscript operation";
let description = [{
With the `subscript` operation the subscript operator `[]` can be applied
to variables or arguments of array type.

Example:

```mlir
%i = index.constant 1
%j = index.constant 7
%0 = emitc.subscript %arg0[%i][%j] : (!emitc.array<4x8xf32>) -> f32
```
}];
let arguments = (ins Arg<EmitC_ArrayType, "the reference to load from">:$array,
Variadic<Index>:$indices);
let results = (outs AnyType:$result);

let builders = [
OpBuilder<(ins "Value":$array, "ValueRange":$indices), [{
build($_builder, $_state, cast<ArrayType>(array.getType()).getElementType(), array, indices);
}]>
];

let hasVerifier = 1;
let assemblyFormat = "$array `[` $indices `]` attr-dict `:` type($array)";
}


#endif // MLIR_DIALECT_EMITC_IR_EMITC
47 changes: 47 additions & 0 deletions mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,51 @@ def EmitC_PointerType : EmitC_Type<"Pointer", "ptr"> {
let assemblyFormat = "`<` qualified($pointee) `>`";
}

def EmitC_ArrayType : EmitC_Type<"Array", "array", [ShapedTypeInterface]> {
let summary = "EmitC array type";

let description = [{
An array data type.

Example:

```mlir
// Array emitted as `int32_t[10]`
!emitc.array<10xi32>
// Array emitted as `float[10][20]`
!emitc.ptr<10x20xf32>
```
}];

let parameters = (ins
ArrayRefParameter<"int64_t">:$shape,
"Type":$elementType
);

let builders = [
TypeBuilderWithInferredContext<(ins
"ArrayRef<int64_t>":$shape,
"Type":$elementType
), [{
return $_get(elementType.getContext(), shape, elementType);
}]>
];
let extraClassDeclaration = [{
/// Returns if this type is ranked (always true).
bool hasRank() const { return true; }

/// Clone this vector type with the given shape and element type. If the
/// provided shape is `std::nullopt`, the current shape of the type is used.
ArrayType cloneWith(std::optional<ArrayRef<int64_t>> shape,
Type elementType) const;

static bool isValidElementType(Type type) {
return type.isIntOrIndexOrFloat() ||
llvm::isa<PointerType, OpaqueType>(type);
}
}];
let genVerifyDecl = 1;
let hasCustomAssemblyFormat = 1;
}

#endif // MLIR_DIALECT_EMITC_IR_EMITCTYPES
57 changes: 57 additions & 0 deletions mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,60 @@ bool isSignatureLegal(FunctionType ty) {
return isLegal(llvm::concat<const Type>(ty.getInputs(), ty.getResults()));
}

struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(memref::LoadOp op, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {

rewriter.replaceOpWithNewOp<emitc::SubscriptOp>(op, operands.getMemref(),
operands.getIndices());
return success();
}
};

struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {

auto subscript = rewriter.create<emitc::SubscriptOp>(
op.getLoc(), operands.getMemref(), operands.getIndices());
rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript,
operands.getValue());
return success();
}
};

struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
using OpConversionPattern::OpConversionPattern;

LogicalResult
matchAndRewrite(memref::AllocaOp op, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {

if (!op.getType().hasStaticShape()) {
return rewriter.notifyMatchFailure(
op.getLoc(), "cannot transform alloca with dynamic shape");
}

if (op.getAlignment().value_or(1) > 1) {
// TODO: Allow alignment if it is not more than the natural alignment
// of the C array.
return rewriter.notifyMatchFailure(
op.getLoc(), "cannot transform alloca with alignment requirement");
}

auto resultTy = getTypeConverter()->convertType(op.getType());
auto noInit = emitc::OpaqueAttr::get(getContext(), "");
rewriter.replaceOpWithNewOp<emitc::VariableOp>(op, resultTy, noInit);
return success();
}
};

struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
void runOnOperation() override {
Expand Down Expand Up @@ -91,6 +145,7 @@ struct ConvertMemRefToEmitCPass
target.addDynamicallyLegalDialect<func::FuncDialect>(
[](Operation *op) { return isLegal(op); });
target.addIllegalDialect<memref::MemRefDialect>();
target.addLegalDialect<emitc::EmitCDialect>();

if (failed(applyPartialConversion(getOperation(), target,
std::move(patterns))))
Expand All @@ -106,6 +161,8 @@ void mlir::populateMemRefToEmitCConversionPatterns(RewritePatternSet &patterns,
converter);
populateCallOpTypeConversionPattern(patterns, converter);
populateReturnOpTypeConversionPattern(patterns, converter);
patterns.add<ConvertLoad, ConvertStore, ConvertAlloca>(converter,
patterns.getContext());
}

std::unique_ptr<OperationPass<>> mlir::createConvertMemRefToEmitCPass() {
Expand Down
Loading

0 comments on commit 530667f

Please sign in to comment.