Skip to content

Commit 903eeab

Browse files
[SYCLomaitc][User define migration rules] Add "!include" syntax for user defined migration rule, re-org predefined IPEX and PyTorch rules (#2654)
1 parent 082a959 commit 903eeab

18 files changed

Lines changed: 492 additions & 436 deletions

clang/lib/DPCT/UserDefinedRules/UserDefinedRules.cpp

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace clang {
2626
namespace dpct {
2727
std::vector<clang::tooling::UnifiedPath> MetaRuleObject::RuleFiles;
2828
std::vector<std::shared_ptr<MetaRuleObject>> MetaRules;
29+
llvm::DenseSet<llvm::StringRef> ProcessedYamlFiles;
2930

3031
OutputBuilder::~OutputBuilder() {}
3132

@@ -344,17 +345,147 @@ MetaRuleObject::PatternRewriter::PatternRewriter(
344345
Subrules = S;
345346
}
346347

348+
// Read a YAML file recursively and substitute any "!include <filename>"
349+
// directive with the contents of the referenced file.
350+
std::unique_ptr<llvm::MemoryBuffer>
351+
readYAMLFile(const llvm::StringRef &RuleFilePath) {
352+
// Check if the rule file has already been processed
353+
// to avoid infinite recursion
354+
if (!ProcessedYamlFiles.insert(RuleFilePath).second) {
355+
return llvm::MemoryBuffer::getMemBufferCopy("");
356+
}
357+
358+
// Load the rule file into a MemoryBuffer
359+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
360+
llvm::MemoryBuffer::getFile(RuleFilePath);
361+
if (!Buffer) {
362+
llvm::errs() << "Error: failed to read " << RuleFilePath << ": "
363+
<< Buffer.getError().message() << "\n";
364+
clang::dpct::ShowStatus(MigrationErrorInvalidRuleFilePath);
365+
dpctExit(MigrationErrorInvalidRuleFilePath);
366+
}
367+
368+
// Get the directory path of the rule file.
369+
llvm::SmallString<128> DirectoryPath(RuleFilePath);
370+
llvm::sys::path::remove_filename(DirectoryPath);
371+
372+
// Iterate over the input line by line.
373+
std::stringstream Output, IncRuleFilePath;
374+
const std::string IncDirective = "!include";
375+
376+
size_t Idx = 0;
377+
bool IncDirectiveFound = false;
378+
bool SkipWhiteSpaces = false;
379+
bool IsLineBeginning = true;
380+
381+
llvm::StringRef BuffContent = std::move(*Buffer)->getBuffer();
382+
const auto BuffSize = BuffContent.size();
383+
while (Idx < BuffSize) {
384+
unsigned char Ch = BuffContent[Idx];
385+
386+
// Skip white spaces at the beginning of the line if it contains a directive
387+
if (IsLineBeginning) {
388+
auto i = Idx;
389+
auto c = Ch;
390+
391+
// lookahead for "!" directive after white spaces
392+
for (; i < BuffContent.size(); i++) {
393+
c = BuffContent[i];
394+
395+
// Stop at new line or first non-white space character
396+
if (c == '\n' || !std::isspace(c)) {
397+
break;
398+
}
399+
}
400+
401+
// Check if the line starts with a directive
402+
if (c == '!') {
403+
// Move Idx to the beginning of directive
404+
Idx = i;
405+
406+
// Check if the directive is "!include"
407+
if (!IncDirectiveFound && Idx + IncDirective.length() <= BuffSize &&
408+
BuffContent.substr(Idx, IncDirective.length()) == IncDirective) {
409+
// Move Idx to the end of directive
410+
Idx += IncDirective.length();
411+
IncDirectiveFound = true;
412+
SkipWhiteSpaces = true;
413+
}
414+
415+
// Update current character
416+
Ch = BuffContent[Idx];
417+
}
418+
419+
IsLineBeginning = false;
420+
}
421+
422+
// Skip return carriage character
423+
if (Ch == '\r') {
424+
Idx++;
425+
continue;
426+
}
427+
428+
// Process IncRuleFilePath at end of the line
429+
if (Ch == '\n') {
430+
if (IncDirectiveFound) {
431+
auto IncRuleFilePathStr = IncRuleFilePath.str();
432+
433+
if (!IncRuleFilePathStr.empty()) {
434+
// Find the absolute path for the included rule file path
435+
llvm::SmallString<128> IncRuleFileAbsPath = DirectoryPath;
436+
llvm::sys::path::append(IncRuleFileAbsPath, IncRuleFilePathStr);
437+
438+
// Recursively process the included file
439+
if (llvm::sys::fs::exists(IncRuleFileAbsPath)) {
440+
Output << readYAMLFile(IncRuleFileAbsPath.str())->getBuffer().str();
441+
} else {
442+
Output << readYAMLFile(IncRuleFilePathStr)->getBuffer().str();
443+
}
444+
445+
// Clear the contents of include rule file path
446+
IncRuleFilePath.str("");
447+
}
448+
}
449+
450+
// Reset include directive info for each new line
451+
IncDirectiveFound = false;
452+
SkipWhiteSpaces = false;
453+
IsLineBeginning = true;
454+
}
455+
456+
if (IncDirectiveFound) {
457+
// Skip adding quotes to the include rule file path
458+
if (Ch == '"' || Ch == '\'') {
459+
Idx++;
460+
// Flip white space skip flag at the boundaries of quotes
461+
SkipWhiteSpaces = !SkipWhiteSpaces;
462+
continue;
463+
}
464+
465+
// Skip white space characters
466+
if (SkipWhiteSpaces && std::isspace(Ch)) {
467+
Idx++;
468+
continue;
469+
}
470+
471+
// Append the character to the include rule file path for !include line
472+
IncRuleFilePath << Ch;
473+
} else {
474+
// Append the character to the output buffer
475+
Output << Ch;
476+
}
477+
478+
Idx++;
479+
}
480+
481+
return llvm::MemoryBuffer::getMemBufferCopy(Output.str(), RuleFilePath);
482+
}
483+
347484
void importRules(std::vector<clang::tooling::UnifiedPath> &RuleFiles) {
348485
for (auto &RuleFile : RuleFiles) {
349486
// open the yaml file
350487
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
351-
llvm::MemoryBuffer::getFile(RuleFile.getCanonicalPath());
352-
if (!Buffer) {
353-
llvm::errs() << "Error: failed to read " << RuleFile << ": "
354-
<< Buffer.getError().message() << "\n";
355-
clang::dpct::ShowStatus(MigrationErrorInvalidRuleFilePath);
356-
dpctExit(MigrationErrorInvalidRuleFilePath);
357-
}
488+
readYAMLFile(RuleFile.getCanonicalPath());
358489

359490
// load rules
360491
std::vector<std::shared_ptr<MetaRuleObject>> CurrentRules;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import a_repl
2+
import b_repl
3+
4+
a_repl()
5+
b_repl()
6+
b1_repl()
7+
b2_repl()
8+
b3_repl()
9+
b4_repl()
10+
b5_repl()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: rm -rf %T && mkdir -p %T
2+
// RUN: cd %T
3+
// RUN: cp %S/input.py ./
4+
// RUN: cp %S/expected.py ./
5+
// RUN: cp -r %S/rules ./
6+
// RUN: echo "!include %T/rules/b/b5.yaml" >> %T/rules/python_build_script_migration_rule_inc.yaml
7+
8+
// RUN: dpct -in-root ./ --migrate-build-script-only --migrate-build-script=Python --rule-file=%T/rules/python_build_script_migration_rule_inc.yaml input.py
9+
// RUN: echo "begin" > %T/diff.txt
10+
// RUN: diff --strip-trailing-cr %S/expected.py %T/dpct_output/input.py >> %T/diff.txt
11+
// RUN: echo "end" >> %T/diff.txt
12+
// CHECK: begin
13+
// CHECK-NEXT: end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import a
2+
import b
3+
4+
a()
5+
b()
6+
b1()
7+
b2()
8+
b3()
9+
b4()
10+
b5()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_a
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_a
6+
In: a()
7+
Out: a_repl()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_b4
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_b4
6+
In: b4()
7+
Out: b4_repl()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_b
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_b
6+
In: b()
7+
Out: b_repl()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_b1
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_b1
6+
In: b1()
7+
Out: b1_repl()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_b2
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_b2
6+
In: b2()
7+
Out: b2_repl()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- Rule: rule_call_b3
2+
Kind: PythonRule
3+
Priority: Fallback
4+
MatchMode: Partial
5+
PythonSyntax: call_b3
6+
In: b3()
7+
Out: b3_repl()

0 commit comments

Comments
 (0)