Create a super rough prototype of B3
[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 "AirPhaseScope.h"
34
35 namespace JSC { namespace B3 { namespace Air {
36
37 void handleCalleeSaves(Code& code)
38 {
39     PhaseScope phaseScope(code, "handleCalleeSaves");
40
41     RegisterSet usedCalleeSaves;
42
43     for (BasicBlock* block : code) {
44         for (Inst& inst : *block) {
45             inst.forEachTmpFast(
46                 [&] (Tmp& tmp) {
47                     // At first we just record all used regs.
48                     usedCalleeSaves.set(tmp.reg());
49                 });
50         }
51     }
52
53     // Now we filter to really get the callee saves.
54     usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
55
56     if (!usedCalleeSaves.numberOfSetRegisters())
57         return;
58
59     code.calleeSaveRegisters() = RegisterAtOffsetList(usedCalleeSaves);
60
61     size_t byteSize = 0;
62     for (const RegisterAtOffset& entry : code.calleeSaveRegisters())
63         byteSize = std::max(static_cast<size_t>(-entry.offset()), byteSize);
64
65     StackSlot* savesArea = code.addStackSlot(byteSize, StackSlotKind::Locked);
66     // This is a bit weird since we could have already pinned a different stack slot to this
67     // area. Also, our runtime does not require us to pin the saves area. Maybe we shouldn't pin it?
68     savesArea->setOffsetFromFP(-byteSize);
69
70     auto argFor = [&] (const RegisterAtOffset& entry) -> Arg {
71         return Arg::stack(savesArea, entry.offset() + byteSize);
72     };
73
74     InsertionSet insertionSet(code);
75     
76     // First insert saving code in the prologue.
77     for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
78         insertionSet.insert(
79             0, entry.reg().isGPR() ? Move : MoveDouble, code[0]->at(0).origin,
80             Tmp(entry.reg()), argFor(entry));
81     }
82     insertionSet.execute(code[0]);
83
84     // Now insert restore code at epilogues.
85     for (BasicBlock* block : code) {
86         Inst& last = block->last();
87         if (last.opcode != Ret)
88             continue;
89
90         for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
91             insertionSet.insert(
92                 block->size() - 1, entry.reg().isGPR() ? Move : MoveDouble, last.origin,
93                 argFor(entry), Tmp(entry.reg()));
94         }
95         insertionSet.execute(block);
96     }
97 }
98
99 } } } // namespace JSC::B3::Air
100
101 #endif // ENABLE(B3_JIT)