xref: /aosp_15_r20/external/swiftshader/src/Reactor/LLVMAsm.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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