Skip to content

Commit

Permalink
Support for disabling pragmas using the preprocessor, for example via
Browse files Browse the repository at this point in the history
#ifdef, and for finding source locations for _Pragma in #defines.

- This doesn't work on #pragma hls_unroll etc yet since CCParser doesn't
look past the #endif line
- This should enable putting _Pragma defines in a header using SourceManager's getFileLoc() to find the source line
- It is unknown how to get macro parameters passed into the _Pragma, as the preprocessed text is unavailable
  - Channel strictness can use a variety of specialized macro names.
  - Use cases needing numeric parameters such as unroll and pipeline_init_interval, intrinsics can be used in the macros, ie __xlscc_pipeline, __xlscc_unroll

PiperOrigin-RevId: 643053861
  • Loading branch information
Sean Purser-Haskell authored and copybara-github committed Jun 13, 2024
1 parent 72da329 commit 0c7892c
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 41 deletions.
65 changes: 58 additions & 7 deletions xls/contrib/xlscc/cc_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ namespace xlscc {

class LibToolVisitor : public clang::RecursiveASTVisitor<LibToolVisitor> {
public:
explicit LibToolVisitor(clang::CompilerInstance& CI, CCParser& translator)
: ast_context_(&(CI.getASTContext())), parser_(translator) {}
explicit LibToolVisitor(clang::CompilerInstance& CI, CCParser& parser)
: ast_context_(&(CI.getASTContext())), parser_(parser) {}
virtual ~LibToolVisitor() = default;
virtual bool VisitVarDecl(clang::VarDecl* decl) {
return parser_.LibToolVisitVarDecl(decl);
Expand All @@ -85,10 +85,39 @@ class LibToolVisitor : public clang::RecursiveASTVisitor<LibToolVisitor> {
clang::ASTContext* ast_context_;
CCParser& parser_;
};

class LibToolPPCallback : public clang::PPCallbacks {
public:
LibToolPPCallback(clang::CompilerInstance* pCI, CCParser& parser)
: pCI_(pCI), parser_(parser) {}

// Callback invoked when starting to read any pragma directive.
void PragmaDirective(clang::SourceLocation Loc,
clang::PragmaIntroducerKind Introducer) override {
clang::SourceLocation spelling_loc =
pCI_->getSourceManager().getSpellingLoc(Loc);

const clang::PresumedLoc presumed_spelling_loc =
pCI_->getSourceManager().getPresumedLoc(spelling_loc);

clang::SourceLocation file_loc =
pCI_->getSourceManager().getSpellingLoc(Loc);

const clang::PresumedLoc presumed_file_loc =
pCI_->getSourceManager().getPresumedLoc(file_loc);

parser_.PreprocessorPragmaCallback(presumed_spelling_loc,
presumed_file_loc);
}

clang::CompilerInstance* pCI_ = nullptr;
CCParser& parser_;
};

class LibToolASTConsumer : public clang::ASTConsumer {
public:
explicit LibToolASTConsumer(clang::CompilerInstance& CI, CCParser& translator)
: visitor_(new LibToolVisitor(CI, translator)) {}
explicit LibToolASTConsumer(clang::CompilerInstance& CI, CCParser& parser)
: visitor_(new LibToolVisitor(CI, parser)) {}

void HandleTranslationUnit(clang::ASTContext& Context) override {
visitor_->TraverseDecl(Context.getTranslationUnitDecl());
Expand All @@ -99,16 +128,23 @@ class LibToolASTConsumer : public clang::ASTConsumer {
};
class LibToolFrontendAction : public clang::ASTFrontendAction {
public:
explicit LibToolFrontendAction(CCParser& translator) : parser_(translator) {}
explicit LibToolFrontendAction(CCParser& parser) : parser_(parser) {}
void EndSourceFileAction() override;
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance& CI, clang::StringRef /*file*/) override {
pCI_ = &CI;
return std::unique_ptr<clang::ASTConsumer>(
new LibToolASTConsumer(CI, parser_));
}
void ExecuteAction() override {
getCompilerInstance().getPreprocessor().addPPCallbacks(
std::make_unique<LibToolPPCallback>(pCI_, parser_));
clang::ASTFrontendAction::ExecuteAction();
}

private:
CCParser& parser_;
clang::CompilerInstance* pCI_ = nullptr;
};
class DiagnosticInterceptor : public clang::TextDiagnosticPrinter {
public:
Expand Down Expand Up @@ -271,6 +307,7 @@ absl::StatusOr<Pragma> CCParser::FindPragmaForLoc(
return Pragma(Pragma_Null);
}
}

return hls_pragmas_.at(loc);
}

Expand Down Expand Up @@ -314,6 +351,13 @@ std::optional<PragmaLine> ExtractPragma(std::string_view line) {
}
} // namespace

void CCParser::PreprocessorPragmaCallback(
const clang::PresumedLoc& spelling_loc,
const clang::PresumedLoc& file_loc) {
pragma_locations_seen_by_preprocessor_.insert(
PragmaLoc(spelling_loc.getFilename(), spelling_loc.getLine()));
}

absl::Status CCParser::ScanFileForPragmas(std::string_view filename) {
std::ifstream fin(std::string(filename).c_str());
if (!fin.good()) {
Expand Down Expand Up @@ -356,6 +400,15 @@ absl::Status CCParser::ScanFileForPragmas(std::string_view filename) {
std::map<std::string, PragmaType>::iterator it =
pragmas.find(absl::AsciiStrToLower(name));
if (it != pragmas.end()) {
PragmaType pragma_val = it->second;
const PragmaLoc location(filename, lineno);
// Check that the preprocessor actually saw the pragmas (not #ifdef'd
// away) #ifdef'ing labels isn't supported
if (!pragma_locations_seen_by_preprocessor_.contains(location) &&
pragma_val != Pragma_Label) {
continue;
}

if (name != absl::AsciiStrToLower(name)) {
LOG(WARNING) << "#pragma must be lowercase: " << line;
continue;
Expand All @@ -376,9 +429,7 @@ absl::Status CCParser::ScanFileForPragmas(std::string_view filename) {
",")
<< "' that will be ignored";
}
const PragmaLoc location(filename, lineno);
prev_location = location;
PragmaType pragma_val = it->second;
int64_t arg = -1;
std::string_view params =
pragma_line->args.empty() ? "" : pragma_line->args.front();
Expand Down
6 changes: 6 additions & 0 deletions xls/contrib/xlscc/cc_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "absl/synchronization/blocking_counter.h"
#include "absl/types/span.h"
#include "clang/include/clang/AST/Decl.h"
#include "clang/include/clang/Basic/SourceLocation.h"
#include "xls/common/thread.h"
#include "xls/contrib/xlscc/metadata_output.pb.h"
#include "xls/ir/package.h"
Expand Down Expand Up @@ -70,6 +71,7 @@ class CCParser;
class LibToolVisitor;
class DiagnosticInterceptor;
class LibToolFrontendAction;
class LibToolPPCallback;

// Needs to be here because std::unique uses sizeof()
class LibToolThread {
Expand Down Expand Up @@ -97,6 +99,7 @@ class CCParser {
friend class LibToolVisitor;
friend class DiagnosticInterceptor;
friend class LibToolFrontendAction;
friend class LibToolPPCallback;

public:
// Deletes the AST
Expand Down Expand Up @@ -165,10 +168,13 @@ class CCParser {
absl::Status VisitFunction(const clang::FunctionDecl* funcdecl);
absl::Status VisitVarDecl(const clang::VarDecl* funcdecl);
absl::Status ScanFileForPragmas(std::string_view filename);
void PreprocessorPragmaCallback(const clang::PresumedLoc& spelling_loc,
const clang::PresumedLoc& file_loc);

using PragmaLoc = std::tuple<std::string, int>;
absl::flat_hash_map<PragmaLoc, Pragma> hls_pragmas_;
absl::flat_hash_set<std::string> files_scanned_for_pragmas_;
absl::flat_hash_set<PragmaLoc> pragma_locations_seen_by_preprocessor_;

const clang::FunctionDecl* top_function_ = nullptr;
std::string_view top_function_name_ = "";
Expand Down
Loading

0 comments on commit 0c7892c

Please sign in to comment.