Changeset 194331 in webkit
- Timestamp:
- Dec 21, 2015, 8:16:01 AM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 added
- 27 edited
-
CMakeLists.txt (modified) (1 diff)
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (5 diffs)
-
assembler/AbstractMacroAssembler.h (modified) (2 diffs)
-
b3/B3LowerToAir.cpp (modified) (3 diffs)
-
b3/B3PatchpointSpecial.cpp (modified) (1 diff)
-
b3/B3StackmapSpecial.cpp (modified) (1 diff)
-
b3/B3Value.h (modified) (1 diff)
-
b3/air/AirAllocateStack.cpp (modified) (2 diffs)
-
b3/air/AirArg.cpp (modified) (1 diff)
-
b3/air/AirArg.h (modified) (8 diffs)
-
b3/air/AirCCallSpecial.cpp (modified) (1 diff)
-
b3/air/AirEliminateDeadCode.cpp (modified) (1 diff)
-
b3/air/AirFixPartialRegisterStalls.cpp (modified) (2 diffs)
-
b3/air/AirInst.cpp (modified) (1 diff)
-
b3/air/AirInst.h (modified) (1 diff)
-
b3/air/AirInstInlines.h (modified) (3 diffs)
-
b3/air/AirIteratedRegisterCoalescing.cpp (modified) (19 diffs)
-
b3/air/AirLiveness.h (modified) (4 diffs)
-
b3/air/AirOpcode.opcodes (modified) (20 diffs)
-
b3/air/AirOptimizeBlockOrder.cpp (modified) (1 diff)
-
b3/air/AirSpillEverything.cpp (modified) (4 diffs)
-
b3/air/AirTmpWidth.cpp (added)
-
b3/air/AirTmpWidth.h (added)
-
b3/air/AirUseCounts.h (modified) (1 diff)
-
b3/air/opcode_generator.rb (modified) (8 diffs)
-
b3/testb3.cpp (modified) (2 diffs)
-
ftl/FTLLowerDFGToLLVM.cpp (modified) (1 diff)
-
ftl/FTLOSRExitHandle.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/CMakeLists.txt
r194328 r194331 91 91 b3/air/AirStackSlot.cpp 92 92 b3/air/AirTmp.cpp 93 b3/air/AirTmpWidth.cpp 93 94 b3/air/AirValidate.cpp 94 95 -
trunk/Source/JavaScriptCore/ChangeLog
r194328 r194331 1 2015-12-21 Filip Pizlo <fpizlo@apple.com> 2 3 B3->Air lowering incorrectly copy-propagates over ZExt32's 4 https://bugs.webkit.org/show_bug.cgi?id=152365 5 6 Reviewed by Benjamin Poulain. 7 8 The instruction selector thinks that Value's that return Int32's are going to always be lowered 9 to instructions that zero-extend the destination. But this isn't actually true. If you have an 10 Add32 with a destination on the stack (i.e. spilled) then it only writes 4 bytes. Then, the 11 filler will load 8 bytes from the stack at the point of use. So, the use of the Add32 will see 12 garbage in the high bits. 13 14 The fact that the spiller chose to use 8 bytes for a Tmp that gets defined by an Add32 is a 15 pretty sad bug, but: 16 17 - It's entirely up to the spiller to decide how many bytes to use for a Tmp, since we do not 18 ascribe a type to Tmps. We could ascribe types to Tmps, but then coalescing would become 19 harder. Our goal is to fix the bug while still enabling coalescing in cases like "a[i]" where 20 "i" is a 32-bit integer that is computed using operations that already do zero-extension. 21 22 - More broadly, it's strange that the instruction selector decides whether a Value will be 23 lowered to something that zero-extends. That's too constraining, since the most optimal 24 instruction selection might involve something that doesn't zero-extend in cases of spilling, so 25 the zero-extension should only happen if it's actually needed. This means that we need to 26 understand which Air instructions cause zero-extensions. 27 28 - If we know which Air instructions cause zero-extensions, then we don't need the instruction 29 selector to copy-propagate ZExt32's. We have copy-propagation in Air thanks to the register 30 allocator. 31 32 In fact, the register allocator is exactly where all of the pieces come together. It's there that 33 we want to know which operations zero-extend and which don't. It also wants to know how many bits 34 of a Tmp each instruction reads. Armed with that information, the register allocator can emit 35 more optimal spill code, use less stack space for spill slots, and coalesce Move32's. As a bonus, 36 on X86, it replaces Move's with Move32's whenever it can. On X86, Move32 is cheaper. 37 38 This fixes a crash bug in V8/encrypt. After fixing this, I only needed two minor fixes to get 39 V8/encrypt to run. We're about 10% behind LLVM on steady state throughput on this test. It 40 appears to be mostly due to excessive spilling caused by CCall slow paths. That's fixable: we 41 could make CCalls on slow paths use a variant of CCallSpecial that promises not to clobber any 42 registers, and then have it emit spill code around the call itself. LLVM probably gets this 43 optimization from its live range splitting. 44 45 I tried writing a regression test. The problem is that you need garbage on the stack for this to 46 work, and I didn't feel like writing a flaky test. It appears that running V8/encrypt will cover 47 this, so we do have coverage. 48 49 * CMakeLists.txt: 50 * JavaScriptCore.xcodeproj/project.pbxproj: 51 * assembler/AbstractMacroAssembler.h: 52 (JSC::isX86): 53 (JSC::isX86_64): 54 (JSC::optimizeForARMv7IDIVSupported): 55 (JSC::optimizeForX86): 56 (JSC::optimizeForX86_64): 57 * b3/B3LowerToAir.cpp: 58 (JSC::B3::Air::LowerToAir::highBitsAreZero): 59 (JSC::B3::Air::LowerToAir::shouldCopyPropagate): 60 (JSC::B3::Air::LowerToAir::lower): 61 * b3/B3PatchpointSpecial.cpp: 62 (JSC::B3::PatchpointSpecial::forEachArg): 63 * b3/B3StackmapSpecial.cpp: 64 (JSC::B3::StackmapSpecial::forEachArgImpl): 65 * b3/B3Value.h: 66 * b3/air/AirAllocateStack.cpp: 67 (JSC::B3::Air::allocateStack): 68 * b3/air/AirArg.cpp: 69 (WTF::printInternal): 70 * b3/air/AirArg.h: 71 (JSC::B3::Air::Arg::pointerWidth): 72 (JSC::B3::Air::Arg::isAnyUse): 73 (JSC::B3::Air::Arg::isColdUse): 74 (JSC::B3::Air::Arg::isEarlyUse): 75 (JSC::B3::Air::Arg::isDef): 76 (JSC::B3::Air::Arg::isZDef): 77 (JSC::B3::Air::Arg::widthForB3Type): 78 (JSC::B3::Air::Arg::conservativeWidth): 79 (JSC::B3::Air::Arg::minimumWidth): 80 (JSC::B3::Air::Arg::bytes): 81 (JSC::B3::Air::Arg::widthForBytes): 82 (JSC::B3::Air::Arg::Arg): 83 (JSC::B3::Air::Arg::forEachTmp): 84 * b3/air/AirCCallSpecial.cpp: 85 (JSC::B3::Air::CCallSpecial::forEachArg): 86 * b3/air/AirEliminateDeadCode.cpp: 87 (JSC::B3::Air::eliminateDeadCode): 88 * b3/air/AirFixPartialRegisterStalls.cpp: 89 (JSC::B3::Air::fixPartialRegisterStalls): 90 * b3/air/AirInst.cpp: 91 (JSC::B3::Air::Inst::hasArgEffects): 92 * b3/air/AirInst.h: 93 (JSC::B3::Air::Inst::forEachTmpFast): 94 (JSC::B3::Air::Inst::forEachTmp): 95 * b3/air/AirInstInlines.h: 96 (JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs): 97 * b3/air/AirIteratedRegisterCoalescing.cpp: 98 * b3/air/AirLiveness.h: 99 (JSC::B3::Air::AbstractLiveness::AbstractLiveness): 100 (JSC::B3::Air::AbstractLiveness::LocalCalc::execute): 101 * b3/air/AirOpcode.opcodes: 102 * b3/air/AirSpillEverything.cpp: 103 (JSC::B3::Air::spillEverything): 104 * b3/air/AirTmpWidth.cpp: Added. 105 (JSC::B3::Air::TmpWidth::TmpWidth): 106 (JSC::B3::Air::TmpWidth::~TmpWidth): 107 * b3/air/AirTmpWidth.h: Added. 108 (JSC::B3::Air::TmpWidth::width): 109 (JSC::B3::Air::TmpWidth::defWidth): 110 (JSC::B3::Air::TmpWidth::useWidth): 111 (JSC::B3::Air::TmpWidth::Widths::Widths): 112 * b3/air/AirUseCounts.h: 113 (JSC::B3::Air::UseCounts::UseCounts): 114 * b3/air/opcode_generator.rb: 115 * b3/testb3.cpp: 116 (JSC::B3::testCheckMegaCombo): 117 (JSC::B3::testCheckTrickyMegaCombo): 118 (JSC::B3::testCheckTwoMegaCombos): 119 (JSC::B3::run): 120 1 121 2015-12-21 Andy VanWagoner <thetalecrafter@gmail.com> 2 122 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r194328 r194331 696 696 0FE0502D1AA9095600D33B33 /* VarOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050241AA9095600D33B33 /* VarOffset.h */; settings = {ATTRIBUTES = (Private, ); }; }; 697 697 0FE0502F1AAA806900D33B33 /* ScopedArgumentsTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */; }; 698 0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */; }; 699 0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */; }; 698 700 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; }; 699 701 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; }; … … 2836 2838 0FE050241AA9095600D33B33 /* VarOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VarOffset.h; sourceTree = "<group>"; }; 2837 2839 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedArgumentsTable.cpp; sourceTree = "<group>"; }; 2840 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirTmpWidth.cpp; path = b3/air/AirTmpWidth.cpp; sourceTree = "<group>"; }; 2841 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirTmpWidth.h; path = b3/air/AirTmpWidth.h; sourceTree = "<group>"; }; 2838 2842 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; }; 2839 2843 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; }; … … 4801 4805 0FEC85691BDACDC70080FF74 /* AirTmp.h */, 4802 4806 0FEC856A1BDACDC70080FF74 /* AirTmpInlines.h */, 4807 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */, 4808 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */, 4803 4809 0F3730921C0D67EE00052BFA /* AirUseCounts.h */, 4804 4810 0FEC856B1BDACDC70080FF74 /* AirValidate.cpp */, … … 7297 7303 0F2B9CF719D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h in Headers */, 7298 7304 0F235BDB17178E1C00690C7F /* FTLExitValue.h in Headers */, 7305 0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */, 7299 7306 A7F2996C17A0BB670010417A /* FTLFail.h in Headers */, 7300 7307 0FEA0A2C170B661900BB722C /* FTLFormattedValue.h in Headers */, … … 9230 9237 BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */, 9231 9238 705B41AB1A6E501E00716757 /* Symbol.cpp in Sources */, 9239 0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */, 9232 9240 705B41AD1A6E501E00716757 /* SymbolConstructor.cpp in Sources */, 9233 9241 705B41AF1A6E501E00716757 /* SymbolObject.cpp in Sources */, -
trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
r193640 r194331 68 68 } 69 69 70 inline bool isX86_64() 71 { 72 #if CPU(X86_64) 73 return true; 74 #else 75 return false; 76 #endif 77 } 78 70 79 inline bool optimizeForARMv7IDIVSupported() 71 80 { … … 81 90 { 82 91 return isX86() && Options::useArchitectureSpecificOptimizations(); 92 } 93 94 inline bool optimizeForX86_64() 95 { 96 return isX86_64() && Options::useArchitectureSpecificOptimizations(); 83 97 } 84 98 -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r194320 r194331 159 159 } 160 160 161 // NOTE: This entire mechanism could be done over Air, if we felt that this would be fast enough.162 // For now we're assuming that it's faster to do this here, since analyzing B3 is so cheap.163 161 bool shouldCopyPropagate(Value* value) 164 162 { … … 167 165 case Identity: 168 166 return true; 169 case ZExt32:170 return highBitsAreZero(value->child(0));171 167 default: 172 168 return false; … … 1776 1772 1777 1773 case ZExt32: { 1778 if (highBitsAreZero(m_value->child(0))) {1779 ASSERT(tmp(m_value->child(0)) == tmp(m_value));1780 return;1781 }1782 1783 1774 appendUnOp<Move32, Air::Oops>(m_value->child(0)); 1784 1775 return; -
trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp
r193640 r194331 55 55 } 56 56 57 callback(inst.args[1], Arg::Def, inst.origin->airType() );57 callback(inst.args[1], Arg::Def, inst.origin->airType(), inst.origin->airWidth()); 58 58 forEachArgImpl(0, 2, inst, SameAsRep, callback); 59 59 } -
trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp
r193631 r194331 112 112 break; 113 113 } 114 115 callback(arg, role, Arg::typeForB3Type(child.value()->type())); 114 115 Type type = child.value()->type(); 116 callback(arg, role, Arg::typeForB3Type(type), Arg::widthForB3Type(type)); 116 117 } 117 118 } -
trunk/Source/JavaScriptCore/b3/B3Value.h
r194314 r194331 77 77 // This is useful when lowering. Note that this is only valid for non-void values. 78 78 Air::Arg::Type airType() const { return Air::Arg::typeForB3Type(type()); } 79 Air::Arg::Width airWidth() const { return Air::Arg::widthForB3Type(type()); } 79 80 80 81 AdjacencyList& children() { return m_children; } -
trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp
r192851 r194331 105 105 for (Inst& inst : *block) { 106 106 inst.forEachArg( 107 [&] (Arg& arg, Arg::Role role, Arg::Type ) {107 [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) { 108 108 if (role == Arg::UseAddr && arg.isStack()) 109 109 escapingStackSlots.add(arg.stackSlot()); … … 149 149 150 150 inst.forEachArg( 151 [&] (Arg& arg, Arg::Role role, Arg::Type ) {151 [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) { 152 152 if (!Arg::isDef(role)) 153 153 return; -
trunk/Source/JavaScriptCore/b3/air/AirArg.cpp
r192863 r194331 179 179 out.print("UseDef"); 180 180 return; 181 case Arg::ZDef: 182 out.print("ZDef"); 183 return; 184 case Arg::UseZDef: 185 out.print("UseZDef"); 186 return; 181 187 case Arg::UseAddr: 182 188 out.print("UseAddr"); -
trunk/Source/JavaScriptCore/b3/air/AirArg.h
r193683 r194331 102 102 Def, 103 103 104 // This is a special variant of Def that implies that the upper bits of the target register are 105 // zero-filled. Specifically, if the Width of a ZDef is less than the largest possible width of 106 // the argument (for example, we're on a 64-bit machine and we have a Width32 ZDef of a GPR) then 107 // this has different implications for the upper bits (i.e. the top 32 bits in our example) 108 // depending on the kind of the argument: 109 // 110 // For register: the upper bits are zero-filled. 111 // For address: the upper bits are not touched (i.e. we do a 32-bit store in our example). 112 // For tmp: either the upper bits are not touched or they are zero-filled, and we won't know 113 // which until we lower the tmp to either a StackSlot or a Reg. 114 // 115 // The behavior of ZDef is consistent with what happens when you perform 32-bit operations on a 116 // 64-bit GPR. It's not consistent with what happens with 8-bit or 16-bit Defs on x86 GPRs, or 117 // what happens with float Defs in ARM NEON or X86 SSE. Hence why we have both Def and ZDef. 118 ZDef, 119 104 120 // This is a combined Use and Def. It means that both things happen. 105 121 UseDef, 122 123 // This is a combined Use and ZDef. It means that both things happen. 124 UseZDef, 106 125 107 126 // This is a special kind of use that is only valid for addresses. It means that the … … 127 146 }; 128 147 148 static Width pointerWidth() 149 { 150 if (sizeof(void*) == 8) 151 return Width64; 152 return Width32; 153 } 154 129 155 enum Signedness : int8_t { 130 156 Signed, … … 140 166 case ColdUse: 141 167 case UseDef: 168 case UseZDef: 142 169 case LateUse: 143 170 return true; 144 171 case Def: 172 case ZDef: 145 173 case UseAddr: 146 174 return false; … … 156 184 case Use: 157 185 case UseDef: 186 case UseZDef: 158 187 case Def: 188 case ZDef: 159 189 case UseAddr: 160 190 return false; … … 174 204 case ColdUse: 175 205 case UseDef: 206 case UseZDef: 176 207 return true; 177 208 case Def: 209 case ZDef: 178 210 case UseAddr: 179 211 case LateUse: … … 199 231 case Def: 200 232 case UseDef: 233 case ZDef: 234 case UseZDef: 235 return true; 236 } 237 } 238 239 // Returns true if the Role implies that the Inst will ZDef the Arg. 240 static bool isZDef(Role role) 241 { 242 switch (role) { 243 case Use: 244 case ColdUse: 245 case UseAddr: 246 case LateUse: 247 case Def: 248 case UseDef: 249 return false; 250 case ZDef: 251 case UseZDef: 201 252 return true; 202 253 } … … 231 282 case Int64: 232 283 case Double: 284 return Width64; 285 } 286 } 287 288 static Width conservativeWidth(Type type) 289 { 290 return type == GP ? pointerWidth() : Width64; 291 } 292 293 static Width minimumWidth(Type type) 294 { 295 return type == GP ? Width8 : Width32; 296 } 297 298 static unsigned bytes(Width width) 299 { 300 return 1 << width; 301 } 302 303 static Width widthForBytes(unsigned bytes) 304 { 305 switch (bytes) { 306 case 0: 307 case 1: 308 return Width8; 309 case 2: 310 return Width16; 311 case 3: 312 case 4: 313 return Width32; 314 default: 233 315 return Width64; 234 316 } … … 718 800 // This defs (%rcx) but uses %rcx. 719 801 template<typename Functor> 720 void forEachTmp(Role argRole, Type argType, const Functor& functor)802 void forEachTmp(Role argRole, Type argType, Width argWidth, const Functor& functor) 721 803 { 722 804 switch (m_kind) { 723 805 case Tmp: 724 806 ASSERT(isAnyUse(argRole) || isDef(argRole)); 725 functor(m_base, argRole, argType );807 functor(m_base, argRole, argType, argWidth); 726 808 break; 727 809 case Addr: 728 functor(m_base, Use, GP );810 functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth()); 729 811 break; 730 812 case Index: 731 functor(m_base, Use, GP );732 functor(m_index, Use, GP );813 functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth()); 814 functor(m_index, Use, GP, argRole == UseAddr ? argWidth : pointerWidth()); 733 815 break; 734 816 default: -
trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp
r192841 r194331 46 46 { 47 47 for (unsigned i = 0; i < numCalleeArgs; ++i) 48 callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP );48 callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP, Arg::pointerWidth()); 49 49 for (unsigned i = 0; i < numReturnGPArgs; ++i) 50 callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP );50 callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP, Arg::pointerWidth()); 51 51 for (unsigned i = 0; i < numReturnFPArgs; ++i) 52 callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP );52 callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP, Arg::Width64); 53 53 54 54 for (unsigned i = argArgOffset; i < inst.args.size(); ++i) { 55 55 // For the type, we can just query the arg's type. The arg will have a type, because we 56 56 // require these args to be argument registers. 57 callback(inst.args[i], Arg::Use, inst.args[i].type()); 57 Arg::Type type = inst.args[i].type(); 58 callback(inst.args[i], Arg::Use, type, Arg::conservativeWidth(type)); 58 59 } 59 60 } -
trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp
r192826 r194331 81 81 bool storesToLive = false; 82 82 inst.forEachArg( 83 [&] (Arg& arg, Arg::Role role, Arg::Type ) {83 [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) { 84 84 if (!Arg::isDef(role)) 85 85 return; -
trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp
r193683 r194331 114 114 } 115 115 116 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type ) {116 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) { 117 117 ASSERT_WITH_MESSAGE(tmp.isReg(), "This phase must be run after register allocation."); 118 118 … … 204 204 RegisterSet defs; 205 205 RegisterSet uses; 206 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type ) {206 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) { 207 207 if (tmp.isFPR()) { 208 208 if (Arg::isDef(role)) -
trunk/Source/JavaScriptCore/b3/air/AirInst.cpp
r192121 r194331 39 39 bool result = false; 40 40 forEachArg( 41 [&] (Arg&, Arg::Role role, Arg::Type ) {41 [&] (Arg&, Arg::Role role, Arg::Type, Arg::Width) { 42 42 if (Arg::isDef(role)) 43 43 result = true; -
trunk/Source/JavaScriptCore/b3/air/AirInst.h
r192841 r194331 99 99 } 100 100 101 typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type );101 typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type, Arg::Width); 102 102 103 // Calls the functor with (arg, role, type ). This function is auto-generated by103 // Calls the functor with (arg, role, type, width). This function is auto-generated by 104 104 // opcode_generator.rb. 105 105 template<typename Functor> 106 106 void forEachArg(const Functor&); 107 107 108 // Calls the functor with (tmp, role, type ).108 // Calls the functor with (tmp, role, type, width). 109 109 template<typename Functor> 110 110 void forEachTmp(const Functor& functor) 111 111 { 112 112 forEachArg( 113 [&] (Arg& arg, Arg::Role role, Arg::Type type ) {114 arg.forEachTmp(role, type, functor);113 [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) { 114 arg.forEachTmp(role, type, width, functor); 115 115 }); 116 116 } -
trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h
r192841 r194331 56 56 { 57 57 inst.forEachArg( 58 [&] (Arg& arg, Arg::Role role, Arg::Type type ) {58 [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) { 59 59 if (!arg.isStack()) 60 60 return; … … 67 67 // https://bugs.webkit.org/show_bug.cgi?id=151128 68 68 69 functor(stackSlot, role, type );69 functor(stackSlot, role, type, width); 70 70 arg = Arg::stack(stackSlot, arg.offset()); 71 71 }); … … 100 100 { 101 101 forEachTmp( 102 [&] (Tmp& tmpArg, Arg::Role role, Arg::Type argType ) {103 functor(tmpArg, role, argType );102 [&] (Tmp& tmpArg, Arg::Role role, Arg::Type argType, Arg::Width argWidth) { 103 functor(tmpArg, role, argType, argWidth); 104 104 }); 105 105 106 106 auto reportReg = [&] (Reg reg) { 107 functor(Tmp(reg), Arg::Def, reg.isGPR() ? Arg::GP : Arg::FP); 107 Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP; 108 functor(Tmp(reg), Arg::Def, type, Arg::conservativeWidth(type)); 108 109 }; 109 110 -
trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp
r194316 r194331 36 36 #include "AirRegisterPriority.h" 37 37 #include "AirTmpInlines.h" 38 #include "AirTmpWidth.h" 38 39 #include "AirUseCounts.h" 39 40 #include <wtf/ListDump.h> … … 631 632 class ColoringAllocator : public AbstractColoringAllocator<unsigned> { 632 633 public: 633 ColoringAllocator(Code& code, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp)634 ColoringAllocator(Code& code, TmpWidth& tmpWidth, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp) 634 635 : AbstractColoringAllocator<unsigned>(regsInPriorityOrder(type), AbsoluteTmpMapper<type>::lastMachineRegisterIndex(), tmpArraySize(code)) 635 636 , m_code(code) 637 , m_tmpWidth(tmpWidth) 636 638 , m_useCounts(useCounts) 637 639 , m_unspillableTmps(unspillableTmp) … … 647 649 } 648 650 651 // This tells you if a Move will be coalescable if the src and dst end up matching. This method 652 // relies on an analysis that is invalidated by register allocation, so you it's only meaningful to 653 // call this *before* replacing the Tmp's in this Inst with registers or spill slots. 654 bool mayBeCoalescable(const Inst& inst) const 655 { 656 return mayBeCoalescableImpl(inst, &m_tmpWidth); 657 } 658 649 659 bool isUselessMove(const Inst& inst) const 650 660 { 651 return mayBeCoalescable (inst) && inst.args[0].tmp() == inst.args[1].tmp();661 return mayBeCoalescableImpl(inst, nullptr) && inst.args[0].tmp() == inst.args[1].tmp(); 652 662 } 653 663 … … 771 781 inst.forEachTmpWithExtraClobberedRegs( 772 782 nextInst, 773 [&] (const Tmp& arg, Arg::Role role, Arg::Type argType ) {783 [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) { 774 784 if (!Arg::isDef(role) || argType != type) 775 785 return; … … 778 788 // We should not use forEachDefAndExtraClobberedTmp() here since colored Tmps 779 789 // do not need interference edges in our implementation. 780 inst.forEachTmp([&] (Tmp& otherArg, Arg::Role role, Arg::Type argType ) {790 inst.forEachTmp([&] (Tmp& otherArg, Arg::Role role, Arg::Type argType, Arg::Width) { 781 791 if (!Arg::isDef(role) || argType != type) 782 792 return; … … 792 802 Tmp defTmp; 793 803 Tmp useTmp; 794 inst.forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type ) {804 inst.forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type, Arg::Width) { 795 805 if (Arg::isDef(role)) 796 806 defTmp = argTmp; … … 840 850 inst.forEachTmpWithExtraClobberedRegs( 841 851 nextInst, 842 [&] (const Tmp& arg, Arg::Role role, Arg::Type argType ) {852 [&] (const Tmp& arg, Arg::Role role, Arg::Type argType, Arg::Width) { 843 853 if (!Arg::isDef(role) || argType != type) 844 854 return; … … 858 868 } 859 869 860 bool mayBeCoalescable(const Inst& inst) const 870 // Calling this without a tmpWidth will perform a more conservative coalescing analysis that assumes 871 // that Move32's are not coalescable. 872 static bool mayBeCoalescableImpl(const Inst& inst, TmpWidth* tmpWidth) 861 873 { 862 874 switch (type) { … … 864 876 switch (inst.opcode) { 865 877 case Move: 878 case Move32: 866 879 break; 867 880 default: … … 888 901 ASSERT(inst.args[1].type() == type); 889 902 903 // We can coalesce a Move32 so long as either of the following holds: 904 // - The input is already zero-filled. 905 // - The output only cares about the low 32 bits. 906 // 907 // Note that the input property requires an analysis over ZDef's, so it's only valid so long 908 // as the input gets a register. We don't know if the input gets a register, but we do know 909 // that if it doesn't get a register then we will still emit this Move32. 910 if (inst.opcode == Move32) { 911 if (!tmpWidth) 912 return false; 913 914 if (tmpWidth->defWidth(inst.args[0].tmp()) > Arg::Width32 915 && tmpWidth->useWidth(inst.args[1].tmp()) > Arg::Width32) 916 return false; 917 } 918 890 919 return true; 891 920 } … … 1025 1054 1026 1055 Code& m_code; 1056 TmpWidth& m_tmpWidth; 1027 1057 // FIXME: spilling should not type specific. It is only a side effect of using UseCounts. 1028 1058 const UseCounts<Tmp>& m_useCounts; … … 1054 1084 while (true) { 1055 1085 ++m_numIterations; 1056 ColoringAllocator<type> allocator(m_code, m_useCounts, unspillableTmps); 1086 1087 // FIXME: One way to optimize this code is to remove the recomputation inside the fixpoint. 1088 // We need to recompute because spilling adds tmps, but we could just update tmpWidth when we 1089 // add those tmps. Note that one easy way to remove the recomputation is to make any newly 1090 // added Tmps get the same use/def widths that the original Tmp got. But, this may hurt the 1091 // spill code we emit. Since we currently recompute TmpWidth after spilling, the newly 1092 // created Tmps may get narrower use/def widths. On the other hand, the spiller already 1093 // selects which move instruction to use based on the original Tmp's widths, so it may not 1094 // matter than a subsequent iteration sees a coservative width for the new Tmps. Also, the 1095 // recomputation may not actually be a performance problem; it's likely that a better way to 1096 // improve performance of TmpWidth is to replace its HashMap with something else. It's 1097 // possible that most of the TmpWidth overhead is from queries of TmpWidth rather than the 1098 // recomputation, in which case speeding up the lookup would be a bigger win. 1099 // https://bugs.webkit.org/show_bug.cgi?id=152478 1100 m_tmpWidth.recompute(m_code); 1101 1102 ColoringAllocator<type> allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps); 1057 1103 if (!allocator.requiresSpilling()) { 1058 1104 assignRegistersToTmp(allocator); … … 1070 1116 for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) { 1071 1117 Inst& inst = block->at(instIndex); 1118 1119 // The mayBeCoalescable() method will change its mind for some operations after we 1120 // complete register allocation. So, we record this before starting. 1121 bool mayBeCoalescable = allocator.mayBeCoalescable(inst); 1122 1123 // On X86_64, Move32 is cheaper if we know that it's equivalent to a Move. It's 1124 // equivalent if the destination's high bits are not observable or if the source's high 1125 // bits are all zero. Note that we don't have the opposite optimization for other 1126 // architectures, which may prefer Move over Move32, because Move is canonical already. 1127 if (type == Arg::GP && optimizeForX86_64() && inst.opcode == Move 1128 && inst.args[0].isTmp() && inst.args[1].isTmp()) { 1129 if (m_tmpWidth.useWidth(inst.args[1].tmp()) <= Arg::Width32 1130 || m_tmpWidth.defWidth(inst.args[0].tmp()) <= Arg::Width32) 1131 inst.opcode = Move32; 1132 } 1133 1072 1134 inst.forEachTmpFast([&] (Tmp& tmp) { 1073 1135 if (tmp.isReg() || tmp.isGP() == (type != Arg::GP)) … … 1086 1148 tmp = assignedTmp; 1087 1149 }); 1150 1151 if (mayBeCoalescable && inst.args[0].isTmp() && inst.args[1].isTmp() 1152 && inst.args[0].tmp() == inst.args[1].tmp()) 1153 inst = Inst(); 1088 1154 } 1089 1155 1090 1156 // Remove all the useless moves we created in this block. 1091 1157 block->insts().removeAllMatching([&] (const Inst& inst) { 1092 return allocator.isUselessMove(inst);1158 return !inst; 1093 1159 }); 1094 1160 } … … 1104 1170 1105 1171 // Allocate stack slot for each spilled value. 1106 bool isNewTmp = stackSlots.add(tmp, m_code.addStackSlot(8, StackSlotKind::Anonymous)).isNewEntry; 1172 StackSlot* stackSlot = m_code.addStackSlot( 1173 m_tmpWidth.width(tmp) <= Arg::Width32 ? 4 : 8, StackSlotKind::Anonymous); 1174 bool isNewTmp = stackSlots.add(tmp, stackSlot).isNewEntry; 1107 1175 ASSERT_UNUSED(isNewTmp, isNewTmp); 1108 1176 } … … 1115 1183 for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) { 1116 1184 Inst& inst = block->at(instIndex); 1185 1186 // The TmpWidth analysis will say that a Move only stores 32 bits into the destination, 1187 // if the source only had 32 bits worth of non-zero bits. Same for the source: it will 1188 // only claim to read 32 bits from the source if only 32 bits of the destination are 1189 // read. Note that we only apply this logic if this turns into a load or store, since 1190 // Move is the canonical way to move data between GPRs. 1191 bool forceMove32IfDidSpill = false; 1192 bool didSpill = false; 1193 if (type == Arg::GP && inst.opcode == Move) { 1194 if (m_tmpWidth.defWidth(inst.args[0].tmp()) <= Arg::Width32 1195 || m_tmpWidth.useWidth(inst.args[1].tmp()) <= Arg::Width32) 1196 forceMove32IfDidSpill = true; 1197 } 1117 1198 1118 1199 // Try to replace the register use by memory use when possible. … … 1121 1202 if (arg.isTmp() && arg.type() == type && !arg.isReg()) { 1122 1203 auto stackSlotEntry = stackSlots.find(arg.tmp()); 1123 if (stackSlotEntry != stackSlots.end() && inst.admitsStack(i)) 1204 if (stackSlotEntry != stackSlots.end() && inst.admitsStack(i)) { 1124 1205 arg = Arg::stack(stackSlotEntry->value); 1206 didSpill = true; 1207 } 1125 1208 } 1126 1209 } 1127 1210 1211 if (didSpill && forceMove32IfDidSpill) 1212 inst.opcode = Move32; 1213 1128 1214 // For every other case, add Load/Store as needed. 1129 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type argType ) {1215 inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type argType, Arg::Width) { 1130 1216 if (tmp.isReg() || argType != type) 1131 1217 return; … … 1142 1228 1143 1229 Arg arg = Arg::stack(stackSlotEntry->value); 1144 Opcode move = type == Arg::GP ? Move : MoveDouble; 1230 Opcode move = Oops; 1231 switch (stackSlotEntry->value->byteSize()) { 1232 case 4: 1233 move = type == Arg::GP ? Move32 : MoveFloat; 1234 break; 1235 case 8: 1236 move = type == Arg::GP ? Move : MoveDouble; 1237 break; 1238 default: 1239 RELEASE_ASSERT_NOT_REACHED(); 1240 break; 1241 } 1145 1242 1146 1243 if (Arg::isAnyUse(role)) { … … 1167 1264 1168 1265 Code& m_code; 1266 TmpWidth m_tmpWidth; 1169 1267 UseCounts<Tmp> m_useCounts; 1170 1268 unsigned m_numIterations { 0 }; -
trunk/Source/JavaScriptCore/b3/air/AirLiveness.h
r192863 r194331 91 91 92 92 block->last().forEach<typename Adapter::Thing>( 93 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type ) {93 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) { 94 94 if (Arg::isLateUse(role) && Adapter::acceptsType(type)) 95 95 liveAtTail.add(Adapter::valueToIndex(thing)); … … 217 217 // First handle def's. 218 218 inst.forEach<typename Adapter::Thing>( 219 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type ) {219 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) { 220 220 if (Arg::isDef(role) && Adapter::acceptsType(type)) 221 221 workset.remove(Adapter::valueToIndex(thing)); … … 224 224 // Then handle use's. 225 225 inst.forEach<typename Adapter::Thing>( 226 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type ) {226 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) { 227 227 if (Arg::isEarlyUse(role) && Adapter::acceptsType(type)) 228 228 workset.add(Adapter::valueToIndex(thing)); … … 233 233 Inst& prevInst = m_block->at(instIndex - 1); 234 234 prevInst.forEach<typename Adapter::Thing>( 235 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type ) {235 [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) { 236 236 if (Arg::isLateUse(role) && Adapter::acceptsType(type)) 237 237 workset.add(Adapter::valueToIndex(thing)); -
trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
r194320 r194331 24 24 # Syllabus: 25 25 # 26 # Roles and types: 27 # U:G => use of a general-purpose register or value 28 # D:G => def of a general-purpose register or value 29 # UD:G => use and def of a general-purpose register or value 30 # UA:G => UseAddr (see comment in Arg.h) 31 # U:F => use of a float register or value 32 # D:F => def of a float register or value 33 # UD:F => use and def of a float register or value 26 # Examples of some roles, types, and widths: 27 # U:G:32 => use of the low 32 bits of a general-purpose register or value 28 # D:G:32 => def of the low 32 bits of a general-purpose register or value 29 # UD:G:32 => use and def of the low 32 bits of a general-purpose register or value 30 # U:G:64 => use of the low 64 bits of a general-purpose register or value 31 # ZD:G:32 => def of all bits of a general-purpose register, where all but the low 32 bits are guaranteed to be zeroed. 32 # UA:G:Ptr => UseAddr (see comment in Arg.h) 33 # U:F:32 => use of a float register or value 34 # U:F:64 => use of a double register or value 35 # D:F:32 => def of a float register or value 36 # UD:F:32 => use and def of a float register or value 34 37 # 35 38 # Argument kinds: … … 45 48 # even newlines are meaningful to the parser. For example, you could write: 46 49 # 47 # Foo42 U:G , UD:FImm, Tmp Addr, Tmp50 # Foo42 U:G:32, UD:F:32 Imm, Tmp Addr, Tmp 48 51 # 49 52 # And the parser would know that this is the same as: 50 53 # 51 # Foo42 U:G , UD:F54 # Foo42 U:G:32, UD:F:32 52 55 # Imm, Tmp 53 56 # Addr, Tmp … … 59 62 # opcode only available on x86_64: 60 63 # 61 # x86_64: Fuzz UD:G , D:G64 # x86_64: Fuzz UD:G:64, D:G:64 62 65 # Tmp, Tmp 63 66 # Tmp, Addr … … 65 68 # But this only restricts the two-operand form, the other form is allowed on all architectures: 66 69 # 67 # x86_64: Fuzz UD:G , D:G70 # x86_64: Fuzz UD:G:64, D:G:64 68 71 # Tmp, Tmp 69 72 # Tmp, Addr 70 # Fuzz UD:G , D:G, U:F73 # Fuzz UD:G:Ptr, D:G:Ptr, U:F:Ptr 71 74 # Tmp, Tmp, Tmp 72 75 # Tmp, Addr, Tmp … … 74 77 # And you can also restrict individual forms: 75 78 # 76 # Thingy UD:G , D:G79 # Thingy UD:G:32, D:G:32 77 80 # Tmp, Tmp 78 81 # arm64: Tmp, Addr … … 82 85 # versions are available on armv7 or x86_64: 83 86 # 84 # x86_64 armv7: Buzz U:G , UD:F87 # x86_64 armv7: Buzz U:G:32, UD:F:32 85 88 # Tmp, Tmp 86 89 # Imm, Tmp … … 104 107 Nop 105 108 106 Add32 U:G , UD:G107 Tmp, Tmp 108 x86: Imm, Addr 109 Imm, Tmp 110 x86: Addr, Tmp 111 x86: Tmp, Addr 112 113 Add32 U:G , U:G, D:G109 Add32 U:G:32, UZD:G:32 110 Tmp, Tmp 111 x86: Imm, Addr 112 Imm, Tmp 113 x86: Addr, Tmp 114 x86: Tmp, Addr 115 116 Add32 U:G:32, U:G:32, ZD:G:32 114 117 Imm, Tmp, Tmp 115 118 Tmp, Tmp, Tmp 116 119 117 64: Add64 U:G , UD:G118 Tmp, Tmp 119 x86: Imm, Addr 120 Imm, Tmp 121 x86: Addr, Tmp 122 x86: Tmp, Addr 123 124 64: Add64 U:G , U:G, D:G120 64: Add64 U:G:64, UD:G:64 121 Tmp, Tmp 122 x86: Imm, Addr 123 Imm, Tmp 124 x86: Addr, Tmp 125 x86: Tmp, Addr 126 127 64: Add64 U:G:64, U:G:64, D:G:64 125 128 Imm, Tmp, Tmp 126 129 Tmp, Tmp, Tmp 127 130 128 AddDouble U:F , UD:F129 Tmp, Tmp 130 x86: Addr, Tmp 131 132 AddFloat U:F , UD:F133 Tmp, Tmp 134 x86: Addr, Tmp 135 136 Sub32 U:G , UD:G137 Tmp, Tmp 138 x86: Imm, Addr 139 Imm, Tmp 140 x86: Addr, Tmp 141 x86: Tmp, Addr 142 143 64: Sub64 U:G , UD:G144 Tmp, Tmp 145 x86: Imm, Addr 146 Imm, Tmp 147 x86: Addr, Tmp 148 x86: Tmp, Addr 149 150 SubDouble U:F , UD:F151 Tmp, Tmp 152 x86: Addr, Tmp 153 154 SubFloat U:F , UD:F155 Tmp, Tmp 156 x86: Addr, Tmp 157 158 Neg32 U D:G131 AddDouble U:F:64, UD:F:64 132 Tmp, Tmp 133 x86: Addr, Tmp 134 135 AddFloat U:F:32, UD:F:32 136 Tmp, Tmp 137 x86: Addr, Tmp 138 139 Sub32 U:G:32, UZD:G:32 140 Tmp, Tmp 141 x86: Imm, Addr 142 Imm, Tmp 143 x86: Addr, Tmp 144 x86: Tmp, Addr 145 146 64: Sub64 U:G:64, UD:G:64 147 Tmp, Tmp 148 x86: Imm, Addr 149 Imm, Tmp 150 x86: Addr, Tmp 151 x86: Tmp, Addr 152 153 SubDouble U:F:64, UD:F:64 154 Tmp, Tmp 155 x86: Addr, Tmp 156 157 SubFloat U:F:32, UD:F:32 158 Tmp, Tmp 159 x86: Addr, Tmp 160 161 Neg32 UZD:G:32 159 162 Tmp 160 163 Addr 161 164 162 64: Neg64 UD:G 165 64: Neg64 UD:G:64 163 166 Tmp 164 167 165 Mul32 U:G , UD:G166 Tmp, Tmp 167 x86: Addr, Tmp 168 169 Mul32 U:G , U:G, D:G168 Mul32 U:G:32, UZD:G:32 169 Tmp, Tmp 170 x86: Addr, Tmp 171 172 Mul32 U:G:32, U:G:32, ZD:G:32 170 173 Imm, Tmp, Tmp 171 174 172 64: Mul64 U:G , UD:G173 Tmp, Tmp 174 175 MulDouble U:F , UD:F176 Tmp, Tmp 177 x86: Addr, Tmp 178 179 MulFloat U:F , UD:F180 Tmp, Tmp 181 x86: Addr, Tmp 182 183 DivDouble U:F , UD:F184 Tmp, Tmp 185 x86: Addr, Tmp 186 187 DivFloat U:F , UD:F188 Tmp, Tmp 189 x86: Addr, Tmp 190 191 x86: X86ConvertToDoubleWord32 U:G , D:G175 64: Mul64 U:G:64, UD:G:64 176 Tmp, Tmp 177 178 MulDouble U:F:64, UD:F:64 179 Tmp, Tmp 180 x86: Addr, Tmp 181 182 MulFloat U:F:32, UD:F:32 183 Tmp, Tmp 184 x86: Addr, Tmp 185 186 DivDouble U:F:32, UD:F:32 187 Tmp, Tmp 188 x86: Addr, Tmp 189 190 DivFloat U:F:32, UD:F:32 191 Tmp, Tmp 192 x86: Addr, Tmp 193 194 x86: X86ConvertToDoubleWord32 U:G:32, ZD:G:32 192 195 Tmp*, Tmp* 193 196 194 x86_64: X86ConvertToQuadWord64 U:G , D:G197 x86_64: X86ConvertToQuadWord64 U:G:64, D:G:64 195 198 Tmp*, Tmp* 196 199 197 x86: X86Div32 U D:G, UD:G, U:G200 x86: X86Div32 UZD:G:32, UZD:G:32, U:G:32 198 201 Tmp*, Tmp*, Tmp 199 202 200 x86_64: X86Div64 U D:G, UD:G, U:G203 x86_64: X86Div64 UZD:G:64, UZD:G:64, U:G:64 201 204 Tmp*, Tmp*, Tmp 202 205 203 Lea UA:G , D:G204 Addr, Tmp 205 206 And32 U:G , UD:G207 Tmp, Tmp 208 Imm, Tmp 209 x86: Tmp, Addr 210 x86: Addr, Tmp 211 x86: Imm, Addr 212 213 64: And64 U:G , UD:G214 Tmp, Tmp 215 Imm, Tmp 216 217 AndDouble U:F , UD:F218 Tmp, Tmp 219 220 AndFloat U:F , UD:F221 Tmp, Tmp 222 223 Lshift32 U:G , UD:G206 Lea UA:G:Ptr, D:G:Ptr 207 Addr, Tmp 208 209 And32 U:G:32, UZD:G:32 210 Tmp, Tmp 211 Imm, Tmp 212 x86: Tmp, Addr 213 x86: Addr, Tmp 214 x86: Imm, Addr 215 216 64: And64 U:G:64, UD:G:64 217 Tmp, Tmp 218 Imm, Tmp 219 220 AndDouble U:F:64, UD:F:64 221 Tmp, Tmp 222 223 AndFloat U:F:32, UD:F:32 224 Tmp, Tmp 225 226 Lshift32 U:G:32, UZD:G:32 224 227 Tmp*, Tmp 225 228 Imm, Tmp 226 229 227 64: Lshift64 U:G , UD:G230 64: Lshift64 U:G:64, UD:G:64 228 231 Tmp*, Tmp 229 232 Imm, Tmp 230 233 231 Rshift32 U:G , UD:G234 Rshift32 U:G:32, UZD:G:32 232 235 Tmp*, Tmp 233 236 Imm, Tmp 234 237 235 64: Rshift64 U:G , UD:G238 64: Rshift64 U:G:64, UD:G:64 236 239 Tmp*, Tmp 237 240 Imm, Tmp 238 241 239 Urshift32 U:G , UD:G242 Urshift32 U:G:32, UZD:G:32 240 243 Tmp*, Tmp 241 244 Imm, Tmp 242 245 243 64: Urshift64 U:G , UD:G246 64: Urshift64 U:G:64, UD:G:64 244 247 Tmp*, Tmp 245 248 Imm, Tmp 246 249 247 Or32 U:G , UD:G248 Tmp, Tmp 249 Imm, Tmp 250 x86: Tmp, Addr 251 x86: Addr, Tmp 252 x86: Imm, Addr 253 254 64: Or64 U:G , UD:G255 Tmp, Tmp 256 Imm, Tmp 257 258 Xor32 U:G , UD:G259 Tmp, Tmp 260 Imm, Tmp 261 x86: Tmp, Addr 262 x86: Addr, Tmp 263 x86: Imm, Addr 264 265 64: Xor64 U:G , UD:G266 Tmp, Tmp 267 x86: Tmp, Addr 268 Imm, Tmp 269 270 Not32 U D:G250 Or32 U:G:32, UZD:G:32 251 Tmp, Tmp 252 Imm, Tmp 253 x86: Tmp, Addr 254 x86: Addr, Tmp 255 x86: Imm, Addr 256 257 64: Or64 U:G:64, UD:G:64 258 Tmp, Tmp 259 Imm, Tmp 260 261 Xor32 U:G:32, UZD:G:32 262 Tmp, Tmp 263 Imm, Tmp 264 x86: Tmp, Addr 265 x86: Addr, Tmp 266 x86: Imm, Addr 267 268 64: Xor64 U:G:64, UD:G:64 269 Tmp, Tmp 270 x86: Tmp, Addr 271 Imm, Tmp 272 273 Not32 UZD:G:32 271 274 Tmp 272 275 x86: Addr 273 276 274 64: Not64 UD:G 277 64: Not64 UD:G:64 275 278 Tmp 276 279 x86: Addr 277 280 278 CeilDouble U:F , UD:F279 Tmp, Tmp 280 Addr, Tmp 281 282 CeilFloat U:F , UD:F283 Tmp, Tmp 284 Addr, Tmp 285 286 SqrtDouble U:F , UD:F287 Tmp, Tmp 288 x86: Addr, Tmp 289 290 SqrtFloat U:F , UD:F291 Tmp, Tmp 292 x86: Addr, Tmp 293 294 ConvertInt32ToDouble U:G , D:F295 Tmp, Tmp 296 x86: Addr, Tmp 297 298 64: ConvertInt64ToDouble U:G , D:F299 Tmp, Tmp 300 301 CountLeadingZeros32 U:G , D:G302 Tmp, Tmp 303 x86: Addr, Tmp 304 305 64: CountLeadingZeros64 U:G , D:G306 Tmp, Tmp 307 x86: Addr, Tmp 308 309 ConvertDoubleToFloat U:F , D:F310 Tmp, Tmp 311 x86: Addr, Tmp 312 313 ConvertFloatToDouble U:F , D:F281 CeilDouble U:F:64, UD:F:64 282 Tmp, Tmp 283 Addr, Tmp 284 285 CeilFloat U:F:32, UD:F:32 286 Tmp, Tmp 287 Addr, Tmp 288 289 SqrtDouble U:F:64, UD:F:64 290 Tmp, Tmp 291 x86: Addr, Tmp 292 293 SqrtFloat U:F:32, UD:F:32 294 Tmp, Tmp 295 x86: Addr, Tmp 296 297 ConvertInt32ToDouble U:G:32, D:F:64 298 Tmp, Tmp 299 x86: Addr, Tmp 300 301 64: ConvertInt64ToDouble U:G:64, D:F:64 302 Tmp, Tmp 303 304 CountLeadingZeros32 U:G:32, ZD:G:32 305 Tmp, Tmp 306 x86: Addr, Tmp 307 308 64: CountLeadingZeros64 U:G:64, D:G:64 309 Tmp, Tmp 310 x86: Addr, Tmp 311 312 ConvertDoubleToFloat U:F:64, D:F:32 313 Tmp, Tmp 314 x86: Addr, Tmp 315 316 ConvertFloatToDouble U:F:32, D:F:64 314 317 Tmp, Tmp 315 318 x86: Addr, Tmp … … 319 322 # Move64 instruction. OTOH, our MacroAssemblers already have this notion of "move()" that basically 320 323 # means movePtr. 321 Move U:G , D:G324 Move U:G:Ptr, D:G:Ptr 322 325 Tmp, Tmp 323 326 Imm, Tmp as signExtend32ToPtr … … 329 332 Imm, Addr as storePtr 330 333 331 Move32 U:G , D:G334 Move32 U:G:32, ZD:G:32 332 335 Tmp, Tmp as zeroExtend32ToPtr 333 336 Addr, Tmp as load32 … … 338 341 Imm, Index as store32 339 342 340 SignExtend32ToPtr U:G , D:G341 Tmp, Tmp 342 343 ZeroExtend8To32 U:G , D:G343 SignExtend32ToPtr U:G:32, D:G:Ptr 344 Tmp, Tmp 345 346 ZeroExtend8To32 U:G:8, ZD:G:32 344 347 Tmp, Tmp 345 348 Addr, Tmp as load8 346 349 Index, Tmp as load8 347 350 348 SignExtend8To32 U:G , D:G351 SignExtend8To32 U:G:8, ZD:G:32 349 352 Tmp, Tmp 350 353 x86: Addr, Tmp as load8SignedExtendTo32 351 354 Index, Tmp as load8SignedExtendTo32 352 355 353 ZeroExtend16To32 U:G , D:G356 ZeroExtend16To32 U:G:16, ZD:G:32 354 357 Tmp, Tmp 355 358 Addr, Tmp as load16 356 359 Index, Tmp as load16 357 360 358 SignExtend16To32 U:G , D:G361 SignExtend16To32 U:G:16, ZD:G:32 359 362 Tmp, Tmp 360 363 Addr, Tmp as load16SignedExtendTo32 361 364 Index, Tmp as load16SignedExtendTo32 362 365 363 MoveFloat U:F , D:F366 MoveFloat U:F:32, D:F:32 364 367 Tmp, Tmp as moveDouble 365 368 Addr, Tmp as loadFloat … … 368 371 Tmp, Index as storeFloat 369 372 370 MoveDouble U:F , D:F373 MoveDouble U:F:64, D:F:64 371 374 Tmp, Tmp 372 375 Addr, Tmp as loadDouble … … 375 378 Tmp, Index as storeDouble 376 379 377 MoveZeroToDouble D:F 380 MoveZeroToDouble D:F:64 378 381 Tmp 379 382 380 64: Move64ToDouble U:G , D:F383 64: Move64ToDouble U:G:64, D:F:64 381 384 Tmp, Tmp 382 385 Addr, Tmp as loadDouble 383 386 Index, Tmp as loadDouble 384 387 385 MoveInt32ToPacked U:G , D:F388 MoveInt32ToPacked U:G:32, D:F:32 386 389 Tmp, Tmp 387 390 Addr, Tmp as loadFloat 388 391 Index, Tmp as loadFloat 389 392 390 64: MoveDoubleTo64 U:F , D:G393 64: MoveDoubleTo64 U:F:64, D:G:64 391 394 Tmp, Tmp 392 395 Addr, Tmp as load64 393 396 Index, Tmp as load64 394 397 395 MovePackedToInt32 U:F , D:G398 MovePackedToInt32 U:F:32, D:G:32 396 399 Tmp, Tmp 397 400 Addr, Tmp as load32 398 401 Index, Tmp as load32 399 402 400 Load8 U:G , D:G403 Load8 U:G:8, ZD:G:32 401 404 Addr, Tmp 402 405 Index, Tmp 403 406 404 Store8 U:G , D:G407 Store8 U:G:8, D:G:8 405 408 Tmp, Index 406 409 Tmp, Addr … … 408 411 Imm, Addr 409 412 410 Load8SignedExtendTo32 U:G , D:G413 Load8SignedExtendTo32 U:G:8, ZD:G:32 411 414 Addr, Tmp 412 415 Index, Tmp 413 416 414 Load16 U:G , D:G417 Load16 U:G:16, ZD:G:32 415 418 Addr, Tmp 416 419 Index, Tmp 417 420 418 Load16SignedExtendTo32 U:G , D:G421 Load16SignedExtendTo32 U:G:16, ZD:G:32 419 422 Addr, Tmp 420 423 Index, Tmp 421 424 422 Compare32 U:G , U:G, U:G, D:G425 Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32 423 426 RelCond, Tmp, Tmp, Tmp 424 427 RelCond, Tmp, Imm, Tmp 425 428 426 64: Compare64 U:G , U:G, U:G, D:G429 64: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32 427 430 RelCond, Tmp, Imm, Tmp 428 431 RelCond, Tmp, Tmp, Tmp 429 432 430 Test32 U:G , U:G, U:G, D:G433 Test32 U:G:32, U:G:32, U:G:32, ZD:G:32 431 434 x86: ResCond, Addr, Imm, Tmp 432 435 ResCond, Tmp, Tmp, Tmp 433 436 434 64: Test64 U:G , U:G, U:G, D:G437 64: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32 435 438 ResCond, Tmp, Imm, Tmp 436 439 ResCond, Tmp, Tmp, Tmp 437 440 438 CompareDouble U:G , U:F, U:F, D:G441 CompareDouble U:G:32, U:F:64, U:F:64, ZD:G:32 439 442 DoubleCond, Tmp, Tmp, Tmp 440 443 441 CompareFloat U:G , U:F, U:F, D:G444 CompareFloat U:G:32, U:F:32, U:F:32, ZD:G:32 442 445 DoubleCond, Tmp, Tmp, Tmp 443 446 … … 445 448 # you opt them into the block order optimizations. 446 449 447 Branch8 U:G , U:G, U:G/branch450 Branch8 U:G:32, U:G:8, U:G:8 /branch 448 451 x86: RelCond, Addr, Imm 449 452 x86: RelCond, Index, Imm 450 453 451 Branch32 U:G , U:G, U:G/branch454 Branch32 U:G:32, U:G:32, U:G:32 /branch 452 455 x86: RelCond, Addr, Imm 453 456 RelCond, Tmp, Tmp … … 457 460 x86: RelCond, Index, Imm 458 461 459 64: Branch64 U:G , U:G, U:G/branch462 64: Branch64 U:G:32, U:G:64, U:G:64 /branch 460 463 RelCond, Tmp, Tmp 461 464 x86: RelCond, Tmp, Addr … … 463 466 x86: RelCond, Index, Tmp 464 467 465 BranchTest8 U:G , U:G, U:G/branch468 BranchTest8 U:G:32, U:G:8, U:G:8 /branch 466 469 x86: ResCond, Addr, Imm 467 470 x86: ResCond, Index, Imm 468 471 469 BranchTest32 U:G , U:G, U:G/branch472 BranchTest32 U:G:32, U:G:32, U:G:32 /branch 470 473 ResCond, Tmp, Tmp 471 474 ResCond, Tmp, Imm … … 475 478 # Warning: forms that take an immediate will sign-extend their immediate. You probably want 476 479 # BranchTest32 in most cases where you use an immediate. 477 64: BranchTest64 U:G , U:G, U:G/branch480 64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch 478 481 ResCond, Tmp, Tmp 479 482 ResCond, Tmp, Imm … … 482 485 x86: ResCond, Index, Imm 483 486 484 BranchDouble U:G , U:F, U:F/branch487 BranchDouble U:G:32, U:F:64, U:F:64 /branch 485 488 DoubleCond, Tmp, Tmp 486 489 487 BranchFloat U:G , U:F, U:F/branch490 BranchFloat U:G:32, U:F:32, U:F:32 /branch 488 491 DoubleCond, Tmp, Tmp 489 492 490 BranchAdd32 U:G , U:G, UD:G/branch493 BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch 491 494 ResCond, Tmp, Tmp 492 495 ResCond, Imm, Tmp … … 495 498 x86: ResCond, Addr, Tmp 496 499 497 64: BranchAdd64 U:G , U:G, UD:G/branch500 64: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch 498 501 ResCond, Imm, Tmp 499 502 ResCond, Tmp, Tmp 500 503 501 BranchMul32 U:G , U:G, UD:G/branch504 BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch 502 505 ResCond, Tmp, Tmp 503 506 x86: ResCond, Addr, Tmp 504 507 505 BranchMul32 U:G , U:G, U:G, D:G/branch508 BranchMul32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch 506 509 ResCond, Tmp, Imm, Tmp 507 510 508 64: BranchMul64 U:G , U:G, UD:G/branch509 ResCond, Tmp, Tmp 510 511 BranchSub32 U:G , U:G, UD:G/branch511 64: BranchMul64 U:G:32, U:G:64, UZD:G:64 /branch 512 ResCond, Tmp, Tmp 513 514 BranchSub32 U:G:32, U:G:32, UZD:G:32 /branch 512 515 ResCond, Tmp, Tmp 513 516 ResCond, Imm, Tmp … … 516 519 x86: ResCond, Addr, Tmp 517 520 518 64: BranchSub64 U:G , U:G, UD:G/branch521 64: BranchSub64 U:G:32, U:G:64, UD:G:64 /branch 519 522 ResCond, Imm, Tmp 520 523 ResCond, Tmp, Tmp 521 524 522 BranchNeg32 U:G , UD:G/branch525 BranchNeg32 U:G:32, UZD:G:32 /branch 523 526 ResCond, Tmp 524 527 525 64: BranchNeg64 U:G , UD:G/branch528 64: BranchNeg64 U:G:32, UZD:G:64 /branch 526 529 ResCond, Tmp 527 530 528 MoveConditionally32 U:G , U:G, U:G, U:G, UD:G531 MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr 529 532 RelCond, Tmp, Tmp, Tmp, Tmp 530 533 531 64: MoveConditionally64 U:G , U:G, U:G, U:G, UD:G534 64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr 532 535 RelCond, Tmp, Tmp, Tmp, Tmp 533 536 534 MoveConditionallyTest32 U:G , U:G, U:G, U:G, UD:G537 MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr 535 538 ResCond, Tmp, Tmp, Tmp, Tmp 536 539 ResCond, Tmp, Imm, Tmp, Tmp 537 540 538 64: MoveConditionallyTest64 U:G , U:G, U:G, U:G, UD:G541 64: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr 539 542 ResCond, Tmp, Tmp, Tmp, Tmp 540 543 ResCond, Tmp, Imm, Tmp, Tmp 541 544 542 MoveConditionallyDouble U:G , U:F, U:F, U:G, UD:G545 MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr 543 546 DoubleCond, Tmp, Tmp, Tmp, Tmp 544 547 545 MoveConditionallyFloat U:G , U:F, U:F, U:G, UD:G548 MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr 546 549 DoubleCond, Tmp, Tmp, Tmp, Tmp 547 550 548 MoveDoubleConditionally32 U:G , U:G, U:G, U:F, UD:F551 MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64 549 552 RelCond, Tmp, Tmp, Tmp, Tmp 550 553 551 64: MoveDoubleConditionally64 U:G , U:G, U:G, U:F, UD:F554 64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64 552 555 RelCond, Tmp, Tmp, Tmp, Tmp 553 556 554 MoveDoubleConditionallyTest32 U:G , U:G, U:G, U:F, UD:F557 MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64 555 558 ResCond, Tmp, Tmp, Tmp, Tmp 556 559 ResCond, Tmp, Imm, Tmp, Tmp 557 560 558 64: MoveDoubleConditionallyTest64 U:G , U:G, U:G, U:F, UD:F561 64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64 559 562 ResCond, Tmp, Tmp, Tmp, Tmp 560 563 ResCond, Tmp, Imm, Tmp, Tmp 561 564 562 MoveDoubleConditionallyDouble U:G , U:F, U:F, U:F, UD:F565 MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, UD:F:64 563 566 DoubleCond, Tmp, Tmp, Tmp, Tmp 564 567 565 MoveDoubleConditionallyFloat U:G , U:F, U:F, U:F, UD:F568 MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, UD:F:64 566 569 DoubleCond, Tmp, Tmp, Tmp, Tmp 567 570 -
trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp
r192539 r194331 149 149 case BranchTest32: 150 150 case BranchTest64: 151 case BranchFloat: 151 152 case BranchDouble: 152 153 case BranchAdd32: -
trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp
r192863 r194331 68 68 inst.forEachTmpWithExtraClobberedRegs( 69 69 index < block->size() ? &block->at(index) : nullptr, 70 [®isterSet] (const Tmp& tmp, Arg::Role role, Arg::Type ) {70 [®isterSet] (const Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) { 71 71 if (tmp.isReg() && Arg::isDef(role)) 72 72 registerSet.set(tmp.reg()); … … 120 120 // Now fall back on spilling using separate Move's to load/store the tmp. 121 121 inst.forEachTmp( 122 [&] (Tmp& tmp, Arg::Role role, Arg::Type type ) {122 [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width) { 123 123 if (tmp.isReg()) 124 124 return; … … 141 141 break; 142 142 case Arg::Def: 143 case Arg::ZDef: 143 144 for (Reg reg : regsInPriorityOrder(type)) { 144 145 if (!setAfter.get(reg)) { … … 150 151 break; 151 152 case Arg::UseDef: 153 case Arg::UseZDef: 152 154 case Arg::LateUse: 153 155 for (Reg reg : regsInPriorityOrder(type)) { -
trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h
r192863 r194331 78 78 for (Inst& inst : *block) { 79 79 inst.forEach<Thing>( 80 [&] (Thing& arg, Arg::Role role, Arg::Type ) {80 [&] (Thing& arg, Arg::Role role, Arg::Type, Arg::Width) { 81 81 Counts& counts = m_counts.add(arg, Counts()).iterator->value; 82 82 -
trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb
r194045 r194331 45 45 46 46 class Arg 47 attr_reader :role, :type 48 49 def initialize(role, type )47 attr_reader :role, :type, :width 48 49 def initialize(role, type, width) 50 50 @role = role 51 51 @type = type 52 @width = width 52 53 end 53 54 end … … 174 175 175 176 def isUD(token) 176 token =~ /\A((U)|(D)|(UD)|( UA))\Z/177 token =~ /\A((U)|(D)|(UD)|(ZD)|(UZD)|(UA))\Z/ 177 178 end 178 179 … … 189 190 end 190 191 192 def isWidth(token) 193 token =~ /\A((8)|(16)|(32)|(64)|(Ptr))\Z/ 194 end 195 191 196 def isKeyword(token) 192 isUD(token) or isGF(token) or isKind(token) or isArch(token) or 197 isUD(token) or isGF(token) or isKind(token) or isArch(token) or isWidth(token) or 193 198 token == "special" or token == "as" 194 199 end … … 253 258 result = token.string 254 259 parseError("Expected kind (Imm, Imm64, Tmp, Addr, Index, RelCond, ResCond, or DoubleCond)") unless isKind(result) 260 advance 261 result 262 end 263 264 def consumeWidth 265 result = token.string 266 parseError("Expected width (8, 16, 32, or 64)") unless isWidth(result) 255 267 advance 256 268 result … … 351 363 consume(":") 352 364 type = consumeType 365 consume(":") 366 width = consumeWidth 353 367 354 signature << Arg.new(role, type )368 signature << Arg.new(role, type, width) 355 369 356 370 break unless token == "," … … 607 621 | opcode, overload | 608 622 if opcode.special 609 outp.puts "functor(args[0], Arg::Use, Arg::GP ); // This is basically bogus, but it works f analysesmodel Special as an immediate."623 outp.puts "functor(args[0], Arg::Use, Arg::GP, Arg::pointerWidth()); // This is basically bogus, but it works for analyses that model Special as an immediate." 610 624 outp.puts "args[0].special()->forEachArg(*this, scopedLambda<EachArgCallback>(functor));" 611 625 else 612 626 overload.signature.each_with_index { 613 627 | arg, index | 628 614 629 role = nil 615 630 case arg.role … … 618 633 when "D" 619 634 role = "Def" 635 when "ZD" 636 role = "ZDef" 620 637 when "UD" 621 638 role = "UseDef" 639 when "UZD" 640 role = "UseZDef" 622 641 when "UA" 623 642 role = "UseAddr" … … 625 644 raise 626 645 end 646 647 if arg.width == "Ptr" 648 width = "Arg::pointerWidth()" 649 else 650 width = "Arg::Width#{arg.width}" 651 end 627 652 628 outp.puts "functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P );"653 outp.puts "functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{width});" 629 654 } 630 655 end -
trunk/Source/JavaScriptCore/b3/testb3.cpp
r194320 r194331 6367 6367 value = -1; 6368 6368 CHECK(invoke<int>(*code, &value - 2, 1) == 42); 6369 } 6370 6371 void testCheckTrickyMegaCombo() 6372 { 6373 Procedure proc; 6374 BasicBlock* root = proc.addBlock(); 6375 Value* base = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 6376 Value* index = root->appendNew<Value>( 6377 proc, ZExt32, Origin(), 6378 root->appendNew<Value>( 6379 proc, Add, Origin(), 6380 root->appendNew<Value>( 6381 proc, Trunc, Origin(), 6382 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)), 6383 root->appendNew<Const32Value>(proc, Origin(), 1))); 6384 6385 Value* ptr = root->appendNew<Value>( 6386 proc, Add, Origin(), base, 6387 root->appendNew<Value>( 6388 proc, Shl, Origin(), index, 6389 root->appendNew<Const32Value>(proc, Origin(), 1))); 6390 6391 CheckValue* check = root->appendNew<CheckValue>( 6392 proc, Check, Origin(), 6393 root->appendNew<Value>( 6394 proc, LessThan, Origin(), 6395 root->appendNew<MemoryValue>(proc, Load8S, Origin(), ptr), 6396 root->appendNew<Const32Value>(proc, Origin(), 42))); 6397 check->setGenerator( 6398 [&] (CCallHelpers& jit, const StackmapGenerationParams& params) { 6399 AllowMacroScratchRegisterUsage allowScratch(jit); 6400 CHECK(!params.size()); 6401 6402 // This should always work because a function this simple should never have callee 6403 // saves. 6404 jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); 6405 jit.emitFunctionEpilogue(); 6406 jit.ret(); 6407 }); 6408 root->appendNew<ControlValue>( 6409 proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0)); 6410 6411 auto code = compile(proc); 6412 6413 int8_t value; 6414 value = 42; 6415 CHECK(invoke<int>(*code, &value - 2, 0) == 0); 6416 value = 127; 6417 CHECK(invoke<int>(*code, &value - 2, 0) == 0); 6418 value = 41; 6419 CHECK(invoke<int>(*code, &value - 2, 0) == 42); 6420 value = 0; 6421 CHECK(invoke<int>(*code, &value - 2, 0) == 42); 6422 value = -1; 6423 CHECK(invoke<int>(*code, &value - 2, 0) == 42); 6369 6424 } 6370 6425 … … 9475 9530 RUN(testCheckLessThan()); 9476 9531 RUN(testCheckMegaCombo()); 9532 RUN(testCheckTrickyMegaCombo()); 9477 9533 RUN(testCheckTwoMegaCombos()); 9478 9534 RUN(testCheckTwoNonRedundantMegaCombos()); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
r194314 r194331 4219 4219 for (unsigned i = 1; i < numKids; ++i) { 4220 4220 flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags)); 4221 #if FTL_USES_B3 4222 B3::CheckValue* lengthCheck = m_out.speculateAdd( 4223 length, m_out.load32(kids[i], m_heaps.JSString_length)); 4224 blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin); 4225 length = lengthCheck; 4226 #else // FTL_USES_B3 4221 4227 LValue lengthAndOverflow = m_out.addWithOverflow32( 4222 4228 length, m_out.load32(kids[i], m_heaps.JSString_length)); 4223 4229 speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1)); 4224 4230 length = m_out.extractValue(lengthAndOverflow, 0); 4231 #endif // FTL_USES_B3 4225 4232 } 4226 4233 m_out.store32( -
trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp
r193362 r194331 40 40 jit.pushToSaveImmediateWithoutTouchingRegisters(CCallHelpers::TrustedImm32(index)); 41 41 CCallHelpers::PatchableJump jump = jit.patchableJump(); 42 RefPtr<OSRExitHandle> self = this; 42 43 jit.addLinkTask( 43 [ this, jump] (LinkBuffer& linkBuffer) {44 exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump));44 [self, jump] (LinkBuffer& linkBuffer) { 45 self->exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump)); 45 46 46 47 linkBuffer.link(
Note:
See TracChangeset
for help on using the changeset viewer.