bed36f3b712b06c25087b64ede4a22549224fce7
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirGenerate.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 "AirGenerate.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirAllocateStack.h"
32 #include "AirCode.h"
33 #include "AirGenerationContext.h"
34 #include "AirHandleCalleeSaves.h"
35 #include "AirReportUsedRegisters.h"
36 #include "AirSpillEverything.h"
37 #include "AirValidate.h"
38 #include "B3Common.h"
39 #include "B3IndexMap.h"
40 #include "CCallHelpers.h"
41
42 namespace JSC { namespace B3 { namespace Air {
43
44 void generate(Code& code, CCallHelpers& jit)
45 {
46     // We don't expect the incoming code to have predecessors computed.
47     code.resetReachability();
48     
49     if (shouldValidateIR())
50         validate(code);
51
52     // If we're doing super verbose dumping, the phase scope of any phase will already do a dump.
53     if (shouldDumpIR() && !shouldDumpIRAtEachPhase()) {
54         dataLog("Initial air:\n");
55         dataLog(code);
56     }
57
58     // This is where we run our optimizations and transformations.
59     // FIXME: Add Air optimizations.
60     // https://bugs.webkit.org/show_bug.cgi?id=150456
61
62     // This is where we would have a real register allocator. Then, we could use spillEverything()
63     // in place of the register allocator only for testing.
64     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=150457
65     spillEverything(code);
66
67     // Prior to this point the prologue and epilogue is implicit. This makes it explicit. It also
68     // does things like identify which callee-saves we're using and saves them.
69     handleCalleeSaves(code);
70
71     // This turns all Stack and CallArg Args into Addr args that use the frame pointer. It does
72     // this by first-fit allocating stack slots. It should be pretty darn close to optimal, so we
73     // shouldn't have to worry about this very much.
74     allocateStack(code);
75
76     // FIXME: We should really have a code layout optimization here.
77     // https://bugs.webkit.org/show_bug.cgi?id=150478
78
79     reportUsedRegisters(code);
80
81     if (shouldValidateIR())
82         validate(code);
83
84     // Do a final dump of Air. Note that we have to do this even if we are doing per-phase dumping,
85     // since the final generation is not a phase.
86     if (shouldDumpIR()) {
87         dataLog("Air after ", code.lastPhaseName(), ", before generation:\n");
88         dataLog(code);
89     }
90
91     // And now, we generate code.
92     jit.emitFunctionPrologue();
93     jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
94
95     GenerationContext context;
96     context.code = &code;
97     IndexMap<BasicBlock, CCallHelpers::Label> blockLabels(code.size());
98     IndexMap<BasicBlock, CCallHelpers::JumpList> blockJumps(code.size());
99
100     auto link = [&] (CCallHelpers::Jump jump, BasicBlock* target) {
101         if (blockLabels[target].isSet()) {
102             jump.linkTo(blockLabels[target], &jit);
103             return;
104         }
105
106         blockJumps[target].append(jump);
107     };
108
109     for (BasicBlock* block : code) {
110         blockJumps[block].link(&jit);
111         ASSERT(block->size() >= 1);
112         for (unsigned i = 0; i < block->size() - 1; ++i) {
113             CCallHelpers::Jump jump = block->at(i).generate(jit, context);
114             ASSERT_UNUSED(jump, !jump.isSet());
115         }
116
117         if (block->last().opcode == Jump
118             && block->successorBlock(0) == code.findNextBlock(block))
119             continue;
120
121         if (block->last().opcode == Ret) {
122             // We currently don't represent the full prologue/epilogue in Air, so we need to
123             // have this override.
124             jit.emitFunctionEpilogue();
125             jit.ret();
126             continue;
127         }
128         
129         CCallHelpers::Jump jump = block->last().generate(jit, context);
130         for (Inst& inst : *block)
131             jump = inst.generate(jit, context);
132         switch (block->numSuccessors()) {
133         case 0:
134             ASSERT(!jump.isSet());
135             break;
136         case 1:
137             link(jump, block->successorBlock(0));
138             break;
139         case 2:
140             link(jump, block->successorBlock(0));
141             if (block->successorBlock(1) != code.findNextBlock(block))
142                 link(jit.jump(), block->successorBlock(1));
143             break;
144         default:
145             RELEASE_ASSERT_NOT_REACHED();
146             break;
147         }
148     }
149
150     for (auto& latePath : context.latePaths)
151         latePath->run(jit, context);
152 }
153
154 } } } // namespace JSC::B3::Air
155
156 #endif // ENABLE(B3_JIT)