Changeset 201613 in webkit
- Timestamp:
- Jun 2, 2016, 1:05:08 PM (10 years ago)
- Location:
- trunk/Websites/webkit.org
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
docs/b3/assembly-intermediate-representation.html (modified) (8 diffs)
-
docs/b3/index.html (modified) (5 diffs)
-
docs/b3/intermediate-representation.html (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Websites/webkit.org/ChangeLog
r201527 r201613 1 2016-06-02 Filip Pizlo <fpizlo@apple.com> 2 3 Fix typos and make some revisions to the B3 docs 4 https://bugs.webkit.org/show_bug.cgi?id=158311 5 6 Reviewed by Michael Saboff. 7 8 I found typos and fixed them. Also, I clarified some things: 9 10 - Is B3 IR platform-agnostic? Sort of. I tried to describe when it is (Values usually behave 11 the same way regardless of CPU) and when it isn't (it lets you speak of registers if that's 12 what you want to do, for example). 13 14 - How does isValidForm really get used? You don't really need to create an Inst to use it. 15 16 - Some other incremental improvements to make the docs clearer. 17 18 * docs/b3/assembly-intermediate-representation.html: 19 * docs/b3/index.html: 20 * docs/b3/intermediate-representation.html: 21 1 22 2016-05-31 Filip Pizlo <fpizlo@apple.com> 2 23 -
trunk/Websites/webkit.org/docs/b3/assembly-intermediate-representation.html
r201527 r201613 45 45 <p>B3 is designed to be portable to many kinds of CPUs. Currently, it supports x86-64 and ARM64, 46 46 which are quite different from each other. In B3 IR, we expose very few instruction set 47 details. Most clients only have to worry about the pointer type varying between Int32 and 48 Int64. It's a goal of B3 IR to ensure that B3 values behave the same way except when the 49 alternative would be prohibitive (like with pointer size or the corner-case behaviors of 50 division). But to effectively compile code to different CPUs, the compiler has to eventually 51 make instruction set details explicit. This is where Air comes in. B3 locks in most 52 CPU-specific details at the moment of conversion to Air, and the Air code is irreversibly tied 53 to some specific CPU.</p> 47 details. It's a goal of B3 IR to ensure that B3 values behave the same way except when the 48 alternative would be counterproductive (like with pointer size, the corner-case behaviors of 49 division, or calling convention customization). But to effectively compile code to different 50 CPUs, the compiler has to eventually make instruction set details explicit. This is where Air 51 comes in. B3 locks in most CPU-specific details at the moment of conversion to Air, and the Air 52 code is irreversibly tied to some specific CPU.</p> 54 53 55 54 <p>Air is an instruction <i>superset</i>: it recognizes all of the instructions from all CPUs … … 61 60 and abstract 62 61 <a href="http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/b3/air/AirStackSlot.h">stack 63 slots</a>.</p> 62 slots</a>. A <code>Tmp</code> object can either hold an unallocated temporary or a 63 register.</p> 64 64 65 65 <h3>Air as an Instruction Superset</h3> 66 <p>It is possible to speak of an x86-64 instruction while compiling for ARM64, 67 for example. Clients of Air, such as the B3 to Air lowering phase, are allowed to pick with any 68 Air opcode and ask if that opcode would be valid on the current CPU. They are also allowed to 69 check if specific forms of any given opcode are valid. This allows clients to optimize for 70 multiple instruction sets by cascading through the possible opcodes that they know of, starting 71 with the one they think is most efficient. Some of those opcodes may only be available on one 72 CPU while others are available everywhere.</p> 66 <p>Air has syntax to speak of all of the CPU instructions we know about. It is possible to speak 67 of an x86-64 instruction while compiling for ARM64, for example. Clients of Air, such as the B3 68 to Air lowering phase, are allowed to pick any Air opcode and ask if that opcode would be 69 valid on the current CPU. They are also allowed to check if specific forms of any given opcode 70 are valid. This allows clients to optimize for multiple instruction sets by cascading through 71 the possible opcodes that they know of, starting with the one they think is most efficient. 72 Some of those opcodes may only be available on one CPU while others are available 73 everywhere. Instruction selection does not need to know which instructions work on which CPUs; 74 Air will tell you if some instruction happens to not be valid right now for whatever reason.</p> 73 75 74 76 <p>Air opcodes support overloading. For example, the Add32 opcode has both two-operand and 75 three-operand overloads, and those overloads have multiple forms: the first operand may or 76 may not be an immediate and depending on the CPU, some of the other operands may or may not 77 be memory addresses. A fundamental Air operation is <code>Inst::isValidForm()</code>, which 78 tells the client if the instruction's current form is valid on the current CPU. This may 79 return false either because the Inst is not well-formed for any CPU or because it is not 80 valid for the current CPU even though it may be valid on some other CPU. This allows clients 81 to generate Air by experimenting with various different instruction forms before settling on 82 the one that the current CPU supports.</p> 77 three-operand <i>overloads</i>, and those overloads have multiple <i>forms</i>: the first 78 operand may or may not be permitted to be an immediate and depending on the CPU and some of the 79 other operands may or may not be allowed to be memory addresses. We use <i>opcode overload</i> 80 to refer to all forms of an opcode that share the same number of arguments, and <i>opcode 81 form</i> to mean the number of arguments and their types. A fundamental Air operation is 82 <code>Inst::isValidForm()</code>, which tells the client if the instruction's current form is 83 valid on the current CPU. This may return false either because the Inst is not well-formed for 84 any CPU or because it is not valid for the current CPU even though it may be valid on some 85 other CPU. There is also <code>Air::isValidForm()</code>, which can answer if the form you are 86 intending to use will be valid even if you have not created an <code>Inst</code> yet. This 87 allows clients to generate Air by experimenting with different forms before settling on the one 88 that the current CPU supports.</p> 83 89 84 90 <h3>Air as a High-Level Assembly</h3> … … 94 100 Air code.</p> 95 101 96 <p>Air's philosophy allows B3 to use it for converting high-level, CPU-agnostic SSA procedures97 into code for the current CPU. Air is an instruction superset that allows clients to consider98 all available instructions on all possible CPUs and query which forms of those instructions are99 available on the current CPU. Air also supports for high-level concepts like <code>Tmp</code>s100 and stack slots, which allows B3 to Air lowering to focus on which instructions to use without101 worrying about register allocation or stack layout.</p>102 <p>Air's philosophy allows B3 to use it for converting high-level, mostly-CPU-agnostic SSA 103 procedures into code for the current CPU. Air is an instruction superset that allows clients to 104 consider all available instructions on all possible CPUs and query which forms of those 105 instructions are available on the current CPU. Air also supports for high-level concepts like 106 <code>Tmp</code>s and stack slots, which allows B3 to Air lowering to focus on which 107 instructions to use without worrying about register allocation or stack layout.</p> 102 108 103 109 <h2>Args and the Air Execution Model</h2> … … 108 114 write to them, for example. Orthognality implies that any argument that is read may be either 109 115 a register (or <code>Tmp</code>), an address, or an immediate; while any argument that is 110 written may be either a register or an address. Air constrain ts orthognality where the target116 written may be either a register or an address. Air constrains orthognality where the target 111 117 CPU would. For example, none of Air's target CPUs would support an <code>Add32</code> 112 118 instruction that loads its sources from memory <i>and</i> stores its result into memory. Even … … 187 193 </ol> 188 194 189 <p> Note that the early actions of one instruction happen immediately after the late actions of195 <p>The early actions of one instruction happen immediately after the late actions of 190 196 the instruction before it. However, many Air analyses view them as happening at the same time. 191 For example, any register usage in the early action of one instruction interfere with the197 For example, any register usage in the early action of one instruction interferes with the 192 198 register usage in the late action of the instruction that came before it. All of Air's 193 199 liveness and interference analyses reason about the … … 246 252 </ol> 247 253 254 <p>Air's introspection of <code>Inst</code>s tends to be quite fast thanks to the use of template 255 specialization and C++ lambdas. The <code>forEachArg()</code> template method uses an efficient 256 arrangement of switch statements to determine the opcode and overload. If <code>func</code> is 257 a C++ lambda, we expect <code>forEachArg()</code> to be specialized for that lambda. Therefore, 258 this idiom avoids virtual dispatch or memory allocation.</p> 259 248 260 <p>Air supports exotic roles, such as late uses and early defs. There is even the 249 261 <code>Scratch</code> role, which means early def and late use. Speaking of a <code>Tmp</code> 250 262 in the <code>Scratch</code> role means that the <code>Tmp</code> will be assigned a register 251 263 that is guaranteed to not interfere with any of the other registers that the instruction 252 speaks of. Late uses and early defs are crucial for patchpoints, which may for examplerequire264 speaks of. Late uses and early defs are crucial for patchpoints, which may require 253 265 that one of the incoming values be given a register that does not interfere with whatever 254 266 register is used for the result. This can be expressed either as giving the inputs a late use … … 300 312 late actions is determined by the opcode and the number of arguments (i.e. the overload). 301 313 Clients of Air may create an <code>Inst</code> with any combination of opcode and arguments 302 and then query, using <code> Inst::isValidForm()</code> if the opcode, overload, and specific314 and then query, using <code>isValidForm()</code> if the opcode, overload, and specific 303 315 arguments are valid for the current CPU.</p> 304 316 … … 345 357 CPUs, such as x86 or x86-64.</p> 346 358 359 <p>Air opcodes are designed to work with JavaScriptCore's existing MacroAssembler. By default, an 360 opcode is automatically given a code generator that calls 361 <code>MacroAssembler::<i>opcodeName</i></code>, where <i>opcodeName</i> is derived by 362 lower-casing the first letter of the Air opcode name. <code>Add32</code> becomes 363 <code>MacroAssembler::add32</code>, for example.</p> 364 347 365 <p>See the header of 348 366 <a href="http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes">AirOpcode.opcodes</a> -
trunk/Websites/webkit.org/docs/b3/index.html
r196029 r201613 31 31 its argument and returns it:</p> 32 32 33 <pre><code>Procedure proc; 33 <pre><code>// Create a Procedure that holds our code. 34 Procedure proc; 34 35 BasicBlock* root = proc.addBlock(); 35 36 root->appendNew<ControlValue>( … … 40 41 root->appendNew<Const64Value>(proc, Origin(), 2))); 41 42 43 // Have B3 compile the Procedure into code. The code and all of its artifacts (constant pools, jump tables) 44 // will stay alive so long as Compilation stays alive. 42 45 std::unique_ptr<Compilation> compilation = std::make_unique<Compilation>(vm, proc); 46 47 // Get a function pointer that we can call. This function pointer points to JIT-generated machine code. 43 48 int64_t (*function)(int64_t) = bitwise_cast<int64_t (*)(int64_t)>(compilation->code().executableAddress()); 44 49 45 printf("%lld\n", function(42)); // prints 44</code></pre> 50 // Run it and print the result! 51 printf("%lld\n", function(42)); // Prints 44.</code></pre> 46 52 47 53 <p>When compiled, the resulting machine code looks like this:</p> … … 63 69 <a href="intermediate-representation.html">B3 IR</a>. It's C-like, in the sense that it 64 70 models heap references as integers and does not attempt to verify memory accesses. It 65 enforces static single assignment, or SSA for short. An SSA program will contain only one 66 assignment to each variable, which makes it trivial to trace from a use of a variable to 67 the operation that defined its value. B3 IR is designed to be easy to generate and cheap 68 to manipulate.</p> 69 70 <p>B3 is designed to be used as a backend for JITs, rather than as a tool that programmers 71 use directly. Therefore, B3 embraces platform-specific concepts like argument registers, 72 stack frame layout, the frame pointer, and the call argument areas. It's possible to emit 73 B3 IR that defines completely novel calling conventions, both for callers of the procedure 74 being generated and for callees of the procedure's callsites. B3 also makes it easy to 75 just emit a C call. There's an opcode for that.</p> 71 enforces <a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">static single 72 assignment</a>, or SSA for short. An SSA program will contain only one assignment to each 73 variable, which makes it trivial to trace from a use of a variable to the operation that 74 defined its value. B3 IR is designed to be easy to generate and cheap to manipulate.</p> 75 76 <p>In most ways, B3 IR is platform-agnostic. However, since B3 is designed to be used as a 77 backend for JITs, it does embrace some platform-specific concepts whenever it is pragmatic to 78 do so. B3 exposes direct control over argument registers, stack frame layout, the frame 79 pointer, and the call argument areas. It's possible to emit B3 IR that defines completely 80 novel calling conventions, both for callers of the procedure being generated and for callees of 81 the procedure's callsites. B3 also makes it easy to just emit a C call. There's an opcode for 82 that.</p> 76 83 77 84 <p>See <a href="intermediate-representation.html">the IR documentation</a> for more … … 147 154 Ret64 %rax, @3</code></pre> 148 155 149 <h2>B3 ->Air lowering, also known as Instruction Selection</h2>156 <h2>B3→Air lowering, also known as Instruction Selection</h2> 150 157 151 158 <p>The B3::LowerToAir phase converts B3 into Air by doing pattern-matching. It processes … … 194 201 <h2>Code generation</h2> 195 202 196 <p>The final form of Air contains no registers or abstract stack slots. Therefore, it maps197 directly to machine code. The final code generation step is a very fast transformation203 <p>The final form of Air contains no unallocated temporaries or abstract stack slots. Therefore, 204 it maps directly to machine code. The final code generation step is a very fast transformation 198 205 from Air's object-oriented way of representing those instructions to the target's machine 199 206 code. We use JavaScriptCore's macro assembler for this purpose.</p> -
trunk/Websites/webkit.org/docs/b3/intermediate-representation.html
r197380 r201613 66 66 </dl> 67 67 68 <p>B3 does not have a pointer type. Instead, the <code>B3::pointerType()</code> function will 69 return either Int32 or Int64 depending on which kind of integer can be used to represent a 70 pointer on the current platform. It's not a goal of B3 to support hardware targets that require 71 pointers and integers to be segregated. It's not a goal of B3 to support GC (garbage 72 collection) roots as a separate type, since JSC uses 73 <a href="http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-88-2.pdf">Bartlett-style conservative 74 root scanning</a>. This doesn't preclude any mainstream garbage collection algorithms, 75 including copying, generational, or concurrent collectors, and frees up the compiler to perform 76 more optimizations.</p> 77 68 78 <h2>Values</h2> 69 79 … … 413 423 414 424 <dt>T1 Patchpoint([T2, [T3, ...]])</dt> 415 <dd>A Patchpoint is a customizable value. Patchpoints take zero or more values of any 416 type and return any type. A Patchpoint's behavior is determined by the generator 417 object. The generator is a C++ lambda that gets called during code generation. It gets 418 passed an assembler instance (specifically, CCallHelpers&) and an object describing 419 where to find all of the input values and where to put the result. Here's an example: 425 <dd> 426 <p>A Patchpoint is a customizable value. Patchpoints take zero or more values of any 427 type and return any type. A Patchpoint's behavior is determined by the generator 428 object. The generator is a C++ lambda that gets called during code generation. It gets 429 passed an assembler instance (specifically, CCallHelpers&) and an object describing 430 where to find all of the input values and where to put the result. Here's an example:</p> 420 431 421 432 <pre><code>PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, Int32, Origin());
Note:
See TracChangeset
for help on using the changeset viewer.