38 static std::vector<std::string>
opt_core_lines(
const std::vector<std::string> &lines) {
39 std::regex re_mov_reg(R
"(^\s*mov[bwlq]?\s+(%[a-z0-9]+)\s*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
40 std::regex re_mem_to_reg(R"(^\s*mov[bwlq]?\s+([A-Za-z0-9_]+(?:\(%rip\))?)\s*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
41 std::regex re_reg_to_mem(R"(^\s*mov[bwlq]?\s+(%[a-z0-9]+)\s*,\s*([A-Za-z0-9_]+(?:\(%rip\))?)\s*(?:[#;].*)?$)", std::regex::icase);
42 std::regex re_modifies_reg(R"(^\s*(?:add|sub|mul|imul|div|idiv|and|or|xor|shl|shr|sal|sar|not|neg)[a-z]*\s+.*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
43 std::regex re_call_or_jmp(R"(^\s*(?:call|jmp|je|jne|jz|jnz|jg|jge|jl|jle|ja|jae|jb|jbe)[a-z]*\s+)", std::regex::icase);
44 std::regex re_xor_eax(R"(^\s*xorq?\s+%eax\s*,\s*%eax\s*(?:[#;].*)?$)", std::regex::icase);
45 std::regex re_call_func(R"(^\s*call\s+([_A-Za-z][_A-Za-z0-9]*)\s*(?:[#;].*)?$)", std::regex::icase);
46 static const std::unordered_set<std::string> variadic_funcs = {
47 "printf",
"fprintf",
"sprintf",
"snprintf",
"scanf",
"fscanf",
"sscanf",
48 "vprintf",
"vfprintf",
"vsprintf",
"vsnprintf",
"vscanf",
"vfscanf",
"vsscanf"};
49 std::vector<std::string> out;
50 out.reserve(lines.size());
55 std::unordered_map<std::string, ValueInfo> reg_contents;
56 std::unordered_map<std::string, ValueInfo> mem_contents;
57 auto invalidate_tracking = [&]() {
61 auto clobber_reg = [&](
const std::string ®) {
62 reg_contents.erase(reg);
63 for (
auto it = mem_contents.begin(); it != mem_contents.end();) {
64 if (it->second.location == reg)
65 it = mem_contents.erase(it);
70 for (
size_t i = 0; i < lines.size(); ++i) {
71 const std::string &line = lines[i];
73 if (std::regex_match(line, re_xor_eax) && (i + 1 < lines.size())) {
75 if (std::regex_match(lines[i + 1], m, re_call_func)) {
76 std::string func_name = m[1].str();
77 if (variadic_funcs.find(func_name) == variadic_funcs.end()) {
82 if (
is_label(line) || std::regex_search(line, re_call_or_jmp)) {
84 invalidate_tracking();
90 if (std::regex_match(line, m, re_modifies_reg)) {
91 clobber_reg(m[1].str());
99 if (std::regex_match(line, m, re_mem_to_reg)) {
100 const std::string mem = m[1].str();
101 const std::string reg = m[2].str();
105 auto it = mem_contents.find(mem);
106 if (it != mem_contents.end() && it->second.valid) {
107 const std::string &src_reg = it->second.location;
109 out.push_back(
"\tmovq " + src_reg +
", " + reg);
110 reg_contents[reg] = {mem,
true};
115 reg_contents[reg] = {mem,
true};
122 if (std::regex_match(line, m, re_reg_to_mem)) {
123 const std::string reg = m[1].str();
124 const std::string mem = m[2].str();
125 mem_contents[mem] = {reg,
true};
133 if (std::regex_match(line, m, re_mov_reg)) {
134 const std::string src = m[1].str();
135 const std::string dst = m[2].str();
141 auto it_src = reg_contents.find(src);
142 if (it_src != reg_contents.end())
143 reg_contents[dst] = it_src->second;
145 reg_contents[dst] = {src,
true};
152 invalidate_tracking();
160 std::regex re_mov_reg(R
"(^\s*movq?\s+(%[a-z0-9]+)\s*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
161 std::regex re_mem_to_reg(R"(^\s*movq?\s+([A-Za-z0-9_]+(?:\(%rip\))?)\s*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
162 std::regex re_reg_to_mem(R"(^\s*movq?\s+(%[a-z0-9]+)\s*,\s*([A-Za-z0-9_]+(?:\(%rip\))?)\s*(?:[#;].*)?$)", std::regex::icase);
163 std::regex re_modifies_reg(R"(^\s*(?:add|sub|mul|imul|div|idiv|and|or|xor|shl|shr|sal|sar|not|neg)[a-z]*\s+.*,\s*(%[a-z0-9]+)\s*(?:[#;].*)?$)", std::regex::icase);
164 std::regex re_call_or_jmp(R"(^\s*(?:call|jmp|je|jne|jz|jnz|jg|jge|jl|jle|ja|jae|jb|jbe)[a-z]*\s+)", std::regex::icase);
166 std::regex re_xor_eax(R"(^\s*xorq?\s+%eax\s*,\s*%eax\s*(?:[#;].*)?$)", std::regex::icase);
167 std::regex re_call_func(R"(^\s*call\s+([_A-Za-z][_A-ZaZ0-9]*)\s*(?:[#;].*)?$)", std::regex::icase);
168 static const std::unordered_set<std::string> variadic_funcs = {
169 "printf",
"fprintf",
"sprintf",
"snprintf",
"scanf",
"fscanf",
"sscanf",
170 "vprintf",
"vfprintf",
"vsprintf",
"vsnprintf",
"vscanf",
"vfscanf",
"vsscanf"};
171 auto local_is_label = [](
const std::string &s) {
172 static const std::regex re(R
"(^\s*(?:[A-Za-z_.$][\w.$]*|\d+)\s*:)");
173 return std::regex_search(s, re);
175 auto has_call_or_ret = [](
const std::string &s) {
176 return s.find(
" call ") != std::string::npos ||
177 s.find(
"\tcall ") != std::string::npos ||
178 s.find(
" ret") != std::string::npos ||
179 s.find(
"\tret") != std::string::npos;
181 auto touches_rsp = [](
const std::string &s) {
182 return s.find(
"%rsp") != std::string::npos || s.find(
"(%rsp") != std::string::npos;
185 std::vector<std::string> out;
186 out.reserve(lines.size());
187 std::vector<int> frame_bytes;
189 std::regex re_sub_rsp(R
"(^\s*sub\s+\$([0-9]+)\s*,\s*%rsp\s*(?:[#;].*)?$)", std::regex::icase);
190 std::regex re_add_rsp(R"(^\s*add\s+\$([0-9]+)\s*,\s*%rsp\s*(?:[#;].*)?$)", std::regex::icase);
193 std::string location;
196 std::unordered_map<std::string, ValueInfo> reg_contents;
197 std::unordered_map<std::string, ValueInfo> mem_contents;
199 auto invalidate_tracking = [&]() {
200 reg_contents.clear();
201 mem_contents.clear();
204 auto clobber_reg = [&](
const std::string ®) {
205 reg_contents.erase(reg);
206 for (
auto it = mem_contents.begin(); it != mem_contents.end();) {
207 if (it->second.location == reg)
208 it = mem_contents.erase(it);
214 for (
size_t i = 0; i < lines.size(); ++i) {
215 const std::string &line = lines[i];
217 if (std::regex_match(line, re_xor_eax) && (i + 1 < lines.size())) {
219 if (std::regex_match(lines[i + 1], m, re_call_func)) {
220 std::string func_name = m[1].str();
221 if (!func_name.empty() && func_name[0] ==
'_') {
222 func_name = func_name.substr(1);
224 if (variadic_funcs.find(func_name) == variadic_funcs.end()) {
229 if (local_is_label(line)) {
231 invalidate_tracking();
236 if (std::regex_match(line, m, re_sub_rsp)) {
237 frame_bytes.push_back(std::stoi(m[1].str()));
242 if (!frame_bytes.empty()) {
245 if (std::regex_match(line, m, re_add_rsp)) {
246 int n = std::stoi(m[1].str());
247 if (!frame_bytes.empty() && frame_bytes.back() == n)
248 frame_bytes.pop_back();
252 if (has_call_or_ret(line) || touches_rsp(line) || std::regex_search(line, re_call_or_jmp)) {
254 invalidate_tracking();
260 if (std::regex_match(line, m, re_modifies_reg)) {
261 clobber_reg(m[1].str());
269 if (std::regex_match(line, m, re_reg_to_mem)) {
270 const std::string reg = m[1].str();
271 const std::string mem = m[2].str();
272 mem_contents[mem] = {reg,
true};
280 if (std::regex_match(line, m, re_mov_reg)) {
281 const std::string src = m[1].str();
282 const std::string dst = m[2].str();
288 auto it_src = reg_contents.find(src);
289 if (it_src != reg_contents.end())
290 reg_contents[dst] = it_src->second;
292 reg_contents[dst] = {src,
true};
301 if (std::regex_match(line, m, re_mem_to_reg)) {
302 const std::string mem = m[1].str();
303 const std::string reg = m[2].str();
307 auto it = mem_contents.find(mem);
308 if (it != mem_contents.end() && it->second.valid) {
309 const std::string &src_reg = it->second.location;
311 out.push_back(
"\tmovq " + src_reg +
", " + reg);
312 reg_contents[reg] = {mem,
true};
317 reg_contents[reg] = {mem,
true};
322 invalidate_tracking();
330 const std::unordered_set<std::string> &macos_functions) {
331 static const std::regex re_call(R
"(\b(call|jmp)\s+([_A-Za-z][_A-Za-z0-9]*)\b)");
333 result.reserve(line.size() + 16);
336 for (std::sregex_iterator it(line.begin(), line.end(), re_call), end; it != end; ++it) {
338 const auto pos =
static_cast<size_t>(m.position());
339 const auto len =
static_cast<size_t>(m.length());
340 const std::string fn = m[2].str();
342 result.append(line, last,
pos - last);
344 std::string piece = m.str();
345 if (fn ==
"main" || macos_functions.count(fn)) {
346 const auto fnpos = piece.rfind(fn);
347 if (fnpos != std::string::npos)
348 piece.replace(fnpos, fn.size(),
"_" + fn);
354 result.append(line, last, std::string::npos);
359 std::vector<std::string> out;
360 out.reserve(lines.size());
362 std::regex re_stdin_access(R
"(movq?\s+stdin\(%rip\)\s*,\s*(%\w+))", std::regex::icase);
363 std::regex re_stdout_access(R"(movq?\s+stdout\(%rip\)\s*,\s*(%\w+))", std::regex::icase);
364 std::regex re_stderr_access(R"(movq?\s+stderr\(%rip\)\s*,\s*(%\w+))", std::regex::icase);
365 std::regex re_global_main(R"(^\s*\.(?:global|globl)\s+main\s*$)");
366 std::regex re_main_label(R"(^\s*main\s*:\s*$)");
367 std::regex re_global_function(R"(^\s*\.(?:global|globl)\s+([_a-zA-Z][_a-zA-Z0-9]*)(?:\s|$))");
368 std::regex re_function_label(R"(^([_a-zA-Z][_a-zA-Z0-9]*)\s*:\s*$)");
370 std::unordered_set<std::string> macos_functions;
372 for (
const auto &raw : lines) {
373 std::string line = raw;
375 if (std::regex_search(line, re_global_main)) {
376 out.push_back(
"\t.globl _main");
379 if (std::regex_search(line, re_main_label)) {
380 out.push_back(
"_main:");
385 if (std::regex_search(line, m_func, re_global_function)) {
386 std::string fn = m_func[1].str();
388 macos_functions.insert(fn);
389 out.push_back(
"\t.globl _" + fn);
393 if (std::regex_search(line, m_func, re_function_label)) {
394 std::string fn = m_func[1].str();
395 if (fn !=
"main" && macos_functions.count(fn)) {
396 out.push_back(
"_" + fn +
":");
404 if (std::regex_search(line, m, re_stdin_access)) {
405 std::string r = m[1].str();
406 out.push_back(
"\tmovq ___stdinp@GOTPCREL(%rip), %rax");
407 out.push_back(
"\tmovq (%rax), " + r);
410 if (std::regex_search(line, m, re_stdout_access)) {
411 std::string r = m[1].str();
412 out.push_back(
"\tmovq ___stdoutp@GOTPCREL(%rip), %rax");
413 out.push_back(
"\tmovq (%rax), " + r);
416 if (std::regex_search(line, m, re_stderr_access)) {
417 std::string r = m[1].str();
418 out.push_back(
"\tmovq ___stderrp@GOTPCREL(%rip), %rax");
419 out.push_back(
"\tmovq (%rax), " + r);
423 std::regex re_single_stdout(R
"(^\s*movq?\s+_stdout\(%rip\)\s*,\s*(%\w+)\s*(?:[#;].*)?$)", std::regex::icase);
424 if (std::regex_search(line, m, re_single_stdout)) {
425 std::string r = m[1].str();
426 out.push_back(
"\tmovq ___stdoutp@GOTPCREL(%rip), %rax");
427 out.push_back(
"\tmovq (%rax), " + r);
430 std::regex re_single_stderr(R
"(^\s*movq?\s+_stderr\(%rip\)\s*,\s*(%\w+)\s*(?:[#;].*)?$)", std::regex::icase);
431 if (std::regex_search(line, m, re_single_stderr)) {
432 std::string r = m[1].str();
433 out.push_back(
"\tmovq ___stderrp@GOTPCREL(%rip), %rax");
434 out.push_back(
"\tmovq (%rax), " + r);
437 std::regex re_single_stdin(R
"(^\s*movq?\s+_stdin\(%rip\)\s*,\s*(%\w+)\s*(?:[#;].*)?$)", std::regex::icase);
438 if (std::regex_search(line, m, re_single_stdin)) {
439 std::string r = m[1].str();
440 out.push_back(
"\tmovq ___stdinp@GOTPCREL(%rip), %rax");
441 out.push_back(
"\tmovq (%rax), " + r);
453 static const std::regex add_rx(R
"(^\s*addq?\s+\$([0-9]+|0x[0-9a-fA-F]+)\s*,\s*%rsp\s*(?:#.*)?$)");
454 static const std::regex sub_rx(R
"(^\s*subq?\s+\$([0-9]+|0x[0-9a-fA-F]+)\s*,\s*%rsp\s*(?:#.*)?$)");
456 auto parse_imm = [](
const std::string &s) ->
unsigned long long {
457 return std::stoull(s,
nullptr, 0);
460 std::vector<std::string> out;
461 out.reserve(lines.size());
463 for (
size_t i = 0; i < lines.size();) {
464 const std::string &a = lines[i];
467 bool a_is_add = std::regex_match(a, ma, add_rx);
468 bool a_is_sub = !a_is_add && std::regex_match(a, ma, sub_rx);
470 if ((a_is_add || a_is_sub) && (i + 1) < lines.size()) {
471 const std::string &b = lines[i + 1];
472 bool b_is_add = std::regex_match(b, mb, add_rx);
473 bool b_is_sub = !b_is_add && std::regex_match(b, mb, sub_rx);
475 if ((a_is_add && b_is_sub) || (a_is_sub && b_is_add)) {
476 unsigned long long ia = parse_imm(ma[1].str());
477 unsigned long long ib = parse_imm(mb[1].str());