Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tools/cgeist/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions tools/cgeist/Lib/clang-mlir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ static cl::opt<bool> memRefABI("memref-abi", cl::init(true),
cl::opt<std::string> PrefixABI("prefix-abi", cl::init(""),
cl::desc("Prefix for emitted symbols"));

cl::opt<bool> HLSAnnotate("hls-annotate", cl::init(false),
cl::desc("annotate hls pragmas"));

cl::opt<bool> CStyleMemRef("c-style-memref", cl::init(true),
cl::desc("Use c style memrefs when possible"));

Expand Down
5 changes: 5 additions & 0 deletions tools/cgeist/Lib/clang-mlir.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -44,6 +46,8 @@ using namespace mlir;

extern llvm::cl::opt<std::string> PrefixABI;

extern llvm::cl::opt<bool> HLSAnnotate;

struct LoopContext {
mlir::Value keepRunning;
mlir::Value noBreak;
Expand Down Expand Up @@ -96,6 +100,7 @@ struct MLIRASTConsumer : public ASTConsumer {
addPragmaScopHandlers(PP, scopLocList);
addPragmaEndScopHandlers(PP, scopLocList);
addPragmaLowerToHandlers(PP, LTInfo);
addPragmaHLSHandlers(PP);
}

~MLIRASTConsumer() {}
Expand Down
54 changes: 54 additions & 0 deletions tools/cgeist/Lib/pragmaHandlerHLS.cc
Original file line number Diff line number Diff line change
@@ -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<HLSPragmaMetaData> g_HLSMetadata;

PragmaHLSHandler::PragmaHLSHandler(std::vector<HLSPragmaMetaData> &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));
}
51 changes: 51 additions & 0 deletions tools/cgeist/Lib/pragmaHandlerHLS.h
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <vector>

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<HLSPragmaMetaData> &Metadata);

void HandlePragma(clang::Preprocessor &PP,
clang::PragmaIntroducer Introducer,
clang::Token &PragmaTok) override;
private:
std::vector<HLSPragmaMetaData> &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<HLSPragmaMetaData> g_HLSMetadata;


#endif
2 changes: 2 additions & 0 deletions tools/cgeist/Lib/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
43 changes: 43 additions & 0 deletions tools/cgeist/Test/HLS/AccessMemberArrayPartition.cpp
Original file line number Diff line number Diff line change
@@ -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"}

23 changes: 23 additions & 0 deletions tools/cgeist/Test/HLS/Allocation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//RUN: cgeist %s --function="*" -S --hls-annotate --raise-scf-to-affine --memref-fullrank| FileCheck %s

template <typename DT>
DT foo(DT a, DT b) {
return a + b;
}

// ------------------------------------------------------------
// Top-level function that calls foo<int> and foo<float>
// ------------------------------------------------------------
void top(int *out_int, float *out_float, int a, int b, float x, float y) {

#pragma HLS ALLOCATION function instances=foo<int> limit=1
#pragma HLS ALLOCATION function instances=foo<float> limit=1

int r1 = foo<int>(a, b);
float r2 = foo<float>(x, y);

*out_int = r1;
*out_float = r2;
}

// CHECK: hls.allocation = [{instances = "foo<int>", limit = 1 : i32, type = "function"}, {instances = "foo<float>", limit = 1 : i32, type = "function"}
12 changes: 12 additions & 0 deletions tools/cgeist/Test/HLS/BasicArrayPartition.cpp
Original file line number Diff line number Diff line change
@@ -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"}
11 changes: 11 additions & 0 deletions tools/cgeist/Test/HLS/BindOp.cpp
Original file line number Diff line number Diff line change
@@ -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"]}
23 changes: 23 additions & 0 deletions tools/cgeist/Test/HLS/BindStorage.cpp
Original file line number Diff line number Diff line change
@@ -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>
12 changes: 12 additions & 0 deletions tools/cgeist/Test/HLS/Pipeline.cpp
Original file line number Diff line number Diff line change
@@ -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"}]
13 changes: 13 additions & 0 deletions tools/cgeist/Test/HLS/Unroll.cpp
Original file line number Diff line number Diff line change
@@ -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}]}
8 changes: 8 additions & 0 deletions tools/cgeist/driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ int emitBinary(char *Argv0, const char *filename,
}

#include "Lib/clang-mlir.cc"
#include "Lib/HandleHLS.h"
#include "Lib/pragmaHandlerHLS.h"
#include "Lib/utils.h"
int main(int argc, char **argv) {

if (argc >= 1) {
Expand Down Expand Up @@ -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);
Expand Down
Loading