Repository navigation
Expand file tree
/
Copy pathsample_plugin.cpp
More file actions
170 lines (143 loc) · 6.6 KB
/
Copy pathsample_plugin.cpp
File metadata and controls
170 lines (143 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
* Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
* Licensed under the MIT License.
*/
// Sample static plugin for the plugin registrar + pipeline-slot tests.
// Exercises the public plugin surface (PluginAPI.h / PluginRegistry.h) end to
// end: registers a pass, requests a pipeline slot, contributes a minimal vendor
// dialect (via addDialectRegistration), and contributes runtime bitcode + a
// link library. Statically linked into the host, so its registrations land in
// the host's single MLIR/pass/dialect registry.
#include "hip/Compiler/PluginAPI.h"
#include "hip/Compiler/PluginRegistry.h"
#include "hip/Dialect/IR/HipDialect.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "sample_dialect.h"
#include <cstddef>
// Embedded bitcode from sample_plugin_runtime.cpp (generated
// sample_plugin_bitcode.cpp; see CMakeLists.txt). Empty (size 0) in a build
// without clang/python -- the unit test skips the round-trip in that case.
extern "C" const unsigned char kSamplePluginBitcode[];
extern "C" const std::size_t kSamplePluginBitcodeSize;
namespace {
void emitSampleConstant(mlir::func::FuncOp function,
llvm::StringRef sourceName) {
mlir::Block &entry = function.front();
mlir::OpBuilder builder(function.getContext());
builder.setInsertionPointToStart(&entry);
auto tensorType = mlir::RankedTensorType::get({2}, builder.getF32Type());
llvm::SmallVector<mlir::Attribute> values = {
builder.getF32FloatAttr(101.0f),
builder.getF32FloatAttr(102.0f),
};
auto value = mlir::DenseElementsAttr::get(tensorType, values);
auto constant = mlir::hip::ConstantOp::create(builder, function.getLoc(),
tensorType, value);
auto name = builder.getStringAttr(sourceName);
constant.setSymbolNameHintAttr(name);
constant.setSourceNameAttr(name);
mlir::Value context;
for (mlir::BlockArgument argument : function.getArguments()) {
if (mlir::isa<mlir::hip::ContextType>(argument.getType())) {
context = argument;
break;
}
}
auto terminator = mlir::dyn_cast<mlir::func::ReturnOp>(entry.getTerminator());
if (!context || !terminator)
return;
for (mlir::OpOperand &returned : terminator->getOpOperands()) {
if (returned.get().getType() != tensorType)
continue;
builder.setInsertionPoint(terminator);
mlir::Value init = mlir::tensor::EmptyOp::create(
builder, function.getLoc(), tensorType.getShape(),
tensorType.getElementType());
auto biased =
mlir::hip::AddOp::create(builder, function.getLoc(), context,
returned.get(), constant.getResult(), init);
returned.set(biased->getResult(0));
break;
}
}
// Emits one remark per func.func. A marked function also gets a plugin-owned
// hip.constant at the start of its entry block; because this pass runs at
// AfterConvertOnnxToHip, the production externalizer consumes it.
struct SamplePrintFunctionsPass
: public mlir::PassWrapper<SamplePrintFunctionsPass,
mlir::OperationPass<mlir::func::FuncOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(SamplePrintFunctionsPass)
llvm::StringRef getArgument() const final {
return "hip-ep-sample-print-functions";
}
llvm::StringRef getDescription() const final {
return "Sample plugin pass: emit a remark and optional hip.constant";
}
void getDependentDialects(mlir::DialectRegistry ®istry) const override {
registry.insert<mlir::hip::HipDialect, mlir::tensor::TensorDialect>();
}
void runOnOperation() override {
auto fn = getOperation();
fn.emitRemark() << "[hip-ep-sample] visited " << fn.getSymName();
if (fn->hasAttr("hip_ep_sample.emit_constant"))
emitSampleConstant(fn, "sample_plugin_weight");
}
};
// Negative fixture for the supported producer boundary. A marked function gets
// a carrier at BeforeBufferization, where the production late-carrier guard
// must reject it.
struct SampleEmitLateConstantPass
: public mlir::PassWrapper<SampleEmitLateConstantPass,
mlir::OperationPass<mlir::func::FuncOp>> {
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(SampleEmitLateConstantPass)
llvm::StringRef getArgument() const final {
return "hip-ep-sample-emit-late-constant";
}
llvm::StringRef getDescription() const final {
return "Sample plugin negative fixture: emit a late hip.constant";
}
void getDependentDialects(mlir::DialectRegistry ®istry) const override {
registry.insert<mlir::hip::HipDialect, mlir::tensor::TensorDialect>();
}
void runOnOperation() override {
auto function = getOperation();
if (function->hasAttr("hip_ep_sample.emit_late_constant"))
emitSampleConstant(function, "sample_plugin_late_weight");
}
};
} // namespace
// HIP_EP_DEFINE_PLUGIN(sample) expands to
// `extern "C" void hipEpRegisterPlugin_sample(HipEpPluginRegistry &R)`; the
// generated registrar calls it once when `sample` is selected.
HIP_EP_DEFINE_PLUGIN(sample) {
R.registerPass<SamplePrintFunctionsPass>();
R.registerPass<SampleEmitLateConstantPass>();
// Run the pass at the most common vendor slot (after onnx->hip). A func.func
// pass must be nested as func.func(<arg>) per parsePassPipeline syntax;
// <arg> matches getArgument() above.
R.requestPipelineSlot(::hip::compiler::PipelineSlot::AfterConvertOnnxToHip,
"func.func(hip-ep-sample-print-functions)");
R.requestPipelineSlot(::hip::compiler::PipelineSlot::BeforeBufferization,
"func.func(hip-ep-sample-emit-late-constant)");
// Contribute a minimal vendor dialect (hip_ep_sample.marker + its
// ConvertToLLVMPatternInterface). This is the only in-tree exercise of the
// addDialectRegistration -> loadAllDialects path and the convert-hip-to-llvm
// hasPromisedInterface guard, so a refactor of either fails a host test.
R.addDialectRegistration(®isterHipEpSampleDialect);
// Contribute the embedded bitcode (process-lifetime static, as
// addRuntimeBitcode requires); skip the empty no-clang build.
if (kSamplePluginBitcodeSize != 0) {
R.addRuntimeBitcode(kSamplePluginBitcode, kSamplePluginBitcodeSize);
}
// Contribute the sibling static lib; path + name come from CMake defines.
// The model module never references it, so the link succeeds regardless.
R.addLibraryPath(HIP_EP_SAMPLE_LIB_DIR);
R.addLibrary(HIP_EP_SAMPLE_LIB_NAME);
}