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