1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2020 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "LLVMAsm.hpp"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #ifdef ENABLE_RR_EMIT_ASM_FILE
18*03ce13f7SAndroid Build Coastguard Worker
19*03ce13f7SAndroid Build Coastguard Worker # include "Debug.hpp"
20*03ce13f7SAndroid Build Coastguard Worker # include "llvm/IR/LegacyPassManager.h"
21*03ce13f7SAndroid Build Coastguard Worker # include "llvm/Support/FileSystem.h"
22*03ce13f7SAndroid Build Coastguard Worker # include <fstream>
23*03ce13f7SAndroid Build Coastguard Worker # include <iomanip>
24*03ce13f7SAndroid Build Coastguard Worker # include <regex>
25*03ce13f7SAndroid Build Coastguard Worker # include <sstream>
26*03ce13f7SAndroid Build Coastguard Worker
27*03ce13f7SAndroid Build Coastguard Worker namespace rr {
28*03ce13f7SAndroid Build Coastguard Worker namespace AsmFile {
29*03ce13f7SAndroid Build Coastguard Worker
generateFilename(const std::string & emitDir,std::string routineName)30*03ce13f7SAndroid Build Coastguard Worker std::string generateFilename(const std::string &emitDir, std::string routineName)
31*03ce13f7SAndroid Build Coastguard Worker {
32*03ce13f7SAndroid Build Coastguard Worker // Names from gtests sometimes have invalid file name characters
33*03ce13f7SAndroid Build Coastguard Worker std::replace(routineName.begin(), routineName.end(), '/', '_');
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Worker static size_t counter = 0;
36*03ce13f7SAndroid Build Coastguard Worker std::stringstream f;
37*03ce13f7SAndroid Build Coastguard Worker f << emitDir << "reactor_jit_llvm_" << std::setfill('0') << std::setw(4) << counter++ << "_" << routineName << ".asm";
38*03ce13f7SAndroid Build Coastguard Worker return f.str();
39*03ce13f7SAndroid Build Coastguard Worker }
40*03ce13f7SAndroid Build Coastguard Worker
emitAsmFile(const std::string & filename,llvm::orc::JITTargetMachineBuilder builder,llvm::Module & module)41*03ce13f7SAndroid Build Coastguard Worker bool emitAsmFile(const std::string &filename, llvm::orc::JITTargetMachineBuilder builder, llvm::Module &module)
42*03ce13f7SAndroid Build Coastguard Worker {
43*03ce13f7SAndroid Build Coastguard Worker auto targetMachine = builder.createTargetMachine();
44*03ce13f7SAndroid Build Coastguard Worker if(!targetMachine)
45*03ce13f7SAndroid Build Coastguard Worker return false;
46*03ce13f7SAndroid Build Coastguard Worker
47*03ce13f7SAndroid Build Coastguard Worker auto fileType = llvm::CGFT_AssemblyFile;
48*03ce13f7SAndroid Build Coastguard Worker std::error_code EC;
49*03ce13f7SAndroid Build Coastguard Worker llvm::raw_fd_ostream dest(filename, EC, llvm::sys::fs::OF_None);
50*03ce13f7SAndroid Build Coastguard Worker ASSERT(!EC);
51*03ce13f7SAndroid Build Coastguard Worker llvm::legacy::PassManager pm;
52*03ce13f7SAndroid Build Coastguard Worker auto &options = targetMachine.get()->Options.MCOptions;
53*03ce13f7SAndroid Build Coastguard Worker options.ShowMCEncoding = true;
54*03ce13f7SAndroid Build Coastguard Worker options.AsmVerbose = true;
55*03ce13f7SAndroid Build Coastguard Worker targetMachine.get()->addPassesToEmitFile(pm, dest, nullptr, fileType);
56*03ce13f7SAndroid Build Coastguard Worker pm.run(module);
57*03ce13f7SAndroid Build Coastguard Worker return true;
58*03ce13f7SAndroid Build Coastguard Worker }
59*03ce13f7SAndroid Build Coastguard Worker
fixupAsmFile(const std::string & filename,std::vector<const void * > addresses)60*03ce13f7SAndroid Build Coastguard Worker void fixupAsmFile(const std::string &filename, std::vector<const void *> addresses)
61*03ce13f7SAndroid Build Coastguard Worker {
62*03ce13f7SAndroid Build Coastguard Worker // Read input asm file into memory so we can overwrite it. This also allows us to merge multiline
63*03ce13f7SAndroid Build Coastguard Worker // comments into a single line for easier parsing below.
64*03ce13f7SAndroid Build Coastguard Worker std::vector<std::string> lines;
65*03ce13f7SAndroid Build Coastguard Worker {
66*03ce13f7SAndroid Build Coastguard Worker std::ifstream fin(filename);
67*03ce13f7SAndroid Build Coastguard Worker std::string line;
68*03ce13f7SAndroid Build Coastguard Worker while(std::getline(fin, line))
69*03ce13f7SAndroid Build Coastguard Worker {
70*03ce13f7SAndroid Build Coastguard Worker auto firstChar = [&] {
71*03ce13f7SAndroid Build Coastguard Worker auto index = line.find_first_not_of(" \t");
72*03ce13f7SAndroid Build Coastguard Worker if(index == std::string::npos)
73*03ce13f7SAndroid Build Coastguard Worker return '\n';
74*03ce13f7SAndroid Build Coastguard Worker return line[index];
75*03ce13f7SAndroid Build Coastguard Worker };
76*03ce13f7SAndroid Build Coastguard Worker
77*03ce13f7SAndroid Build Coastguard Worker if(!lines.empty() && firstChar() == '#')
78*03ce13f7SAndroid Build Coastguard Worker {
79*03ce13f7SAndroid Build Coastguard Worker lines.back() += line;
80*03ce13f7SAndroid Build Coastguard Worker }
81*03ce13f7SAndroid Build Coastguard Worker else
82*03ce13f7SAndroid Build Coastguard Worker {
83*03ce13f7SAndroid Build Coastguard Worker lines.push_back(line);
84*03ce13f7SAndroid Build Coastguard Worker }
85*03ce13f7SAndroid Build Coastguard Worker }
86*03ce13f7SAndroid Build Coastguard Worker }
87*03ce13f7SAndroid Build Coastguard Worker
88*03ce13f7SAndroid Build Coastguard Worker std::ofstream fout(filename);
89*03ce13f7SAndroid Build Coastguard Worker
90*03ce13f7SAndroid Build Coastguard Worker // Output function table
91*03ce13f7SAndroid Build Coastguard Worker fout << "\nFunction Addresses:\n";
92*03ce13f7SAndroid Build Coastguard Worker for(size_t i = 0; i < addresses.size(); i++)
93*03ce13f7SAndroid Build Coastguard Worker {
94*03ce13f7SAndroid Build Coastguard Worker fout << "f" << i << ": " << addresses[i] << "\n";
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker fout << "\n";
97*03ce13f7SAndroid Build Coastguard Worker
98*03ce13f7SAndroid Build Coastguard Worker size_t functionIndex = ~0;
99*03ce13f7SAndroid Build Coastguard Worker size_t instructionAddress = 0;
100*03ce13f7SAndroid Build Coastguard Worker
101*03ce13f7SAndroid Build Coastguard Worker for(auto &line : lines)
102*03ce13f7SAndroid Build Coastguard Worker {
103*03ce13f7SAndroid Build Coastguard Worker size_t pos{};
104*03ce13f7SAndroid Build Coastguard Worker
105*03ce13f7SAndroid Build Coastguard Worker if(line.find("# -- Begin function") != std::string::npos)
106*03ce13f7SAndroid Build Coastguard Worker {
107*03ce13f7SAndroid Build Coastguard Worker ++functionIndex;
108*03ce13f7SAndroid Build Coastguard Worker
109*03ce13f7SAndroid Build Coastguard Worker if(functionIndex < addresses.size())
110*03ce13f7SAndroid Build Coastguard Worker {
111*03ce13f7SAndroid Build Coastguard Worker instructionAddress = (size_t)addresses[functionIndex];
112*03ce13f7SAndroid Build Coastguard Worker }
113*03ce13f7SAndroid Build Coastguard Worker else
114*03ce13f7SAndroid Build Coastguard Worker {
115*03ce13f7SAndroid Build Coastguard Worker // For coroutines, more functions are compiled than the top-level three.
116*03ce13f7SAndroid Build Coastguard Worker // For now, just output 0-based instructions.
117*03ce13f7SAndroid Build Coastguard Worker instructionAddress = 0;
118*03ce13f7SAndroid Build Coastguard Worker }
119*03ce13f7SAndroid Build Coastguard Worker }
120*03ce13f7SAndroid Build Coastguard Worker
121*03ce13f7SAndroid Build Coastguard Worker // Handle alignment directives by aligning the instruction address. When lowered, these actually
122*03ce13f7SAndroid Build Coastguard Worker // map to a nops to pad to the next aligned address.
123*03ce13f7SAndroid Build Coastguard Worker pos = line.find(".p2align");
124*03ce13f7SAndroid Build Coastguard Worker if(pos != std::string::npos)
125*03ce13f7SAndroid Build Coastguard Worker {
126*03ce13f7SAndroid Build Coastguard Worker // This assumes GNU asm format (https://sourceware.org/binutils/docs/as/P2align.html#P2align)
127*03ce13f7SAndroid Build Coastguard Worker static std::regex reAlign(R"(.*\.p2align.*([0-9]+).*)");
128*03ce13f7SAndroid Build Coastguard Worker std::smatch matches;
129*03ce13f7SAndroid Build Coastguard Worker auto found = std::regex_search(line, matches, reAlign);
130*03ce13f7SAndroid Build Coastguard Worker ASSERT(found);
131*03ce13f7SAndroid Build Coastguard Worker auto alignPow2 = std::stoi(matches[1]);
132*03ce13f7SAndroid Build Coastguard Worker auto align = 1 << alignPow2;
133*03ce13f7SAndroid Build Coastguard Worker instructionAddress = (instructionAddress + align - 1) & ~(align - 1);
134*03ce13f7SAndroid Build Coastguard Worker }
135*03ce13f7SAndroid Build Coastguard Worker
136*03ce13f7SAndroid Build Coastguard Worker // Detect instruction lines and prepend the location (address)
137*03ce13f7SAndroid Build Coastguard Worker pos = line.find("encoding: [");
138*03ce13f7SAndroid Build Coastguard Worker if(pos != std::string::npos)
139*03ce13f7SAndroid Build Coastguard Worker {
140*03ce13f7SAndroid Build Coastguard Worker // Determine offset of next instruction (size of this instruction in bytes)
141*03ce13f7SAndroid Build Coastguard Worker // e.g. # encoding: [0x48,0x89,0x4c,0x24,0x40]
142*03ce13f7SAndroid Build Coastguard Worker // Count number of commas in the array + 1
143*03ce13f7SAndroid Build Coastguard Worker auto endPos = line.find("]", pos);
144*03ce13f7SAndroid Build Coastguard Worker auto instructionSize = 1 + std::count_if(line.begin() + pos, line.begin() + endPos, [](char c) { return c == ','; });
145*03ce13f7SAndroid Build Coastguard Worker
146*03ce13f7SAndroid Build Coastguard Worker // Prepend current location to instruction line
147*03ce13f7SAndroid Build Coastguard Worker std::stringstream location;
148*03ce13f7SAndroid Build Coastguard Worker location << "[0x" << std::uppercase << std::hex << instructionAddress << "] ";
149*03ce13f7SAndroid Build Coastguard Worker line = location.str() + line;
150*03ce13f7SAndroid Build Coastguard Worker
151*03ce13f7SAndroid Build Coastguard Worker instructionAddress += instructionSize;
152*03ce13f7SAndroid Build Coastguard Worker }
153*03ce13f7SAndroid Build Coastguard Worker
154*03ce13f7SAndroid Build Coastguard Worker fout << line + "\n";
155*03ce13f7SAndroid Build Coastguard Worker }
156*03ce13f7SAndroid Build Coastguard Worker }
157*03ce13f7SAndroid Build Coastguard Worker
158*03ce13f7SAndroid Build Coastguard Worker } // namespace AsmFile
159*03ce13f7SAndroid Build Coastguard Worker } // namespace rr
160*03ce13f7SAndroid Build Coastguard Worker
161*03ce13f7SAndroid Build Coastguard Worker #endif // ENABLE_RR_EMIT_ASM_FILE
162