Skip to content

Commit 349a1e8

Browse files
committed
Closes #13
1 parent 40fe31f commit 349a1e8

File tree

4 files changed

+167
-3
lines changed

4 files changed

+167
-3
lines changed

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "llvm/Support/Format.h"
4848
#include "llvm/Support/Path.h"
4949
#include "llvm/Support/raw_ostream.h"
50+
#include "llvm/Transforms/IPO/MSVCMacroRebuilding.h"
5051
#include <algorithm>
5152
#include <cassert>
5253
#include <cstddef>
@@ -1581,9 +1582,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
15811582
//[MSVC Compalibility] Use file name and line to replace '__FUNCTION__'
15821583
#ifdef _WIN32
15831584
if (II == Ident__FUNCTION__) {
1584-
FN += "(Line:";
1585-
FN += Twine(PLoc.getLine()).str();
1586-
FN += ")";
1585+
SmallString<256> FNTemp =
1586+
llvm::MSVCMacroRebuildingPass::get__FUNCTION__MarkerName();
1587+
FNTemp += FN;
1588+
FNTemp += "(Line:";
1589+
FNTemp += Twine(PLoc.getLine()).str();
1590+
FNTemp += ")";
1591+
FN = FNTemp;
15871592
}
15881593
#endif
15891594
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef LLVM_MSVC_MACRO_REBUILDING_PASS_H
2+
#define LLVM_MSVC_MACRO_REBUILDING_PASS_H
3+
4+
#include "llvm/IR/PassManager.h"
5+
#include <string>
6+
7+
namespace llvm {
8+
// Forward declarations of classes used in the implementation of the pass.
9+
class raw_ostream;
10+
class Function;
11+
class Module;
12+
class GlobalVariable;
13+
class ConstantDataArray;
14+
class Pass;
15+
16+
class MSVCMacroRebuildingPass : public PassInfoMixin<MSVCMacroRebuildingPass> {
17+
18+
private:
19+
// Replace '__FUNCTION__'
20+
bool replace__FUNCTION__(GlobalVariable &GV, ConstantDataArray *CDA,
21+
StringRef FunctionName);
22+
23+
public:
24+
MSVCMacroRebuildingPass() {}
25+
26+
// Run the pass on the given module, and return the results as a set of
27+
// preserved analyses.
28+
PreservedAnalyses run(Module &M, AnalysisManager<Module> &);
29+
30+
// Check whether this pass is required for correctness. This should always
31+
// return true.
32+
static bool isRequired() { return true; }
33+
34+
// Return the name of marker for '__FUNCTION__'.
35+
static StringRef get__FUNCTION__MarkerName() {
36+
return "llvm_msvc__FUNCTION__E94550C93CD70FE748E6982B3439AD3B_";
37+
}
38+
};
39+
40+
} // namespace llvm
41+
#endif

llvm/lib/Transforms/IPO/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ add_llvm_component_library(LLVMipo
4343
ThinLTOBitcodeWriter.cpp
4444
WholeProgramDevirt.cpp
4545
WelComeToLLVMMSVC.cpp
46+
MSVCMacroRebuilding.cpp
4647

4748
ADDITIONAL_HEADER_DIRS
4849
${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include "llvm/Transforms/IPO/MSVCMacroRebuilding.h"
2+
#include "llvm/ADT/StringRef.h"
3+
#include "llvm/Analysis/ModuleSummaryAnalysis.h"
4+
#include "llvm/Demangle/Demangle.h"
5+
#include "llvm/IR/Function.h"
6+
#include "llvm/IR/IRBuilder.h"
7+
#include "llvm/IR/InlineAsm.h"
8+
#include "llvm/IR/Module.h"
9+
#include "llvm/IR/PrintPasses.h"
10+
#include "llvm/IRPrinter/IRAutoGeneratorPass.h"
11+
#include "llvm/Pass.h"
12+
#include "llvm/Support/Debug.h"
13+
#include "llvm/Support/FileSystem.h"
14+
#include "llvm/Support/Path.h"
15+
#include "llvm/Support/ToolOutputFile.h"
16+
#include "llvm/Support/raw_ostream.h"
17+
#include "llvm/Transforms/Utils/ModuleUtils.h"
18+
#include <fstream>
19+
#include <iostream>
20+
#include <regex>
21+
22+
using namespace llvm;
23+
24+
// Replace '__FUNCTION__'
25+
bool MSVCMacroRebuildingPass::replace__FUNCTION__(GlobalVariable &GV,
26+
ConstantDataArray *CDA,
27+
StringRef FunctionName) {
28+
// Construct the regular expression used to match the
29+
// macro marker and the file name with escaped backslashes and line number.
30+
static std::string RegexStr =
31+
MSVCMacroRebuildingPass::get__FUNCTION__MarkerName().str() +
32+
std::regex_replace(GV.getParent()->getSourceFileName(),
33+
std::regex("\\\\"), "\\\\") +
34+
"\\(Line:\\d+\\)";
35+
36+
// Get the original string value of the constant data array.
37+
std::string OriginalStr = CDA->getAsCString().str();
38+
// Replace the macro marker and file name in the original string with
39+
// the name of the function containing the instruction.
40+
std::string ReplacedStr =
41+
std::regex_replace(OriginalStr, std::regex(RegexStr), FunctionName.str());
42+
43+
// If the replaced string is the same as the original string, skip the
44+
// variable.
45+
if (ReplacedStr == OriginalStr)
46+
return false;
47+
48+
// Demangle the replaced string and extract the function name.
49+
std::string DemangledReplacedStr = demangle(ReplacedStr);
50+
size_t StartIndex = DemangledReplacedStr.find("(");
51+
if (StartIndex != std::string::npos) {
52+
size_t EndIndex = DemangledReplacedStr.rfind(" ", StartIndex);
53+
if (EndIndex != std::string::npos) {
54+
DemangledReplacedStr =
55+
DemangledReplacedStr.substr(EndIndex + 1, StartIndex - EndIndex - 1);
56+
}
57+
}
58+
59+
// Create a new constant data array containing the demangled function
60+
// name and set it as the initializer of the global variable.
61+
Constant *NewStr = ConstantDataArray::getString(GV.getParent()->getContext(),
62+
DemangledReplacedStr);
63+
GV.setInitializer(NewStr);
64+
65+
return true;
66+
}
67+
68+
// Implementation of the run() function for the MSVCMacroRebuildingPass
69+
// class
70+
PreservedAnalyses MSVCMacroRebuildingPass::run(Module &M,
71+
ModuleAnalysisManager &AM) {
72+
bool Changed = false;
73+
74+
// Iterate over all global variables in the input module.
75+
for (GlobalVariable &GV : M.globals()) {
76+
// Skip the variable if it does not have an initializer.
77+
if (!GV.hasInitializer())
78+
continue;
79+
80+
// Check if the initializer is a constant data array of strings.
81+
if (ConstantDataArray *CDA =
82+
dyn_cast<ConstantDataArray>(GV.getInitializer())) {
83+
if (!CDA->isString())
84+
continue;
85+
86+
// Iterate over all users of the global variable and check if it is an
87+
// instruction in a function.
88+
for (auto UserIt = GV.users().begin(); UserIt != GV.users().end();
89+
++UserIt) {
90+
if (Instruction *Inst = dyn_cast<Instruction>(*UserIt)) {
91+
if (!Inst->getParent())
92+
continue;
93+
94+
Function *F = Inst->getParent()->getParent();
95+
if (!F)
96+
continue;
97+
98+
// Replace '__FUNCTION__'
99+
Changed |= replace__FUNCTION__(GV, CDA, F->getName());
100+
}
101+
}
102+
}
103+
}
104+
105+
/**
106+
* This statement returns a PreservedAnalyses object based on whether there
107+
* were any changes during the pass execution. If `Changed` is true,
108+
* indicating that changes occurred, it returns
109+
* `llvm::PreservedAnalyses::none()`. This means that some analyses may not be
110+
* preserved and should be re-run as the pass has potentially invalidated
111+
* their results. If `Changed` is false, indicating that no changes occurred,
112+
* it returns `llvm::PreservedAnalyses::all()`. This means that all analyses
113+
* are preserved and their results are still valid after the pass execution.
114+
*/
115+
return (Changed ? llvm::PreservedAnalyses::none()
116+
: llvm::PreservedAnalyses::all());
117+
}

0 commit comments

Comments
 (0)