FTL B3 fails cdjs-tests.yaml/red_black_tree_test.js.ftl-eager-no-cjit
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirHandleCalleeSaves.cpp
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "AirHandleCalleeSaves.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirCode.h"
32 #include "AirInsertionSet.h"
33 #include "AirInstInlines.h"
34 #include "AirPhaseScope.h"
35
36 namespace JSC { namespace B3 { namespace Air {
37
38 void handleCalleeSaves(Code& code)
39 {
40     PhaseScope phaseScope(code, "handleCalleeSaves");
41
42     RegisterSet usedCalleeSaves;
43
44     for (BasicBlock* block : code) {
45         for (Inst& inst : *block) {
46             inst.forEachTmpFast(
47                 [&] (Tmp& tmp) {
48                     // At first we just record all used regs.
49                     usedCalleeSaves.set(tmp.reg());
50                 });
51
52             if (inst.hasSpecial())
53                 usedCalleeSaves.merge(inst.extraClobberedRegs());
54         }
55     }
56
57     // Now we filter to really get the callee saves.
58     usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
59     usedCalleeSaves.exclude(RegisterSet::stackRegisters()); // We don't need to save FP here.
60
61     if (!usedCalleeSaves.numberOfSetRegisters())
62         return;
63
64     code.calleeSaveRegisters() = RegisterAtOffsetList(usedCalleeSaves);
65
66     size_t byteSize = 0;
67     for (const RegisterAtOffset& entry : code.calleeSaveRegisters())
68         byteSize = std::max(static_cast<size_t>(-entry.offset()), byteSize);
69
70     StackSlot* savesArea = code.addStackSlot(byteSize, StackSlotKind::Locked);
71     // This is a bit weird since we could have already pinned a different stack slot to this
72     // area. Also, our runtime does not require us to pin the saves area. Maybe we shouldn't pin it?
73     savesArea->setOffsetFromFP(-byteSize);
74
75     auto argFor = [&] (const RegisterAtOffset& entry) -> Arg {
76         return Arg::stack(savesArea, entry.offset() + byteSize);
77     };
78
79     InsertionSet insertionSet(code);
80     
81     // First insert saving code in the prologue.
82     for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
83         insertionSet.insert(
84             0, entry.reg().isGPR() ? Move : MoveDouble, code[0]->at(0).origin,
85             Tmp(entry.reg()), argFor(entry));
86     }
87     insertionSet.execute(code[0]);
88
89     // Now insert restore code at epilogues.
90     for (BasicBlock* block : code) {
91         Inst& last = block->last();
92         if (!isReturn(last.opcode))
93             continue;
94
95         for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
96             insertionSet.insert(
97                 block->size() - 1, entry.reg().isGPR() ? Move : MoveDouble, last.origin,
98                 argFor(entry), Tmp(entry.reg()));
99         }
100         insertionSet.execute(block);
101     }
102 }
103
104 } } } // namespace JSC::B3::Air
105
106 #endif // ENABLE(B3_JIT)