Skip to content

Commit

Permalink
Add built-in function call intrinsics for loop directives.
Browse files Browse the repository at this point in the history
These work as an alternative to #pragmas which can be used in templated code or with other constexprs. For example:

template<int N>
struct Thing {
    void doit() {
        __xlscc_pipeline(N);
        for (int i=0;i<128;++i) {
        }
    }
};

PiperOrigin-RevId: 553981491
  • Loading branch information
Sean Purser-Haskell authored and copybara-github committed Aug 5, 2023
1 parent 7531ba9 commit 6bfeb74
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 32 deletions.
1 change: 1 addition & 0 deletions xls/contrib/xlscc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ cc_library(
"//xls/ir:source_location",
"@com_github_google_re2//:re2",
"@llvm-project//clang:ast",
"@llvm-project//clang:basic",
"@llvm-project//clang:frontend",
"@llvm-project//clang:tooling",
],
Expand Down
24 changes: 17 additions & 7 deletions xls/contrib/xlscc/cc_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "absl/synchronization/blocking_counter.h"
#include "clang/include/clang/AST/Decl.h"
#include "clang/include/clang/AST/RecursiveASTVisitor.h"
#include "clang/include/clang/Basic/SourceLocation.h"
#include "clang/include/clang/Frontend/CompilerInstance.h"
#include "clang/include/clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/include/clang/Tooling/Tooling.h"
Expand Down Expand Up @@ -205,23 +206,26 @@ xls::SourceInfo CCParser::GetLoc(const clang::PresumedLoc& loc) {
}

absl::StatusOr<Pragma> CCParser::FindPragmaForLoc(
const clang::SourceLocation& loc) {
return FindPragmaForLoc(sm_->getPresumedLoc(loc));
const clang::SourceLocation& loc, bool ignore_label) {
return FindPragmaForLoc(sm_->getPresumedLoc(loc), ignore_label);
}

absl::StatusOr<Pragma> CCParser::FindPragmaForLoc(
const clang::PresumedLoc& ploc) {
const clang::PresumedLoc& ploc, bool ignore_label) {
// NOTE: Semantics should be the same as Translator::FindIntrinsicCall()!
if (!files_scanned_for_pragmas_.contains(ploc.getFilename())) {
XLS_RETURN_IF_ERROR(ScanFileForPragmas(ploc.getFilename()));
}
// Look on the line before.
PragmaLoc loc(ploc.getFilename(), ploc.getLine() - 1);

if (!hls_pragmas_.contains(loc)) {
return Pragma(Pragma_Null);
}

// Look for a label there. If found, look at the line before that.
if (hls_pragmas_.at(loc).type() == Pragma_Label && std::get<1>(loc) > 0) {
if (ignore_label && hls_pragmas_.at(loc).type() == Pragma_Label &&
std::get<1>(loc) > 0) {
loc = PragmaLoc(ploc.getFilename(), ploc.getLine() - 2);
if (!hls_pragmas_.contains(loc)) {
return Pragma(Pragma_Null);
Expand Down Expand Up @@ -424,8 +428,9 @@ absl::Status CCParser::VisitFunction(const clang::FunctionDecl* funcdecl) {
return absl::OkStatus();
}

XLS_ASSIGN_OR_RETURN(Pragma pragma,
FindPragmaForLoc(GetPresumedLoc(*funcdecl)));
XLS_ASSIGN_OR_RETURN(
Pragma pragma,
FindPragmaForLoc(GetPresumedLoc(*funcdecl), /*ignore_label=*/true));

if (pragma.type() == Pragma_Top || fname == top_function_name_) {
if (top_function_ == nullptr) {
Expand Down Expand Up @@ -547,6 +552,8 @@ class __xls_channel {
template<typename T, unsigned long long Size>
class __xls_memory {
public:
static constexpr unsigned long long size = Size;
T& operator[](long long int addr) {
static T ret;
return ret;
Expand Down Expand Up @@ -577,6 +584,10 @@ bool __xlscc_on_reset = false;
__xls_bits<64> __xlscc_fixed_32_32_bits_for_double(double input);
__xls_bits<64> __xlscc_fixed_32_32_bits_for_float(float input);
// For use with loops
void __xlscc_pipeline(long long factor) { }
void __xlscc_unroll(long long factor) { }
#endif//__XLS_BUILTIN_H
)"));

Expand All @@ -595,7 +606,6 @@ void __xlscc_top_class_instance_ref() {
void __xlscc_top_class_instance_ref2() {
__xlscc_top_class_instance_ref();
}
} // namespace
)",
top_class_name_);
Expand Down
6 changes: 4 additions & 2 deletions xls/contrib/xlscc/cc_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ class CCParser {

void AddSourceInfoToMetadata(xlscc_metadata::MetadataOutput& output);
void AddSourceInfoToPackage(xls::Package& package);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::SourceLocation& loc);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::PresumedLoc& ploc);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::SourceLocation& loc,
bool ignore_label);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::PresumedLoc& ploc,
bool ignore_label);

xls::SourceInfo GetLoc(const clang::Stmt& stmt);
clang::PresumedLoc GetPresumedLoc(const clang::Stmt& stmt);
Expand Down
67 changes: 62 additions & 5 deletions xls/contrib/xlscc/translate_loops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "clang/include/clang/AST/Decl.h"
#include "clang/include/clang/AST/Expr.h"
#include "xls/common/logging/logging.h"
#include "xls/common/status/status_macros.h"
#include "xls/contrib/xlscc/cc_parser.h"
#include "xls/contrib/xlscc/translator.h"
#include "xls/contrib/xlscc/xlscc_logging.h"
#include "xls/ir/bits.h"
Expand Down Expand Up @@ -61,23 +63,78 @@ absl::Status Translator::GenerateIR_Loop(
return absl::OkStatus();
}
}

bool have_relevant_intrinsic = false;
bool intrinsic_unroll = false;

XLS_ASSIGN_OR_RETURN(const clang::CallExpr* intrinsic_call,
FindIntrinsicCall(presumed_loc));
if (intrinsic_call != nullptr) {
const std::string& intrinsic_name =
intrinsic_call->getDirectCallee()->getNameAsString();

if (intrinsic_name == "__xlscc_pipeline") {
have_relevant_intrinsic = true;
intrinsic_unroll = false;
} else if (intrinsic_name == "__xlscc_unroll") {
have_relevant_intrinsic = true;
intrinsic_unroll = true;
}
}

XLS_ASSIGN_OR_RETURN(Pragma pragma, FindPragmaForLoc(presumed_loc));
if (pragma.type() == Pragma_Unroll || context().for_loops_default_unroll) {

bool have_relevant_pragma =
(pragma.type() == Pragma_Unroll || pragma.type() == Pragma_InitInterval);

if (have_relevant_intrinsic && have_relevant_pragma) {
return absl::InvalidArgumentError(
ErrorMessage(loc,
"Have both an __xlscc_ intrinsic and a #pragma directive, "
"don't know what to do"));
}

bool do_unroll = false;

if ((have_relevant_intrinsic && intrinsic_unroll) ||
(pragma.type() == Pragma_Unroll) || context().for_loops_default_unroll) {
do_unroll = true;
}

if (do_unroll) {
return GenerateIR_UnrolledLoop(always_first_iter, init, cond_expr, inc,
body, ctx, loc);
}

int64_t init_interval = -1;

if (have_relevant_intrinsic) {
XLSCC_CHECK(!intrinsic_unroll, loc);
XLSCC_CHECK_EQ(intrinsic_call->getNumArgs(), 1, loc);
XLS_ASSIGN_OR_RETURN(init_interval,
EvaluateInt64(*intrinsic_call->getArg(0), ctx, loc));
} else if (have_relevant_pragma) {
XLSCC_CHECK(pragma.type() == Pragma_InitInterval, loc);
init_interval = pragma.int_argument();
}

if (have_relevant_intrinsic || have_relevant_pragma) {
if (init_interval <= 0) {
return absl::InvalidArgumentError(
ErrorMessage(loc, "Invalid initiation interval %i", init_interval));
}
}

// Pipelined loops can inherit their initiation interval from enclosing
// loops, so they can be allowed not to have a #pragma.
int init_interval = pragma.int_argument();
// Pragma might not be null, because labels get searched backwards
if (pragma.type() != Pragma_InitInterval) {
if (init_interval < 0) {
XLS_CHECK(!context().in_pipelined_for_body ||
(context().outer_pipelined_loop_init_interval > 0));
init_interval = context().outer_pipelined_loop_init_interval;
}
if (init_interval <= 0) {
return absl::UnimplementedError(
ErrorMessage(loc, "For loop missing #pragma"));
ErrorMessage(loc, "For loop missing #pragma or __xlscc_ intrinsic"));
}

// Pipelined do-while
Expand Down
62 changes: 58 additions & 4 deletions xls/contrib/xlscc/translator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2741,6 +2741,13 @@ absl::StatusOr<std::pair<bool, CValue>> Translator::GenerateIR_BuiltInCall(
return absl::UnimplementedError(ErrorMessage(loc, "Unimplemented marker"));
}

if (funcdecl->getNameAsString() == "__xlscc_pipeline" ||
funcdecl->getNameAsString() == "__xlscc_unroll" ||
funcdecl->getNameAsString() == "__xlscc_asap") {
context().last_intrinsic_call = call;
return std::make_pair(true, CValue());
}

if (funcdecl->getNameAsString() == "__xlscc_fixed_32_32_bits_for_double" ||
funcdecl->getNameAsString() == "__xlscc_fixed_32_32_bits_for_float") {
XLSCC_CHECK_EQ(call->getNumArgs(), 1, loc);
Expand Down Expand Up @@ -5916,16 +5923,63 @@ clang::PresumedLoc Translator::GetPresumedLoc(const clang::Decl& decl) {
return parser_->GetPresumedLoc(decl);
}

absl::StatusOr<const clang::CallExpr*> Translator::FindIntrinsicCall(
const clang::PresumedLoc& target_loc) {
// NOTE: Semantics should be the same as CCParser::FindPragmaForLoc()!

xls::SourceInfo xls_loc = parser_->GetLoc(target_loc);

const clang::CallExpr* ret = context().last_intrinsic_call;

// No intrinsics yet in this scope
if (ret == nullptr) {
return nullptr;
}

const clang::PresumedLoc intrinsic_loc = GetPresumedLoc(*ret);

// Not in the same file at all (macros?)

if (target_loc.getFilename() != intrinsic_loc.getFilename()) {
return absl::UnimplementedError(ErrorMessage(
xls_loc, "Intrinsic call in this scope, but in another file (macro?)"));
}

XLSCC_CHECK_GE(target_loc.getLine(), intrinsic_loc.getLine(), xls_loc);

// Does not apply if more than 2 lines behind
if (target_loc.getLine() > (intrinsic_loc.getLine() + 2)) {
return nullptr;
}

// Applies if it's the same line or the one before
if (target_loc.getLine() <= (intrinsic_loc.getLine() + 1)) {
return ret;
}

XLSCC_CHECK_GE(target_loc.getLine(), intrinsic_loc.getLine() + 2, xls_loc);

// Must be a label in between if it's two lines before
XLS_ASSIGN_OR_RETURN(Pragma pragma_before,
FindPragmaForLoc(target_loc, /*ignore_label=*/false));

if (pragma_before.type() != PragmaType::Pragma_Label) {
return nullptr;
}

return ret;
}

absl::StatusOr<Pragma> Translator::FindPragmaForLoc(
const clang::SourceLocation& loc) {
const clang::SourceLocation& loc, bool ignore_label) {
XLS_CHECK_NE(parser_.get(), nullptr);
return parser_->FindPragmaForLoc(loc);
return parser_->FindPragmaForLoc(loc, ignore_label);
}

absl::StatusOr<Pragma> Translator::FindPragmaForLoc(
const clang::PresumedLoc& ploc) {
const clang::PresumedLoc& ploc, bool ignore_label) {
XLS_CHECK_NE(parser_.get(), nullptr);
return parser_->FindPragmaForLoc(ploc);
return parser_->FindPragmaForLoc(ploc, ignore_label);
}

} // namespace xlscc
13 changes: 11 additions & 2 deletions xls/contrib/xlscc/translator.h
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,8 @@ struct TranslationContext {

bool mask_io_other_than_memory_writes = false;
bool mask_memory_writes = false;

const clang::CallExpr* last_intrinsic_call = nullptr;
};

std::string Debug_VariablesChangedBetween(const TranslationContext& before,
Expand Down Expand Up @@ -1959,9 +1961,16 @@ class Translator {

std::unique_ptr<CCParser> parser_;

// Uses context's last_intrinsic_call
// Returns nullptr if no applicable intrinsic call is found
absl::StatusOr<const clang::CallExpr*> FindIntrinsicCall(
const clang::PresumedLoc& target_loc);

// Convenience calls to CCParser
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::SourceLocation& loc);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::PresumedLoc& ploc);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::SourceLocation& loc,
bool ignore_label = true);
absl::StatusOr<Pragma> FindPragmaForLoc(const clang::PresumedLoc& ploc,
bool ignore_label = true);
std::string LocString(const xls::SourceInfo& loc);
xls::SourceInfo GetLoc(const clang::Stmt& stmt);
xls::SourceInfo GetLoc(const clang::Decl& decl);
Expand Down
3 changes: 1 addition & 2 deletions xls/contrib/xlscc/unit_tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,10 @@ cc_test(
":unit_test",
"//xls/common:xls_gunit",
"//xls/common:xls_gunit_main",
"//xls/common/file:temp_file",
"//xls/common/status:matchers",
"//xls/contrib/xlscc:cc_parser",
"//xls/contrib/xlscc:metadata_output_cc_proto",
"//xls/ir:ir_test_base",
"@llvm-project//clang:basic",
],
)

Expand Down
Loading

0 comments on commit 6bfeb74

Please sign in to comment.