From ff01b175d08961f4936e57aa047ebf324d66ab18 Mon Sep 17 00:00:00 2001 From: AnirudhK Date: Mon, 15 Jun 2026 01:47:23 -0400 Subject: [PATCH 1/2] Apply peterc changes to polygesit for HLS pragma handling --- tools/cgeist/Lib/pragmaHandlerHLS.cc | 54 +++++++++++++++++++ tools/cgeist/Lib/pragmaHandlerHLS.h | 51 ++++++++++++++++++ .../Test/HLS/AccessMemberArrayPartition.cpp | 43 +++++++++++++++ tools/cgeist/Test/HLS/Allocation.cpp | 23 ++++++++ tools/cgeist/Test/HLS/BasicArrayPartition.cpp | 12 +++++ tools/cgeist/Test/HLS/BindOp.cpp | 11 ++++ tools/cgeist/Test/HLS/BindStorage.cpp | 23 ++++++++ tools/cgeist/Test/HLS/Pipeline.cpp | 12 +++++ tools/cgeist/Test/HLS/Unroll.cpp | 13 +++++ tools/cgeist/driver.cc | 8 +++ 10 files changed, 250 insertions(+) create mode 100644 tools/cgeist/Lib/pragmaHandlerHLS.cc create mode 100644 tools/cgeist/Lib/pragmaHandlerHLS.h create mode 100644 tools/cgeist/Test/HLS/AccessMemberArrayPartition.cpp create mode 100644 tools/cgeist/Test/HLS/Allocation.cpp create mode 100644 tools/cgeist/Test/HLS/BasicArrayPartition.cpp create mode 100644 tools/cgeist/Test/HLS/BindOp.cpp create mode 100644 tools/cgeist/Test/HLS/BindStorage.cpp create mode 100644 tools/cgeist/Test/HLS/Pipeline.cpp create mode 100644 tools/cgeist/Test/HLS/Unroll.cpp diff --git a/tools/cgeist/Lib/pragmaHandlerHLS.cc b/tools/cgeist/Lib/pragmaHandlerHLS.cc new file mode 100644 index 000000000000..f7cd1f624906 --- /dev/null +++ b/tools/cgeist/Lib/pragmaHandlerHLS.cc @@ -0,0 +1,54 @@ +#include "pragmaHandlerHLS.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "mlir/IR/Builders.h" + +using namespace clang; + +std::vector g_HLSMetadata; + +PragmaHLSHandler::PragmaHLSHandler(std::vector &Metadata) + : PragmaHandler("HLS"), HLSMetaData(Metadata) {} + +void PragmaHLSHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducer Introducer, + Token &PragmaTok) { + SourceManager &SM = PP.getSourceManager(); + Token Tok{}; + PP.Lex(Tok); + + if (Tok.isNot(tok::identifier)) return; + HLSPragmaMetaData P; + P.Name = StringRef(PP.getSpelling(Tok)).lower(); + P.Loc = Tok.getLocation(); + P.OffsetLoc = SM.getSpellingLineNumber(P.Loc); // ← add this line + PP.Lex(Tok); + + if (Tok.is(tok::eod)) { + HLSMetaData.push_back(P); + return; + } + + SourceLocation Start = Tok.getLocation(); + SourceLocation End = Start; + while (PP.Lex(Tok), Tok.isNot(tok::eod)) + End = Tok.getEndLoc(); + + // Extract raw text from source + bool Invalid = false; + const char *StartPtr = SM.getCharacterData(Start, &Invalid); + const char *EndPtr = SM.getCharacterData(End, &Invalid); + + if (!Invalid && StartPtr && EndPtr && EndPtr > StartPtr) { + StringRef RawPragma(StartPtr, EndPtr - StartPtr); + P.Args = RawPragma.str(); + } + llvm::outs() << "[HLS] pragma name: " << P.Name << " pragma args: " + << P.Args << "\n"; + HLSMetaData.push_back(P); +} + +void addPragmaHLSHandlers(Preprocessor &PP) { + PP.AddPragmaHandler(new PragmaHLSHandler(g_HLSMetadata)); +} \ No newline at end of file diff --git a/tools/cgeist/Lib/pragmaHandlerHLS.h b/tools/cgeist/Lib/pragmaHandlerHLS.h new file mode 100644 index 000000000000..6f979e213da2 --- /dev/null +++ b/tools/cgeist/Lib/pragmaHandlerHLS.h @@ -0,0 +1,51 @@ +#ifndef MLIR_TOOLS_MLIRCLANG_LIB_PRAGMAHANDLERHLS_H +#define MLIR_TOOLS_MLIRCLANG_LIB_PRAGMAHANDLERHLS_H + +#include "clang/Frontend/FrontendAction.h" +#include "clang/Lex/Pragma.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "mlir/IR/Operation.h" +#include +#include + +enum HLSPragmaType { + ArrayPartition, + ArrayReshape, + BindStorage, + BindOp, + Allocation, + Unroll, + Pipeline + }; + +/// Holds metadata parsed from #pragma HLS +struct HLSPragmaMetaData { + std::string Name; // e.g., "pipeline" + std::string Args; // e.g., "II=1" + clang::SourceLocation Loc; + mlir::Operation *Op = nullptr; + unsigned OffsetLoc = 0; +}; + +/// Handles the transition from Preprocessor (#pragma) to AST metadata +class PragmaHLSHandler : public clang::PragmaHandler { +public: + PragmaHLSHandler(std::vector &Metadata); + + void HandlePragma(clang::Preprocessor &PP, + clang::PragmaIntroducer Introducer, + clang::Token &PragmaTok) override; +private: + std::vector &HLSMetaData; +}; + +void addPragmaHLSHandlers(clang::Preprocessor &PP); + +// Global storage for HLS pragma metadata collected during parse. +// Populated by PragmaHLSHandler::HandlePragma, consumed in driver.cc +// after the MLIR pass pipeline runs. +extern std::vector g_HLSMetadata; + + +#endif \ No newline at end of file diff --git a/tools/cgeist/Test/HLS/AccessMemberArrayPartition.cpp b/tools/cgeist/Test/HLS/AccessMemberArrayPartition.cpp new file mode 100644 index 000000000000..94b0c5dedd52 --- /dev/null +++ b/tools/cgeist/Test/HLS/AccessMemberArrayPartition.cpp @@ -0,0 +1,43 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +struct C { + int A[8]; + int B[4]; +}; + +struct S { + int A[8]; + int B[4]; + C c; +}; + +int top(int input1[8], int input2[4]) { + S s; +#pragma HLS array_partition variable=s.A complete +#pragma HLS array_partition variable=s.c.A complete +#pragma HLS array_partition variable=s.B block factor=2 + for (int i = 0; i < 8; i++) { + s.A[i] = input1[i]; + s.c.A[i] = 2 * input1[i]; + } + for (int i = 0; i < 4; i++) { + s.B[i] = input2[i]; + s.c.B[i] = 2 * input2[i]; + } + + for (int i = 0; i < 8; i++) { + s.A[i] = s.A[i] + 1; + s.c.A[i] = s.c.A[i] + 1; + } + int sum = 0; + for (int i = 0; i < 8; i++) { + sum += s.A[i]; + sum += s.c.A[i]; + } + + return sum; + +} + +// CHECK: %alloca = memref.alloca() {hls.array_partition = [{kind = "complete", variable = "s.A"}, {kind = "complete", variable = "s.c.A"}, {factor = 2 : i32, kind = "block", variable = "s.B"}], polygeist.varname = "s"} + diff --git a/tools/cgeist/Test/HLS/Allocation.cpp b/tools/cgeist/Test/HLS/Allocation.cpp new file mode 100644 index 000000000000..7bea626fad52 --- /dev/null +++ b/tools/cgeist/Test/HLS/Allocation.cpp @@ -0,0 +1,23 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +template +DT foo(DT a, DT b) { + return a + b; +} + +// ------------------------------------------------------------ +// Top-level function that calls foo and foo +// ------------------------------------------------------------ +void top(int *out_int, float *out_float, int a, int b, float x, float y) { + +#pragma HLS ALLOCATION function instances=foo limit=1 +#pragma HLS ALLOCATION function instances=foo limit=1 + + int r1 = foo(a, b); + float r2 = foo(x, y); + + *out_int = r1; + *out_float = r2; +} + +// CHECK: hls.allocation = [{instances = "foo", limit = 1 : i32, type = "function"}, {instances = "foo", limit = 1 : i32, type = "function"} \ No newline at end of file diff --git a/tools/cgeist/Test/HLS/BasicArrayPartition.cpp b/tools/cgeist/Test/HLS/BasicArrayPartition.cpp new file mode 100644 index 000000000000..b2d2c446da37 --- /dev/null +++ b/tools/cgeist/Test/HLS/BasicArrayPartition.cpp @@ -0,0 +1,12 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +void basic_array_partition() { + int arr[8]; +#pragma HLS array_partition variable=arr complete + // Simple computation to test parallel access + for(int i = 0; i < 8; i++) { + arr[i] += 1; + } +} + +// CHECK: %alloca = memref.alloca() {hls.array_partition = [{kind = "complete", variable = "arr"}], polygeist.varname = "arr"} \ No newline at end of file diff --git a/tools/cgeist/Test/HLS/BindOp.cpp b/tools/cgeist/Test/HLS/BindOp.cpp new file mode 100644 index 000000000000..ac47fc746e35 --- /dev/null +++ b/tools/cgeist/Test/HLS/BindOp.cpp @@ -0,0 +1,11 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +int foo (int a, int b) { + int c, d; +#pragma HLS BIND_OP variable=c op=mul impl=fabric latency=2 + c = a*b; + d = a*c; + return d; +} + +// CHECK: {hls.bind_op = [{impl = "fabric", latency = 2 : i32, op = "mul"}], polygeist.ssa_names = ["c"]} \ No newline at end of file diff --git a/tools/cgeist/Test/HLS/BindStorage.cpp b/tools/cgeist/Test/HLS/BindStorage.cpp new file mode 100644 index 000000000000..bcec9b5b1bfe --- /dev/null +++ b/tools/cgeist/Test/HLS/BindStorage.cpp @@ -0,0 +1,23 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +void mac_top(int input[64], int &result) { +#pragma HLS bind_storage variable=weights type=ram_1p impl=bram +#pragma HLS bind_storage variable=bias type=ram_1p impl=lutram +#pragma HLS bind_storage variable=output type=ram_2p impl=uram latency=3 + int weights[64]; + int bias[16]; + int output[16]; + + for (int i = 0; i < 16; i++) { + output[i] = bias[i]; + for (int j = 0; j < 4; j++) + output[i] += input[i*4+j] * weights[i*4+j]; + } + for (int i = 0; i < 64; i++) { + result += output[i]; + } +} + +// CHECK: %alloca = memref.alloca() {hls.bind_storage = [{impl = "uram", latency = 3 : i32, type = "ram_2p", variable = "output"}], polygeist.varname = "output"} : memref<16xi32> +// CHECK: %alloca_0 = memref.alloca() {hls.bind_storage = [{impl = "lutram", type = "ram_1p", variable = "bias"}], polygeist.varname = "bias"} : memref<16xi32> +// CHECK: %alloca_1 = memref.alloca() {hls.bind_storage = [{impl = "bram", type = "ram_1p", variable = "weights"}], polygeist.varname = "weights"} : memref<64xi32> diff --git a/tools/cgeist/Test/HLS/Pipeline.cpp b/tools/cgeist/Test/HLS/Pipeline.cpp new file mode 100644 index 000000000000..c7d2e99619c2 --- /dev/null +++ b/tools/cgeist/Test/HLS/Pipeline.cpp @@ -0,0 +1,12 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + + +void my_kernel(int j) { + j = 0; + for(int i = 0; i < 10; ++i) { + #pragma HLS pipeline II=1 + j += 1; + } +} + +// CHECK: hls.pipeline = [{II = 1 : i32, rewind = false, style = "stp"}] \ No newline at end of file diff --git a/tools/cgeist/Test/HLS/Unroll.cpp b/tools/cgeist/Test/HLS/Unroll.cpp new file mode 100644 index 000000000000..785ec1138e57 --- /dev/null +++ b/tools/cgeist/Test/HLS/Unroll.cpp @@ -0,0 +1,13 @@ +//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s + +void fir_filter(int x[16], int h[8], int y[16]) { + for (int i = 0; i < 16; i++) { +#pragma HLS unroll + int acc = 0; + for (int j = 0; j < 8; j++) + acc += x[i-j] * h[j]; + y[i] = acc; + } +} + +// CHECK: {hls.unroll = [{factor = 0 : i32, skip_exit_check = false}]} \ No newline at end of file diff --git a/tools/cgeist/driver.cc b/tools/cgeist/driver.cc index b49eecdcfec5..812ed11cb08c 100644 --- a/tools/cgeist/driver.cc +++ b/tools/cgeist/driver.cc @@ -458,6 +458,9 @@ int emitBinary(char *Argv0, const char *filename, } #include "Lib/clang-mlir.cc" +#include "Lib/HandleHLS.h" +#include "Lib/PragmaHanderHLS.h" +#include "Lib/utils.h" int main(int argc, char **argv) { if (argc >= 1) { @@ -961,6 +964,11 @@ int main(int argc, char **argv) { } while (changed); }); + if (HLSAnnotate) { + ResolveScope(module.get(), g_HLSMetadata); + AttachMetadata(g_HLSMetadata); + } + if (EmitLLVM || !EmitAssembly || EmitOpenMPIR || EmitLLVMDialect) { mlir::PassManager pm2(&context); enablePrinting(pm2); From 857598a1adc6dce2645121ca635c2d2efd8a2487 Mon Sep 17 00:00:00 2001 From: AnirudhK Date: Mon, 15 Jun 2026 21:27:59 -0400 Subject: [PATCH 2/2] Additional changes to build polygeist --- tools/cgeist/CMakeLists.txt | 2 ++ tools/cgeist/Lib/clang-mlir.cc | 3 +++ tools/cgeist/Lib/clang-mlir.h | 5 +++++ tools/cgeist/Lib/utils.h | 2 ++ tools/cgeist/driver.cc | 2 +- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/cgeist/CMakeLists.txt b/tools/cgeist/CMakeLists.txt index 84b4a739e9df..fdcfad45f222 100644 --- a/tools/cgeist/CMakeLists.txt +++ b/tools/cgeist/CMakeLists.txt @@ -24,6 +24,8 @@ add_clang_executable(cgeist "${LLVM_SOURCE_DIR}/../clang/tools/driver/cc1as_main.cpp" "${LLVM_SOURCE_DIR}/../clang/tools/driver/cc1gen_reproducer_main.cpp" Lib/pragmaHandler.cc + Lib/pragmaHandlerHLS.cc + Lib/HandleHLS.cc Lib/AffineUtils.cc Lib/ValueCategory.cc Lib/utils.cc diff --git a/tools/cgeist/Lib/clang-mlir.cc b/tools/cgeist/Lib/clang-mlir.cc index b944cbda2e04..8a694f2df874 100644 --- a/tools/cgeist/Lib/clang-mlir.cc +++ b/tools/cgeist/Lib/clang-mlir.cc @@ -60,6 +60,9 @@ static cl::opt memRefABI("memref-abi", cl::init(true), cl::opt PrefixABI("prefix-abi", cl::init(""), cl::desc("Prefix for emitted symbols")); +cl::opt HLSAnnotate("hls-annotate", cl::init(false), + cl::desc("annotate hls pragmas")); + cl::opt CStyleMemRef("c-style-memref", cl::init(true), cl::desc("Use c style memrefs when possible")); diff --git a/tools/cgeist/Lib/clang-mlir.h b/tools/cgeist/Lib/clang-mlir.h index 117bcf162557..ccc4029ef60a 100644 --- a/tools/cgeist/Lib/clang-mlir.h +++ b/tools/cgeist/Lib/clang-mlir.h @@ -26,6 +26,8 @@ #include "mlir/Target/LLVMIR/TypeToLLVM.h" #include "polygeist/Ops.h" #include "pragmaHandler.h" +#include "pragmaHandlerHLS.h" +#include "HandleHLS.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/HeaderSearch.h" @@ -44,6 +46,8 @@ using namespace mlir; extern llvm::cl::opt PrefixABI; +extern llvm::cl::opt HLSAnnotate; + struct LoopContext { mlir::Value keepRunning; mlir::Value noBreak; @@ -96,6 +100,7 @@ struct MLIRASTConsumer : public ASTConsumer { addPragmaScopHandlers(PP, scopLocList); addPragmaEndScopHandlers(PP, scopLocList); addPragmaLowerToHandlers(PP, LTInfo); + addPragmaHLSHandlers(PP); } ~MLIRASTConsumer() {} diff --git a/tools/cgeist/Lib/utils.h b/tools/cgeist/Lib/utils.h index f80132c0b65e..e8af3dc420ce 100644 --- a/tools/cgeist/Lib/utils.h +++ b/tools/cgeist/Lib/utils.h @@ -12,6 +12,8 @@ #include "mlir/IR/Builders.h" #include "llvm/ADT/ArrayRef.h" +inline bool g_HLSpragmaAnnotate = false; + namespace mlir { class Operation; namespace func { diff --git a/tools/cgeist/driver.cc b/tools/cgeist/driver.cc index 812ed11cb08c..abd10d4c0107 100644 --- a/tools/cgeist/driver.cc +++ b/tools/cgeist/driver.cc @@ -459,7 +459,7 @@ int emitBinary(char *Argv0, const char *filename, #include "Lib/clang-mlir.cc" #include "Lib/HandleHLS.h" -#include "Lib/PragmaHanderHLS.h" +#include "Lib/pragmaHandlerHLS.h" #include "Lib/utils.h" int main(int argc, char **argv) {